1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
Functions to handle space-packed-records and blobs
19
A row may be stored in one or more linked blocks.
20
The block size is between MI_MIN_BLOCK_LENGTH and MI_MAX_BLOCK_LENGTH.
21
Each block is aligned on MI_DYN_ALIGN_SIZE.
22
The reson for the max block size is to not have too many different types
23
of blocks. For the differnet block types, look at _mi_get_block_info()
26
#include "myisam_priv.h"
29
#include <sys/types.h>
31
#ifdef HAVE_SYS_MMAN_H
34
#include <drizzled/util/test.h>
35
#include "drizzled/error.h"
40
using namespace drizzled;
43
/* Enough for comparing if number is zero */
44
static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
46
static int write_dynamic_record(MI_INFO *info,const unsigned char *record,
48
static int _mi_find_writepos(MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
50
static int update_dynamic_record(MI_INFO *info,internal::my_off_t filepos,unsigned char *record,
52
static int delete_dynamic_record(MI_INFO *info,internal::my_off_t filepos,
53
uint32_t second_read);
54
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
57
/* Interface function from MI_INFO */
61
Create mmaped area for MyISAM handler
72
bool mi_dynmap_file(MI_INFO *info, internal::my_off_t size)
74
if (size > (internal::my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
79
I wonder if it is good to use MAP_NORESERVE. From the Linux man page:
81
Do not reserve swap space for this mapping. When swap space is
82
reserved, one has the guarantee that it is possible to modify the
83
mapping. When swap space is not reserved one might get SIGSEGV
84
upon a write if no physical memory is available.
86
info->s->file_map= (unsigned char*)
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
if (info->s->file_map == (unsigned char*) MAP_FAILED)
94
info->s->file_map= NULL;
97
/* per krow we should look at removing the following code */
98
#if !defined(TARGET_OS_SOLARIS)
99
madvise((char*) info->s->file_map, size, MADV_RANDOM);
101
info->s->mmaped_length= size;
107
Resize mmaped area for MyISAM handler
116
void mi_remap_file(MI_INFO *info, internal::my_off_t size)
118
if (info->s->file_map)
120
munmap((char*) info->s->file_map,
121
(size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
122
mi_dynmap_file(info, size);
128
Read bytes from MySAM handler, using mmap or pread
134
Count Count of bytes for read
135
offset Start position
142
size_t mi_mmap_pread(MI_INFO *info, unsigned char *Buffer,
143
size_t Count, internal::my_off_t offset, myf MyFlags)
146
The following test may fail in the following cases:
147
- We failed to remap a memory area (fragmented memory?)
148
- This thread has done some writes, but not yet extended the
152
if (info->s->mmaped_length >= offset + Count)
154
memcpy(Buffer, info->s->file_map + offset, Count);
159
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
164
/* wrapper for my_pread in case if mmap isn't used */
166
size_t mi_nommap_pread(MI_INFO *info, unsigned char *Buffer,
167
size_t Count, internal::my_off_t offset, myf MyFlags)
169
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
174
Write bytes to MySAM handler, using mmap or pwrite
180
Count Count of bytes for write
181
offset Start position
186
!=0 error. In this case return error from pwrite
189
size_t mi_mmap_pwrite(MI_INFO *info, const unsigned char *Buffer,
190
size_t Count, internal::my_off_t offset, myf MyFlags)
194
The following test may fail in the following cases:
195
- We failed to remap a memory area (fragmented memory?)
196
- This thread has done some writes, but not yet extended the
200
if (info->s->mmaped_length >= offset + Count)
202
memcpy(info->s->file_map + offset, Buffer, Count);
207
info->s->nonmmaped_inserts++;
208
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
214
/* wrapper for my_pwrite in case if mmap isn't used */
216
size_t mi_nommap_pwrite(MI_INFO *info, const unsigned char *Buffer,
217
size_t Count, internal::my_off_t offset, myf MyFlags)
219
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
223
int _mi_write_dynamic_record(MI_INFO *info, const unsigned char *record)
225
ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
226
return (write_dynamic_record(info,info->rec_buff,reclength));
229
int _mi_update_dynamic_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
231
uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
232
return (update_dynamic_record(info,pos,info->rec_buff,length));
235
int _mi_write_blob_record(MI_INFO *info, const unsigned char *record)
237
unsigned char *rec_buff;
239
ulong reclength,reclength2,extra;
241
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
242
MI_DYN_DELETE_BLOCK_HEADER+1);
243
reclength= (info->s->base.pack_reclength +
244
_my_calc_total_blob_length(info,record)+ extra);
245
#ifdef NOT_USED /* We now support big rows */
246
if (reclength > MI_DYN_MAX_ROW_LENGTH)
248
errno=HA_ERR_TO_BIG_ROW;
252
if (!(rec_buff=(unsigned char*) malloc(reclength)))
254
errno= HA_ERR_OUT_OF_MEM;
257
reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
259
assert(reclength2 <= reclength);
260
error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
267
int _mi_update_blob_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
269
unsigned char *rec_buff;
271
ulong reclength,extra;
273
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
274
MI_DYN_DELETE_BLOCK_HEADER);
275
reclength= (info->s->base.pack_reclength+
276
_my_calc_total_blob_length(info,record)+ extra);
277
#ifdef NOT_USED /* We now support big rows */
278
if (reclength > MI_DYN_MAX_ROW_LENGTH)
280
errno=HA_ERR_TO_BIG_ROW;
284
if (!(rec_buff=(unsigned char*) malloc(reclength)))
286
errno= HA_ERR_OUT_OF_MEM;
289
reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
291
error=update_dynamic_record(info,pos,
292
rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
299
int _mi_delete_dynamic_record(MI_INFO *info)
301
return delete_dynamic_record(info,info->lastpos,0);
305
/* Write record to data-file */
307
static int write_dynamic_record(MI_INFO *info, const unsigned char *record,
312
internal::my_off_t filepos;
317
Check if we have enough room for the new record.
318
First we do simplified check to make usual case faster.
319
Then we do more precise check for the space left.
320
Though it still is not absolutely precise, as
321
we always use MI_MAX_DYN_BLOCK_HEADER while it can be
322
less in the most of the cases.
325
if (unlikely(info->s->base.max_data_file_length -
326
info->state->data_file_length <
327
reclength + MI_MAX_DYN_BLOCK_HEADER))
329
if (info->s->base.max_data_file_length - info->state->data_file_length +
330
info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
331
reclength + MI_MAX_DYN_BLOCK_HEADER)
333
errno=HA_ERR_RECORD_FILE_FULL;
340
if (_mi_find_writepos(info,reclength,&filepos,&length))
342
if (_mi_write_part_record(info,filepos,length,
343
(info->append_insert_at_end ?
344
HA_OFFSET_ERROR : info->s->state.dellink),
345
(unsigned char**) &record,&reclength,&flag))
355
/* Get a block for data ; The given data-area must be used !! */
357
static int _mi_find_writepos(MI_INFO *info,
358
ulong reclength, /* record length */
359
internal::my_off_t *filepos, /* Return file pos */
360
ulong *length) /* length of block at filepos */
362
MI_BLOCK_INFO block_info;
365
if (info->s->state.dellink != HA_OFFSET_ERROR &&
366
!info->append_insert_at_end)
368
/* Deleted blocks exists; Get last used block */
369
*filepos=info->s->state.dellink;
370
block_info.second_read=0;
371
info->rec_cache.seek_not_done=1;
372
if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
375
errno=HA_ERR_WRONG_IN_RECORD;
378
info->s->state.dellink=block_info.next_filepos;
380
info->state->empty-= block_info.block_len;
381
*length= block_info.block_len;
385
/* No deleted blocks; Allocate a new block */
386
*filepos=info->state->data_file_length;
387
if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
388
info->s->base.min_block_length)
389
tmp= info->s->base.min_block_length;
391
tmp= ((tmp+MI_DYN_ALIGN_SIZE-1) &
392
(~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
393
if (info->state->data_file_length >
394
(info->s->base.max_data_file_length - tmp))
396
errno=HA_ERR_RECORD_FILE_FULL;
399
if (tmp > MI_MAX_BLOCK_LENGTH)
400
tmp=MI_MAX_BLOCK_LENGTH;
402
info->state->data_file_length+= tmp;
403
info->s->state.split++;
404
info->update|=HA_STATE_WRITE_AT_END;
407
} /* _mi_find_writepos */
412
Unlink a deleted block from the deleted list.
413
This block will be combined with the preceding or next block to form
417
static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
419
if (block_info->filepos == info->s->state.dellink)
421
/* First deleted block; We can just use this ! */
422
info->s->state.dellink=block_info->next_filepos;
428
/* Unlink block from the previous block */
429
if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
431
return(1); /* Something is wrong */
432
mi_sizestore(tmp.header+4,block_info->next_filepos);
433
if (info->s->file_write(info, tmp.header+4,8,
434
block_info->prev_filepos+4, MYF(MY_NABP)))
436
/* Unlink block from next block */
437
if (block_info->next_filepos != HA_OFFSET_ERROR)
439
if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
441
return(1); /* Something is wrong */
442
mi_sizestore(tmp.header+12,block_info->prev_filepos);
443
if (info->s->file_write(info, tmp.header+12,8,
444
block_info->next_filepos+12,
449
/* We now have one less deleted block */
451
info->state->empty-= block_info->block_len;
452
info->s->state.split--;
455
If this was a block that we where accessing through table scan
456
(mi_rrnd() or mi_scan(), then ensure that we skip over this block
457
when doing next mi_rrnd() or mi_scan().
459
if (info->nextpos == block_info->filepos)
460
info->nextpos+=block_info->block_len;
466
Add a backward link to delete block
469
update_backward_delete_link()
471
delete_block Position to delete block to update.
472
If this is 'HA_OFFSET_ERROR', nothing will be done
473
filepos Position to block that 'delete_block' should point to
477
1 error. In this case my_error is set.
480
static int update_backward_delete_link(MI_INFO *info, internal::my_off_t delete_block,
481
internal::my_off_t filepos)
483
MI_BLOCK_INFO block_info;
485
if (delete_block != HA_OFFSET_ERROR)
487
block_info.second_read=0;
488
if (_mi_get_block_info(&block_info,info->dfile,delete_block)
491
unsigned char buff[8];
492
mi_sizestore(buff,filepos);
493
if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
494
return(1); /* Error on write */
498
errno=HA_ERR_WRONG_IN_RECORD;
499
return(1); /* Wrong delete link */
505
/* Delete datarecord from database */
506
/* info->rec_cache.seek_not_done is updated in cmp_record */
508
static int delete_dynamic_record(MI_INFO *info, internal::my_off_t filepos,
509
uint32_t second_read)
511
uint32_t length,b_type;
512
MI_BLOCK_INFO block_info,del_block;
514
bool remove_next_block;
516
/* First add a link from the last block to the new one */
517
error= update_backward_delete_link(info, info->s->state.dellink, filepos);
519
block_info.second_read=second_read;
522
/* Remove block at 'filepos' */
523
if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
524
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
525
BLOCK_FATAL_ERROR) ||
526
(length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
529
errno=HA_ERR_WRONG_IN_RECORD;
532
/* Check if next block is a delete block */
533
del_block.second_read=0;
535
if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
536
BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
538
/* We can't remove this yet as this block may be the head block */
540
length+=del_block.block_len;
543
block_info.header[0]=0;
544
mi_int3store(block_info.header+1,length);
545
mi_sizestore(block_info.header+4,info->s->state.dellink);
546
if (b_type & BLOCK_LAST)
547
memset(block_info.header+12, 255, 8);
549
mi_sizestore(block_info.header+12,block_info.next_filepos);
550
if (info->s->file_write(info,(unsigned char*) block_info.header,20,filepos,
553
info->s->state.dellink = filepos;
555
info->state->empty+=length;
556
filepos=block_info.next_filepos;
558
/* Now it's safe to unlink the deleted block directly after this one */
559
if (remove_next_block && unlink_deleted_block(info,&del_block))
561
} while (!(b_type & BLOCK_LAST));
567
/* Write a block to datafile */
569
int _mi_write_part_record(MI_INFO *info,
570
internal::my_off_t filepos, /* points at empty block */
571
ulong length, /* length of block */
572
internal::my_off_t next_filepos,/* Next empty block */
573
unsigned char **record, /* pointer to record ptr */
574
ulong *reclength, /* length of *record */
575
int *flag) /* *flag == 0 if header */
577
ulong head_length,res_length,extra_length,long_block,del_length;
578
unsigned char *pos,*record_end;
579
internal::my_off_t next_delete_block;
580
unsigned char temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
582
next_delete_block=HA_OFFSET_ERROR;
584
res_length=extra_length=0;
585
if (length > *reclength + MI_SPLIT_LENGTH)
586
{ /* Splitt big block */
587
res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
589
length-= res_length; /* Use this for first part */
591
long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
592
if (length == *reclength+ 3 + long_block)
594
/* Block is exactly of the right length */
595
temp[0]=(unsigned char) (1+ *flag)+(unsigned char) long_block; /* Flag is 0 or 6 */
598
mi_int3store(temp+1,*reclength);
603
mi_int2store(temp+1,*reclength);
607
else if (length-long_block < *reclength+4)
608
{ /* To short block */
609
if (next_filepos == HA_OFFSET_ERROR)
610
next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
611
!info->append_insert_at_end ?
612
info->s->state.dellink : info->state->data_file_length);
613
if (*flag == 0) /* First block */
615
if (*reclength > MI_MAX_BLOCK_LENGTH)
619
mi_int4store(temp+1,*reclength);
620
mi_int3store(temp+5,length-head_length);
621
mi_sizestore((unsigned char*) temp+8,next_filepos);
625
head_length=5+8+long_block*2;
626
temp[0]=5+(unsigned char) long_block;
629
mi_int3store(temp+1,*reclength);
630
mi_int3store(temp+4,length-head_length);
631
mi_sizestore((unsigned char*) temp+7,next_filepos);
635
mi_int2store(temp+1,*reclength);
636
mi_int2store(temp+3,length-head_length);
637
mi_sizestore((unsigned char*) temp+5,next_filepos);
643
head_length=3+8+long_block;
644
temp[0]=11+(unsigned char) long_block;
647
mi_int3store(temp+1,length-head_length);
648
mi_sizestore((unsigned char*) temp+4,next_filepos);
652
mi_int2store(temp+1,length-head_length);
653
mi_sizestore((unsigned char*) temp+3,next_filepos);
658
{ /* Block with empty info last */
659
head_length=4+long_block;
660
extra_length= length- *reclength-head_length;
661
temp[0]= (unsigned char) (3+ *flag)+(unsigned char) long_block; /* 3,4 or 9,10 */
664
mi_int3store(temp+1,*reclength);
665
temp[4]= (unsigned char) (extra_length);
669
mi_int2store(temp+1,*reclength);
670
temp[3]= (unsigned char) (extra_length);
672
length= *reclength+head_length; /* Write only what is needed */
675
/* Make a long block for one write */
676
record_end= *record+length-head_length;
677
del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
678
memmove(*record - head_length, temp, head_length);
679
memcpy(temp,record_end,(size_t) (extra_length+del_length));
680
memset(record_end, 0, extra_length);
684
/* Check first if we can join this block with the next one */
685
MI_BLOCK_INFO del_block;
686
internal::my_off_t next_block=filepos+length+extra_length+res_length;
688
del_block.second_read=0;
689
if (next_block < info->state->data_file_length &&
690
info->s->state.dellink != HA_OFFSET_ERROR)
692
if ((_mi_get_block_info(&del_block,info->dfile,next_block)
694
res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
696
if (unlink_deleted_block(info,&del_block))
698
res_length+=del_block.block_len;
702
/* Create a delete link of the last part of the block */
703
pos=record_end+extra_length;
705
mi_int3store(pos+1,res_length);
706
mi_sizestore(pos+4,info->s->state.dellink);
707
memset(pos+12, 255, 8); /* End link */
708
next_delete_block=info->s->state.dellink;
709
info->s->state.dellink= filepos+length+extra_length;
711
info->state->empty+=res_length;
712
info->s->state.split++;
714
if (info->opt_flag & WRITE_CACHE_USED &&
715
info->update & HA_STATE_WRITE_AT_END)
717
if (info->update & HA_STATE_EXTEND_BLOCK)
719
info->update&= ~HA_STATE_EXTEND_BLOCK;
720
if (my_block_write(&info->rec_cache,(unsigned char*) *record-head_length,
721
length+extra_length+del_length,filepos))
724
else if (my_b_write(&info->rec_cache,(unsigned char*) *record-head_length,
725
length+extra_length+del_length))
730
info->rec_cache.seek_not_done=1;
731
if (info->s->file_write(info,(unsigned char*) *record-head_length,length+extra_length+
732
del_length,filepos,info->s->write_flag))
735
memcpy(record_end, temp, extra_length + del_length);
737
*reclength-=(length-head_length);
742
/* link the next delete block to this */
743
if (update_backward_delete_link(info, next_delete_block,
744
info->s->state.dellink))
751
} /*_mi_write_part_record */
754
/* update record from datafile */
756
static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
762
MI_BLOCK_INFO block_info;
764
flag=block_info.second_read=0;
766
Check if we have enough room for the record.
767
First we do simplified check to make usual case faster.
768
Then we do more precise check for the space left.
769
Though it still is not absolutely precise, as
770
we always use MI_MAX_DYN_BLOCK_HEADER while it can be
771
less in the most of the cases.
775
compare with just the reclength as we're going
776
to get some space from the old replaced record
778
if (unlikely(info->s->base.max_data_file_length -
779
info->state->data_file_length < reclength))
782
let's read the old record's block to find out the length of the
785
if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
786
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
788
if (!(error & BLOCK_FATAL_ERROR))
789
errno=HA_ERR_WRONG_IN_RECORD;
794
if new record isn't longer, we can go on safely
796
if (block_info.rec_len < reclength)
798
if (info->s->base.max_data_file_length - info->state->data_file_length +
799
info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
800
reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
802
errno=HA_ERR_RECORD_FILE_FULL;
806
block_info.second_read=0;
809
while (reclength > 0)
811
if (filepos != info->s->state.dellink)
813
block_info.next_filepos= HA_OFFSET_ERROR;
814
if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
815
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
818
if (!(error & BLOCK_FATAL_ERROR))
819
errno=HA_ERR_WRONG_IN_RECORD;
822
length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
823
if (length < reclength)
825
uint32_t tmp=MY_ALIGN(reclength - length + 3 +
826
test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
827
/* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
828
tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
829
/* Check if we can extend this block */
830
if (block_info.filepos + block_info.block_len ==
831
info->state->data_file_length &&
832
info->state->data_file_length <
833
info->s->base.max_data_file_length-tmp)
836
if (info->nextpos == info->state->data_file_length)
838
info->state->data_file_length+= tmp;
839
info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
842
else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
845
Check if next block is a deleted block
846
Above we have MI_MIN_BLOCK_LENGTH to avoid the problem where
847
the next block is so small it can't be splited which could
851
MI_BLOCK_INFO del_block;
852
del_block.second_read=0;
853
if (_mi_get_block_info(&del_block,info->dfile,
854
block_info.filepos + block_info.block_len) &
857
/* Use; Unlink it and extend the current block */
858
if (unlink_deleted_block(info,&del_block))
860
if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
863
New block was too big, link overflow part back to
866
internal::my_off_t next_pos;
867
ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
868
set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
869
next_pos= del_block.filepos+ del_block.block_len - rest_length;
871
if (update_backward_delete_link(info, info->s->state.dellink,
875
/* create delete link for data that didn't fit into the page */
876
del_block.header[0]=0;
877
mi_int3store(del_block.header+1, rest_length);
878
mi_sizestore(del_block.header+4,info->s->state.dellink);
879
memset(del_block.header+12, 255, 8);
880
if (info->s->file_write(info,(unsigned char*) del_block.header,20, next_pos,
883
info->s->state.dellink= next_pos;
884
info->s->state.split++;
886
info->state->empty+= rest_length;
887
length-= rest_length;
895
if (_mi_find_writepos(info,reclength,&filepos,&length))
898
if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
899
&record,&reclength,&flag))
901
if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
903
/* Start writing data on deleted blocks */
904
filepos=info->s->state.dellink;
908
if (block_info.next_filepos != HA_OFFSET_ERROR)
909
if (delete_dynamic_record(info,block_info.next_filepos,1))
917
/* Pack a record. Return new reclength */
919
uint32_t _mi_rec_pack(MI_INFO *info, register unsigned char *to,
920
register const unsigned char *from)
922
uint length,new_length,flag,bit,i;
923
unsigned char *pos,*end,*startpos,*packpos;
924
enum en_fieldtype type;
925
register MI_COLUMNDEF *rec;
929
startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
932
for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
934
length=(uint) rec->length;
935
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
937
if (type == FIELD_BLOB)
944
size_t tmp_length=length-portable_sizeof_char_ptr;
945
memcpy(to,from,tmp_length);
946
memcpy(&temp_pos,from+tmp_length,sizeof(char*));
947
memcpy(to + tmp_length, temp_pos, blob->length);
948
to+=tmp_length+blob->length;
952
else if (type == FIELD_SKIP_ZERO)
954
if (memcmp(from,zero_string,length) == 0)
958
memcpy(to, from, length);
962
else if (type == FIELD_SKIP_ENDSPACE ||
963
type == FIELD_SKIP_PRESPACE)
965
pos= (unsigned char*) from; end= (unsigned char*) from + length;
966
if (type == FIELD_SKIP_ENDSPACE)
967
{ /* Pack trailing spaces */
968
while (end > from && *(end-1) == ' ')
972
{ /* Pack pref-spaces */
973
while (pos < end && *pos == ' ')
976
new_length=(uint) (end-pos);
977
if (new_length +1 + test(rec->length > 255 && new_length > 127)
980
if (rec->length > 255 && new_length > 127)
982
to[0]= (unsigned char) ((new_length & 127) + 128);
983
to[1]= (unsigned char) (new_length >> 7);
987
*to++= (unsigned char) new_length;
988
memcpy(to, pos, new_length);
994
memcpy(to, from, length);
998
else if (type == FIELD_VARCHAR)
1000
uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1001
uint32_t tmp_length;
1002
if (pack_length == 1)
1004
tmp_length= (uint) *(unsigned char*) from;
1009
tmp_length= uint2korr(from);
1010
store_key_length_inc(to,tmp_length);
1012
memcpy(to, from+pack_length, tmp_length);
1018
memcpy(to, from, length);
1020
continue; /* Normal field */
1022
if ((bit= bit << 1) >= 256)
1024
*packpos++= (unsigned char) flag;
1030
memcpy(to, from, length);
1035
*packpos= (unsigned char) flag;
1036
if (info->s->calc_checksum)
1037
*to++= (unsigned char) info->checksum;
1038
return((uint) (to-startpos));
1039
} /* _mi_rec_pack */
1044
Check if a record was correctly packed. Used only by myisamchk
1045
Returns 0 if record is ok.
1048
bool _mi_rec_check(MI_INFO *info,const unsigned char *record, unsigned char *rec_buff,
1049
ulong packed_length, bool with_checksum)
1051
uint length,new_length,flag,bit,i;
1052
unsigned char *pos,*end,*packpos,*to;
1053
enum en_fieldtype type;
1054
register MI_COLUMNDEF *rec;
1056
packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
1058
flag= *packpos; bit=1;
1060
for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
1062
length=(uint) rec->length;
1063
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
1065
if (type == FIELD_BLOB)
1067
uint32_t blob_length=
1068
_mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
1069
if (!blob_length && !(flag & bit))
1072
to+=length - portable_sizeof_char_ptr+ blob_length;
1074
else if (type == FIELD_SKIP_ZERO)
1076
if (memcmp(record,zero_string,length) == 0)
1084
else if (type == FIELD_SKIP_ENDSPACE ||
1085
type == FIELD_SKIP_PRESPACE)
1087
pos= (unsigned char*) record; end= (unsigned char*) record + length;
1088
if (type == FIELD_SKIP_ENDSPACE)
1089
{ /* Pack trailing spaces */
1090
while (end > record && *(end-1) == ' ')
1094
{ /* Pack pre-spaces */
1095
while (pos < end && *pos == ' ')
1098
new_length=(uint) (end-pos);
1099
if (new_length +1 + test(rec->length > 255 && new_length > 127)
1104
if (rec->length > 255 && new_length > 127)
1106
if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
1107
to[1] != (unsigned char) (new_length >> 7))
1111
else if (*to++ != (unsigned char) new_length)
1118
else if (type == FIELD_VARCHAR)
1120
uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1121
uint32_t tmp_length;
1122
if (pack_length == 1)
1124
tmp_length= (uint) *(unsigned char*) record;
1130
tmp_length= uint2korr(record);
1131
to+= get_pack_length(tmp_length)+tmp_length;
1138
continue; /* Normal field */
1140
if ((bit= bit << 1) >= 256)
1149
if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
1150
(bit != 1 && (flag & ~(bit - 1))))
1152
if (with_checksum && ((unsigned char) info->checksum != (unsigned char) *to))
1164
/* Unpacks a record */
1165
/* Returns -1 and errno =HA_ERR_RECORD_DELETED if reclength isn't */
1166
/* right. Returns reclength (>0) if ok */
1168
ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
1171
uint32_t flag,bit,length,rec_length,min_pack_length;
1172
enum en_fieldtype type;
1173
unsigned char *from_end,*to_end,*packpos;
1174
register MI_COLUMNDEF *rec,*end_field;
1176
to_end=to + info->s->base.reclength;
1177
from_end=from+found_length;
1178
flag= (unsigned char) *from; bit=1; packpos=from;
1179
if (found_length < info->s->base.min_pack_length)
1181
from+= info->s->base.pack_bits;
1182
min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
1184
for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
1185
rec < end_field ; to+= rec_length, rec++)
1187
rec_length=rec->length;
1188
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
1189
(type != FIELD_CHECK))
1191
if (type == FIELD_VARCHAR)
1193
uint32_t pack_length= ha_varchar_packlength(rec_length-1);
1194
if (pack_length == 1)
1196
length= (uint) *(unsigned char*) from;
1197
if (length > rec_length-1)
1203
get_key_length(length, from);
1204
if (length > rec_length-2)
1206
int2store(to,length);
1208
if (from+length > from_end)
1210
memcpy(to+pack_length, from, length);
1217
if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1218
memset(to, 0, rec_length);
1219
else if (type == FIELD_SKIP_ENDSPACE ||
1220
type == FIELD_SKIP_PRESPACE)
1222
if (rec->length > 255 && *from & 128)
1224
if (from + 1 >= from_end)
1226
length= (*from & 127)+ ((uint) (unsigned char) *(from+1) << 7); from+=2;
1230
if (from == from_end)
1232
length= (unsigned char) *from++;
1235
if (length >= rec_length ||
1236
min_pack_length + length > (uint) (from_end - from))
1238
if (type == FIELD_SKIP_ENDSPACE)
1240
memcpy(to, from, length);
1241
memset(to+length, ' ', rec_length-length);
1245
memset(to, ' ', rec_length-length);
1246
memcpy(to + rec_length - length, from, length);
1251
else if (type == FIELD_BLOB)
1253
uint32_t size_length=rec_length- portable_sizeof_char_ptr;
1254
ulong blob_length=_mi_calc_blob_length(size_length,from);
1255
ulong from_left= (ulong) (from_end - from);
1256
if (from_left < size_length ||
1257
from_left - size_length < blob_length ||
1258
from_left - size_length - blob_length < min_pack_length)
1260
memcpy(to, from, size_length);
1262
memcpy(to+size_length, &from, sizeof(char*));
1267
if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1269
if (min_pack_length + rec_length > (uint) (from_end - from))
1271
memcpy(to, from, rec_length);
1274
if ((bit= bit << 1) >= 256)
1276
flag= (unsigned char) *++packpos; bit=1;
1281
if (min_pack_length > (uint) (from_end - from))
1283
min_pack_length-=rec_length;
1284
memcpy(to, from, rec_length);
1288
if (info->s->calc_checksum)
1290
if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1291
return(found_length);
1294
errno= HA_ERR_WRONG_IN_RECORD;
1295
return(MY_FILE_ERROR);
1296
} /* _mi_rec_unpack */
1299
/* Calc length of blob. Update info in blobs->length */
1301
ulong _my_calc_total_blob_length(MI_INFO *info, const unsigned char *record)
1306
for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1310
blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
1311
length+=blob->length;
1317
ulong _mi_calc_blob_length(uint32_t length, const unsigned char *pos)
1321
return (uint) (unsigned char) *pos;
1323
return (uint) uint2korr(pos);
1325
return uint3korr(pos);
1327
return uint4korr(pos);
1331
return 0; /* Impossible */
1335
void _my_store_blob_length(unsigned char *pos,uint32_t pack_length,uint32_t length)
1337
switch (pack_length) {
1339
*pos= (unsigned char) length;
1342
int2store(pos,length);
1345
int3store(pos,length);
1348
int4store(pos,length);
1357
Read record from datafile.
1360
_mi_read_dynamic_record()
1361
info MI_INFO pointer to table.
1362
filepos From where to read the record.
1363
buf Destination for record.
1367
If a write buffer is active, it needs to be flushed if its contents
1368
intersects with the record to read. We always check if the position
1369
of the first byte of the write buffer is lower than the position
1370
past the last byte to read. In theory this is also true if the write
1371
buffer is completely below the read segment. That is, if there is no
1372
intersection. But this case is unusual. We flush anyway. Only if the
1373
first byte in the write buffer is above the last byte to read, we do
1376
A dynamic record may need several reads. So this check must be done
1377
before every read. Reading a dynamic record starts with reading the
1378
block header. If the record does not fit into the free space of the
1379
header, the block may be longer than the header. In this case a
1380
second read is necessary. These one or two reads repeat for every
1388
int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
1390
int block_of_record;
1391
uint32_t b_type, left_length= 0;
1392
unsigned char *to= NULL;
1393
MI_BLOCK_INFO block_info;
1396
if (filepos != HA_OFFSET_ERROR)
1399
block_of_record= 0; /* First block of record is numbered as zero. */
1400
block_info.second_read= 0;
1403
/* A corrupted table can have wrong pointers. (Bug# 19835) */
1404
if (filepos == HA_OFFSET_ERROR)
1406
if (info->opt_flag & WRITE_CACHE_USED &&
1407
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1408
flush_io_cache(&info->rec_cache))
1410
info->rec_cache.seek_not_done=1;
1411
if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1412
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1415
if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1416
errno=HA_ERR_RECORD_DELETED;
1419
if (block_of_record++ == 0) /* First block */
1421
if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1423
if (info->s->base.blobs)
1425
if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
1431
left_length=block_info.rec_len;
1433
if (left_length < block_info.data_len || ! block_info.data_len)
1434
goto panic; /* Wrong linked record */
1435
/* copy information that is already read */
1437
uint32_t offset= (uint) (block_info.filepos - filepos);
1438
uint32_t prefetch_len= (sizeof(block_info.header) - offset);
1439
filepos+= sizeof(block_info.header);
1441
if (prefetch_len > block_info.data_len)
1442
prefetch_len= block_info.data_len;
1445
memcpy(to, block_info.header + offset, prefetch_len);
1446
block_info.data_len-= prefetch_len;
1447
left_length-= prefetch_len;
1451
/* read rest of record from file */
1452
if (block_info.data_len)
1454
if (info->opt_flag & WRITE_CACHE_USED &&
1455
info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1456
flush_io_cache(&info->rec_cache))
1459
What a pity that this method is not called 'file_pread' and that
1460
there is no equivalent without seeking. We are at the right
1461
position already. :(
1463
if (info->s->file_read(info, (unsigned char*) to, block_info.data_len,
1464
filepos, MYF(MY_NABP)))
1466
left_length-=block_info.data_len;
1467
to+=block_info.data_len;
1469
filepos= block_info.next_filepos;
1470
} while (left_length);
1472
info->update|= HA_STATE_AKTIV; /* We have a aktive record */
1473
fast_mi_writeinfo(info);
1474
return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1475
MY_FILE_ERROR ? 0 : -1);
1477
fast_mi_writeinfo(info);
1478
return(-1); /* Wrong data to read */
1481
errno=HA_ERR_WRONG_IN_RECORD;
1483
_mi_writeinfo(info,0);
1487
/* compare unique constraint between stored rows */
1489
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
1490
const unsigned char *record, internal::my_off_t pos)
1492
unsigned char *rec_buff,*old_record;
1495
if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
1498
/* Don't let the compare destroy blobs that may be in use */
1499
rec_buff=info->rec_buff;
1500
if (info->s->base.blobs)
1502
error=_mi_read_dynamic_record(info,pos,old_record);
1504
error=mi_unique_comp(def, record, old_record, def->null_are_equal);
1505
if (info->s->base.blobs)
1507
void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
1508
if (rec_buff_ptr != NULL)
1510
info->rec_buff=rec_buff;
1517
/* Compare of record one disk with packed record in memory */
1519
int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
1521
uint32_t flag,reclength,b_type;
1522
internal::my_off_t filepos;
1523
unsigned char *buffer;
1524
MI_BLOCK_INFO block_info;
1526
if (info->opt_flag & WRITE_CACHE_USED)
1528
info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1529
if (flush_io_cache(&info->rec_cache))
1532
info->rec_cache.seek_not_done=1;
1534
/* If nobody have touched the database we don't have to test rec */
1536
buffer=info->rec_buff;
1537
if ((info->opt_flag & READ_CHECK_USED))
1538
{ /* If check isn't disabled */
1539
if (info->s->base.blobs)
1541
if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
1542
_my_calc_total_blob_length(info,record))))
1545
reclength=_mi_rec_pack(info,buffer,record);
1548
filepos=info->lastpos;
1549
flag=block_info.second_read=0;
1550
block_info.next_filepos=filepos;
1551
while (reclength > 0)
1553
if ((b_type=_mi_get_block_info(&block_info,info->dfile,
1554
block_info.next_filepos))
1555
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1558
if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1559
errno=HA_ERR_RECORD_CHANGED;
1562
if (flag == 0) /* First block */
1565
if (reclength != block_info.rec_len)
1567
errno=HA_ERR_RECORD_CHANGED;
1570
} else if (reclength < block_info.data_len)
1572
errno=HA_ERR_WRONG_IN_RECORD;
1575
reclength-=block_info.data_len;
1576
if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1577
block_info.data_len))
1579
errno=HA_ERR_RECORD_CHANGED;
1583
record+=block_info.data_len;
1588
if (buffer != info->rec_buff)
1589
free((unsigned char*) buffer);
1594
/* Compare file to buffert */
1596
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
1599
uint32_t next_length;
1600
unsigned char temp_buff[IO_SIZE*2];
1602
next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1604
while (length > IO_SIZE*2)
1606
if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1607
memcmp(buff, temp_buff, next_length))
1609
filepos+=next_length;
1611
length-= next_length;
1612
next_length=IO_SIZE*2;
1614
if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1616
return(memcmp(buff,temp_buff,length));
1623
Read record from datafile.
1626
_mi_read_rnd_dynamic_record()
1627
info MI_INFO pointer to table.
1628
buf Destination for record.
1629
filepos From where to read the record.
1630
skip_deleted_blocks If to repeat reading until a non-deleted
1635
If a write buffer is active, it needs to be flushed if its contents
1636
intersects with the record to read. We always check if the position
1637
of the first byte of the write buffer is lower than the position
1638
past the last byte to read. In theory this is also true if the write
1639
buffer is completely below the read segment. That is, if there is no
1640
intersection. But this case is unusual. We flush anyway. Only if the
1641
first byte in the write buffer is above the last byte to read, we do
1644
A dynamic record may need several reads. So this check must be done
1645
before every read. Reading a dynamic record starts with reading the
1646
block header. If the record does not fit into the free space of the
1647
header, the block may be longer than the header. In this case a
1648
second read is necessary. These one or two reads repeat for every
1656
int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
1657
register internal::my_off_t filepos,
1658
bool skip_deleted_blocks)
1660
int block_of_record, info_read, save_errno;
1661
uint32_t left_len,b_type;
1662
unsigned char *to= NULL;
1663
MI_BLOCK_INFO block_info;
1664
MYISAM_SHARE *share=info->s;
1668
if (info->lock_type == F_UNLCK)
1670
info->tmp_lock_type=F_RDLCK;
1673
info_read=1; /* memory-keyinfoblock is ok */
1675
block_of_record= 0; /* First block of record is numbered as zero. */
1676
block_info.second_read= 0;
1680
if (filepos >= info->state->data_file_length)
1683
{ /* Check if changed */
1685
info->rec_cache.seek_not_done=1;
1686
if (mi_state_info_read_dsk(share->kfile,&share->state,1))
1689
if (filepos >= info->state->data_file_length)
1691
errno= HA_ERR_END_OF_FILE;
1695
if (info->opt_flag & READ_CACHE_USED)
1697
if (_mi_read_cache(&info->rec_cache,(unsigned char*) block_info.header,filepos,
1698
sizeof(block_info.header),
1699
(!block_of_record && skip_deleted_blocks ?
1700
READING_NEXT : 0) | READING_HEADER))
1702
b_type=_mi_get_block_info(&block_info,-1,filepos);
1706
if (info->opt_flag & WRITE_CACHE_USED &&
1707
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1708
flush_io_cache(&info->rec_cache))
1710
info->rec_cache.seek_not_done=1;
1711
b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1714
if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1717
if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1718
&& skip_deleted_blocks)
1720
filepos=block_info.filepos+block_info.block_len;
1721
block_info.second_read=0;
1722
continue; /* Search after next_record */
1724
if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1726
errno=HA_ERR_RECORD_DELETED;
1727
info->lastpos=block_info.filepos;
1728
info->nextpos=block_info.filepos+block_info.block_len;
1732
if (block_of_record == 0) /* First block */
1734
if (block_info.rec_len > (uint) share->base.max_pack_length)
1736
info->lastpos=filepos;
1737
if (share->base.blobs)
1739
if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
1745
left_len=block_info.rec_len;
1747
if (left_len < block_info.data_len)
1748
goto panic; /* Wrong linked record */
1750
/* copy information that is already read */
1752
uint32_t offset=(uint) (block_info.filepos - filepos);
1753
uint32_t tmp_length= (sizeof(block_info.header) - offset);
1754
filepos=block_info.filepos;
1756
if (tmp_length > block_info.data_len)
1757
tmp_length= block_info.data_len;
1760
memcpy(to, block_info.header+offset,tmp_length);
1761
block_info.data_len-=tmp_length;
1762
left_len-=tmp_length;
1764
filepos+=tmp_length;
1767
/* read rest of record from file */
1768
if (block_info.data_len)
1770
if (info->opt_flag & READ_CACHE_USED)
1772
if (_mi_read_cache(&info->rec_cache,(unsigned char*) to,filepos,
1773
block_info.data_len,
1774
(!block_of_record && skip_deleted_blocks) ?
1780
if (info->opt_flag & WRITE_CACHE_USED &&
1781
info->rec_cache.pos_in_file <
1782
block_info.filepos + block_info.data_len &&
1783
flush_io_cache(&info->rec_cache))
1785
/* lseek(info->dfile,filepos,SEEK_SET); */
1786
if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1789
errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1795
Increment block-of-record counter. If it was the first block,
1796
remember the position behind the block for the next call.
1798
if (block_of_record++ == 0)
1800
info->nextpos= block_info.filepos + block_info.block_len;
1801
skip_deleted_blocks= 0;
1803
left_len-=block_info.data_len;
1804
to+=block_info.data_len;
1805
filepos=block_info.next_filepos;
1808
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1809
fast_mi_writeinfo(info);
1810
if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1813
return(errno); /* Wrong record */
1816
errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1819
_mi_writeinfo(info,0);
1820
return(errno=save_errno);
1824
/* Read and process header from a dynamic-record-file */
1826
uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
1828
uint32_t return_val=0;
1829
unsigned char *header=info->header;
1834
We do not use my_pread() here because we want to have the file
1835
pointer set to the end of the header after this function.
1836
my_pread() may leave the file pointer untouched.
1838
lseek(file,filepos,SEEK_SET);
1839
if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
1840
sizeof(info->header))
1843
if (info->second_read)
1845
if (info->header[0] <= 6 || info->header[0] == 13)
1846
return_val=BLOCK_SYNC_ERROR;
1850
if (info->header[0] > 6 && info->header[0] != 13)
1851
return_val=BLOCK_SYNC_ERROR;
1853
info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
1855
switch (info->header[0]) {
1857
if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1858
MI_MIN_BLOCK_LENGTH ||
1859
(info->block_len & (MI_DYN_ALIGN_SIZE -1)))
1861
info->filepos=filepos;
1862
info->next_filepos=mi_sizekorr(header+4);
1863
info->prev_filepos=mi_sizekorr(header+12);
1864
#if SIZEOF_OFF_T == 4
1865
if ((mi_uint4korr(header+4) != 0 &&
1866
(mi_uint4korr(header+4) != UINT32_MAX ||
1867
info->next_filepos != UINT32_MAX) ||
1868
(mi_uint4korr(header+12) != 0 &&
1869
(mi_uint4korr(header+12) != UINT32_MAX ||
1870
info->prev_filepos != UINT32_MAX))
1873
return return_val | BLOCK_DELETED; /* Deleted block */
1876
info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1877
info->filepos=filepos+3;
1878
return return_val | BLOCK_FIRST | BLOCK_LAST;
1880
info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1881
info->filepos=filepos+4;
1882
return return_val | BLOCK_FIRST | BLOCK_LAST;
1885
info->rec_len=mi_uint4korr(header+1);
1886
info->block_len=info->data_len=mi_uint3korr(header+5);
1887
info->next_filepos=mi_sizekorr(header+8);
1888
info->second_read=1;
1889
info->filepos=filepos+16;
1890
return return_val | BLOCK_FIRST;
1893
info->rec_len=info->data_len=mi_uint2korr(header+1);
1894
info->block_len=info->rec_len+ (uint) header[3];
1895
info->filepos=filepos+4;
1896
return return_val | BLOCK_FIRST | BLOCK_LAST;
1898
info->rec_len=info->data_len=mi_uint3korr(header+1);
1899
info->block_len=info->rec_len+ (uint) header[4];
1900
info->filepos=filepos+5;
1901
return return_val | BLOCK_FIRST | BLOCK_LAST;
1904
info->rec_len=mi_uint2korr(header+1);
1905
info->block_len=info->data_len=mi_uint2korr(header+3);
1906
info->next_filepos=mi_sizekorr(header+5);
1907
info->second_read=1;
1908
info->filepos=filepos+13;
1909
return return_val | BLOCK_FIRST;
1911
info->rec_len=mi_uint3korr(header+1);
1912
info->block_len=info->data_len=mi_uint3korr(header+4);
1913
info->next_filepos=mi_sizekorr(header+7);
1914
info->second_read=1;
1915
info->filepos=filepos+15;
1916
return return_val | BLOCK_FIRST;
1918
/* The following blocks are identical to 1-6 without rec_len */
1920
info->data_len=info->block_len=mi_uint2korr(header+1);
1921
info->filepos=filepos+3;
1922
return return_val | BLOCK_LAST;
1924
info->data_len=info->block_len=mi_uint3korr(header+1);
1925
info->filepos=filepos+4;
1926
return return_val | BLOCK_LAST;
1929
info->data_len=mi_uint2korr(header+1);
1930
info->block_len=info->data_len+ (uint) header[3];
1931
info->filepos=filepos+4;
1932
return return_val | BLOCK_LAST;
1934
info->data_len=mi_uint3korr(header+1);
1935
info->block_len=info->data_len+ (uint) header[4];
1936
info->filepos=filepos+5;
1937
return return_val | BLOCK_LAST;
1940
info->data_len=info->block_len=mi_uint2korr(header+1);
1941
info->next_filepos=mi_sizekorr(header+3);
1942
info->second_read=1;
1943
info->filepos=filepos+11;
1946
info->data_len=info->block_len=mi_uint3korr(header+1);
1947
info->next_filepos=mi_sizekorr(header+4);
1948
info->second_read=1;
1949
info->filepos=filepos+12;
1954
errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */