Commit b95d2778 authored by Michael Widenius's avatar Michael Widenius

Fixes bugs found by testcase for lp:815022 and lp:726374 "ma_blockrec.c:3000:...

Fixes bugs found by testcase for lp:815022 and lp:726374 "ma_blockrec.c:3000: write_block_record: Assertion `cur_block[1].page_count == 0' failed with a multi-index Aria workload"
The issues was:
- For some tables with a lot of not packed fields, we didn't allocate enough memory in head page which caused DBUG_ASSERT's
- Removed wrong DBUG_ASSERT()
- Fixed a problem with underflow() where it generates a key page where all keys didn't fit.
- Max key length is now limited by block_size/3  (was block_size /2).  This is required for underflow() to work with packed keys.




mysql-test/lib/v1/mysql-test-run.pl:
  Remove --alignment=8 as this doesn't work on 64 bit systems
mysql-test/suite/maria/r/small_blocksize.result:
  Test case for Aria bug
mysql-test/suite/maria/t/small_blocksize-master.opt:
  Test case for Aria bug
mysql-test/suite/maria/t/small_blocksize.test:
  Test case for Aria bug
storage/maria/ha_maria.cc:
  Fixed comment
storage/maria/ma_bitmap.c:
  Fixed wrong variable usage in find_where_to_split_row() where we allocated too little memory for head page.
  We did not take into account space for head extents (long VARCHAR) when trying to split row on head page. This caused us to allocate too little space from bitmap which lead to ASSERT failures later.
storage/maria/ma_blockrec.c:
  Made some argument const (to ensure they was not accidently changed)
  Removed wrong DBUG_ASSERT()
storage/maria/ma_blockrec.h:
  Removed not used variable
storage/maria/ma_delete.c:
  Added my_afree() in case of error
  More comments and DBUG_ASSERT() for underflow()
storage/maria/ma_open.c:
  Make keyinfo->underflow_block_length smaller for packed keys. This has to be done as for long packed keys, underflow() otherwise generates a key page where all keys didn't fit.
storage/maria/ma_page.c:
  New DBUG_ASSERT()
storage/maria/ma_write.c:
  Fixed comment
storage/maria/maria_def.h:
  We have to have space for at least 3 keys on a key page.
  (Otherwise the underflow() code doesn't work for packed keys, even when we have an underflow() for an empty key page)
parent eeb04a33
...@@ -5285,7 +5285,6 @@ sub valgrind_arguments { ...@@ -5285,7 +5285,6 @@ sub valgrind_arguments {
else else
{ {
mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
mtr_add_arg($args, "--alignment=8");
mtr_add_arg($args, "--leak-check=yes"); mtr_add_arg($args, "--leak-check=yes");
mtr_add_arg($args, "--num-callers=16"); mtr_add_arg($args, "--num-callers=16");
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
......
DROP TABLE if exists t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (col_longtext_ucs2 longtext, col_longtext_utf8 longtext, col_varchar_255_ucs2_key varchar(255), col_set_utf8 set ('a','b'), col_char_255_ucs2 char(255), col_char_255_ucs2_key char(255), col_enum_ucs2 enum ('a','b'), col_varchar_255_ucs2 varchar(255), col_longtext_ucs2_key longtext, col_longtext_utf8_key longtext, col_enum_utf8 enum ('a','b'), col_varchar_255_utf8_key varchar(1024), col_varchar_255_utf8 varchar(255), col_enum_ucs2_key enum ('a','b'), col_enum_utf8_key enum ('a','b'), col_set_utf8_key set ('a','b'), col_char_255_utf8 char(255), pk integer auto_increment, col_set_ucs2_key set ('a','b'), col_char_255_utf8_key char(255), col_set_ucs2 set ('a','b'), primary key (pk)) ENGINE=aria;
INSERT INTO t1 ( col_char_255_utf8, col_varchar_255_utf8_key, col_longtext_utf8_key ) VALUES ( 'lggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrk', REPEAT( 'a', 627 ), 'mlggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrklnipcmzbtwdqfnyinqfohgtiwmvfpbuslgobjhslxnaybcyebhsrlipnuvalhmvhlwbwujtvjsdrbyapfzprnxfgtrukwhywtkaoupsaogxsjxhqjkidvnpeytjgndtnrrbm' );
UPDATE t1 SET col_varchar_255_utf8 = REPEAT('a', 197 );
UPDATE t1 SET col_char_255_utf8 = 'bmjihzjtxegprqfvmczyzbavjuozkyxrlxvqyzcfvsjrhcccqnecyohzhzbgsbqkqvzmtlhtlcgzheirkyfwczoolilkrfimfnuoapyylbghdhdgfebjjajfoigagozypqtrflrvdiwfgqalsqbmlllsanvtuuutiaastqtbzeoaawl';
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
create table t1 (a int primary key auto_increment, e1 enum('a','b'), e2 enum('a','b'), vl int, bl int, c char(10), v1 varchar(10000), v2 varchar(10000), b1 blob, b2 blob) engine=aria;
insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(5000,5000),(8000,12000);
update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl/2),b1=repeat('c',bl),b2=repeat('d',bl);
insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(1000,5000);
update t1 set c="test", v1=repeat(vl/4,'a'),v2=repeat(vl/5,'b'),b1=repeat(b1*2,'c'),b2=repeat(bl/2,'d');
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
Warning 1292 Truncated incorrect INTEGER value: 'a'
Warning 1292 Truncated incorrect INTEGER value: 'b'
Warning 1292 Truncated incorrect INTEGER value: 'c'
Warning 1292 Truncated incorrect INTEGER value: 'd'
update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/5),b1=repeat('c',bl*2),b2=repeat('d',bl/2);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl),b1=repeat('c',bl*2),b2=repeat('d',bl/2);
update t1 set c="test", v1=repeat('a',vl/2),v2=repeat('b',vl/2),b1=repeat('c',bl/2),b2=repeat('d',bl/2);
update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/4),b1=repeat('c',bl/4),b2=repeat('d',bl/4);
update t1 set c="test", v1=repeat('a',vl/20),v2=repeat('b',vl),b1=repeat('c',bl/20),b2=repeat('d',bl/20);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl/100),b1=repeat('c',bl/100);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl),b1=repeat('c',bl);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',10),v2=repeat('b',10);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',2000),v2=repeat('b',2000);
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
DROP TABLE if exists t1;
#
# Test of extending updated rows.
# This caused failures in lp:815022
#
CREATE TABLE t1 (col_longtext_ucs2 longtext, col_longtext_utf8 longtext, col_varchar_255_ucs2_key varchar(255), col_set_utf8 set ('a','b'), col_char_255_ucs2 char(255), col_char_255_ucs2_key char(255), col_enum_ucs2 enum ('a','b'), col_varchar_255_ucs2 varchar(255), col_longtext_ucs2_key longtext, col_longtext_utf8_key longtext, col_enum_utf8 enum ('a','b'), col_varchar_255_utf8_key varchar(1024), col_varchar_255_utf8 varchar(255), col_enum_ucs2_key enum ('a','b'), col_enum_utf8_key enum ('a','b'), col_set_utf8_key set ('a','b'), col_char_255_utf8 char(255), pk integer auto_increment, col_set_ucs2_key set ('a','b'), col_char_255_utf8_key char(255), col_set_ucs2 set ('a','b'), primary key (pk)) ENGINE=aria;
INSERT INTO t1 ( col_char_255_utf8, col_varchar_255_utf8_key, col_longtext_utf8_key ) VALUES ( 'lggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrk', REPEAT( 'a', 627 ), 'mlggnqojgqectqlkvskffihliqcwoakzzzjvhkqlwjybkngdbubskflpmzegdrklnipcmzbtwdqfnyinqfohgtiwmvfpbuslgobjhslxnaybcyebhsrlipnuvalhmvhlwbwujtvjsdrbyapfzprnxfgtrukwhywtkaoupsaogxsjxhqjkidvnpeytjgndtnrrbm' );
UPDATE t1 SET col_varchar_255_utf8 = REPEAT('a', 197 );
UPDATE t1 SET col_char_255_utf8 = 'bmjihzjtxegprqfvmczyzbavjuozkyxrlxvqyzcfvsjrhcccqnecyohzhzbgsbqkqvzmtlhtlcgzheirkyfwczoolilkrfimfnuoapyylbghdhdgfebjjajfoigagozypqtrflrvdiwfgqalsqbmlllsanvtuuutiaastqtbzeoaawl';
check table t1;
drop table t1;
create table t1 (a int primary key auto_increment, e1 enum('a','b'), e2 enum('a','b'), vl int, bl int, c char(10), v1 varchar(10000), v2 varchar(10000), b1 blob, b2 blob) engine=aria;
insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(5000,5000),(8000,12000);
update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl/2),b1=repeat('c',bl),b2=repeat('d',bl);
insert into t1 (vl,bl) values (10,10),(100,100),(1000,1000),(1000,5000);
update t1 set c="test", v1=repeat(vl/4,'a'),v2=repeat(vl/5,'b'),b1=repeat(b1*2,'c'),b2=repeat(bl/2,'d');
update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/5),b1=repeat('c',bl*2),b2=repeat('d',bl/2);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl),v2=repeat('b',vl),b1=repeat('c',bl*2),b2=repeat('d',bl/2);
update t1 set c="test", v1=repeat('a',vl/2),v2=repeat('b',vl/2),b1=repeat('c',bl/2),b2=repeat('d',bl/2);
update t1 set c="test", v1=repeat('a',vl/4),v2=repeat('b',vl/4),b1=repeat('c',bl/4),b2=repeat('d',bl/4);
update t1 set c="test", v1=repeat('a',vl/20),v2=repeat('b',vl),b1=repeat('c',bl/20),b2=repeat('d',bl/20);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl/100),b1=repeat('c',bl/100);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',vl),b1=repeat('c',bl);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',10),v2=repeat('b',10);
insert into t1 (vl,bl) values (100,100);
update t1 set c="test", v1=repeat('a',2000),v2=repeat('b',2000);
check table t1;
drop table t1;
...@@ -874,7 +874,7 @@ double ha_maria::scan_time() ...@@ -874,7 +874,7 @@ double ha_maria::scan_time()
} }
/* /*
We need to be able to store at least two keys on an index page as the We need to be able to store at least 2 keys on an index page as the
splitting algorithms depends on this. (With only one key on a page splitting algorithms depends on this. (With only one key on a page
we also can't use any compression, which may make the index file much we also can't use any compression, which may make the index file much
larger) larger)
......
...@@ -1853,7 +1853,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size, ...@@ -1853,7 +1853,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size,
find_where_to_split_row() find_where_to_split_row()
share Maria share share Maria share
row Information of what is in the row (from calc_record_size()) row Information of what is in the row (from calc_record_size())
extents_length Number of bytes needed to store all extents extents Max number of extents we have to store in header
split_size Free size on the page (The head length must be less split_size Free size on the page (The head length must be less
than this) than this)
...@@ -1862,7 +1862,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size, ...@@ -1862,7 +1862,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size,
*/ */
static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row, static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row,
uint extents_length, uint split_size) uint extents, uint split_size)
{ {
uint *lengths, *lengths_end; uint *lengths, *lengths_end;
/* /*
...@@ -1872,19 +1872,20 @@ static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row, ...@@ -1872,19 +1872,20 @@ static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row,
- One extent - One extent
*/ */
uint row_length= (row->min_length + uint row_length= (row->min_length +
size_to_store_key_length(extents_length) + size_to_store_key_length(extents) +
ROW_EXTENT_SIZE); ROW_EXTENT_SIZE);
DBUG_ASSERT(row_length < split_size); DBUG_ASSERT(row_length <= split_size);
/* /*
Store first in all_field_lengths the different parts that are written Store first in all_field_lengths the different parts that are written
to the row. This needs to be in same order as in to the row. This needs to be in same order as in
ma_block_rec.c::write_block_record() ma_block_rec.c::write_block_record()
*/ */
row->null_field_lengths[-3]= extents_length; row->null_field_lengths[-3]= extents * ROW_EXTENT_SIZE;
row->null_field_lengths[-2]= share->base.fixed_not_null_fields_length; row->null_field_lengths[-2]= share->base.fixed_not_null_fields_length;
row->null_field_lengths[-1]= row->field_lengths_length; row->null_field_lengths[-1]= row->field_lengths_length;
for (lengths= row->null_field_lengths - EXTRA_LENGTH_FIELDS, for (lengths= row->null_field_lengths - EXTRA_LENGTH_FIELDS,
lengths_end= (lengths + share->base.pack_fields - share->base.blobs + lengths_end= (lengths + share->base.fields - share->base.blobs +
EXTRA_LENGTH_FIELDS); lengths < lengths_end; lengths++) EXTRA_LENGTH_FIELDS); lengths < lengths_end; lengths++)
{ {
if (row_length + *lengths > split_size) if (row_length + *lengths > split_size)
...@@ -2040,18 +2041,19 @@ my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row, ...@@ -2040,18 +2041,19 @@ my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row,
head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE; head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE;
/* The first segment size is stored in 'row_length' */ /* The first segment size is stored in 'row_length' */
row_length= find_where_to_split_row(share, row, extents_length, row_length= find_where_to_split_row(share, row, row->extents_count +
ELEMENTS_RESERVED_FOR_MAIN_PART-1,
max_page_size); max_page_size);
full_page_size= MAX_TAIL_SIZE(share->block_size); full_page_size= MAX_TAIL_SIZE(share->block_size);
position= 0; position= 0;
if (head_length - row_length <= full_page_size) rest_length= head_length - row_length;
if (rest_length <= full_page_size)
position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */ position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */
if (find_head(info, row_length, position)) if (find_head(info, row_length, position))
goto abort; goto abort;
row->space_on_head_page= row_length; row->space_on_head_page= row_length;
rest_length= head_length - row_length;
if (write_rest_of_head(info, position, rest_length)) if (write_rest_of_head(info, position, rest_length))
goto abort; goto abort;
...@@ -2137,16 +2139,22 @@ my_bool _ma_bitmap_find_new_place(MARIA_HA *info, MARIA_ROW *row, ...@@ -2137,16 +2139,22 @@ my_bool _ma_bitmap_find_new_place(MARIA_HA *info, MARIA_ROW *row,
/* Allocate enough space */ /* Allocate enough space */
head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE; head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE;
/* The first segment size is stored in 'row_length' */ /*
row_length= find_where_to_split_row(share, row, extents_length, free_size); The first segment size is stored in 'row_length'
We have to add ELEMENTS_RESERVED_FOR_MAIN_PART here as the extent
information may be up to this size when the header splits.
*/
row_length= find_where_to_split_row(share, row, row->extents_count +
ELEMENTS_RESERVED_FOR_MAIN_PART-1,
free_size);
position= 0; position= 0;
if (head_length - row_length < MAX_TAIL_SIZE(share->block_size)) rest_length= head_length - row_length;
if (rest_length <= MAX_TAIL_SIZE(share->block_size))
position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */ position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */
use_head(info, page, row_length, position); use_head(info, page, row_length, position);
row->space_on_head_page= row_length; row->space_on_head_page= row_length;
rest_length= head_length - row_length;
if (write_rest_of_head(info, position, rest_length)) if (write_rest_of_head(info, position, rest_length))
goto abort; goto abort;
......
...@@ -1721,7 +1721,7 @@ struct st_row_pos_info ...@@ -1721,7 +1721,7 @@ struct st_row_pos_info
static my_bool get_head_or_tail_page(MARIA_HA *info, static my_bool get_head_or_tail_page(MARIA_HA *info,
MARIA_BITMAP_BLOCK *block, const MARIA_BITMAP_BLOCK *block,
uchar *buff, uint length, uint page_type, uchar *buff, uint length, uint page_type,
enum pagecache_page_lock lock, enum pagecache_page_lock lock,
struct st_row_pos_info *res) struct st_row_pos_info *res)
...@@ -1821,7 +1821,7 @@ crashed: ...@@ -1821,7 +1821,7 @@ crashed:
*/ */
static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info, static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
MARIA_BITMAP_BLOCK *block, const MARIA_BITMAP_BLOCK *block,
uchar *buff, uint length, uchar *buff, uint length,
uint page_type, uint page_type,
enum pagecache_page_lock lock, enum pagecache_page_lock lock,
...@@ -2257,7 +2257,7 @@ static void store_extent_info(uchar *to, ...@@ -2257,7 +2257,7 @@ static void store_extent_info(uchar *to,
for (block= first_block, end_block= first_block+count ; for (block= first_block, end_block= first_block+count ;
block < end_block; block++) block < end_block; block++)
{ {
/* The following is only false for marker blocks */ /* The following is only false for marker (unused) blocks */
if (likely(block->used & BLOCKUSED_USED)) if (likely(block->used & BLOCKUSED_USED))
{ {
uint page_count= block->page_count; uint page_count= block->page_count;
...@@ -3088,9 +3088,10 @@ static my_bool write_block_record(MARIA_HA *info, ...@@ -3088,9 +3088,10 @@ static my_bool write_block_record(MARIA_HA *info,
extent_data= row_extents_second_part + extent_data= row_extents_second_part +
((last_head_block - head_block) - 2) * ROW_EXTENT_SIZE; ((last_head_block - head_block) - 2) * ROW_EXTENT_SIZE;
} }
DBUG_ASSERT(uint2korr(extent_data+5) & TAIL_BIT); /* Write information for tail block in the reserved space */
page_store(extent_data, head_tail_block->page); page_store(extent_data, head_tail_block->page);
int2store(extent_data + PAGE_STORE_SIZE, head_tail_block->page_count); pagerange_store(extent_data + PAGE_STORE_SIZE,
head_tail_block->page_count);
} }
} }
else else
......
...@@ -59,7 +59,6 @@ ...@@ -59,7 +59,6 @@
/* Minimum header size needed for a new row */ /* Minimum header size needed for a new row */
#define BASE_ROW_HEADER_SIZE FLAG_SIZE #define BASE_ROW_HEADER_SIZE FLAG_SIZE
#define TRANS_ROW_EXTRA_HEADER_SIZE TRANSID_SIZE
#define PAGE_TYPE_MASK 7 #define PAGE_TYPE_MASK 7
enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE }; enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE };
......
...@@ -571,6 +571,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key, ...@@ -571,6 +571,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key,
endpos= leaf_page->buff + leaf_length; endpos= leaf_page->buff + leaf_length;
tmp_key.keyinfo= keyinfo; tmp_key.keyinfo= keyinfo;
tmp_key.data= keybuff; tmp_key.data= keybuff;
next_buff= 0;
if (!(key_start= _ma_get_last_key(&tmp_key, leaf_page, endpos))) if (!(key_start= _ma_get_last_key(&tmp_key, leaf_page, endpos)))
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -597,9 +598,11 @@ static int del(MARIA_HA *info, MARIA_KEY *key, ...@@ -597,9 +598,11 @@ static int del(MARIA_HA *info, MARIA_KEY *key,
/* underflow writes "next_page" to disk */ /* underflow writes "next_page" to disk */
ret_value= underflow(info, keyinfo, leaf_page, &next_page, ret_value= underflow(info, keyinfo, leaf_page, &next_page,
endpos); endpos);
if (ret_value == 0 && leaf_page->size > if (ret_value < 0)
share->max_index_block_size) goto err;
if (leaf_page->size > share->max_index_block_size)
{ {
DBUG_ASSERT(ret_value == 0);
ret_value= (_ma_split_page(info, key, leaf_page, ret_value= (_ma_split_page(info, key, leaf_page,
share->max_index_block_size, share->max_index_block_size,
(uchar*) 0, 0, 0, (uchar*) 0, 0, 0,
...@@ -632,6 +635,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key, ...@@ -632,6 +635,7 @@ static int del(MARIA_HA *info, MARIA_KEY *key,
goto err; goto err;
} }
my_afree(next_buff); my_afree(next_buff);
DBUG_ASSERT(leaf_page->size <= share->max_index_block_size);
DBUG_RETURN(ret_value); DBUG_RETURN(ret_value);
} }
...@@ -709,10 +713,14 @@ static int del(MARIA_HA *info, MARIA_KEY *key, ...@@ -709,10 +713,14 @@ static int del(MARIA_HA *info, MARIA_KEY *key,
KEY_OP_DEBUG_LOG_ADD_2)) KEY_OP_DEBUG_LOG_ADD_2))
goto err; goto err;
DBUG_ASSERT(leaf_page->size <= share->max_index_block_size);
DBUG_RETURN(new_leaf_length <= DBUG_RETURN(new_leaf_length <=
(info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH : (info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
(uint) keyinfo->underflow_block_length)); (uint) keyinfo->underflow_block_length));
err: err:
if (next_buff)
my_afree(next_buff);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} /* del */ } /* del */
...@@ -731,9 +739,18 @@ err: ...@@ -731,9 +739,18 @@ err:
leaf_page is saved to disk leaf_page is saved to disk
Caller must save anc_buff Caller must save anc_buff
For the algoritm to work, we have to ensure for packed keys that
key_length + (underflow_length + max_block_length + key_length) / 2
<= block_length.
From which follows that underflow_length <= block_length - key_length *3
For not packed keys we have:
(underflow_length + max_block_length + key_length) / 2 <= block_length
From which follows that underflow_length < block_length - key_length
This is ensured by setting of underflow_block_length.
@return @return
@retval 0 ok @retval 0 ok
@retval 1 ok, but anc_buff did underflow @retval 1 ok, but anc_page did underflow
@retval -1 error @retval -1 error
*/ */
...@@ -1153,7 +1170,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, ...@@ -1153,7 +1170,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
_ma_kpointer(info,leaf_key.data + leaf_key.data_length + _ma_kpointer(info,leaf_key.data + leaf_key.data_length +
leaf_key.ref_length, leaf_page->pos); leaf_key.ref_length, leaf_page->pos);
/* Save key in anc_page */ /* Save parting key found by _ma_find_half_pos() in anc_page */
DBUG_DUMP("anc_buff", anc_buff, new_anc_length); DBUG_DUMP("anc_buff", anc_buff, new_anc_length);
DBUG_DUMP_KEY("key_to_anc", &leaf_key); DBUG_DUMP_KEY("key_to_anc", &leaf_key);
anc_end_pos= anc_buff + new_anc_length; anc_end_pos= anc_buff + new_anc_length;
...@@ -1191,6 +1208,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, ...@@ -1191,6 +1208,7 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
bmove(leaf_buff+p_length+t_length, half_pos, tmp_length); bmove(leaf_buff+p_length+t_length, half_pos, tmp_length);
(*keyinfo->store_key)(keyinfo,leaf_buff+p_length, &key_inserted); (*keyinfo->store_key)(keyinfo,leaf_buff+p_length, &key_inserted);
new_leaf_length= tmp_length + t_length + p_length; new_leaf_length= tmp_length + t_length + p_length;
DBUG_ASSERT(new_leaf_length <= share->max_index_block_size);
leaf_page->size= new_leaf_length; leaf_page->size= new_leaf_length;
leaf_page->flag= page_flag; leaf_page->flag= page_flag;
...@@ -1232,7 +1250,6 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo, ...@@ -1232,7 +1250,6 @@ static int underflow(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
/* /*
Log changes to next page Log changes to next page
This contains original data with some suffix data deleted This contains original data with some suffix data deleted
*/ */
DBUG_ASSERT(new_buff_length <= buff_length); DBUG_ASSERT(new_buff_length <= buff_length);
if (_ma_log_suffix(&next_page, buff_length, new_buff_length)) if (_ma_log_suffix(&next_page, buff_length, new_buff_length))
......
...@@ -563,21 +563,40 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -563,21 +563,40 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->block_size= share->base.block_size; /* Convenience */ share->block_size= share->base.block_size; /* Convenience */
share->max_index_block_size= share->block_size - KEYPAGE_CHECKSUM_SIZE; share->max_index_block_size= share->block_size - KEYPAGE_CHECKSUM_SIZE;
share->keypage_header= ((share->base.born_transactional ?
LSN_STORE_SIZE + TRANSID_SIZE :
0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
KEYPAGE_USED_SIZE);
{ {
HA_KEYSEG *pos=share->keyparts; HA_KEYSEG *pos=share->keyparts;
uint32 ftkey_nr= 1; uint32 ftkey_nr= 1;
for (i=0 ; i < keys ; i++) for (i=0 ; i < keys ; i++)
{ {
share->keyinfo[i].share= share; MARIA_KEYDEF *keyinfo= &share->keyinfo[i];
disk_pos=_ma_keydef_read(disk_pos, &share->keyinfo[i]); keyinfo->share= share;
share->keyinfo[i].key_nr= i; disk_pos=_ma_keydef_read(disk_pos, keyinfo);
keyinfo->key_nr= i;
/* See ma_delete.cc::underflow() */
if (!(keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
keyinfo->underflow_block_length= keyinfo->block_length/3;
else
{
/* Packed key, ensure we don't get overflow in underflow() */
keyinfo->underflow_block_length=
max((int) (share->max_index_block_size - keyinfo->maxlength * 3),
(int) (share->keypage_header + share->base.key_reflength));
set_if_smaller(keyinfo->underflow_block_length,
keyinfo->block_length/3);
}
disk_pos_assert(share, disk_pos_assert(share,
disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE, disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE,
end_pos); end_pos);
if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE) if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
share->have_rtree= 1; share->have_rtree= 1;
share->keyinfo[i].seg=pos; keyinfo->seg=pos;
for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) for (j=0 ; j < keyinfo->keysegs; j++,pos++)
{ {
disk_pos=_ma_keyseg_read(disk_pos, pos); disk_pos=_ma_keyseg_read(disk_pos, pos);
if (pos->type == HA_KEYTYPE_TEXT || if (pos->type == HA_KEYTYPE_TEXT ||
...@@ -595,25 +614,25 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -595,25 +614,25 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
else if (pos->type == HA_KEYTYPE_BINARY) else if (pos->type == HA_KEYTYPE_BINARY)
pos->charset= &my_charset_bin; pos->charset= &my_charset_bin;
} }
if (share->keyinfo[i].flag & HA_SPATIAL) if (keyinfo->flag & HA_SPATIAL)
{ {
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
uint sp_segs=SPDIMS*2; uint sp_segs=SPDIMS*2;
share->keyinfo[i].seg=pos-sp_segs; keyinfo->seg=pos-sp_segs;
share->keyinfo[i].keysegs--; keyinfo->keysegs--;
versioning= 0; versioning= 0;
#else #else
my_errno=HA_ERR_UNSUPPORTED; my_errno=HA_ERR_UNSUPPORTED;
goto err; goto err;
#endif #endif
} }
else if (share->keyinfo[i].flag & HA_FULLTEXT) else if (keyinfo->flag & HA_FULLTEXT)
{ {
versioning= 0; versioning= 0;
DBUG_ASSERT(fulltext_keys); DBUG_ASSERT(fulltext_keys);
{ {
uint k; uint k;
share->keyinfo[i].seg=pos; keyinfo->seg=pos;
for (k=0; k < FT_SEGS; k++) for (k=0; k < FT_SEGS; k++)
{ {
*pos= ft_keysegs[k]; *pos= ft_keysegs[k];
...@@ -628,8 +647,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -628,8 +647,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
} }
if (!share->ft2_keyinfo.seg) if (!share->ft2_keyinfo.seg)
{ {
memcpy(&share->ft2_keyinfo, &share->keyinfo[i], memcpy(&share->ft2_keyinfo, keyinfo, sizeof(MARIA_KEYDEF));
sizeof(MARIA_KEYDEF));
share->ft2_keyinfo.keysegs=1; share->ft2_keyinfo.keysegs=1;
share->ft2_keyinfo.flag=0; share->ft2_keyinfo.flag=0;
share->ft2_keyinfo.keylength= share->ft2_keyinfo.keylength=
...@@ -639,10 +657,10 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -639,10 +657,10 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->ft2_keyinfo.end=pos; share->ft2_keyinfo.end=pos;
setup_key_functions(& share->ft2_keyinfo); setup_key_functions(& share->ft2_keyinfo);
} }
share->keyinfo[i].ftkey_nr= ftkey_nr++; keyinfo->ftkey_nr= ftkey_nr++;
} }
setup_key_functions(share->keyinfo+i); setup_key_functions(keyinfo);
share->keyinfo[i].end=pos; keyinfo->end=pos;
pos->type=HA_KEYTYPE_END; /* End */ pos->type=HA_KEYTYPE_END; /* End */
pos->length=share->base.rec_reflength; pos->length=share->base.rec_reflength;
pos->null_bit=0; pos->null_bit=0;
...@@ -686,10 +704,6 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -686,10 +704,6 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->base.null_bytes + share->base.null_bytes +
share->base.pack_bytes + share->base.pack_bytes +
test(share->options & HA_OPTION_CHECKSUM)); test(share->options & HA_OPTION_CHECKSUM));
share->keypage_header= ((share->base.born_transactional ?
LSN_STORE_SIZE + TRANSID_SIZE :
0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
KEYPAGE_USED_SIZE);
share->kfile.file= kfile; share->kfile.file= kfile;
if (open_flags & HA_OPEN_COPY) if (open_flags & HA_OPEN_COPY)
...@@ -1580,7 +1594,6 @@ uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef) ...@@ -1580,7 +1594,6 @@ uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef)
keydef->keylength = mi_uint2korr(ptr); ptr+= 2; keydef->keylength = mi_uint2korr(ptr); ptr+= 2;
keydef->minlength = mi_uint2korr(ptr); ptr+= 2; keydef->minlength = mi_uint2korr(ptr); ptr+= 2;
keydef->maxlength = mi_uint2korr(ptr); ptr+= 2; keydef->maxlength = mi_uint2korr(ptr); ptr+= 2;
keydef->underflow_block_length=keydef->block_length/3;
keydef->version = 0; /* Not saved */ keydef->version = 0; /* Not saved */
keydef->parser = &ft_default_parser; keydef->parser = &ft_default_parser;
keydef->ftkey_nr = 0; keydef->ftkey_nr = 0;
......
...@@ -193,6 +193,7 @@ my_bool _ma_write_keypage(MARIA_PAGE *page, enum pagecache_page_lock lock, ...@@ -193,6 +193,7 @@ my_bool _ma_write_keypage(MARIA_PAGE *page, enum pagecache_page_lock lock,
nod_flag= _ma_test_if_nod(share, buff); nod_flag= _ma_test_if_nod(share, buff);
DBUG_ASSERT(page->size == page_length); DBUG_ASSERT(page->size == page_length);
DBUG_ASSERT(page->size <= share->max_index_block_size);
DBUG_ASSERT(page->flag == _ma_get_keypage_flag(share, buff)); DBUG_ASSERT(page->flag == _ma_get_keypage_flag(share, buff));
if (page->pos < share->base.keystart || if (page->pos < share->base.keystart ||
......
...@@ -1068,7 +1068,6 @@ int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, MARIA_PAGE *split_page, ...@@ -1068,7 +1068,6 @@ int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, MARIA_PAGE *split_page,
Returns pointer to start of key. Returns pointer to start of key.
key will contain the key. key will contain the key.
return_key_length will contain the length of key
after_key will contain the position to where the next key starts after_key will contain the position to where the next key starts
*/ */
......
...@@ -740,7 +740,7 @@ struct st_maria_handler ...@@ -740,7 +740,7 @@ struct st_maria_handler
{ length=mi_uint2korr((key)+1)+3; } \ { length=mi_uint2korr((key)+1)+3; } \
} }
#define maria_max_key_length() ((maria_block_size - MAX_KEYPAGE_HEADER_SIZE)/2 - MARIA_INDEX_OVERHEAD_SIZE) #define maria_max_key_length() ((maria_block_size - MAX_KEYPAGE_HEADER_SIZE)/3 - MARIA_INDEX_OVERHEAD_SIZE)
#define get_pack_length(length) ((length) >= 255 ? 3 : 1) #define get_pack_length(length) ((length) >= 255 ? 3 : 1)
#define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID) #define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment