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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "myisamdef.h"
28
/* Enough for comparing if number is zero */
29
static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
31
static int write_dynamic_record(MI_INFO *info,const uchar *record,
33
static int _mi_find_writepos(MI_INFO *info,ulong reclength,my_off_t *filepos,
35
static int update_dynamic_record(MI_INFO *info,my_off_t filepos,uchar *record,
37
static int delete_dynamic_record(MI_INFO *info,my_off_t filepos,
39
static int _mi_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
43
/* Play it safe; We have a small stack when using threads */
46
#define my_alloca(A) my_malloc((A),MYF(0))
47
#define my_afree(A) my_free((A),MYF(0))
50
/* Interface function from MI_INFO */
55
Create mmaped area for MyISAM handler
66
my_bool mi_dynmap_file(MI_INFO *info, my_off_t size)
68
DBUG_ENTER("mi_dynmap_file");
69
if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
71
DBUG_PRINT("warning", ("File is too large for mmap"));
75
I wonder if it is good to use MAP_NORESERVE. From the Linux man page:
77
Do not reserve swap space for this mapping. When swap space is
78
reserved, one has the guarantee that it is possible to modify the
79
mapping. When swap space is not reserved one might get SIGSEGV
80
upon a write if no physical memory is available.
82
info->s->file_map= (uchar*)
83
my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
84
info->s->mode==O_RDONLY ? PROT_READ :
85
PROT_READ | PROT_WRITE,
86
MAP_SHARED | MAP_NORESERVE,
88
if (info->s->file_map == (uchar*) MAP_FAILED)
90
info->s->file_map= NULL;
93
#if defined(HAVE_MADVISE)
94
madvise((char*) info->s->file_map, size, MADV_RANDOM);
96
info->s->mmaped_length= size;
102
Resize mmaped area for MyISAM handler
111
void mi_remap_file(MI_INFO *info, my_off_t size)
113
if (info->s->file_map)
115
VOID(my_munmap((char*) info->s->file_map,
116
(size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
117
mi_dynmap_file(info, size);
124
Read bytes from MySAM handler, using mmap or pread
130
Count Count of bytes for read
131
offset Start position
138
size_t mi_mmap_pread(MI_INFO *info, uchar *Buffer,
139
size_t Count, my_off_t offset, myf MyFlags)
141
DBUG_PRINT("info", ("mi_read with mmap %d\n", info->dfile));
142
if (info->s->concurrent_insert)
143
rw_rdlock(&info->s->mmap_lock);
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);
155
if (info->s->concurrent_insert)
156
rw_unlock(&info->s->mmap_lock);
161
if (info->s->concurrent_insert)
162
rw_unlock(&info->s->mmap_lock);
163
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
168
/* wrapper for my_pread in case if mmap isn't used */
170
size_t mi_nommap_pread(MI_INFO *info, uchar *Buffer,
171
size_t Count, my_off_t offset, myf MyFlags)
173
return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
178
Write bytes to MySAM handler, using mmap or pwrite
184
Count Count of bytes for write
185
offset Start position
190
!=0 error. In this case return error from pwrite
193
size_t mi_mmap_pwrite(MI_INFO *info, const uchar *Buffer,
194
size_t Count, my_off_t offset, myf MyFlags)
196
DBUG_PRINT("info", ("mi_write with mmap %d\n", info->dfile));
197
if (info->s->concurrent_insert)
198
rw_rdlock(&info->s->mmap_lock);
201
The following test may fail in the following cases:
202
- We failed to remap a memory area (fragmented memory?)
203
- This thread has done some writes, but not yet extended the
207
if (info->s->mmaped_length >= offset + Count)
209
memcpy(info->s->file_map + offset, Buffer, Count);
210
if (info->s->concurrent_insert)
211
rw_unlock(&info->s->mmap_lock);
216
info->s->nonmmaped_inserts++;
217
if (info->s->concurrent_insert)
218
rw_unlock(&info->s->mmap_lock);
219
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
225
/* wrapper for my_pwrite in case if mmap isn't used */
227
size_t mi_nommap_pwrite(MI_INFO *info, const uchar *Buffer,
228
size_t Count, my_off_t offset, myf MyFlags)
230
return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
234
int _mi_write_dynamic_record(MI_INFO *info, const uchar *record)
236
ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
237
return (write_dynamic_record(info,info->rec_buff,reclength));
240
int _mi_update_dynamic_record(MI_INFO *info, my_off_t pos, const uchar *record)
242
uint length=_mi_rec_pack(info,info->rec_buff,record);
243
return (update_dynamic_record(info,pos,info->rec_buff,length));
246
int _mi_write_blob_record(MI_INFO *info, const uchar *record)
250
ulong reclength,reclength2,extra;
252
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
253
MI_DYN_DELETE_BLOCK_HEADER+1);
254
reclength= (info->s->base.pack_reclength +
255
_my_calc_total_blob_length(info,record)+ extra);
256
#ifdef NOT_USED /* We now support big rows */
257
if (reclength > MI_DYN_MAX_ROW_LENGTH)
259
my_errno=HA_ERR_TO_BIG_ROW;
263
if (!(rec_buff=(uchar*) my_alloca(reclength)))
265
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
268
reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
270
DBUG_PRINT("info",("reclength: %lu reclength2: %lu",
271
reclength, reclength2));
272
DBUG_ASSERT(reclength2 <= reclength);
273
error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
280
int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const uchar *record)
284
ulong reclength,extra;
286
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
287
MI_DYN_DELETE_BLOCK_HEADER);
288
reclength= (info->s->base.pack_reclength+
289
_my_calc_total_blob_length(info,record)+ extra);
290
#ifdef NOT_USED /* We now support big rows */
291
if (reclength > MI_DYN_MAX_ROW_LENGTH)
293
my_errno=HA_ERR_TO_BIG_ROW;
297
if (!(rec_buff=(uchar*) my_alloca(reclength)))
299
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
302
reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
304
error=update_dynamic_record(info,pos,
305
rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
312
int _mi_delete_dynamic_record(MI_INFO *info)
314
return delete_dynamic_record(info,info->lastpos,0);
318
/* Write record to data-file */
320
static int write_dynamic_record(MI_INFO *info, const uchar *record,
326
DBUG_ENTER("write_dynamic_record");
331
Check if we have enough room for the new record.
332
First we do simplified check to make usual case faster.
333
Then we do more precise check for the space left.
334
Though it still is not absolutely precise, as
335
we always use MI_MAX_DYN_BLOCK_HEADER while it can be
336
less in the most of the cases.
339
if (unlikely(info->s->base.max_data_file_length -
340
info->state->data_file_length <
341
reclength + MI_MAX_DYN_BLOCK_HEADER))
343
if (info->s->base.max_data_file_length - info->state->data_file_length +
344
info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
345
reclength + MI_MAX_DYN_BLOCK_HEADER)
347
my_errno=HA_ERR_RECORD_FILE_FULL;
354
if (_mi_find_writepos(info,reclength,&filepos,&length))
356
if (_mi_write_part_record(info,filepos,length,
357
(info->append_insert_at_end ?
358
HA_OFFSET_ERROR : info->s->state.dellink),
359
(uchar**) &record,&reclength,&flag))
369
/* Get a block for data ; The given data-area must be used !! */
371
static int _mi_find_writepos(MI_INFO *info,
372
ulong reclength, /* record length */
373
my_off_t *filepos, /* Return file pos */
374
ulong *length) /* length of block at filepos */
376
MI_BLOCK_INFO block_info;
378
DBUG_ENTER("_mi_find_writepos");
380
if (info->s->state.dellink != HA_OFFSET_ERROR &&
381
!info->append_insert_at_end)
383
/* Deleted blocks exists; Get last used block */
384
*filepos=info->s->state.dellink;
385
block_info.second_read=0;
386
info->rec_cache.seek_not_done=1;
387
if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
390
DBUG_PRINT("error",("Delete link crashed"));
391
my_errno=HA_ERR_WRONG_IN_RECORD;
394
info->s->state.dellink=block_info.next_filepos;
396
info->state->empty-= block_info.block_len;
397
*length= block_info.block_len;
401
/* No deleted blocks; Allocate a new block */
402
*filepos=info->state->data_file_length;
403
if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
404
info->s->base.min_block_length)
405
tmp= info->s->base.min_block_length;
407
tmp= ((tmp+MI_DYN_ALIGN_SIZE-1) &
408
(~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
409
if (info->state->data_file_length >
410
(info->s->base.max_data_file_length - tmp))
412
my_errno=HA_ERR_RECORD_FILE_FULL;
415
if (tmp > MI_MAX_BLOCK_LENGTH)
416
tmp=MI_MAX_BLOCK_LENGTH;
418
info->state->data_file_length+= tmp;
419
info->s->state.split++;
420
info->update|=HA_STATE_WRITE_AT_END;
423
} /* _mi_find_writepos */
428
Unlink a deleted block from the deleted list.
429
This block will be combined with the preceding or next block to form
433
static my_bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
435
DBUG_ENTER("unlink_deleted_block");
436
if (block_info->filepos == info->s->state.dellink)
438
/* First deleted block; We can just use this ! */
439
info->s->state.dellink=block_info->next_filepos;
445
/* Unlink block from the previous block */
446
if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
448
DBUG_RETURN(1); /* Something is wrong */
449
mi_sizestore(tmp.header+4,block_info->next_filepos);
450
if (info->s->file_write(info, tmp.header+4,8,
451
block_info->prev_filepos+4, MYF(MY_NABP)))
453
/* Unlink block from next block */
454
if (block_info->next_filepos != HA_OFFSET_ERROR)
456
if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
458
DBUG_RETURN(1); /* Something is wrong */
459
mi_sizestore(tmp.header+12,block_info->prev_filepos);
460
if (info->s->file_write(info, tmp.header+12,8,
461
block_info->next_filepos+12,
466
/* We now have one less deleted block */
468
info->state->empty-= block_info->block_len;
469
info->s->state.split--;
472
If this was a block that we where accessing through table scan
473
(mi_rrnd() or mi_scan(), then ensure that we skip over this block
474
when doing next mi_rrnd() or mi_scan().
476
if (info->nextpos == block_info->filepos)
477
info->nextpos+=block_info->block_len;
483
Add a backward link to delete block
486
update_backward_delete_link()
488
delete_block Position to delete block to update.
489
If this is 'HA_OFFSET_ERROR', nothing will be done
490
filepos Position to block that 'delete_block' should point to
494
1 error. In this case my_error is set.
497
static int update_backward_delete_link(MI_INFO *info, my_off_t delete_block,
500
MI_BLOCK_INFO block_info;
501
DBUG_ENTER("update_backward_delete_link");
503
if (delete_block != HA_OFFSET_ERROR)
505
block_info.second_read=0;
506
if (_mi_get_block_info(&block_info,info->dfile,delete_block)
510
mi_sizestore(buff,filepos);
511
if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
512
DBUG_RETURN(1); /* Error on write */
516
my_errno=HA_ERR_WRONG_IN_RECORD;
517
DBUG_RETURN(1); /* Wrong delete link */
523
/* Delete datarecord from database */
524
/* info->rec_cache.seek_not_done is updated in cmp_record */
526
static int delete_dynamic_record(MI_INFO *info, my_off_t filepos,
530
MI_BLOCK_INFO block_info,del_block;
532
my_bool remove_next_block;
533
DBUG_ENTER("delete_dynamic_record");
535
/* First add a link from the last block to the new one */
536
error= update_backward_delete_link(info, info->s->state.dellink, filepos);
538
block_info.second_read=second_read;
541
/* Remove block at 'filepos' */
542
if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
543
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
544
BLOCK_FATAL_ERROR) ||
545
(length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
548
my_errno=HA_ERR_WRONG_IN_RECORD;
551
/* Check if next block is a delete block */
552
del_block.second_read=0;
554
if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
555
BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
557
/* We can't remove this yet as this block may be the head block */
559
length+=del_block.block_len;
562
block_info.header[0]=0;
563
mi_int3store(block_info.header+1,length);
564
mi_sizestore(block_info.header+4,info->s->state.dellink);
565
if (b_type & BLOCK_LAST)
566
bfill(block_info.header+12,8,255);
568
mi_sizestore(block_info.header+12,block_info.next_filepos);
569
if (info->s->file_write(info,(uchar*) block_info.header,20,filepos,
572
info->s->state.dellink = filepos;
574
info->state->empty+=length;
575
filepos=block_info.next_filepos;
577
/* Now it's safe to unlink the deleted block directly after this one */
578
if (remove_next_block && unlink_deleted_block(info,&del_block))
580
} while (!(b_type & BLOCK_LAST));
586
/* Write a block to datafile */
588
int _mi_write_part_record(MI_INFO *info,
589
my_off_t filepos, /* points at empty block */
590
ulong length, /* length of block */
591
my_off_t next_filepos,/* Next empty block */
592
uchar **record, /* pointer to record ptr */
593
ulong *reclength, /* length of *record */
594
int *flag) /* *flag == 0 if header */
596
ulong head_length,res_length,extra_length,long_block,del_length;
597
uchar *pos,*record_end;
598
my_off_t next_delete_block;
599
uchar temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
600
DBUG_ENTER("_mi_write_part_record");
602
next_delete_block=HA_OFFSET_ERROR;
604
res_length=extra_length=0;
605
if (length > *reclength + MI_SPLIT_LENGTH)
606
{ /* Splitt big block */
607
res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
609
length-= res_length; /* Use this for first part */
611
long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
612
if (length == *reclength+ 3 + long_block)
614
/* Block is exactly of the right length */
615
temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */
618
mi_int3store(temp+1,*reclength);
623
mi_int2store(temp+1,*reclength);
627
else if (length-long_block < *reclength+4)
628
{ /* To short block */
629
if (next_filepos == HA_OFFSET_ERROR)
630
next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
631
!info->append_insert_at_end ?
632
info->s->state.dellink : info->state->data_file_length);
633
if (*flag == 0) /* First block */
635
if (*reclength > MI_MAX_BLOCK_LENGTH)
639
mi_int4store(temp+1,*reclength);
640
mi_int3store(temp+5,length-head_length);
641
mi_sizestore((uchar*) temp+8,next_filepos);
645
head_length=5+8+long_block*2;
646
temp[0]=5+(uchar) long_block;
649
mi_int3store(temp+1,*reclength);
650
mi_int3store(temp+4,length-head_length);
651
mi_sizestore((uchar*) temp+7,next_filepos);
655
mi_int2store(temp+1,*reclength);
656
mi_int2store(temp+3,length-head_length);
657
mi_sizestore((uchar*) temp+5,next_filepos);
663
head_length=3+8+long_block;
664
temp[0]=11+(uchar) long_block;
667
mi_int3store(temp+1,length-head_length);
668
mi_sizestore((uchar*) temp+4,next_filepos);
672
mi_int2store(temp+1,length-head_length);
673
mi_sizestore((uchar*) temp+3,next_filepos);
678
{ /* Block with empty info last */
679
head_length=4+long_block;
680
extra_length= length- *reclength-head_length;
681
temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
684
mi_int3store(temp+1,*reclength);
685
temp[4]= (uchar) (extra_length);
689
mi_int2store(temp+1,*reclength);
690
temp[3]= (uchar) (extra_length);
692
length= *reclength+head_length; /* Write only what is needed */
694
DBUG_DUMP("header",(uchar*) temp,head_length);
696
/* Make a long block for one write */
697
record_end= *record+length-head_length;
698
del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
699
bmove((uchar*) (*record-head_length),(uchar*) temp,head_length);
700
memcpy(temp,record_end,(size_t) (extra_length+del_length));
701
bzero((uchar*) record_end,extra_length);
705
/* Check first if we can join this block with the next one */
706
MI_BLOCK_INFO del_block;
707
my_off_t next_block=filepos+length+extra_length+res_length;
709
del_block.second_read=0;
710
if (next_block < info->state->data_file_length &&
711
info->s->state.dellink != HA_OFFSET_ERROR)
713
if ((_mi_get_block_info(&del_block,info->dfile,next_block)
715
res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
717
if (unlink_deleted_block(info,&del_block))
719
res_length+=del_block.block_len;
723
/* Create a delete link of the last part of the block */
724
pos=record_end+extra_length;
726
mi_int3store(pos+1,res_length);
727
mi_sizestore(pos+4,info->s->state.dellink);
728
bfill(pos+12,8,255); /* End link */
729
next_delete_block=info->s->state.dellink;
730
info->s->state.dellink= filepos+length+extra_length;
732
info->state->empty+=res_length;
733
info->s->state.split++;
735
if (info->opt_flag & WRITE_CACHE_USED &&
736
info->update & HA_STATE_WRITE_AT_END)
738
if (info->update & HA_STATE_EXTEND_BLOCK)
740
info->update&= ~HA_STATE_EXTEND_BLOCK;
741
if (my_block_write(&info->rec_cache,(uchar*) *record-head_length,
742
length+extra_length+del_length,filepos))
745
else if (my_b_write(&info->rec_cache,(uchar*) *record-head_length,
746
length+extra_length+del_length))
751
info->rec_cache.seek_not_done=1;
752
if (info->s->file_write(info,(uchar*) *record-head_length,length+extra_length+
753
del_length,filepos,info->s->write_flag))
756
memcpy(record_end,temp,(size_t) (extra_length+del_length));
758
*reclength-=(length-head_length);
763
/* link the next delete block to this */
764
if (update_backward_delete_link(info, next_delete_block,
765
info->s->state.dellink))
771
DBUG_PRINT("exit",("errno: %d",my_errno));
773
} /*_mi_write_part_record */
776
/* update record from datafile */
778
static int update_dynamic_record(MI_INFO *info, my_off_t filepos, uchar *record,
784
MI_BLOCK_INFO block_info;
785
DBUG_ENTER("update_dynamic_record");
787
flag=block_info.second_read=0;
789
Check if we have enough room for the record.
790
First we do simplified check to make usual case faster.
791
Then we do more precise check for the space left.
792
Though it still is not absolutely precise, as
793
we always use MI_MAX_DYN_BLOCK_HEADER while it can be
794
less in the most of the cases.
798
compare with just the reclength as we're going
799
to get some space from the old replaced record
801
if (unlikely(info->s->base.max_data_file_length -
802
info->state->data_file_length < reclength))
805
let's read the old record's block to find out the length of the
808
if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
809
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
811
DBUG_PRINT("error",("Got wrong block info"));
812
if (!(error & BLOCK_FATAL_ERROR))
813
my_errno=HA_ERR_WRONG_IN_RECORD;
818
if new record isn't longer, we can go on safely
820
if (block_info.rec_len < reclength)
822
if (info->s->base.max_data_file_length - info->state->data_file_length +
823
info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
824
reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
826
my_errno=HA_ERR_RECORD_FILE_FULL;
830
block_info.second_read=0;
833
while (reclength > 0)
835
if (filepos != info->s->state.dellink)
837
block_info.next_filepos= HA_OFFSET_ERROR;
838
if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
839
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
842
DBUG_PRINT("error",("Got wrong block info"));
843
if (!(error & BLOCK_FATAL_ERROR))
844
my_errno=HA_ERR_WRONG_IN_RECORD;
847
length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
848
if (length < reclength)
850
uint tmp=MY_ALIGN(reclength - length + 3 +
851
test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
852
/* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
853
tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
854
/* Check if we can extend this block */
855
if (block_info.filepos + block_info.block_len ==
856
info->state->data_file_length &&
857
info->state->data_file_length <
858
info->s->base.max_data_file_length-tmp)
861
DBUG_PRINT("info",("Extending file with %d bytes",tmp));
862
if (info->nextpos == info->state->data_file_length)
864
info->state->data_file_length+= tmp;
865
info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
868
else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
871
Check if next block is a deleted block
872
Above we have MI_MIN_BLOCK_LENGTH to avoid the problem where
873
the next block is so small it can't be splited which could
877
MI_BLOCK_INFO del_block;
878
del_block.second_read=0;
879
if (_mi_get_block_info(&del_block,info->dfile,
880
block_info.filepos + block_info.block_len) &
883
/* Use; Unlink it and extend the current block */
884
DBUG_PRINT("info",("Extending current block"));
885
if (unlink_deleted_block(info,&del_block))
887
if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
890
New block was too big, link overflow part back to
894
ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
895
set_if_bigger(rest_length, MI_MIN_BLOCK_LENGTH);
896
next_pos= del_block.filepos+ del_block.block_len - rest_length;
898
if (update_backward_delete_link(info, info->s->state.dellink,
902
/* create delete link for data that didn't fit into the page */
903
del_block.header[0]=0;
904
mi_int3store(del_block.header+1, rest_length);
905
mi_sizestore(del_block.header+4,info->s->state.dellink);
906
bfill(del_block.header+12,8,255);
907
if (info->s->file_write(info,(uchar*) del_block.header,20, next_pos,
910
info->s->state.dellink= next_pos;
911
info->s->state.split++;
913
info->state->empty+= rest_length;
914
length-= rest_length;
922
if (_mi_find_writepos(info,reclength,&filepos,&length))
925
if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
926
&record,&reclength,&flag))
928
if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
930
/* Start writing data on deleted blocks */
931
filepos=info->s->state.dellink;
935
if (block_info.next_filepos != HA_OFFSET_ERROR)
936
if (delete_dynamic_record(info,block_info.next_filepos,1))
944
/* Pack a record. Return new reclength */
946
uint _mi_rec_pack(MI_INFO *info, register uchar *to,
947
register const uchar *from)
949
uint length,new_length,flag,bit,i;
950
uchar *pos,*end,*startpos,*packpos;
951
enum en_fieldtype type;
952
register MI_COLUMNDEF *rec;
954
DBUG_ENTER("_mi_rec_pack");
957
startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
960
for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
962
length=(uint) rec->length;
963
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
965
if (type == FIELD_BLOB)
972
size_t tmp_length=length-portable_sizeof_char_ptr;
973
memcpy((uchar*) to,from,tmp_length);
974
memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
975
memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
976
to+=tmp_length+blob->length;
980
else if (type == FIELD_SKIP_ZERO)
982
if (memcmp((uchar*) from,zero_string,length) == 0)
986
memcpy((uchar*) to,from,(size_t) length); to+=length;
989
else if (type == FIELD_SKIP_ENDSPACE ||
990
type == FIELD_SKIP_PRESPACE)
992
pos= (uchar*) from; end= (uchar*) from + length;
993
if (type == FIELD_SKIP_ENDSPACE)
994
{ /* Pack trailing spaces */
995
while (end > from && *(end-1) == ' ')
999
{ /* Pack pref-spaces */
1000
while (pos < end && *pos == ' ')
1003
new_length=(uint) (end-pos);
1004
if (new_length +1 + test(rec->length > 255 && new_length > 127)
1007
if (rec->length > 255 && new_length > 127)
1009
to[0]= (uchar) ((new_length & 127) + 128);
1010
to[1]= (uchar) (new_length >> 7);
1014
*to++= (uchar) new_length;
1015
memcpy((uchar*) to,pos,(size_t) new_length); to+=new_length;
1020
memcpy(to,from,(size_t) length); to+=length;
1023
else if (type == FIELD_VARCHAR)
1025
uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1);
1027
if (pack_length == 1)
1029
tmp_length= (uint) *(uchar*) from;
1034
tmp_length= uint2korr(from);
1035
store_key_length_inc(to,tmp_length);
1037
memcpy(to, from+pack_length,tmp_length);
1043
memcpy(to,from,(size_t) length); to+=length;
1044
continue; /* Normal field */
1046
if ((bit= bit << 1) >= 256)
1048
*packpos++= (uchar) flag;
1054
memcpy(to,from,(size_t) length); to+=length;
1058
*packpos= (uchar) flag;
1059
if (info->s->calc_checksum)
1060
*to++= (uchar) info->checksum;
1061
DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
1062
DBUG_RETURN((uint) (to-startpos));
1063
} /* _mi_rec_pack */
1068
Check if a record was correctly packed. Used only by myisamchk
1069
Returns 0 if record is ok.
1072
my_bool _mi_rec_check(MI_INFO *info,const uchar *record, uchar *rec_buff,
1073
ulong packed_length, my_bool with_checksum)
1075
uint length,new_length,flag,bit,i;
1076
uchar *pos,*end,*packpos,*to;
1077
enum en_fieldtype type;
1078
register MI_COLUMNDEF *rec;
1079
DBUG_ENTER("_mi_rec_check");
1081
packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
1083
flag= *packpos; bit=1;
1085
for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
1087
length=(uint) rec->length;
1088
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
1090
if (type == FIELD_BLOB)
1093
_mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
1094
if (!blob_length && !(flag & bit))
1097
to+=length - portable_sizeof_char_ptr+ blob_length;
1099
else if (type == FIELD_SKIP_ZERO)
1101
if (memcmp((uchar*) record,zero_string,length) == 0)
1109
else if (type == FIELD_SKIP_ENDSPACE ||
1110
type == FIELD_SKIP_PRESPACE)
1112
pos= (uchar*) record; end= (uchar*) record + length;
1113
if (type == FIELD_SKIP_ENDSPACE)
1114
{ /* Pack trailing spaces */
1115
while (end > record && *(end-1) == ' ')
1119
{ /* Pack pre-spaces */
1120
while (pos < end && *pos == ' ')
1123
new_length=(uint) (end-pos);
1124
if (new_length +1 + test(rec->length > 255 && new_length > 127)
1129
if (rec->length > 255 && new_length > 127)
1131
/* purecov: begin inspected */
1132
if (to[0] != (uchar) ((new_length & 127) + 128) ||
1133
to[1] != (uchar) (new_length >> 7))
1138
else if (*to++ != (uchar) new_length)
1145
else if (type == FIELD_VARCHAR)
1147
uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length -1);
1149
if (pack_length == 1)
1151
tmp_length= (uint) *(uchar*) record;
1157
tmp_length= uint2korr(record);
1158
to+= get_pack_length(tmp_length)+tmp_length;
1165
continue; /* Normal field */
1167
if ((bit= bit << 1) >= 256)
1176
if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
1177
(bit != 1 && (flag & ~(bit - 1))))
1179
if (with_checksum && ((uchar) info->checksum != (uchar) *to))
1181
DBUG_PRINT("error",("wrong checksum for row"));
1192
/* Unpacks a record */
1193
/* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
1194
/* right. Returns reclength (>0) if ok */
1196
ulong _mi_rec_unpack(register MI_INFO *info, register uchar *to, uchar *from,
1199
uint flag,bit,length,rec_length,min_pack_length;
1200
enum en_fieldtype type;
1201
uchar *from_end,*to_end,*packpos;
1202
register MI_COLUMNDEF *rec,*end_field;
1203
DBUG_ENTER("_mi_rec_unpack");
1205
to_end=to + info->s->base.reclength;
1206
from_end=from+found_length;
1207
flag= (uchar) *from; bit=1; packpos=from;
1208
if (found_length < info->s->base.min_pack_length)
1210
from+= info->s->base.pack_bits;
1211
min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
1213
for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
1214
rec < end_field ; to+= rec_length, rec++)
1216
rec_length=rec->length;
1217
if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
1218
(type != FIELD_CHECK))
1220
if (type == FIELD_VARCHAR)
1222
uint pack_length= HA_VARCHAR_PACKLENGTH(rec_length-1);
1223
if (pack_length == 1)
1225
length= (uint) *(uchar*) from;
1226
if (length > rec_length-1)
1232
get_key_length(length, from);
1233
if (length > rec_length-2)
1235
int2store(to,length);
1237
if (from+length > from_end)
1239
memcpy(to+pack_length, from, length);
1246
if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1247
bzero((uchar*) to,rec_length);
1248
else if (type == FIELD_SKIP_ENDSPACE ||
1249
type == FIELD_SKIP_PRESPACE)
1251
if (rec->length > 255 && *from & 128)
1253
if (from + 1 >= from_end)
1255
length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
1259
if (from == from_end)
1261
length= (uchar) *from++;
1264
if (length >= rec_length ||
1265
min_pack_length + length > (uint) (from_end - from))
1267
if (type == FIELD_SKIP_ENDSPACE)
1269
memcpy(to,(uchar*) from,(size_t) length);
1270
bfill((uchar*) to+length,rec_length-length,' ');
1274
bfill((uchar*) to,rec_length-length,' ');
1275
memcpy(to+rec_length-length,(uchar*) from,(size_t) length);
1280
else if (type == FIELD_BLOB)
1282
uint size_length=rec_length- portable_sizeof_char_ptr;
1283
ulong blob_length=_mi_calc_blob_length(size_length,from);
1284
ulong from_left= (ulong) (from_end - from);
1285
if (from_left < size_length ||
1286
from_left - size_length < blob_length ||
1287
from_left - size_length - blob_length < min_pack_length)
1289
memcpy((uchar*) to,(uchar*) from,(size_t) size_length);
1291
memcpy_fixed((uchar*) to+size_length,(uchar*) &from,sizeof(char*));
1296
if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1298
if (min_pack_length + rec_length > (uint) (from_end - from))
1300
memcpy(to,(uchar*) from,(size_t) rec_length); from+=rec_length;
1302
if ((bit= bit << 1) >= 256)
1304
flag= (uchar) *++packpos; bit=1;
1309
if (min_pack_length > (uint) (from_end - from))
1311
min_pack_length-=rec_length;
1312
memcpy(to, (uchar*) from, (size_t) rec_length);
1316
if (info->s->calc_checksum)
1318
if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1319
DBUG_RETURN(found_length);
1322
my_errno= HA_ERR_WRONG_IN_RECORD;
1323
DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx from_end: 0x%lx -> 0x%lx",
1324
(long) to, (long) to_end, (long) from, (long) from_end));
1325
DBUG_DUMP("from",(uchar*) info->rec_buff,info->s->base.min_pack_length);
1326
DBUG_RETURN(MY_FILE_ERROR);
1327
} /* _mi_rec_unpack */
1330
/* Calc length of blob. Update info in blobs->length */
1332
ulong _my_calc_total_blob_length(MI_INFO *info, const uchar *record)
1337
for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1341
blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
1342
length+=blob->length;
1348
ulong _mi_calc_blob_length(uint length, const uchar *pos)
1352
return (uint) (uchar) *pos;
1354
return (uint) uint2korr(pos);
1356
return uint3korr(pos);
1358
return uint4korr(pos);
1362
return 0; /* Impossible */
1366
void _my_store_blob_length(uchar *pos,uint pack_length,uint length)
1368
switch (pack_length) {
1370
*pos= (uchar) length;
1373
int2store(pos,length);
1376
int3store(pos,length);
1379
int4store(pos,length);
1388
Read record from datafile.
1391
_mi_read_dynamic_record()
1392
info MI_INFO pointer to table.
1393
filepos From where to read the record.
1394
buf Destination for record.
1398
If a write buffer is active, it needs to be flushed if its contents
1399
intersects with the record to read. We always check if the position
1400
of the first byte of the write buffer is lower than the position
1401
past the last byte to read. In theory this is also true if the write
1402
buffer is completely below the read segment. That is, if there is no
1403
intersection. But this case is unusual. We flush anyway. Only if the
1404
first byte in the write buffer is above the last byte to read, we do
1407
A dynamic record may need several reads. So this check must be done
1408
before every read. Reading a dynamic record starts with reading the
1409
block header. If the record does not fit into the free space of the
1410
header, the block may be longer than the header. In this case a
1411
second read is necessary. These one or two reads repeat for every
1419
int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, uchar *buf)
1421
int block_of_record;
1422
uint b_type, left_length= 0;
1424
MI_BLOCK_INFO block_info;
1426
DBUG_ENTER("mi_read_dynamic_record");
1428
if (filepos != HA_OFFSET_ERROR)
1431
block_of_record= 0; /* First block of record is numbered as zero. */
1432
block_info.second_read= 0;
1435
/* A corrupted table can have wrong pointers. (Bug# 19835) */
1436
if (filepos == HA_OFFSET_ERROR)
1438
if (info->opt_flag & WRITE_CACHE_USED &&
1439
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1440
flush_io_cache(&info->rec_cache))
1442
info->rec_cache.seek_not_done=1;
1443
if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1444
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1447
if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1448
my_errno=HA_ERR_RECORD_DELETED;
1451
if (block_of_record++ == 0) /* First block */
1453
if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1455
if (info->s->base.blobs)
1457
if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
1463
left_length=block_info.rec_len;
1465
if (left_length < block_info.data_len || ! block_info.data_len)
1466
goto panic; /* Wrong linked record */
1467
/* copy information that is already read */
1469
uint offset= (uint) (block_info.filepos - filepos);
1470
uint prefetch_len= (sizeof(block_info.header) - offset);
1471
filepos+= sizeof(block_info.header);
1473
if (prefetch_len > block_info.data_len)
1474
prefetch_len= block_info.data_len;
1477
memcpy((uchar*) to, block_info.header + offset, prefetch_len);
1478
block_info.data_len-= prefetch_len;
1479
left_length-= prefetch_len;
1483
/* read rest of record from file */
1484
if (block_info.data_len)
1486
if (info->opt_flag & WRITE_CACHE_USED &&
1487
info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1488
flush_io_cache(&info->rec_cache))
1491
What a pity that this method is not called 'file_pread' and that
1492
there is no equivalent without seeking. We are at the right
1493
position already. :(
1495
if (info->s->file_read(info, (uchar*) to, block_info.data_len,
1496
filepos, MYF(MY_NABP)))
1498
left_length-=block_info.data_len;
1499
to+=block_info.data_len;
1501
filepos= block_info.next_filepos;
1502
} while (left_length);
1504
info->update|= HA_STATE_AKTIV; /* We have a aktive record */
1505
fast_mi_writeinfo(info);
1506
DBUG_RETURN(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1507
MY_FILE_ERROR ? 0 : -1);
1509
fast_mi_writeinfo(info);
1510
DBUG_RETURN(-1); /* Wrong data to read */
1513
my_errno=HA_ERR_WRONG_IN_RECORD;
1515
VOID(_mi_writeinfo(info,0));
1519
/* compare unique constraint between stored rows */
1521
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
1522
const uchar *record, my_off_t pos)
1524
uchar *rec_buff,*old_record;
1526
DBUG_ENTER("_mi_cmp_dynamic_unique");
1528
if (!(old_record=my_alloca(info->s->base.reclength)))
1531
/* Don't let the compare destroy blobs that may be in use */
1532
rec_buff=info->rec_buff;
1533
if (info->s->base.blobs)
1535
error=_mi_read_dynamic_record(info,pos,old_record);
1537
error=mi_unique_comp(def, record, old_record, def->null_are_equal);
1538
if (info->s->base.blobs)
1540
my_free(mi_get_rec_buff_ptr(info, info->rec_buff), MYF(MY_ALLOW_ZERO_PTR));
1541
info->rec_buff=rec_buff;
1543
my_afree(old_record);
1548
/* Compare of record one disk with packed record in memory */
1550
int _mi_cmp_dynamic_record(register MI_INFO *info, register const uchar *record)
1552
uint flag,reclength,b_type;
1555
MI_BLOCK_INFO block_info;
1556
DBUG_ENTER("_mi_cmp_dynamic_record");
1558
/* We are going to do changes; dont let anybody disturb */
1559
dont_break(); /* Dont allow SIGHUP or SIGINT */
1561
if (info->opt_flag & WRITE_CACHE_USED)
1563
info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1564
if (flush_io_cache(&info->rec_cache))
1567
info->rec_cache.seek_not_done=1;
1569
/* If nobody have touched the database we don't have to test rec */
1571
buffer=info->rec_buff;
1572
if ((info->opt_flag & READ_CHECK_USED))
1573
{ /* If check isn't disabled */
1574
if (info->s->base.blobs)
1576
if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
1577
_my_calc_total_blob_length(info,record))))
1580
reclength=_mi_rec_pack(info,buffer,record);
1583
filepos=info->lastpos;
1584
flag=block_info.second_read=0;
1585
block_info.next_filepos=filepos;
1586
while (reclength > 0)
1588
if ((b_type=_mi_get_block_info(&block_info,info->dfile,
1589
block_info.next_filepos))
1590
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1593
if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1594
my_errno=HA_ERR_RECORD_CHANGED;
1597
if (flag == 0) /* First block */
1600
if (reclength != block_info.rec_len)
1602
my_errno=HA_ERR_RECORD_CHANGED;
1605
} else if (reclength < block_info.data_len)
1607
my_errno=HA_ERR_WRONG_IN_RECORD;
1610
reclength-=block_info.data_len;
1611
if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1612
block_info.data_len))
1614
my_errno=HA_ERR_RECORD_CHANGED;
1618
record+=block_info.data_len;
1623
if (buffer != info->rec_buff)
1624
my_afree((uchar*) buffer);
1625
DBUG_RETURN(my_errno);
1629
/* Compare file to buffert */
1631
static int _mi_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
1635
uchar temp_buff[IO_SIZE*2];
1636
DBUG_ENTER("_mi_cmp_buffer");
1638
next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1640
while (length > IO_SIZE*2)
1642
if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1643
memcmp(buff, temp_buff, next_length))
1645
filepos+=next_length;
1647
length-= next_length;
1648
next_length=IO_SIZE*2;
1650
if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1652
DBUG_RETURN(memcmp(buff,temp_buff,length));
1659
Read record from datafile.
1662
_mi_read_rnd_dynamic_record()
1663
info MI_INFO pointer to table.
1664
buf Destination for record.
1665
filepos From where to read the record.
1666
skip_deleted_blocks If to repeat reading until a non-deleted
1671
If a write buffer is active, it needs to be flushed if its contents
1672
intersects with the record to read. We always check if the position
1673
of the first byte of the write buffer is lower than the position
1674
past the last byte to read. In theory this is also true if the write
1675
buffer is completely below the read segment. That is, if there is no
1676
intersection. But this case is unusual. We flush anyway. Only if the
1677
first byte in the write buffer is above the last byte to read, we do
1680
A dynamic record may need several reads. So this check must be done
1681
before every read. Reading a dynamic record starts with reading the
1682
block header. If the record does not fit into the free space of the
1683
header, the block may be longer than the header. In this case a
1684
second read is necessary. These one or two reads repeat for every
1692
int _mi_read_rnd_dynamic_record(MI_INFO *info, uchar *buf,
1693
register my_off_t filepos,
1694
my_bool skip_deleted_blocks)
1696
int block_of_record, info_read, save_errno;
1697
uint left_len,b_type;
1699
MI_BLOCK_INFO block_info;
1700
MYISAM_SHARE *share=info->s;
1701
DBUG_ENTER("_mi_read_rnd_dynamic_record");
1705
if (info->lock_type == F_UNLCK)
1707
#ifndef UNSAFE_LOCKING
1708
if (share->tot_locks == 0)
1710
if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
1711
MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
1712
DBUG_RETURN(my_errno);
1715
info->tmp_lock_type=F_RDLCK;
1719
info_read=1; /* memory-keyinfoblock is ok */
1721
block_of_record= 0; /* First block of record is numbered as zero. */
1722
block_info.second_read= 0;
1726
if (filepos >= info->state->data_file_length)
1729
{ /* Check if changed */
1731
info->rec_cache.seek_not_done=1;
1732
if (mi_state_info_read_dsk(share->kfile,&share->state,1))
1735
if (filepos >= info->state->data_file_length)
1737
my_errno= HA_ERR_END_OF_FILE;
1741
if (info->opt_flag & READ_CACHE_USED)
1743
if (_mi_read_cache(&info->rec_cache,(uchar*) block_info.header,filepos,
1744
sizeof(block_info.header),
1745
(!block_of_record && skip_deleted_blocks ?
1746
READING_NEXT : 0) | READING_HEADER))
1748
b_type=_mi_get_block_info(&block_info,-1,filepos);
1752
if (info->opt_flag & WRITE_CACHE_USED &&
1753
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1754
flush_io_cache(&info->rec_cache))
1755
DBUG_RETURN(my_errno);
1756
info->rec_cache.seek_not_done=1;
1757
b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1760
if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1763
if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1764
&& skip_deleted_blocks)
1766
filepos=block_info.filepos+block_info.block_len;
1767
block_info.second_read=0;
1768
continue; /* Search after next_record */
1770
if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1772
my_errno=HA_ERR_RECORD_DELETED;
1773
info->lastpos=block_info.filepos;
1774
info->nextpos=block_info.filepos+block_info.block_len;
1778
if (block_of_record == 0) /* First block */
1780
if (block_info.rec_len > (uint) share->base.max_pack_length)
1782
info->lastpos=filepos;
1783
if (share->base.blobs)
1785
if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
1791
left_len=block_info.rec_len;
1793
if (left_len < block_info.data_len)
1794
goto panic; /* Wrong linked record */
1796
/* copy information that is already read */
1798
uint offset=(uint) (block_info.filepos - filepos);
1799
uint tmp_length= (sizeof(block_info.header) - offset);
1800
filepos=block_info.filepos;
1802
if (tmp_length > block_info.data_len)
1803
tmp_length= block_info.data_len;
1806
memcpy((uchar*) to, block_info.header+offset,tmp_length);
1807
block_info.data_len-=tmp_length;
1808
left_len-=tmp_length;
1810
filepos+=tmp_length;
1813
/* read rest of record from file */
1814
if (block_info.data_len)
1816
if (info->opt_flag & READ_CACHE_USED)
1818
if (_mi_read_cache(&info->rec_cache,(uchar*) to,filepos,
1819
block_info.data_len,
1820
(!block_of_record && skip_deleted_blocks) ?
1826
if (info->opt_flag & WRITE_CACHE_USED &&
1827
info->rec_cache.pos_in_file <
1828
block_info.filepos + block_info.data_len &&
1829
flush_io_cache(&info->rec_cache))
1831
/* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */
1832
if (my_read(info->dfile,(uchar*) to,block_info.data_len,MYF(MY_NABP)))
1835
my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1841
Increment block-of-record counter. If it was the first block,
1842
remember the position behind the block for the next call.
1844
if (block_of_record++ == 0)
1846
info->nextpos= block_info.filepos + block_info.block_len;
1847
skip_deleted_blocks= 0;
1849
left_len-=block_info.data_len;
1850
to+=block_info.data_len;
1851
filepos=block_info.next_filepos;
1854
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1855
fast_mi_writeinfo(info);
1856
if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1859
DBUG_RETURN(my_errno); /* Wrong record */
1862
my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1864
save_errno=my_errno;
1865
VOID(_mi_writeinfo(info,0));
1866
DBUG_RETURN(my_errno=save_errno);
1870
/* Read and process header from a dynamic-record-file */
1872
uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
1875
uchar *header=info->header;
1880
We do not use my_pread() here because we want to have the file
1881
pointer set to the end of the header after this function.
1882
my_pread() may leave the file pointer untouched.
1884
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
1885
if (my_read(file, header, sizeof(info->header),MYF(0)) !=
1886
sizeof(info->header))
1889
DBUG_DUMP("header",header,MI_BLOCK_INFO_HEADER_LENGTH);
1890
if (info->second_read)
1892
if (info->header[0] <= 6 || info->header[0] == 13)
1893
return_val=BLOCK_SYNC_ERROR;
1897
if (info->header[0] > 6 && info->header[0] != 13)
1898
return_val=BLOCK_SYNC_ERROR;
1900
info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
1902
switch (info->header[0]) {
1904
if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1905
MI_MIN_BLOCK_LENGTH ||
1906
(info->block_len & (MI_DYN_ALIGN_SIZE -1)))
1908
info->filepos=filepos;
1909
info->next_filepos=mi_sizekorr(header+4);
1910
info->prev_filepos=mi_sizekorr(header+12);
1911
#if SIZEOF_OFF_T == 4
1912
if ((mi_uint4korr(header+4) != 0 &&
1913
(mi_uint4korr(header+4) != (ulong) ~0 ||
1914
info->next_filepos != (ulong) ~0)) ||
1915
(mi_uint4korr(header+12) != 0 &&
1916
(mi_uint4korr(header+12) != (ulong) ~0 ||
1917
info->prev_filepos != (ulong) ~0)))
1920
return return_val | BLOCK_DELETED; /* Deleted block */
1923
info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1924
info->filepos=filepos+3;
1925
return return_val | BLOCK_FIRST | BLOCK_LAST;
1927
info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1928
info->filepos=filepos+4;
1929
return return_val | BLOCK_FIRST | BLOCK_LAST;
1932
info->rec_len=mi_uint4korr(header+1);
1933
info->block_len=info->data_len=mi_uint3korr(header+5);
1934
info->next_filepos=mi_sizekorr(header+8);
1935
info->second_read=1;
1936
info->filepos=filepos+16;
1937
return return_val | BLOCK_FIRST;
1940
info->rec_len=info->data_len=mi_uint2korr(header+1);
1941
info->block_len=info->rec_len+ (uint) header[3];
1942
info->filepos=filepos+4;
1943
return return_val | BLOCK_FIRST | BLOCK_LAST;
1945
info->rec_len=info->data_len=mi_uint3korr(header+1);
1946
info->block_len=info->rec_len+ (uint) header[4];
1947
info->filepos=filepos+5;
1948
return return_val | BLOCK_FIRST | BLOCK_LAST;
1951
info->rec_len=mi_uint2korr(header+1);
1952
info->block_len=info->data_len=mi_uint2korr(header+3);
1953
info->next_filepos=mi_sizekorr(header+5);
1954
info->second_read=1;
1955
info->filepos=filepos+13;
1956
return return_val | BLOCK_FIRST;
1958
info->rec_len=mi_uint3korr(header+1);
1959
info->block_len=info->data_len=mi_uint3korr(header+4);
1960
info->next_filepos=mi_sizekorr(header+7);
1961
info->second_read=1;
1962
info->filepos=filepos+15;
1963
return return_val | BLOCK_FIRST;
1965
/* The following blocks are identical to 1-6 without rec_len */
1967
info->data_len=info->block_len=mi_uint2korr(header+1);
1968
info->filepos=filepos+3;
1969
return return_val | BLOCK_LAST;
1971
info->data_len=info->block_len=mi_uint3korr(header+1);
1972
info->filepos=filepos+4;
1973
return return_val | BLOCK_LAST;
1976
info->data_len=mi_uint2korr(header+1);
1977
info->block_len=info->data_len+ (uint) header[3];
1978
info->filepos=filepos+4;
1979
return return_val | BLOCK_LAST;
1981
info->data_len=mi_uint3korr(header+1);
1982
info->block_len=info->data_len+ (uint) header[4];
1983
info->filepos=filepos+5;
1984
return return_val | BLOCK_LAST;
1987
info->data_len=info->block_len=mi_uint2korr(header+1);
1988
info->next_filepos=mi_sizekorr(header+3);
1989
info->second_read=1;
1990
info->filepos=filepos+11;
1993
info->data_len=info->block_len=mi_uint3korr(header+1);
1994
info->next_filepos=mi_sizekorr(header+4);
1995
info->second_read=1;
1996
info->filepos=filepos+12;
2001
my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */