Drizzled Public API Documentation

mi_dynrec.cc
1 /* Copyright (C) 2000-2006 MySQL AB
2 
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.
6 
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.
11 
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 */
15 
16 /*
17  Functions to handle space-packed-records and blobs
18 
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()
24 */
25 
26 #include "myisam_priv.h"
27 
28 #ifdef HAVE_SYS_TYPES
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_MMAN_H
32 #include <sys/mman.h>
33 #endif
34 #include <drizzled/util/test.h>
35 #include <drizzled/error.h>
36 
37 #include <cassert>
38 #include <algorithm>
39 
40 using namespace drizzled;
41 using namespace std;
42 
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};
45 
46 static int write_dynamic_record(MI_INFO *info,const unsigned char *record,
47  ulong reclength);
48 static int _mi_find_writepos(MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
49  ulong *length);
50 static int update_dynamic_record(MI_INFO *info,internal::my_off_t filepos,unsigned char *record,
51  ulong reclength);
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,
55  uint32_t length);
56 
57  /* Interface function from MI_INFO */
58 
59 
60 /*
61  Create mmaped area for MyISAM handler
62 
63  SYNOPSIS
64  mi_dynmap_file()
65  info MyISAM handler
66 
67  RETURN
68  0 ok
69  1 error.
70 */
71 
72 bool mi_dynmap_file(MI_INFO *info, internal::my_off_t size)
73 {
74  if (size > (internal::my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
75  {
76  return(1);
77  }
78  /*
79  I wonder if it is good to use MAP_NORESERVE. From the Linux man page:
80  MAP_NORESERVE
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.
85  */
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,
91  info->dfile, 0L);
92  if (info->s->file_map == (unsigned char*) MAP_FAILED)
93  {
94  info->s->file_map= NULL;
95  return(1);
96  }
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);
100 #endif
101  info->s->mmaped_length= size;
102  return(0);
103 }
104 
105 
106 /*
107  Resize mmaped area for MyISAM handler
108 
109  SYNOPSIS
110  mi_remap_file()
111  info MyISAM handler
112 
113  RETURN
114 */
115 
116 void mi_remap_file(MI_INFO *info, internal::my_off_t size)
117 {
118  if (info->s->file_map)
119  {
120  munmap((char*) info->s->file_map,
121  (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
122  mi_dynmap_file(info, size);
123  }
124 }
125 
126 
127 /*
128  Read bytes from MySAM handler, using mmap or pread
129 
130  SYNOPSIS
131  mi_mmap_pread()
132  info MyISAM handler
133  Buffer Input buffer
134  Count Count of bytes for read
135  offset Start position
136  MyFlags
137 
138  RETURN
139  0 ok
140 */
141 
142 size_t mi_mmap_pread(MI_INFO *info, unsigned char *Buffer,
143  size_t Count, internal::my_off_t offset, myf MyFlags)
144 {
145  /*
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
149  memory mapped area.
150  */
151 
152  if (info->s->mmaped_length >= offset + Count)
153  {
154  memcpy(Buffer, info->s->file_map + offset, Count);
155  return 0;
156  }
157  else
158  {
159  return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
160  }
161 }
162 
163 
164  /* wrapper for my_pread in case if mmap isn't used */
165 
166 size_t mi_nommap_pread(MI_INFO *info, unsigned char *Buffer,
167  size_t Count, internal::my_off_t offset, myf MyFlags)
168 {
169  return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
170 }
171 
172 
173 /*
174  Write bytes to MySAM handler, using mmap or pwrite
175 
176  SYNOPSIS
177  mi_mmap_pwrite()
178  info MyISAM handler
179  Buffer Output buffer
180  Count Count of bytes for write
181  offset Start position
182  MyFlags
183 
184  RETURN
185  0 ok
186  !=0 error. In this case return error from pwrite
187 */
188 
189 size_t mi_mmap_pwrite(MI_INFO *info, const unsigned char *Buffer,
190  size_t Count, internal::my_off_t offset, myf MyFlags)
191 {
192 
193  /*
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
197  memory mapped area.
198  */
199 
200  if (info->s->mmaped_length >= offset + Count)
201  {
202  memcpy(info->s->file_map + offset, Buffer, Count);
203  return 0;
204  }
205  else
206  {
207  info->s->nonmmaped_inserts++;
208  return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
209  }
210 
211 }
212 
213 
214  /* wrapper for my_pwrite in case if mmap isn't used */
215 
216 size_t mi_nommap_pwrite(MI_INFO *info, const unsigned char *Buffer,
217  size_t Count, internal::my_off_t offset, myf MyFlags)
218 {
219  return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
220 }
221 
222 
223 int _mi_write_dynamic_record(MI_INFO *info, const unsigned char *record)
224 {
225  ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
226  return (write_dynamic_record(info,info->rec_buff,reclength));
227 }
228 
229 int _mi_update_dynamic_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
230 {
231  uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
232  return (update_dynamic_record(info,pos,info->rec_buff,length));
233 }
234 
235 int _mi_write_blob_record(MI_INFO *info, const unsigned char *record)
236 {
237  unsigned char *rec_buff;
238  int error;
239  ulong reclength,reclength2,extra;
240 
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)
247  {
248  errno=HA_ERR_TO_BIG_ROW;
249  return -1;
250  }
251 #endif
252  if (!(rec_buff=(unsigned char*) malloc(reclength)))
253  {
254  errno= HA_ERR_OUT_OF_MEM;
255  return(-1);
256  }
257  reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
258  record);
259  assert(reclength2 <= reclength);
260  error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
261  reclength2);
262  free(rec_buff);
263  return(error);
264 }
265 
266 
267 int _mi_update_blob_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
268 {
269  unsigned char *rec_buff;
270  int error;
271  ulong reclength,extra;
272 
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)
279  {
280  errno=HA_ERR_TO_BIG_ROW;
281  return -1;
282  }
283 #endif
284  if (!(rec_buff=(unsigned char*) malloc(reclength)))
285  {
286  errno= HA_ERR_OUT_OF_MEM;
287  return(-1);
288  }
289  reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
290  record);
291  error=update_dynamic_record(info,pos,
292  rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
293  reclength);
294  free(rec_buff);
295  return(error);
296 }
297 
298 
299 int _mi_delete_dynamic_record(MI_INFO *info)
300 {
301  return delete_dynamic_record(info,info->lastpos,0);
302 }
303 
304 
305  /* Write record to data-file */
306 
307 static int write_dynamic_record(MI_INFO *info, const unsigned char *record,
308  ulong reclength)
309 {
310  int flag;
311  ulong length;
312  internal::my_off_t filepos;
313 
314  flag=0;
315 
316  /*
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.
323  */
324 
325  if (unlikely(info->s->base.max_data_file_length -
326  info->state->data_file_length <
327  reclength + MI_MAX_DYN_BLOCK_HEADER))
328  {
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)
332  {
333  errno=HA_ERR_RECORD_FILE_FULL;
334  return(1);
335  }
336  }
337 
338  do
339  {
340  if (_mi_find_writepos(info,reclength,&filepos,&length))
341  goto err;
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))
346  goto err;
347  } while (reclength);
348 
349  return(0);
350 err:
351  return(1);
352 }
353 
354 
355  /* Get a block for data ; The given data-area must be used !! */
356 
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 */
361 {
362  MI_BLOCK_INFO block_info;
363  ulong tmp;
364 
365  if (info->s->state.dellink != HA_OFFSET_ERROR &&
366  !info->append_insert_at_end)
367  {
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) &
373  BLOCK_DELETED))
374  {
375  errno=HA_ERR_WRONG_IN_RECORD;
376  return(-1);
377  }
378  info->s->state.dellink=block_info.next_filepos;
379  info->state->del--;
380  info->state->empty-= block_info.block_len;
381  *length= block_info.block_len;
382  }
383  else
384  {
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;
390  else
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))
395  {
396  errno=HA_ERR_RECORD_FILE_FULL;
397  return(-1);
398  }
399  if (tmp > MI_MAX_BLOCK_LENGTH)
400  tmp=MI_MAX_BLOCK_LENGTH;
401  *length= tmp;
402  info->state->data_file_length+= tmp;
403  info->s->state.split++;
404  info->update|=HA_STATE_WRITE_AT_END;
405  }
406  return(0);
407 } /* _mi_find_writepos */
408 
409 
410 
411 /*
412  Unlink a deleted block from the deleted list.
413  This block will be combined with the preceding or next block to form
414  a big block.
415 */
416 
417 static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
418 {
419  if (block_info->filepos == info->s->state.dellink)
420  {
421  /* First deleted block; We can just use this ! */
422  info->s->state.dellink=block_info->next_filepos;
423  }
424  else
425  {
426  MI_BLOCK_INFO tmp;
427  tmp.second_read=0;
428  /* Unlink block from the previous block */
429  if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
430  & BLOCK_DELETED))
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)))
435  return(1);
436  /* Unlink block from next block */
437  if (block_info->next_filepos != HA_OFFSET_ERROR)
438  {
439  if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
440  & BLOCK_DELETED))
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,
445  MYF(MY_NABP)))
446  return(1);
447  }
448  }
449  /* We now have one less deleted block */
450  info->state->del--;
451  info->state->empty-= block_info->block_len;
452  info->s->state.split--;
453 
454  /*
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().
458  */
459  if (info->nextpos == block_info->filepos)
460  info->nextpos+=block_info->block_len;
461  return(0);
462 }
463 
464 
465 /*
466  Add a backward link to delete block
467 
468  SYNOPSIS
469  update_backward_delete_link()
470  info MyISAM handler
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
474 
475  RETURN
476  0 ok
477  1 error. In this case my_error is set.
478 */
479 
480 static int update_backward_delete_link(MI_INFO *info, internal::my_off_t delete_block,
481  internal::my_off_t filepos)
482 {
483  MI_BLOCK_INFO block_info;
484 
485  if (delete_block != HA_OFFSET_ERROR)
486  {
487  block_info.second_read=0;
488  if (_mi_get_block_info(&block_info,info->dfile,delete_block)
489  & BLOCK_DELETED)
490  {
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 */
495  }
496  else
497  {
498  errno=HA_ERR_WRONG_IN_RECORD;
499  return(1); /* Wrong delete link */
500  }
501  }
502  return(0);
503 }
504 
505  /* Delete datarecord from database */
506  /* info->rec_cache.seek_not_done is updated in cmp_record */
507 
508 static int delete_dynamic_record(MI_INFO *info, internal::my_off_t filepos,
509  uint32_t second_read)
510 {
511  uint32_t length,b_type;
512  MI_BLOCK_INFO block_info,del_block;
513  int error;
514  bool remove_next_block;
515 
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);
518 
519  block_info.second_read=second_read;
520  do
521  {
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) <
527  MI_MIN_BLOCK_LENGTH)
528  {
529  errno=HA_ERR_WRONG_IN_RECORD;
530  return(1);
531  }
532  /* Check if next block is a delete block */
533  del_block.second_read=0;
534  remove_next_block=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)
537  {
538  /* We can't remove this yet as this block may be the head block */
539  remove_next_block=1;
540  length+=del_block.block_len;
541  }
542 
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);
548  else
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,
551  MYF(MY_NABP)))
552  return(1);
553  info->s->state.dellink = filepos;
554  info->state->del++;
555  info->state->empty+=length;
556  filepos=block_info.next_filepos;
557 
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))
560  error=1;
561  } while (!(b_type & BLOCK_LAST));
562 
563  return(error);
564 }
565 
566 
567  /* Write a block to datafile */
568 
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 */
576 {
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];
581 
582  next_delete_block=HA_OFFSET_ERROR;
583 
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,
588  MI_DYN_ALIGN_SIZE);
589  length-= res_length; /* Use this for first part */
590  }
591  long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
592  if (length == *reclength+ 3 + long_block)
593  {
594  /* Block is exactly of the right length */
595  temp[0]=(unsigned char) (1+ *flag)+(unsigned char) long_block; /* Flag is 0 or 6 */
596  if (long_block)
597  {
598  mi_int3store(temp+1,*reclength);
599  head_length=4;
600  }
601  else
602  {
603  mi_int2store(temp+1,*reclength);
604  head_length=3;
605  }
606  }
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 */
614  {
615  if (*reclength > MI_MAX_BLOCK_LENGTH)
616  {
617  head_length= 16;
618  temp[0]=13;
619  mi_int4store(temp+1,*reclength);
620  mi_int3store(temp+5,length-head_length);
621  mi_sizestore((unsigned char*) temp+8,next_filepos);
622  }
623  else
624  {
625  head_length=5+8+long_block*2;
626  temp[0]=5+(unsigned char) long_block;
627  if (long_block)
628  {
629  mi_int3store(temp+1,*reclength);
630  mi_int3store(temp+4,length-head_length);
631  mi_sizestore((unsigned char*) temp+7,next_filepos);
632  }
633  else
634  {
635  mi_int2store(temp+1,*reclength);
636  mi_int2store(temp+3,length-head_length);
637  mi_sizestore((unsigned char*) temp+5,next_filepos);
638  }
639  }
640  }
641  else
642  {
643  head_length=3+8+long_block;
644  temp[0]=11+(unsigned char) long_block;
645  if (long_block)
646  {
647  mi_int3store(temp+1,length-head_length);
648  mi_sizestore((unsigned char*) temp+4,next_filepos);
649  }
650  else
651  {
652  mi_int2store(temp+1,length-head_length);
653  mi_sizestore((unsigned char*) temp+3,next_filepos);
654  }
655  }
656  }
657  else
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 */
662  if (long_block)
663  {
664  mi_int3store(temp+1,*reclength);
665  temp[4]= (unsigned char) (extra_length);
666  }
667  else
668  {
669  mi_int2store(temp+1,*reclength);
670  temp[3]= (unsigned char) (extra_length);
671  }
672  length= *reclength+head_length; /* Write only what is needed */
673  }
674 
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);
681 
682  if (res_length)
683  {
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;
687 
688  del_block.second_read=0;
689  if (next_block < info->state->data_file_length &&
690  info->s->state.dellink != HA_OFFSET_ERROR)
691  {
692  if ((_mi_get_block_info(&del_block,info->dfile,next_block)
693  & BLOCK_DELETED) &&
694  res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
695  {
696  if (unlink_deleted_block(info,&del_block))
697  goto err;
698  res_length+=del_block.block_len;
699  }
700  }
701 
702  /* Create a delete link of the last part of the block */
703  pos=record_end+extra_length;
704  pos[0]= '\0';
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;
710  info->state->del++;
711  info->state->empty+=res_length;
712  info->s->state.split++;
713  }
714  if (info->opt_flag & WRITE_CACHE_USED &&
715  info->update & HA_STATE_WRITE_AT_END)
716  {
717  if (info->update & HA_STATE_EXTEND_BLOCK)
718  {
719  info->update&= ~HA_STATE_EXTEND_BLOCK;
720  if (info->rec_cache.block_write(*record - head_length,
721  length+extra_length+del_length,filepos))
722  goto err;
723  }
724  else if (info->rec_cache.write(*record-head_length, length+extra_length+del_length))
725  goto err;
726  }
727  else
728  {
729  info->rec_cache.seek_not_done=1;
730  if (info->s->file_write(info,(unsigned char*) *record-head_length,length+extra_length+
731  del_length,filepos,info->s->write_flag))
732  goto err;
733  }
734  memcpy(record_end, temp, extra_length + del_length);
735  *record=record_end;
736  *reclength-=(length-head_length);
737  *flag=6;
738 
739  if (del_length)
740  {
741  /* link the next delete block to this */
742  if (update_backward_delete_link(info, next_delete_block,
743  info->s->state.dellink))
744  goto err;
745  }
746 
747  return(0);
748 err:
749  return(1);
750 } /*_mi_write_part_record */
751 
752 
753  /* update record from datafile */
754 
755 static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
756  ulong reclength)
757 {
758  int flag;
759  uint32_t error;
760  ulong length;
761  MI_BLOCK_INFO block_info;
762 
763  flag=block_info.second_read=0;
764  /*
765  Check if we have enough room for the record.
766  First we do simplified check to make usual case faster.
767  Then we do more precise check for the space left.
768  Though it still is not absolutely precise, as
769  we always use MI_MAX_DYN_BLOCK_HEADER while it can be
770  less in the most of the cases.
771  */
772 
773  /*
774  compare with just the reclength as we're going
775  to get some space from the old replaced record
776  */
777  if (unlikely(info->s->base.max_data_file_length -
778  info->state->data_file_length < reclength))
779  {
780  /*
781  let's read the old record's block to find out the length of the
782  old record
783  */
784  if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
785  & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
786  {
787  if (!(error & BLOCK_FATAL_ERROR))
788  errno=HA_ERR_WRONG_IN_RECORD;
789  goto err;
790  }
791 
792  /*
793  if new record isn't longer, we can go on safely
794  */
795  if (block_info.rec_len < reclength)
796  {
797  if (info->s->base.max_data_file_length - info->state->data_file_length +
798  info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
799  reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
800  {
801  errno=HA_ERR_RECORD_FILE_FULL;
802  goto err;
803  }
804  }
805  block_info.second_read=0;
806  }
807 
808  while (reclength > 0)
809  {
810  if (filepos != info->s->state.dellink)
811  {
812  block_info.next_filepos= HA_OFFSET_ERROR;
813  if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
814  & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
815  BLOCK_FATAL_ERROR))
816  {
817  if (!(error & BLOCK_FATAL_ERROR))
818  errno=HA_ERR_WRONG_IN_RECORD;
819  goto err;
820  }
821  length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
822  if (length < reclength)
823  {
824  uint32_t tmp=MY_ALIGN(reclength - length + 3 +
825  test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
826  /* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
827  tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
828  /* Check if we can extend this block */
829  if (block_info.filepos + block_info.block_len ==
830  info->state->data_file_length &&
831  info->state->data_file_length <
832  info->s->base.max_data_file_length-tmp)
833  {
834  /* extend file */
835  if (info->nextpos == info->state->data_file_length)
836  info->nextpos+= tmp;
837  info->state->data_file_length+= tmp;
838  info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
839  length+=tmp;
840  }
841  else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
842  {
843  /*
844  Check if next block is a deleted block
845  Above we have MI_MIN_BLOCK_LENGTH to avoid the problem where
846  the next block is so small it can't be splited which could
847  casue problems
848  */
849 
850  MI_BLOCK_INFO del_block;
851  del_block.second_read=0;
852  if (_mi_get_block_info(&del_block,info->dfile,
853  block_info.filepos + block_info.block_len) &
854  BLOCK_DELETED)
855  {
856  /* Use; Unlink it and extend the current block */
857  if (unlink_deleted_block(info,&del_block))
858  goto err;
859  if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
860  {
861  /*
862  New block was too big, link overflow part back to
863  delete list
864  */
865  internal::my_off_t next_pos;
866  ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
867  set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
868  next_pos= del_block.filepos+ del_block.block_len - rest_length;
869 
870  if (update_backward_delete_link(info, info->s->state.dellink,
871  next_pos))
872  return(1);
873 
874  /* create delete link for data that didn't fit into the page */
875  del_block.header[0]=0;
876  mi_int3store(del_block.header+1, rest_length);
877  mi_sizestore(del_block.header+4,info->s->state.dellink);
878  memset(del_block.header+12, 255, 8);
879  if (info->s->file_write(info,(unsigned char*) del_block.header,20, next_pos,
880  MYF(MY_NABP)))
881  return(1);
882  info->s->state.dellink= next_pos;
883  info->s->state.split++;
884  info->state->del++;
885  info->state->empty+= rest_length;
886  length-= rest_length;
887  }
888  }
889  }
890  }
891  }
892  else
893  {
894  if (_mi_find_writepos(info,reclength,&filepos,&length))
895  goto err;
896  }
897  if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
898  &record,&reclength,&flag))
899  goto err;
900  if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
901  {
902  /* Start writing data on deleted blocks */
903  filepos=info->s->state.dellink;
904  }
905  }
906 
907  if (block_info.next_filepos != HA_OFFSET_ERROR)
908  if (delete_dynamic_record(info,block_info.next_filepos,1))
909  goto err;
910  return(0);
911 err:
912  return(1);
913 }
914 
915 
916  /* Pack a record. Return new reclength */
917 
918 uint32_t _mi_rec_pack(MI_INFO *info, register unsigned char *to,
919  register const unsigned char *from)
920 {
921  uint length,new_length,flag,bit,i;
922  unsigned char *pos,*end,*startpos,*packpos;
923  enum en_fieldtype type;
924  register MI_COLUMNDEF *rec;
925  MI_BLOB *blob;
926 
927  flag=0 ; bit=1;
928  startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
929  rec=info->s->rec;
930 
931  for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
932  {
933  length=(uint) rec->length;
934  if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
935  {
936  if (type == FIELD_BLOB)
937  {
938  if (!blob->length)
939  flag|=bit;
940  else
941  {
942  char *temp_pos;
943  size_t tmp_length=length-portable_sizeof_char_ptr;
944  memcpy(to,from,tmp_length);
945  memcpy(&temp_pos,from+tmp_length,sizeof(char*));
946  memcpy(to + tmp_length, temp_pos, blob->length);
947  to+=tmp_length+blob->length;
948  }
949  blob++;
950  }
951  else if (type == FIELD_SKIP_ZERO)
952  {
953  if (memcmp(from,zero_string,length) == 0)
954  flag|=bit;
955  else
956  {
957  memcpy(to, from, length);
958  to+=length;
959  }
960  }
961  else if (type == FIELD_SKIP_ENDSPACE ||
962  type == FIELD_SKIP_PRESPACE)
963  {
964  pos= (unsigned char*) from; end= (unsigned char*) from + length;
965  if (type == FIELD_SKIP_ENDSPACE)
966  { /* Pack trailing spaces */
967  while (end > from && *(end-1) == ' ')
968  end--;
969  }
970  else
971  { /* Pack pref-spaces */
972  while (pos < end && *pos == ' ')
973  pos++;
974  }
975  new_length=(uint) (end-pos);
976  if (new_length +1 + test(rec->length > 255 && new_length > 127)
977  < length)
978  {
979  if (rec->length > 255 && new_length > 127)
980  {
981  to[0]= (unsigned char) ((new_length & 127) + 128);
982  to[1]= (unsigned char) (new_length >> 7);
983  to+=2;
984  }
985  else
986  *to++= (unsigned char) new_length;
987  memcpy(to, pos, new_length);
988  to+=new_length;
989  flag|=bit;
990  }
991  else
992  {
993  memcpy(to, from, length);
994  to+=length;
995  }
996  }
997  else if (type == FIELD_VARCHAR)
998  {
999  uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1000  uint32_t tmp_length;
1001  if (pack_length == 1)
1002  {
1003  tmp_length= (uint) *(unsigned char*) from;
1004  *to++= *from;
1005  }
1006  else
1007  {
1008  tmp_length= uint2korr(from);
1009  store_key_length_inc(to,tmp_length);
1010  }
1011  memcpy(to, from+pack_length, tmp_length);
1012  to+= tmp_length;
1013  continue;
1014  }
1015  else
1016  {
1017  memcpy(to, from, length);
1018  to+=length;
1019  continue; /* Normal field */
1020  }
1021  if ((bit= bit << 1) >= 256)
1022  {
1023  *packpos++= (unsigned char) flag;
1024  bit=1; flag=0;
1025  }
1026  }
1027  else
1028  {
1029  memcpy(to, from, length);
1030  to+=length;
1031  }
1032  }
1033  if (bit != 1)
1034  *packpos= (unsigned char) flag;
1035  if (info->s->calc_checksum)
1036  *to++= (unsigned char) info->checksum;
1037  return((uint) (to-startpos));
1038 } /* _mi_rec_pack */
1039 
1040 
1041 
1042 /*
1043  Check if a record was correctly packed. Used only by myisamchk
1044  Returns 0 if record is ok.
1045 */
1046 
1047 bool _mi_rec_check(MI_INFO *info,const unsigned char *record, unsigned char *rec_buff,
1048  ulong packed_length, bool with_checksum)
1049 {
1050  uint length,new_length,flag,bit,i;
1051  unsigned char *pos,*end,*packpos,*to;
1052  enum en_fieldtype type;
1053  register MI_COLUMNDEF *rec;
1054 
1055  packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
1056  rec=info->s->rec;
1057  flag= *packpos; bit=1;
1058 
1059  for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
1060  {
1061  length=(uint) rec->length;
1062  if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
1063  {
1064  if (type == FIELD_BLOB)
1065  {
1066  uint32_t blob_length=
1067  _mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
1068  if (!blob_length && !(flag & bit))
1069  goto err;
1070  if (blob_length)
1071  to+=length - portable_sizeof_char_ptr+ blob_length;
1072  }
1073  else if (type == FIELD_SKIP_ZERO)
1074  {
1075  if (memcmp(record,zero_string,length) == 0)
1076  {
1077  if (!(flag & bit))
1078  goto err;
1079  }
1080  else
1081  to+=length;
1082  }
1083  else if (type == FIELD_SKIP_ENDSPACE ||
1084  type == FIELD_SKIP_PRESPACE)
1085  {
1086  pos= (unsigned char*) record; end= (unsigned char*) record + length;
1087  if (type == FIELD_SKIP_ENDSPACE)
1088  { /* Pack trailing spaces */
1089  while (end > record && *(end-1) == ' ')
1090  end--;
1091  }
1092  else
1093  { /* Pack pre-spaces */
1094  while (pos < end && *pos == ' ')
1095  pos++;
1096  }
1097  new_length=(uint) (end-pos);
1098  if (new_length +1 + test(rec->length > 255 && new_length > 127)
1099  < length)
1100  {
1101  if (!(flag & bit))
1102  goto err;
1103  if (rec->length > 255 && new_length > 127)
1104  {
1105  if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
1106  to[1] != (unsigned char) (new_length >> 7))
1107  goto err;
1108  to+=2;
1109  }
1110  else if (*to++ != (unsigned char) new_length)
1111  goto err;
1112  to+=new_length;
1113  }
1114  else
1115  to+=length;
1116  }
1117  else if (type == FIELD_VARCHAR)
1118  {
1119  uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1120  uint32_t tmp_length;
1121  if (pack_length == 1)
1122  {
1123  tmp_length= (uint) *(unsigned char*) record;
1124  to+= 1+ tmp_length;
1125  continue;
1126  }
1127  else
1128  {
1129  tmp_length= uint2korr(record);
1130  to+= get_pack_length(tmp_length)+tmp_length;
1131  }
1132  continue;
1133  }
1134  else
1135  {
1136  to+=length;
1137  continue; /* Normal field */
1138  }
1139  if ((bit= bit << 1) >= 256)
1140  {
1141  flag= *++packpos;
1142  bit=1;
1143  }
1144  }
1145  else
1146  to+= length;
1147  }
1148  if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
1149  (bit != 1 && (flag & ~(bit - 1))))
1150  goto err;
1151  if (with_checksum && ((unsigned char) info->checksum != (unsigned char) *to))
1152  {
1153  goto err;
1154  }
1155  return(0);
1156 
1157 err:
1158  return(1);
1159 }
1160 
1161 
1162 
1163  /* Unpacks a record */
1164  /* Returns -1 and errno =HA_ERR_RECORD_DELETED if reclength isn't */
1165  /* right. Returns reclength (>0) if ok */
1166 
1167 ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
1168  ulong found_length)
1169 {
1170  uint32_t flag,bit,length,rec_length,min_pack_length;
1171  enum en_fieldtype type;
1172  unsigned char *from_end,*to_end,*packpos;
1173  register MI_COLUMNDEF *rec,*end_field;
1174 
1175  to_end=to + info->s->base.reclength;
1176  from_end=from+found_length;
1177  flag= (unsigned char) *from; bit=1; packpos=from;
1178  if (found_length < info->s->base.min_pack_length)
1179  goto err;
1180  from+= info->s->base.pack_bits;
1181  min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
1182 
1183  for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
1184  rec < end_field ; to+= rec_length, rec++)
1185  {
1186  rec_length=rec->length;
1187  if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
1188  (type != FIELD_CHECK))
1189  {
1190  if (type == FIELD_VARCHAR)
1191  {
1192  uint32_t pack_length= ha_varchar_packlength(rec_length-1);
1193  if (pack_length == 1)
1194  {
1195  length= (uint) *(unsigned char*) from;
1196  if (length > rec_length-1)
1197  goto err;
1198  *to= *from++;
1199  }
1200  else
1201  {
1202  get_key_length(length, from);
1203  if (length > rec_length-2)
1204  goto err;
1205  int2store(to,length);
1206  }
1207  if (from+length > from_end)
1208  goto err;
1209  memcpy(to+pack_length, from, length);
1210  from+= length;
1211  min_pack_length--;
1212  continue;
1213  }
1214  if (flag & bit)
1215  {
1216  if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1217  memset(to, 0, rec_length);
1218  else if (type == FIELD_SKIP_ENDSPACE ||
1219  type == FIELD_SKIP_PRESPACE)
1220  {
1221  if (rec->length > 255 && *from & 128)
1222  {
1223  if (from + 1 >= from_end)
1224  goto err;
1225  length= (*from & 127)+ ((uint) (unsigned char) *(from+1) << 7); from+=2;
1226  }
1227  else
1228  {
1229  if (from == from_end)
1230  goto err;
1231  length= (unsigned char) *from++;
1232  }
1233  min_pack_length--;
1234  if (length >= rec_length ||
1235  min_pack_length + length > (uint) (from_end - from))
1236  goto err;
1237  if (type == FIELD_SKIP_ENDSPACE)
1238  {
1239  memcpy(to, from, length);
1240  memset(to+length, ' ', rec_length-length);
1241  }
1242  else
1243  {
1244  memset(to, ' ', rec_length-length);
1245  memcpy(to + rec_length - length, from, length);
1246  }
1247  from+=length;
1248  }
1249  }
1250  else if (type == FIELD_BLOB)
1251  {
1252  uint32_t size_length=rec_length- portable_sizeof_char_ptr;
1253  ulong blob_length=_mi_calc_blob_length(size_length,from);
1254  ulong from_left= (ulong) (from_end - from);
1255  if (from_left < size_length ||
1256  from_left - size_length < blob_length ||
1257  from_left - size_length - blob_length < min_pack_length)
1258  goto err;
1259  memcpy(to, from, size_length);
1260  from+=size_length;
1261  memcpy(to+size_length, &from, sizeof(char*));
1262  from+=blob_length;
1263  }
1264  else
1265  {
1266  if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1267  min_pack_length--;
1268  if (min_pack_length + rec_length > (uint) (from_end - from))
1269  goto err;
1270  memcpy(to, from, rec_length);
1271  from+=rec_length;
1272  }
1273  if ((bit= bit << 1) >= 256)
1274  {
1275  flag= (unsigned char) *++packpos; bit=1;
1276  }
1277  }
1278  else
1279  {
1280  if (min_pack_length > (uint) (from_end - from))
1281  goto err;
1282  min_pack_length-=rec_length;
1283  memcpy(to, from, rec_length);
1284  from+=rec_length;
1285  }
1286  }
1287  if (info->s->calc_checksum)
1288  from++;
1289  if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1290  return(found_length);
1291 
1292 err:
1293  errno= HA_ERR_WRONG_IN_RECORD;
1294  return(MY_FILE_ERROR);
1295 } /* _mi_rec_unpack */
1296 
1297 
1298  /* Calc length of blob. Update info in blobs->length */
1299 
1300 ulong _my_calc_total_blob_length(MI_INFO *info, const unsigned char *record)
1301 {
1302  ulong length;
1303  MI_BLOB *blob,*end;
1304 
1305  for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1306  blob != end;
1307  blob++)
1308  {
1309  blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
1310  length+=blob->length;
1311  }
1312  return length;
1313 }
1314 
1315 
1316 ulong _mi_calc_blob_length(uint32_t length, const unsigned char *pos)
1317 {
1318  switch (length) {
1319  case 1:
1320  return (uint) (unsigned char) *pos;
1321  case 2:
1322  return (uint) uint2korr(pos);
1323  case 3:
1324  return uint3korr(pos);
1325  case 4:
1326  return uint4korr(pos);
1327  default:
1328  break;
1329  }
1330  return 0; /* Impossible */
1331 }
1332 
1333 
1334 void _my_store_blob_length(unsigned char *pos,uint32_t pack_length,uint32_t length)
1335 {
1336  switch (pack_length) {
1337  case 1:
1338  *pos= (unsigned char) length;
1339  break;
1340  case 2:
1341  int2store(pos,length);
1342  break;
1343  case 3:
1344  int3store(pos,length);
1345  break;
1346  case 4:
1347  int4store(pos,length);
1348  default:
1349  break;
1350  }
1351  return;
1352 }
1353 
1354 
1355 /*
1356  Read record from datafile.
1357 
1358  SYNOPSIS
1359  _mi_read_dynamic_record()
1360  info MI_INFO pointer to table.
1361  filepos From where to read the record.
1362  buf Destination for record.
1363 
1364  NOTE
1365 
1366  If a write buffer is active, it needs to be flushed if its contents
1367  intersects with the record to read. We always check if the position
1368  of the first byte of the write buffer is lower than the position
1369  past the last byte to read. In theory this is also true if the write
1370  buffer is completely below the read segment. That is, if there is no
1371  intersection. But this case is unusual. We flush anyway. Only if the
1372  first byte in the write buffer is above the last byte to read, we do
1373  not flush.
1374 
1375  A dynamic record may need several reads. So this check must be done
1376  before every read. Reading a dynamic record starts with reading the
1377  block header. If the record does not fit into the free space of the
1378  header, the block may be longer than the header. In this case a
1379  second read is necessary. These one or two reads repeat for every
1380  part of the record.
1381 
1382  RETURN
1383  0 OK
1384  -1 Error
1385 */
1386 
1387 int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
1388 {
1389  int block_of_record;
1390  uint32_t b_type, left_length= 0;
1391  unsigned char *to= NULL;
1392  MI_BLOCK_INFO block_info;
1393  int file;
1394 
1395  if (filepos != HA_OFFSET_ERROR)
1396  {
1397  file=info->dfile;
1398  block_of_record= 0; /* First block of record is numbered as zero. */
1399  block_info.second_read= 0;
1400  do
1401  {
1402  /* A corrupted table can have wrong pointers. (Bug# 19835) */
1403  if (filepos == HA_OFFSET_ERROR)
1404  goto panic;
1405  if (info->opt_flag & WRITE_CACHE_USED &&
1406  info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1407  info->rec_cache.flush())
1408  goto err;
1409  info->rec_cache.seek_not_done=1;
1410  if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1411  & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1412  BLOCK_FATAL_ERROR))
1413  {
1414  if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1415  errno=HA_ERR_RECORD_DELETED;
1416  goto err;
1417  }
1418  if (block_of_record++ == 0) /* First block */
1419  {
1420  if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1421  goto panic;
1422  if (info->s->base.blobs)
1423  {
1424  if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
1425  &info->rec_buff)))
1426  goto err;
1427  }
1428  else
1429  to= info->rec_buff;
1430  left_length=block_info.rec_len;
1431  }
1432  if (left_length < block_info.data_len || ! block_info.data_len)
1433  goto panic; /* Wrong linked record */
1434  /* copy information that is already read */
1435  {
1436  uint32_t offset= (uint) (block_info.filepos - filepos);
1437  uint32_t prefetch_len= (sizeof(block_info.header) - offset);
1438  filepos+= sizeof(block_info.header);
1439 
1440  if (prefetch_len > block_info.data_len)
1441  prefetch_len= block_info.data_len;
1442  if (prefetch_len)
1443  {
1444  memcpy(to, block_info.header + offset, prefetch_len);
1445  block_info.data_len-= prefetch_len;
1446  left_length-= prefetch_len;
1447  to+= prefetch_len;
1448  }
1449  }
1450  /* read rest of record from file */
1451  if (block_info.data_len)
1452  {
1453  if (info->opt_flag & WRITE_CACHE_USED &&
1454  info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1455  info->rec_cache.flush())
1456  goto err;
1457  /*
1458  What a pity that this method is not called 'file_pread' and that
1459  there is no equivalent without seeking. We are at the right
1460  position already. :(
1461  */
1462  if (info->s->file_read(info, (unsigned char*) to, block_info.data_len,
1463  filepos, MYF(MY_NABP)))
1464  goto panic;
1465  left_length-=block_info.data_len;
1466  to+=block_info.data_len;
1467  }
1468  filepos= block_info.next_filepos;
1469  } while (left_length);
1470 
1471  info->update|= HA_STATE_AKTIV; /* We have a aktive record */
1472  fast_mi_writeinfo(info);
1473  return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1474  MY_FILE_ERROR ? 0 : -1);
1475  }
1476  fast_mi_writeinfo(info);
1477  return(-1); /* Wrong data to read */
1478 
1479 panic:
1480  errno=HA_ERR_WRONG_IN_RECORD;
1481 err:
1482  _mi_writeinfo(info,0);
1483  return(-1);
1484 }
1485 
1486  /* compare unique constraint between stored rows */
1487 
1488 int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
1489  const unsigned char *record, internal::my_off_t pos)
1490 {
1491  unsigned char *rec_buff,*old_record;
1492  int error;
1493 
1494  if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
1495  return(1);
1496 
1497  /* Don't let the compare destroy blobs that may be in use */
1498  rec_buff=info->rec_buff;
1499  if (info->s->base.blobs)
1500  info->rec_buff=0;
1501  error=_mi_read_dynamic_record(info,pos,old_record);
1502  if (!error)
1503  error=mi_unique_comp(def, record, old_record, def->null_are_equal);
1504  if (info->s->base.blobs)
1505  {
1506  void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
1507  free(rec_buff_ptr);
1508  info->rec_buff=rec_buff;
1509  }
1510  free(old_record);
1511  return(error);
1512 }
1513 
1514 
1515  /* Compare of record one disk with packed record in memory */
1516 
1517 int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
1518 {
1519  uint32_t flag,reclength,b_type;
1520  internal::my_off_t filepos;
1521  unsigned char *buffer;
1522  MI_BLOCK_INFO block_info;
1523 
1524  if (info->opt_flag & WRITE_CACHE_USED)
1525  {
1526  info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1527  if (info->rec_cache.flush())
1528  return(-1);
1529  }
1530  info->rec_cache.seek_not_done=1;
1531 
1532  /* If nobody have touched the database we don't have to test rec */
1533 
1534  buffer=info->rec_buff;
1535  if ((info->opt_flag & READ_CHECK_USED))
1536  { /* If check isn't disabled */
1537  if (info->s->base.blobs)
1538  {
1539  if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
1540  _my_calc_total_blob_length(info,record))))
1541  return(-1);
1542  }
1543  reclength=_mi_rec_pack(info,buffer,record);
1544  record= buffer;
1545 
1546  filepos=info->lastpos;
1547  flag=block_info.second_read=0;
1548  block_info.next_filepos=filepos;
1549  while (reclength > 0)
1550  {
1551  if ((b_type=_mi_get_block_info(&block_info,info->dfile,
1552  block_info.next_filepos))
1553  & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1554  BLOCK_FATAL_ERROR))
1555  {
1556  if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1557  errno=HA_ERR_RECORD_CHANGED;
1558  goto err;
1559  }
1560  if (flag == 0) /* First block */
1561  {
1562  flag=1;
1563  if (reclength != block_info.rec_len)
1564  {
1565  errno=HA_ERR_RECORD_CHANGED;
1566  goto err;
1567  }
1568  } else if (reclength < block_info.data_len)
1569  {
1570  errno=HA_ERR_WRONG_IN_RECORD;
1571  goto err;
1572  }
1573  reclength-=block_info.data_len;
1574  if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1575  block_info.data_len))
1576  {
1577  errno=HA_ERR_RECORD_CHANGED;
1578  goto err;
1579  }
1580  flag=1;
1581  record+=block_info.data_len;
1582  }
1583  }
1584  errno=0;
1585 err:
1586  if (buffer != info->rec_buff)
1587  free((unsigned char*) buffer);
1588  return(errno);
1589 }
1590 
1591 
1592  /* Compare file to buffert */
1593 
1594 static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
1595  uint32_t length)
1596 {
1597  uint32_t next_length;
1598  unsigned char temp_buff[IO_SIZE*2];
1599 
1600  next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1601 
1602  while (length > IO_SIZE*2)
1603  {
1604  if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1605  memcmp(buff, temp_buff, next_length))
1606  goto err;
1607  filepos+=next_length;
1608  buff+=next_length;
1609  length-= next_length;
1610  next_length=IO_SIZE*2;
1611  }
1612  if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1613  goto err;
1614  return(memcmp(buff,temp_buff,length));
1615 err:
1616  return(1);
1617 }
1618 
1619 
1620 /*
1621  Read record from datafile.
1622 
1623  SYNOPSIS
1624  _mi_read_rnd_dynamic_record()
1625  info MI_INFO pointer to table.
1626  buf Destination for record.
1627  filepos From where to read the record.
1628  skip_deleted_blocks If to repeat reading until a non-deleted
1629  record is found.
1630 
1631  NOTE
1632 
1633  If a write buffer is active, it needs to be flushed if its contents
1634  intersects with the record to read. We always check if the position
1635  of the first byte of the write buffer is lower than the position
1636  past the last byte to read. In theory this is also true if the write
1637  buffer is completely below the read segment. That is, if there is no
1638  intersection. But this case is unusual. We flush anyway. Only if the
1639  first byte in the write buffer is above the last byte to read, we do
1640  not flush.
1641 
1642  A dynamic record may need several reads. So this check must be done
1643  before every read. Reading a dynamic record starts with reading the
1644  block header. If the record does not fit into the free space of the
1645  header, the block may be longer than the header. In this case a
1646  second read is necessary. These one or two reads repeat for every
1647  part of the record.
1648 
1649  RETURN
1650  0 OK
1651  != 0 Error
1652 */
1653 
1654 int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
1655  register internal::my_off_t filepos,
1656  bool skip_deleted_blocks)
1657 {
1658  int block_of_record, info_read, save_errno;
1659  uint32_t left_len,b_type;
1660  unsigned char *to= NULL;
1661  MI_BLOCK_INFO block_info;
1662  MYISAM_SHARE *share=info->s;
1663 
1664  info_read=0;
1665 
1666  if (info->lock_type == F_UNLCK)
1667  {
1668  info->tmp_lock_type=F_RDLCK;
1669  }
1670  else
1671  info_read=1; /* memory-keyinfoblock is ok */
1672 
1673  block_of_record= 0; /* First block of record is numbered as zero. */
1674  block_info.second_read= 0;
1675  left_len=1;
1676  do
1677  {
1678  if (filepos >= info->state->data_file_length)
1679  {
1680  if (!info_read)
1681  { /* Check if changed */
1682  info_read=1;
1683  info->rec_cache.seek_not_done=1;
1684  if (mi_state_info_read_dsk(share->kfile,&share->state,1))
1685  goto panic;
1686  }
1687  if (filepos >= info->state->data_file_length)
1688  {
1689  errno= HA_ERR_END_OF_FILE;
1690  goto err;
1691  }
1692  }
1693  if (info->opt_flag & READ_CACHE_USED)
1694  {
1695  if (_mi_read_cache(&info->rec_cache,(unsigned char*) block_info.header,filepos,
1696  sizeof(block_info.header),
1697  (!block_of_record && skip_deleted_blocks ?
1698  READING_NEXT : 0) | READING_HEADER))
1699  goto panic;
1700  b_type=_mi_get_block_info(&block_info,-1,filepos);
1701  }
1702  else
1703  {
1704  if (info->opt_flag & WRITE_CACHE_USED &&
1705  info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1706  info->rec_cache.flush())
1707  return(errno);
1708  info->rec_cache.seek_not_done=1;
1709  b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1710  }
1711 
1712  if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1713  BLOCK_FATAL_ERROR))
1714  {
1715  if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1716  && skip_deleted_blocks)
1717  {
1718  filepos=block_info.filepos+block_info.block_len;
1719  block_info.second_read=0;
1720  continue; /* Search after next_record */
1721  }
1722  if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1723  {
1724  errno=HA_ERR_RECORD_DELETED;
1725  info->lastpos=block_info.filepos;
1726  info->nextpos=block_info.filepos+block_info.block_len;
1727  }
1728  goto err;
1729  }
1730  if (block_of_record == 0) /* First block */
1731  {
1732  if (block_info.rec_len > (uint) share->base.max_pack_length)
1733  goto panic;
1734  info->lastpos=filepos;
1735  if (share->base.blobs)
1736  {
1737  if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
1738  &info->rec_buff)))
1739  goto err;
1740  }
1741  else
1742  to= info->rec_buff;
1743  left_len=block_info.rec_len;
1744  }
1745  if (left_len < block_info.data_len)
1746  goto panic; /* Wrong linked record */
1747 
1748  /* copy information that is already read */
1749  {
1750  uint32_t offset=(uint) (block_info.filepos - filepos);
1751  uint32_t tmp_length= (sizeof(block_info.header) - offset);
1752  filepos=block_info.filepos;
1753 
1754  if (tmp_length > block_info.data_len)
1755  tmp_length= block_info.data_len;
1756  if (tmp_length)
1757  {
1758  memcpy(to, block_info.header+offset,tmp_length);
1759  block_info.data_len-=tmp_length;
1760  left_len-=tmp_length;
1761  to+=tmp_length;
1762  filepos+=tmp_length;
1763  }
1764  }
1765  /* read rest of record from file */
1766  if (block_info.data_len)
1767  {
1768  if (info->opt_flag & READ_CACHE_USED)
1769  {
1770  if (_mi_read_cache(&info->rec_cache,(unsigned char*) to,filepos,
1771  block_info.data_len,
1772  (!block_of_record && skip_deleted_blocks) ?
1773  READING_NEXT : 0))
1774  goto panic;
1775  }
1776  else
1777  {
1778  if (info->opt_flag & WRITE_CACHE_USED &&
1779  info->rec_cache.pos_in_file <
1780  block_info.filepos + block_info.data_len &&
1781  info->rec_cache.flush())
1782  goto err;
1783  /* lseek(info->dfile,filepos,SEEK_SET); */
1784  if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1785  {
1786  if (errno == -1)
1787  errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1788  goto err;
1789  }
1790  }
1791  }
1792  /*
1793  Increment block-of-record counter. If it was the first block,
1794  remember the position behind the block for the next call.
1795  */
1796  if (block_of_record++ == 0)
1797  {
1798  info->nextpos= block_info.filepos + block_info.block_len;
1799  skip_deleted_blocks= 0;
1800  }
1801  left_len-=block_info.data_len;
1802  to+=block_info.data_len;
1803  filepos=block_info.next_filepos;
1804  } while (left_len);
1805 
1806  info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1807  fast_mi_writeinfo(info);
1808  if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1809  MY_FILE_ERROR)
1810  return(0);
1811  return(errno); /* Wrong record */
1812 
1813 panic:
1814  errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1815 err:
1816  save_errno=errno;
1817  _mi_writeinfo(info,0);
1818  return(errno=save_errno);
1819 }
1820 
1821 
1822  /* Read and process header from a dynamic-record-file */
1823 
1824 uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
1825 {
1826  uint32_t return_val=0;
1827  unsigned char *header=info->header;
1828 
1829  if (file >= 0)
1830  {
1831  /*
1832  We do not use my_pread() here because we want to have the file
1833  pointer set to the end of the header after this function.
1834  my_pread() may leave the file pointer untouched.
1835  */
1836  lseek(file,filepos,SEEK_SET);
1837  if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
1838  sizeof(info->header))
1839  goto err;
1840  }
1841  if (info->second_read)
1842  {
1843  if (info->header[0] <= 6 || info->header[0] == 13)
1844  return_val=BLOCK_SYNC_ERROR;
1845  }
1846  else
1847  {
1848  if (info->header[0] > 6 && info->header[0] != 13)
1849  return_val=BLOCK_SYNC_ERROR;
1850  }
1851  info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
1852 
1853  switch (info->header[0]) {
1854  case 0:
1855  if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1856  MI_MIN_BLOCK_LENGTH ||
1857  (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
1858  goto err;
1859  info->filepos=filepos;
1860  info->next_filepos=mi_sizekorr(header+4);
1861  info->prev_filepos=mi_sizekorr(header+12);
1862 #if SIZEOF_OFF_T == 4
1863  if ((mi_uint4korr(header+4) != 0 &&
1864  (mi_uint4korr(header+4) != UINT32_MAX ||
1865  info->next_filepos != UINT32_MAX) ||
1866  (mi_uint4korr(header+12) != 0 &&
1867  (mi_uint4korr(header+12) != UINT32_MAX ||
1868  info->prev_filepos != UINT32_MAX))
1869  goto err;
1870 #endif
1871  return return_val | BLOCK_DELETED; /* Deleted block */
1872 
1873  case 1:
1874  info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1875  info->filepos=filepos+3;
1876  return return_val | BLOCK_FIRST | BLOCK_LAST;
1877  case 2:
1878  info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1879  info->filepos=filepos+4;
1880  return return_val | BLOCK_FIRST | BLOCK_LAST;
1881 
1882  case 13:
1883  info->rec_len=mi_uint4korr(header+1);
1884  info->block_len=info->data_len=mi_uint3korr(header+5);
1885  info->next_filepos=mi_sizekorr(header+8);
1886  info->second_read=1;
1887  info->filepos=filepos+16;
1888  return return_val | BLOCK_FIRST;
1889 
1890  case 3:
1891  info->rec_len=info->data_len=mi_uint2korr(header+1);
1892  info->block_len=info->rec_len+ (uint) header[3];
1893  info->filepos=filepos+4;
1894  return return_val | BLOCK_FIRST | BLOCK_LAST;
1895  case 4:
1896  info->rec_len=info->data_len=mi_uint3korr(header+1);
1897  info->block_len=info->rec_len+ (uint) header[4];
1898  info->filepos=filepos+5;
1899  return return_val | BLOCK_FIRST | BLOCK_LAST;
1900 
1901  case 5:
1902  info->rec_len=mi_uint2korr(header+1);
1903  info->block_len=info->data_len=mi_uint2korr(header+3);
1904  info->next_filepos=mi_sizekorr(header+5);
1905  info->second_read=1;
1906  info->filepos=filepos+13;
1907  return return_val | BLOCK_FIRST;
1908  case 6:
1909  info->rec_len=mi_uint3korr(header+1);
1910  info->block_len=info->data_len=mi_uint3korr(header+4);
1911  info->next_filepos=mi_sizekorr(header+7);
1912  info->second_read=1;
1913  info->filepos=filepos+15;
1914  return return_val | BLOCK_FIRST;
1915 
1916  /* The following blocks are identical to 1-6 without rec_len */
1917  case 7:
1918  info->data_len=info->block_len=mi_uint2korr(header+1);
1919  info->filepos=filepos+3;
1920  return return_val | BLOCK_LAST;
1921  case 8:
1922  info->data_len=info->block_len=mi_uint3korr(header+1);
1923  info->filepos=filepos+4;
1924  return return_val | BLOCK_LAST;
1925 
1926  case 9:
1927  info->data_len=mi_uint2korr(header+1);
1928  info->block_len=info->data_len+ (uint) header[3];
1929  info->filepos=filepos+4;
1930  return return_val | BLOCK_LAST;
1931  case 10:
1932  info->data_len=mi_uint3korr(header+1);
1933  info->block_len=info->data_len+ (uint) header[4];
1934  info->filepos=filepos+5;
1935  return return_val | BLOCK_LAST;
1936 
1937  case 11:
1938  info->data_len=info->block_len=mi_uint2korr(header+1);
1939  info->next_filepos=mi_sizekorr(header+3);
1940  info->second_read=1;
1941  info->filepos=filepos+11;
1942  return return_val;
1943  case 12:
1944  info->data_len=info->block_len=mi_uint3korr(header+1);
1945  info->next_filepos=mi_sizekorr(header+4);
1946  info->second_read=1;
1947  info->filepos=filepos+12;
1948  return return_val;
1949  }
1950 
1951 err:
1952  errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
1953  return BLOCK_ERROR;
1954 }
TODO: Rename this file - func.h is stupid.