YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/* Play it safe; We have a small stack when using threads */ #undef my_alloca #undef my_afree #define my_alloca(A) my_malloc(PSI_NOT_INSTRUMENTED, (A),MYF(0)) #define my_afree(A) my_free((A))
do
{ if (_mi_find_writepos(info,reclength,&filepos,&length)) goto err; if (_mi_write_part_record(info,filepos,length,
(info->append_insert_at_end ?
HA_OFFSET_ERROR : info->s->state.dellink),
(uchar**) &record,&reclength,&flag)) goto err;
} while (reclength);
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
}
/* Get a block for data ; The given data-area must be used !! */
static my_bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
{
DBUG_ENTER("unlink_deleted_block"); if (block_info->filepos == info->s->state.dellink)
{ /* First deleted block; We can just use this ! */
info->s->state.dellink=block_info->next_filepos;
} else
{
MI_BLOCK_INFO tmp;
tmp.second_read=0; /* Unlink block from the previous block */ if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
& BLOCK_DELETED))
DBUG_RETURN(1); /* Something is wrong */
mi_sizestore(tmp.header+4,block_info->next_filepos); if (info->s->file_write(info, tmp.header+4,8,
block_info->prev_filepos+4, MYF(MY_NABP)))
DBUG_RETURN(1); /* Unlink block from next block */ if (block_info->next_filepos != HA_OFFSET_ERROR)
{ if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
& BLOCK_DELETED))
DBUG_RETURN(1); /* Something is wrong */
mi_sizestore(tmp.header+12,block_info->prev_filepos); if (info->s->file_write(info, tmp.header+12,8,
block_info->next_filepos+12,
MYF(MY_NABP)))
DBUG_RETURN(1);
}
} /* We now have one less deleted block */
info->state->del--;
info->state->empty-= block_info->block_len;
info->s->state.split--;
/* First add a link from the last block to the new one */
error= update_backward_delete_link(info, info->s->state.dellink, filepos);
block_info.second_read=second_read; do
{ /* Remove block at 'filepos' */ if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR) ||
(length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
MI_MIN_BLOCK_LENGTH)
{
my_errno=HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(1);
} /* Check if next block is a delete block */
del_block.second_read=0;
remove_next_block=0; if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
{ /* We can't remove this yet as this block may be the head block */
remove_next_block=1;
length+=del_block.block_len;
}
/* Now it's safe to unlink the deleted block directly after this one */ if (remove_next_block && unlink_deleted_block(info,&del_block))
error=1;
} while (!(b_type & BLOCK_LAST));
DBUG_RETURN(error);
}
/* Write a block to datafile */
int _mi_write_part_record(MI_INFO *info,
my_off_t filepos, /* points at empty block */
ulong length, /* length of block */
my_off_t next_filepos,/* Next empty block */
uchar **record, /* pointer to record ptr */
ulong *reclength, /* length of *record */ int *flag) /* *flag == 0 if header */
{
ulong head_length,res_length,extra_length,long_block,del_length;
uchar *pos,*record_end;
my_off_t next_delete_block;
uchar temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
DBUG_ENTER("_mi_write_part_record");
next_delete_block=HA_OFFSET_ERROR;
res_length=extra_length=0; if (length > *reclength + MI_SPLIT_LENGTH)
{ /* Splitt big block */
res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
MI_DYN_ALIGN_SIZE);
length-= res_length; /* Use this for first part */
}
long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1; if (length == *reclength+ 3 + long_block)
{ /* Block is exactly of the right length */
temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */ if (long_block)
{
mi_int3store(temp+1,*reclength);
head_length=4;
} else
{
mi_int2store(temp+1,*reclength);
head_length=3;
}
} elseif (length-long_block < *reclength+4)
{ /* To short block */ if (next_filepos == HA_OFFSET_ERROR)
next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
!info->append_insert_at_end ?
info->s->state.dellink : info->state->data_file_length); if (*flag == 0) /* First block */
{ if (*reclength > MI_MAX_BLOCK_LENGTH)
{
head_length= 16;
temp[0]=13;
mi_int4store(temp+1,*reclength);
mi_int3store(temp+5,length-head_length);
mi_sizestore((uchar*) temp+8,next_filepos);
} else
{
head_length=5+8+long_block*2;
temp[0]=5+(uchar) long_block; if (long_block)
{
mi_int3store(temp+1,*reclength);
mi_int3store(temp+4,length-head_length);
mi_sizestore((uchar*) temp+7,next_filepos);
} else
{
mi_int2store(temp+1,*reclength);
mi_int2store(temp+3,length-head_length);
mi_sizestore((uchar*) temp+5,next_filepos);
}
}
} else
{
head_length=3+8+long_block;
temp[0]=11+(uchar) long_block; if (long_block)
{
mi_int3store(temp+1,length-head_length);
mi_sizestore((uchar*) temp+4,next_filepos);
} else
{
mi_int2store(temp+1,length-head_length);
mi_sizestore((uchar*) temp+3,next_filepos);
}
}
} else
{ /* Block with empty info last */
head_length=4+long_block;
extra_length= length- *reclength-head_length;
temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */ if (long_block)
{
mi_int3store(temp+1,*reclength);
temp[4]= (uchar) (extra_length);
} else
{
mi_int2store(temp+1,*reclength);
temp[3]= (uchar) (extra_length);
}
length= *reclength+head_length; /* Write only what is needed */
}
DBUG_DUMP("header",(uchar*) temp,head_length);
/* Make a long block for one write */
record_end= *record+length-head_length;
del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
bmove((uchar*) (*record-head_length),(uchar*) temp,head_length);
memcpy(temp,record_end,(size_t) (extra_length+del_length));
bzero((uchar*) record_end,extra_length);
if (res_length)
{ /* Check first if we can join this block with the next one */
MI_BLOCK_INFO del_block;
my_off_t next_block=filepos+length+extra_length+res_length;
del_block.second_read=0; if (next_block < info->state->data_file_length &&
info->s->state.dellink != HA_OFFSET_ERROR)
{ if ((_mi_get_block_info(&del_block,info->dfile,next_block)
& BLOCK_DELETED) &&
res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
{ if (unlink_deleted_block(info,&del_block)) goto err;
res_length+=del_block.block_len;
}
}
/* Create a delete link of the last part of the block */
pos=record_end+extra_length;
pos[0]= '\0';
mi_int3store(pos+1,res_length);
mi_sizestore(pos+4,info->s->state.dellink);
bfill(pos+12,8,255); /* End link */
next_delete_block=info->s->state.dellink;
info->s->state.dellink= filepos+length+extra_length;
info->state->del++;
info->state->empty+=res_length;
info->s->state.split++;
} if (info->opt_flag & WRITE_CACHE_USED &&
info->update & HA_STATE_WRITE_AT_END)
{ if (info->update & HA_STATE_EXTEND_BLOCK)
{
info->update&= ~HA_STATE_EXTEND_BLOCK; if (my_block_write(&info->rec_cache,(uchar*) *record-head_length,
length+extra_length+del_length,filepos)) goto err;
} elseif (my_b_write(&info->rec_cache,(uchar*) *record-head_length,
length+extra_length+del_length)) goto err;
} else
{
info->rec_cache.seek_not_done=1; if (info->s->file_write(info,(uchar*) *record-head_length,length+extra_length+
del_length,filepos,info->s->write_flag)) goto err;
}
memcpy(record_end,temp,(size_t) (extra_length+del_length));
*record=record_end;
*reclength-=(length-head_length);
*flag=6;
if (del_length)
{ /* link the next delete block to this */ if (update_backward_delete_link(info, next_delete_block,
info->s->state.dellink)) goto err;
}
while (reclength > 0)
{ if (filepos != info->s->state.dellink)
{
block_info.next_filepos= HA_OFFSET_ERROR; if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR))
{
DBUG_PRINT("error",("Got wrong block info")); if (!(error & BLOCK_FATAL_ERROR))
my_errno=HA_ERR_WRONG_IN_RECORD; goto err;
}
length=(ulong) (block_info.filepos-filepos) + block_info.block_len; if (length < reclength)
{
uint tmp=MY_ALIGN(reclength - length + 3 +
MY_TEST(reclength >= 65520L), MI_DYN_ALIGN_SIZE); /* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
tmp= MY_MIN(length+tmp, MI_MAX_BLOCK_LENGTH)-length; /* Check if we can extend this block */ if (block_info.filepos + block_info.block_len ==
info->state->data_file_length &&
info->state->data_file_length <
info->s->base.max_data_file_length-tmp)
{ /* extend file */
DBUG_PRINT("info",("Extending file with %d bytes",tmp)); if (info->nextpos == info->state->data_file_length)
info->nextpos+= tmp;
info->state->data_file_length+= tmp;
info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
length+=tmp;
} elseif (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
{ /* Checkifnextblockisadeletedblock AbovewehaveMI_MIN_BLOCK_LENGTHtoavoidtheproblemwhere thenextblockissosmallitcan'tbesplitwhichcould causeproblems
*/
MI_BLOCK_INFO del_block;
del_block.second_read=0; if (_mi_get_block_info(&del_block,info->dfile,
block_info.filepos + block_info.block_len) &
BLOCK_DELETED)
{ /* Use; Unlink it and extend the current block */
DBUG_PRINT("info",("Extending current block")); if (unlink_deleted_block(info,&del_block)) goto err; if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
{ /* Newblockwastoobig,linkoverflowpartbackto deletelist
*/
my_off_t next_pos;
ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
set_if_bigger(rest_length, MI_MIN_BLOCK_LENGTH);
next_pos= del_block.filepos+ del_block.block_len - rest_length;
if (update_backward_delete_link(info, info->s->state.dellink,
next_pos))
DBUG_RETURN(1);
/* create delete link for data that didn't fit into the page */
del_block.header[0]=0;
mi_int3store(del_block.header+1, rest_length);
mi_sizestore(del_block.header+4,info->s->state.dellink);
bfill(del_block.header+12,8,255); if (info->s->file_write(info,(uchar*) del_block.header,20, next_pos,
MYF(MY_NABP)))
DBUG_RETURN(1);
info->s->state.dellink= next_pos;
info->s->state.split++;
info->state->del++;
info->state->empty+= rest_length;
length-= rest_length;
}
}
}
}
} else
{ if (_mi_find_writepos(info,reclength,&filepos,&length)) goto err;
} if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
&record,&reclength,&flag)) goto err; if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
{ /* Start writing data on deleted blocks */
filepos=info->s->state.dellink;
}
}
int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, uchar *buf)
{ int block_of_record;
uint b_type,UNINIT_VAR(left_length);
uchar *UNINIT_VAR(to);
MI_BLOCK_INFO block_info;
File file;
DBUG_ENTER("mi_read_dynamic_record");
if (filepos != HA_OFFSET_ERROR)
{
file=info->dfile;
block_of_record= 0; /* First block of record is numbered as zero. */
block_info.second_read= 0; do
{ /* A corrupted table can have wrong pointers. (Bug# 19835) */ if (filepos == HA_OFFSET_ERROR) goto panic; if (info->opt_flag & WRITE_CACHE_USED &&
info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
flush_io_cache(&info->rec_cache)) goto err;
info->rec_cache.seek_not_done=1; if ((b_type= _mi_get_block_info(&block_info, file, filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR))
{ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
my_errno=HA_ERR_RECORD_DELETED; goto err;
} if (block_of_record++ == 0) /* First block */
{ if (block_info.rec_len > (uint) info->s->base.max_pack_length) goto panic; if (info->s->base.blobs)
{ if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
&info->rec_buff))) goto err;
} else
to= info->rec_buff;
left_length=block_info.rec_len;
} if (left_length < block_info.data_len || ! block_info.data_len) goto panic; /* Wrong linked record */ /* copy information that is already read */
{
uint offset= (uint) (block_info.filepos - filepos);
uint prefetch_len= (sizeof(block_info.header) - offset);
filepos+= sizeof(block_info.header);
if (prefetch_len > block_info.data_len)
prefetch_len= block_info.data_len; if (prefetch_len)
{
memcpy((uchar*) to, block_info.header + offset, prefetch_len);
block_info.data_len-= prefetch_len;
left_length-= prefetch_len;
to+= prefetch_len;
}
} /* read rest of record from file */ if (block_info.data_len)
{ if (info->opt_flag & WRITE_CACHE_USED &&
info->rec_cache.pos_in_file < filepos + block_info.data_len &&
flush_io_cache(&info->rec_cache)) goto err; /* Whatapitythatthismethodisnotcalled'file_pread'andthat thereisnoequivalentwithoutseeking.Weareattheright positionalready.:(
*/ if (info->s->file_read(info, (uchar*) to, block_info.data_len,
filepos, MYF(MY_NABP))) goto panic;
left_length-=block_info.data_len;
to+=block_info.data_len;
}
filepos= block_info.next_filepos;
} while (left_length);
info->update|= HA_STATE_AKTIV; /* We have a aktive record */
fast_mi_writeinfo(info);
DBUG_RETURN(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
MY_FILE_ERROR ? 0 : -1);
}
fast_mi_writeinfo(info);
DBUG_RETURN(-1); /* Wrong data to read */
/* compare unique constraint between stored rows */
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def, const uchar *record, my_off_t pos)
{
uchar *rec_buff,*old_record; int error;
DBUG_ENTER("_mi_cmp_dynamic_unique");
if (!(old_record=my_alloca(info->s->base.reclength)))
DBUG_RETURN(1);
/* Don't let the compare destroy blobs that may be in use */
rec_buff=info->rec_buff; if (info->s->base.blobs)
info->rec_buff=0;
error=_mi_read_dynamic_record(info,pos,old_record); if (!error)
error=mi_unique_comp(def, record, old_record, def->null_are_equal); if (info->s->base.blobs)
{
my_free(mi_get_rec_buff_ptr(info, info->rec_buff));
info->rec_buff=rec_buff;
}
my_afree(old_record);
DBUG_RETURN(error);
}
/* Compare of record one disk with packed record in memory */
/* The following blocks are identical to 1-6 without rec_len */ case7:
info->data_len=info->block_len=mi_uint2korr(header+1);
info->filepos=filepos+3; return return_val | BLOCK_LAST; case8:
info->data_len=info->block_len=mi_uint3korr(header+1);
info->filepos=filepos+4; return return_val | BLOCK_LAST;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.