@ -504,11 +504,12 @@ void _ma_end_block_record(MARIA_HA *info)
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
Return the next used uchar on the page after a directory entry .
Return the next unused postion on the page after a directory entry .
SYNOPSIS
start_of_next_entry ( )
dir Directory entry to be used
dir Directory entry to be used . This can not be the
the last entry on the page !
RETURN
# Position in page where next entry starts.
@ -530,6 +531,20 @@ static inline uint start_of_next_entry(uchar *dir)
}
/*
Return the offset where the previous entry ends ( before on page )
SYNOPSIS
end_of_previous_entry ( )
dir Address for current directory entry
end Address to last directory entry
RETURN
# Position where previous entry ends (smallest address on page)
Everything between # and current entry are free to be used .
*/
static inline uint end_of_previous_entry ( uchar * dir , uchar * end )
{
uchar * pos ;
@ -537,14 +552,108 @@ static inline uint end_of_previous_entry(uchar *dir, uchar *end)
{
uint offset ;
if ( ( offset = uint2korr ( pos ) ) )
{
return offset + uint2korr ( pos + 2 ) ;
}
}
return PAGE_HEADER_SIZE ;
}
/**
@ brief Extend a record area to fit a given size block
@ fn extend_area_on_page ( )
@ param buff Page buffer
@ param dir Pointer to dir entry in buffer
@ param rownr Row number we working on
@ param block_size Block size of buffer
@ param request_length How much data we want to put at [ dir ]
@ param empty_space Total empty space in buffer
IMPLEMENTATION
The logic is as follows ( same as in _ma_update_block_record ( ) )
- If new data fits in old block , use old block .
- Extend block with empty space before block . If enough , use it .
- Extend block with empty space after block . If enough , use it .
- Use compact_page ( ) to get all empty space at dir .
RETURN
@ retval 0 ok
@ retval ret_offset Pointer to store offset to found area
@ retval ret_length Pointer to store length of found area
@ retval [ dir ] rec_offset is store here too
@ retval 1 error ( wrong info in block )
*/
static my_bool extend_area_on_page ( uchar * buff , uchar * dir ,
uint rownr , uint block_size ,
uint request_length ,
uint * empty_space , uint * ret_offset ,
uint * ret_length )
{
uint rec_offset , length ;
DBUG_ENTER ( " extend_area_on_page " ) ;
rec_offset = uint2korr ( dir ) ;
length = uint2korr ( dir + 2 ) ;
DBUG_PRINT ( " enter " , ( " rec_offset: %u length: %u request_length: %u " ,
rec_offset , length , request_length ) ) ;
* empty_space + = length ;
if ( length < request_length )
{
uint max_entry = ( uint ) ( ( uchar * ) buff ) [ DIR_COUNT_OFFSET ] ;
uint old_rec_offset ;
/*
New data did not fit in old position .
Find first possible position where to put new data .
*/
old_rec_offset = rec_offset ;
rec_offset = end_of_previous_entry ( dir , buff + block_size -
PAGE_SUFFIX_SIZE ) ;
length + = ( uint ) ( old_rec_offset - rec_offset ) ;
/*
old_rec_offset is 0 if we are doing an insert into a not allocated block .
This can only happen during REDO of INSERT
*/
if ( ! old_rec_offset | | length < request_length )
{
/*
Did not fit in current block + empty space . Extend with
empty space after block .
*/
if ( rownr = = max_entry - 1 )
{
/* Last entry; Everything is free between this and directory */
length = ( ( block_size - PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE * max_entry ) -
rec_offset ) ;
}
else
length = start_of_next_entry ( dir ) - rec_offset ;
DBUG_ASSERT ( ( int ) length > 0 ) ;
if ( length < request_length )
{
/* Not enough continues space, compact page to get more */
int2store ( dir , rec_offset ) ;
compact_page ( buff , block_size , rownr , 1 ) ;
rec_offset = uint2korr ( dir ) ;
length = uint2korr ( dir + 2 ) ;
if ( length < request_length )
DBUG_RETURN ( 1 ) ; /* Error in block */
* empty_space = length ; /* All space is here */
}
}
}
int2store ( dir , rec_offset ) ;
* ret_offset = rec_offset ;
* ret_length = length ;
DBUG_RETURN ( 0 ) ;
}
/*
Check that a region is all zero
@ -2447,7 +2556,7 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos,
if ( ( org_empty_size + cur_row - > head_length ) > = new_row - > total_length )
{
uint empty , offset , length ;
uint rec_ offset, length ;
MARIA_BITMAP_BLOCK block ;
/*
@ -2456,27 +2565,18 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos,
*/
block . org_bitmap_value = _ma_free_size_to_head_pattern ( & share - > bitmap ,
org_empty_size ) ;
offset = uint2korr ( dir ) ;
length = uint2korr ( dir + 2 ) ;
empty = 0 ;
if ( new_row - > total_length > length )
{
/* See if there is empty space after */
if ( rownr ! = ( uint ) ( ( uchar * ) buff ) [ DIR_COUNT_OFFSET ] - 1 )
empty = start_of_next_entry ( dir ) - ( offset + length ) ;
if ( new_row - > total_length > length + empty )
{
compact_page ( buff , share - > block_size , rownr , 1 ) ;
org_empty_size = 0 ;
length = uint2korr ( dir + 2 ) ;
}
}
if ( extend_area_on_page ( buff , dir , rownr , share - > block_size ,
new_row - > total_length , & org_empty_size ,
& rec_offset , & length ) )
DBUG_RETURN ( 1 ) ;
row_pos . buff = buff ;
row_pos . rownr = rownr ;
row_pos . empty_space = org_empty_size + length ;
row_pos . empty_space = org_empty_size ;
row_pos . dir = dir ;
row_pos . data = buff + uint2korr ( dir ) ;
row_pos . length = length + empty ;
row_pos . data = buff + rec_offset ;
row_pos . length = length ;
blocks - > block = & block ;
blocks - > count = 1 ;
block . page = page ;
@ -2551,7 +2651,7 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
{
uint number_of_records = ( uint ) ( ( uchar * ) buff ) [ DIR_COUNT_OFFSET ] ;
uint length , empty_space ;
uchar * dir ;
uchar * dir , * org_dir ;
DBUG_ENTER ( " delete_dir_entry " ) ;
# ifdef SANITY_CHECKS
@ -2567,9 +2667,8 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
# endif
empty_space = uint2korr ( buff + EMPTY_SPACE_OFFSET ) ;
dir = ( buff + block_size - DIR_ENTRY_SIZE * record_number -
org_dir = dir = ( buff + block_size - DIR_ENTRY_SIZE * record_number -
DIR_ENTRY_SIZE - PAGE_SUFFIX_SIZE ) ;
dir [ 0 ] = dir [ 1 ] = 0 ; /* Delete entry */
length = uint2korr ( dir + 2 ) ;
if ( record_number = = number_of_records - 1 )
@ -2582,21 +2681,24 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
dir + = DIR_ENTRY_SIZE ;
empty_space + = DIR_ENTRY_SIZE ;
} while ( dir < end & & dir [ 0 ] = = 0 & & dir [ 1 ] = = 0 ) ;
if ( number_of_records = = 0 )
{
buff [ PAGE_TYPE_OFFSET ] = UNALLOCATED_PAGE ;
* empty_space_res = block_size ;
DBUG_RETURN ( 1 ) ;
}
buff [ DIR_COUNT_OFFSET ] = ( uchar ) number_of_records ;
}
empty_space + = length ;
if ( number_of_records ! = 0 )
{
/* Update directory */
org_dir [ 0 ] = org_dir [ 1 ] = 0 ; org_dir [ 2 ] = org_dir [ 3 ] = 0 ; /* Delete entry */
int2store ( buff + EMPTY_SPACE_OFFSET , empty_space ) ;
buff [ PAGE_TYPE_OFFSET ] | = ( uchar ) PAGE_CAN_BE_COMPACTED ;
* empty_space_res = empty_space ;
DBUG_RETURN ( 0 ) ;
}
buff [ PAGE_TYPE_OFFSET ] = UNALLOCATED_PAGE ;
* empty_space_res = block_size ;
DBUG_RETURN ( 1 ) ;
}
@ -4162,6 +4264,10 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
page = page_korr ( header ) ;
rownr = dirpos_korr ( header + PAGE_STORE_SIZE ) ;
DBUG_PRINT ( " enter " , ( " rowid: %lu page: %lu rownr: %u data_length: %u " ,
( ulong ) ma_recordpos ( page , rownr ) ,
( ulong ) page , rownr , ( uint ) data_length ) ) ;
if ( ( ( page + 1 ) * info - > s - > block_size ) > info - > state - > data_file_length )
{
/*
@ -4248,39 +4354,15 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
}
else
{
uint length ;
/*
r euse old entry . This is empty if the command was an insert and
R euse old entry . This is empty if the command was an insert and
possible used if the command was an update .
*/
uchar * end_data ;
uint rec_end ;
/* Add back space if we are reusing entry */
empty_space + = uint2korr ( dir + 2 ) ;
/* Find first possible position where to put new data */
end_data = ( buff + block_size - PAGE_SUFFIX_SIZE -
DIR_ENTRY_SIZE * max_entry ) ;
rec_offset = end_of_previous_entry ( dir , end_data ) ;
if ( rownr ! = max_entry - 1 )
rec_end = start_of_next_entry ( dir ) ;
else
rec_end = ( uint ) ( buff - end_data ) ;
DBUG_ASSERT ( rec_end > rec_offset ) ;
if ( ( uint ) ( rec_end - rec_offset ) < data_length )
{
uint length ;
/* Not enough continues space, compact page to get more */
int2store ( dir , rec_offset ) ;
compact_page ( buff , block_size , rownr , 1 ) ;
rec_offset = uint2korr ( dir ) ;
length = uint2korr ( dir + 2 ) ;
DBUG_ASSERT ( length > = data_length ) ;
if ( length < data_length )
if ( extend_area_on_page ( buff , dir , rownr , block_size ,
data_length , & empty_space ,
& rec_offset , & length ) )
goto err ;
empty_space = length ;
}
}
}
}