12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
17
Functions to handle space-packed-records and blobs
19
19
A row may be stored in one or more linked blocks.
20
20
The block size is between MI_MIN_BLOCK_LENGTH and MI_MAX_BLOCK_LENGTH.
21
21
Each block is aligned on MI_DYN_ALIGN_SIZE.
32
32
#include <sys/mman.h>
34
34
#include <drizzled/util/test.h>
35
#include <drizzled/error.h>
40
using namespace drizzled;
36
43
/* Enough for comparing if number is zero */
37
44
static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
39
46
static int write_dynamic_record(MI_INFO *info,const unsigned char *record,
41
static int _mi_find_writepos(MI_INFO *info,ulong reclength,my_off_t *filepos,
48
static int _mi_find_writepos(MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
43
static int update_dynamic_record(MI_INFO *info,my_off_t filepos,unsigned char *record,
50
static int update_dynamic_record(MI_INFO *info,internal::my_off_t filepos,unsigned char *record,
45
static int delete_dynamic_record(MI_INFO *info,my_off_t filepos,
52
static int delete_dynamic_record(MI_INFO *info,internal::my_off_t filepos,
46
53
uint32_t second_read);
47
static int _mi_cmp_buffer(File file, const unsigned char *buff, my_off_t filepos,
54
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
50
/* Play it safe; We have a small stack when using threads */
53
#define my_alloca(A) malloc((A))
54
#define my_afree(A) free((A))
56
57
/* Interface function from MI_INFO */
61
61
Create mmaped area for MyISAM handler
72
bool mi_dynmap_file(MI_INFO *info, my_off_t size)
72
bool mi_dynmap_file(MI_INFO *info, internal::my_off_t size)
74
if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
74
if (size > (internal::my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
84
84
upon a write if no physical memory is available.
86
86
info->s->file_map= (unsigned char*)
87
my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
88
info->s->mode==O_RDONLY ? PROT_READ :
89
PROT_READ | PROT_WRITE,
90
MAP_SHARED | MAP_NORESERVE,
87
mmap(NULL, (size_t)(size + MEMMAP_EXTRA_MARGIN),
88
info->s->mode==O_RDONLY ? PROT_READ :
89
PROT_READ | PROT_WRITE,
90
MAP_SHARED | MAP_NORESERVE,
92
92
if (info->s->file_map == (unsigned char*) MAP_FAILED)
94
94
info->s->file_map= NULL;
97
97
/* per krow we should look at removing the following code */
98
#if defined(HAVE_MADVISE) && !defined(TARGET_OS_SOLARIS)
98
#if !defined(TARGET_OS_SOLARIS)
99
99
madvise((char*) info->s->file_map, size, MADV_RANDOM);
101
101
info->s->mmaped_length= size;
116
void mi_remap_file(MI_INFO *info, my_off_t size)
116
void mi_remap_file(MI_INFO *info, internal::my_off_t size)
118
118
if (info->s->file_map)
120
my_munmap((char*) info->s->file_map,
121
(size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
120
munmap((char*) info->s->file_map,
121
(size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
122
122
mi_dynmap_file(info, size);
134
133
Buffer Input buffer
135
134
Count Count of bytes for read
136
135
offset Start position
143
142
size_t mi_mmap_pread(MI_INFO *info, unsigned char *Buffer,
144
size_t Count, my_off_t offset, myf MyFlags)
143
size_t Count, internal::my_off_t offset, myf MyFlags)
146
if (info->s->concurrent_insert)
147
rw_rdlock(&info->s->mmap_lock);
150
146
The following test may fail in the following cases:
151
147
- We failed to remap a memory area (fragmented memory?)
156
152
if (info->s->mmaped_length >= offset + Count)
158
154
memcpy(Buffer, info->s->file_map + offset, Count);
159
if (info->s->concurrent_insert)
160
rw_unlock(&info->s->mmap_lock);
165
if (info->s->concurrent_insert)
166
rw_unlock(&info->s->mmap_lock);
167
159
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
172
164
/* wrapper for my_pread in case if mmap isn't used */
174
166
size_t mi_nommap_pread(MI_INFO *info, unsigned char *Buffer,
175
size_t Count, my_off_t offset, myf MyFlags)
167
size_t Count, internal::my_off_t offset, myf MyFlags)
177
169
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
197
189
size_t mi_mmap_pwrite(MI_INFO *info, const unsigned char *Buffer,
198
size_t Count, my_off_t offset, myf MyFlags)
190
size_t Count, internal::my_off_t offset, myf MyFlags)
200
if (info->s->concurrent_insert)
201
rw_rdlock(&info->s->mmap_lock);
204
194
The following test may fail in the following cases:
210
200
if (info->s->mmaped_length >= offset + Count)
212
memcpy(info->s->file_map + offset, Buffer, Count);
213
if (info->s->concurrent_insert)
214
rw_unlock(&info->s->mmap_lock);
202
memcpy(info->s->file_map + offset, Buffer, Count);
219
207
info->s->nonmmaped_inserts++;
220
if (info->s->concurrent_insert)
221
rw_unlock(&info->s->mmap_lock);
222
208
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
228
214
/* wrapper for my_pwrite in case if mmap isn't used */
230
216
size_t mi_nommap_pwrite(MI_INFO *info, const unsigned char *Buffer,
231
size_t Count, my_off_t offset, myf MyFlags)
217
size_t Count, internal::my_off_t offset, myf MyFlags)
233
219
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
240
226
return (write_dynamic_record(info,info->rec_buff,reclength));
243
int _mi_update_dynamic_record(MI_INFO *info, my_off_t pos, const unsigned char *record)
229
int _mi_update_dynamic_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
245
231
uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
246
232
return (update_dynamic_record(info,pos,info->rec_buff,length));
259
245
#ifdef NOT_USED /* We now support big rows */
260
246
if (reclength > MI_DYN_MAX_ROW_LENGTH)
262
my_errno=HA_ERR_TO_BIG_ROW;
248
errno=HA_ERR_TO_BIG_ROW;
266
if (!(rec_buff=(unsigned char*) my_alloca(reclength)))
252
if (!(rec_buff=(unsigned char*) malloc(reclength)))
268
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
254
errno= HA_ERR_OUT_OF_MEM;
271
257
reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
273
259
assert(reclength2 <= reclength);
274
260
error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
281
int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const unsigned char *record)
267
int _mi_update_blob_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
283
269
unsigned char *rec_buff;
291
277
#ifdef NOT_USED /* We now support big rows */
292
278
if (reclength > MI_DYN_MAX_ROW_LENGTH)
294
my_errno=HA_ERR_TO_BIG_ROW;
280
errno=HA_ERR_TO_BIG_ROW;
298
if (!(rec_buff=(unsigned char*) my_alloca(reclength)))
284
if (!(rec_buff=(unsigned char*) malloc(reclength)))
300
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
286
errno= HA_ERR_OUT_OF_MEM;
303
289
reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
371
357
static int _mi_find_writepos(MI_INFO *info,
372
358
ulong reclength, /* record length */
373
my_off_t *filepos, /* Return file pos */
359
internal::my_off_t *filepos, /* Return file pos */
374
360
ulong *length) /* length of block at filepos */
376
362
MI_BLOCK_INFO block_info;
386
372
if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
389
my_errno=HA_ERR_WRONG_IN_RECORD;
375
errno=HA_ERR_WRONG_IN_RECORD;
392
378
info->s->state.dellink=block_info.next_filepos;
407
393
if (info->state->data_file_length >
408
394
(info->s->base.max_data_file_length - tmp))
410
my_errno=HA_ERR_RECORD_FILE_FULL;
396
errno=HA_ERR_RECORD_FILE_FULL;
413
399
if (tmp > MI_MAX_BLOCK_LENGTH)
491
477
1 error. In this case my_error is set.
494
static int update_backward_delete_link(MI_INFO *info, my_off_t delete_block,
480
static int update_backward_delete_link(MI_INFO *info, internal::my_off_t delete_block,
481
internal::my_off_t filepos)
497
483
MI_BLOCK_INFO block_info;
519
505
/* Delete datarecord from database */
520
506
/* info->rec_cache.seek_not_done is updated in cmp_record */
522
static int delete_dynamic_record(MI_INFO *info, my_off_t filepos,
508
static int delete_dynamic_record(MI_INFO *info, internal::my_off_t filepos,
523
509
uint32_t second_read)
525
511
uint32_t length,b_type;
581
567
/* Write a block to datafile */
583
569
int _mi_write_part_record(MI_INFO *info,
584
my_off_t filepos, /* points at empty block */
570
internal::my_off_t filepos, /* points at empty block */
585
571
ulong length, /* length of block */
586
my_off_t next_filepos,/* Next empty block */
572
internal::my_off_t next_filepos,/* Next empty block */
587
573
unsigned char **record, /* pointer to record ptr */
588
574
ulong *reclength, /* length of *record */
589
575
int *flag) /* *flag == 0 if header */
591
577
ulong head_length,res_length,extra_length,long_block,del_length;
592
578
unsigned char *pos,*record_end;
593
my_off_t next_delete_block;
579
internal::my_off_t next_delete_block;
594
580
unsigned char temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
596
582
next_delete_block=HA_OFFSET_ERROR;
689
675
/* Make a long block for one write */
690
676
record_end= *record+length-head_length;
691
677
del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
692
memcpy(*record - head_length, temp, head_length);
678
memmove(*record - head_length, temp, head_length);
693
679
memcpy(temp,record_end,(size_t) (extra_length+del_length));
694
680
memset(record_end, 0, extra_length);
698
684
/* Check first if we can join this block with the next one */
699
685
MI_BLOCK_INFO del_block;
700
my_off_t next_block=filepos+length+extra_length+res_length;
686
internal::my_off_t next_block=filepos+length+extra_length+res_length;
702
688
del_block.second_read=0;
703
689
if (next_block < info->state->data_file_length &&
731
717
if (info->update & HA_STATE_EXTEND_BLOCK)
733
719
info->update&= ~HA_STATE_EXTEND_BLOCK;
734
if (my_block_write(&info->rec_cache,(unsigned char*) *record-head_length,
720
if (info->rec_cache.block_write(*record - head_length,
735
721
length+extra_length+del_length,filepos))
738
else if (my_b_write(&info->rec_cache,(unsigned char*) *record-head_length,
739
length+extra_length+del_length))
724
else if (info->rec_cache.write(*record-head_length, length+extra_length+del_length))
768
753
/* update record from datafile */
770
static int update_dynamic_record(MI_INFO *info, my_off_t filepos, unsigned char *record,
755
static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
839
824
uint32_t tmp=MY_ALIGN(reclength - length + 3 +
840
825
test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
841
826
/* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
842
tmp= cmin(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
827
tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
843
828
/* Check if we can extend this block */
844
829
if (block_info.filepos + block_info.block_len ==
845
830
info->state->data_file_length &&
877
862
New block was too big, link overflow part back to
865
internal::my_off_t next_pos;
881
866
ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
882
set_if_bigger(rest_length, MI_MIN_BLOCK_LENGTH);
867
set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
883
868
next_pos= del_block.filepos+ del_block.block_len - rest_length;
885
870
if (update_backward_delete_link(info, info->s->state.dellink,
1118
1103
if (rec->length > 255 && new_length > 127)
1120
/* purecov: begin inspected */
1121
1105
if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
1122
1106
to[1] != (unsigned char) (new_length >> 7))
1127
1110
else if (*to++ != (unsigned char) new_length)
1180
1163
/* Unpacks a record */
1181
/* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
1164
/* Returns -1 and errno =HA_ERR_RECORD_DELETED if reclength isn't */
1182
1165
/* right. Returns reclength (>0) if ok */
1184
1167
ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
1404
int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, unsigned char *buf)
1387
int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
1406
1389
int block_of_record;
1407
1390
uint32_t b_type, left_length= 0;
1408
1391
unsigned char *to= NULL;
1409
1392
MI_BLOCK_INFO block_info;
1412
1395
if (filepos != HA_OFFSET_ERROR)
1422
1405
if (info->opt_flag & WRITE_CACHE_USED &&
1423
1406
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1424
flush_io_cache(&info->rec_cache))
1407
info->rec_cache.flush())
1426
1409
info->rec_cache.seek_not_done=1;
1427
1410
if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1503
1486
/* compare unique constraint between stored rows */
1505
1488
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
1506
const unsigned char *record, my_off_t pos)
1489
const unsigned char *record, internal::my_off_t pos)
1508
1491
unsigned char *rec_buff,*old_record;
1511
if (!(old_record=my_alloca(info->s->base.reclength)))
1494
if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
1514
1497
/* Don't let the compare destroy blobs that may be in use */
1535
1517
int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
1537
1519
uint32_t flag,reclength,b_type;
1520
internal::my_off_t filepos;
1539
1521
unsigned char *buffer;
1540
1522
MI_BLOCK_INFO block_info;
1542
1524
if (info->opt_flag & WRITE_CACHE_USED)
1544
1526
info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1545
if (flush_io_cache(&info->rec_cache))
1527
if (info->rec_cache.flush())
1548
1530
info->rec_cache.seek_not_done=1;
1554
1536
{ /* If check isn't disabled */
1555
1537
if (info->s->base.blobs)
1557
if (!(buffer=(unsigned char*) my_alloca(info->s->base.pack_reclength+
1539
if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
1558
1540
_my_calc_total_blob_length(info,record))))
1581
1563
if (reclength != block_info.rec_len)
1583
my_errno=HA_ERR_RECORD_CHANGED;
1565
errno=HA_ERR_RECORD_CHANGED;
1586
1568
} else if (reclength < block_info.data_len)
1588
my_errno=HA_ERR_WRONG_IN_RECORD;
1570
errno=HA_ERR_WRONG_IN_RECORD;
1591
1573
reclength-=block_info.data_len;
1592
1574
if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1593
1575
block_info.data_len))
1595
my_errno=HA_ERR_RECORD_CHANGED;
1577
errno=HA_ERR_RECORD_CHANGED;
1599
1581
record+=block_info.data_len;
1604
1586
if (buffer != info->rec_buff)
1605
my_afree((unsigned char*) buffer);
1587
free((unsigned char*) buffer);
1610
1592
/* Compare file to buffert */
1612
static int _mi_cmp_buffer(File file, const unsigned char *buff, my_off_t filepos,
1594
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
1613
1595
uint32_t length)
1615
1597
uint32_t next_length;
1672
1654
int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
1673
register my_off_t filepos,
1655
register internal::my_off_t filepos,
1674
1656
bool skip_deleted_blocks)
1676
1658
int block_of_record, info_read, save_errno;
1722
1704
if (info->opt_flag & WRITE_CACHE_USED &&
1723
1705
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1724
flush_io_cache(&info->rec_cache))
1706
info->rec_cache.flush())
1726
1708
info->rec_cache.seek_not_done=1;
1727
1709
b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1740
1722
if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1742
my_errno=HA_ERR_RECORD_DELETED;
1724
errno=HA_ERR_RECORD_DELETED;
1743
1725
info->lastpos=block_info.filepos;
1744
1726
info->nextpos=block_info.filepos+block_info.block_len;
1796
1778
if (info->opt_flag & WRITE_CACHE_USED &&
1797
1779
info->rec_cache.pos_in_file <
1798
1780
block_info.filepos + block_info.data_len &&
1799
flush_io_cache(&info->rec_cache))
1781
info->rec_cache.flush())
1801
/* my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0)); */
1802
if (my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1783
/* lseek(info->dfile,filepos,SEEK_SET); */
1784
if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1805
my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1787
errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1826
1808
if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1829
return(my_errno); /* Wrong record */
1811
return(errno); /* Wrong record */
1832
my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1814
errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1834
save_errno=my_errno;
1835
1817
_mi_writeinfo(info,0);
1836
return(my_errno=save_errno);
1818
return(errno=save_errno);
1840
1822
/* Read and process header from a dynamic-record-file */
1842
uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
1824
uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
1844
1826
uint32_t return_val=0;
1845
1827
unsigned char *header=info->header;
1851
1833
pointer set to the end of the header after this function.
1852
1834
my_pread() may leave the file pointer untouched.
1854
my_seek(file,filepos,MY_SEEK_SET,MYF(0));
1855
if (my_read(file, header, sizeof(info->header),MYF(0)) !=
1836
lseek(file,filepos,SEEK_SET);
1837
if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
1856
1838
sizeof(info->header))