[Commits] Rev 3012: 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" in lp:maria/5.2

Michael Widenius monty at askmonty.org
Mon Aug 15 16:39:54 EEST 2011


At lp:maria/5.2

------------------------------------------------------------
revno: 3012
revision-id: monty at askmonty.org-20110815133953-ukflzv0ywgc0lunt
parent: monty at askmonty.org-20110812125105-f4p71sflif3bc934
fixes bug(s): https://launchpad.net/bugs/815022 https://launchpad.net/bugs/726374
committer: Michael Widenius <monty at askmonty.org>
branch nick: maria-5.2
timestamp: Mon 2011-08-15 16:39:53 +0300
message:
  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.
-------------- next part --------------
=== modified file 'mysql-test/lib/v1/mysql-test-run.pl'
--- a/mysql-test/lib/v1/mysql-test-run.pl	2011-02-28 17:39:30 +0000
+++ b/mysql-test/lib/v1/mysql-test-run.pl	2011-08-15 13:39:53 +0000
@@ -5285,7 +5285,6 @@ sub valgrind_arguments {
   else
   {
     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, "--num-callers=16");
     mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)

=== added file 'mysql-test/suite/maria/r/small_blocksize.result'
--- a/mysql-test/suite/maria/r/small_blocksize.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/maria/r/small_blocksize.result	2011-08-15 13:39:53 +0000
@@ -0,0 +1,75 @@
+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;

=== added file 'mysql-test/suite/maria/t/small_blocksize-master.opt'
--- a/mysql-test/suite/maria/t/small_blocksize-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/maria/t/small_blocksize-master.opt	2011-08-15 13:39:53 +0000
@@ -0,0 +1 @@
+--aria-block-size=1024

=== added file 'mysql-test/suite/maria/t/small_blocksize.test'
--- a/mysql-test/suite/maria/t/small_blocksize.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/maria/t/small_blocksize.test	2011-08-15 13:39:53 +0000
@@ -0,0 +1,35 @@
+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;

=== modified file 'storage/maria/ha_maria.cc'
--- a/storage/maria/ha_maria.cc	2011-06-29 21:37:12 +0000
+++ b/storage/maria/ha_maria.cc	2011-08-15 13:39:53 +0000
@@ -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
   we also can't use any compression, which may make the index file much
   larger)

=== modified file 'storage/maria/ma_bitmap.c'
--- a/storage/maria/ma_bitmap.c	2011-08-12 12:51:05 +0000
+++ b/storage/maria/ma_bitmap.c	2011-08-15 13:39:53 +0000
@@ -1853,7 +1853,7 @@ static void use_head(MARIA_HA *info, pgc
     find_where_to_split_row()
     share           Maria share
     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
                     than this)
 
@@ -1862,7 +1862,7 @@ static void use_head(MARIA_HA *info, pgc
 */
 
 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;
   /*
@@ -1872,19 +1872,20 @@ static uint find_where_to_split_row(MARI
     - One extent
   */
   uint row_length= (row->min_length +
-                    size_to_store_key_length(extents_length) +
+                    size_to_store_key_length(extents) +
                     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
     to the row. This needs to be in same order as in
     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[-1]= row->field_lengths_length;
   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++)
   {
     if (row_length + *lengths > split_size)
@@ -2040,18 +2041,19 @@ my_bool _ma_bitmap_find_place(MARIA_HA *
   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,
+  row_length= find_where_to_split_row(share, row, row->extents_count + 
+                                      ELEMENTS_RESERVED_FOR_MAIN_PART-1,
                                       max_page_size);
 
   full_page_size= MAX_TAIL_SIZE(share->block_size);
   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 */
   if (find_head(info, row_length, position))
     goto abort;
   row->space_on_head_page= row_length;
 
-  rest_length= head_length - row_length;
   if (write_rest_of_head(info, position, rest_length))
     goto abort;
 
@@ -2137,16 +2139,22 @@ my_bool _ma_bitmap_find_new_place(MARIA_
   /* Allocate enough space */
   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;
-  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 */
   use_head(info, page, row_length, position);
   row->space_on_head_page= row_length;
 
-  rest_length= head_length - row_length;
   if (write_rest_of_head(info, position, rest_length))
     goto abort;
 

=== modified file 'storage/maria/ma_blockrec.c'
--- a/storage/maria/ma_blockrec.c	2011-08-08 11:53:52 +0000
+++ b/storage/maria/ma_blockrec.c	2011-08-15 13:39:53 +0000
@@ -1721,7 +1721,7 @@ struct st_row_pos_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,
                                      enum pagecache_page_lock lock,
                                      struct st_row_pos_info *res)
@@ -1821,7 +1821,7 @@ static my_bool get_head_or_tail_page(MAR
 */
 
 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,
                                                uint page_type,
                                                enum pagecache_page_lock lock,
@@ -2257,7 +2257,7 @@ static void store_extent_info(uchar *to,
   for (block= first_block, end_block= first_block+count ;
        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))
     {
       uint page_count= block->page_count;
@@ -3088,9 +3088,10 @@ static my_bool write_block_record(MARIA_
           extent_data= row_extents_second_part +
             ((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);
-        int2store(extent_data + PAGE_STORE_SIZE, head_tail_block->page_count);
+        pagerange_store(extent_data + PAGE_STORE_SIZE,
+                        head_tail_block->page_count);
       }
     }
     else

=== modified file 'storage/maria/ma_blockrec.h'
--- a/storage/maria/ma_blockrec.h	2011-07-24 08:25:28 +0000
+++ b/storage/maria/ma_blockrec.h	2011-08-15 13:39:53 +0000
@@ -59,7 +59,6 @@
 
 /* Minimum header size needed for a new row */
 #define BASE_ROW_HEADER_SIZE FLAG_SIZE
-#define TRANS_ROW_EXTRA_HEADER_SIZE TRANSID_SIZE
 
 #define PAGE_TYPE_MASK 7
 enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE };

=== modified file 'storage/maria/ma_delete.c'
--- a/storage/maria/ma_delete.c	2011-02-10 18:33:51 +0000
+++ b/storage/maria/ma_delete.c	2011-08-15 13:39:53 +0000
@@ -571,6 +571,7 @@ static int del(MARIA_HA *info, MARIA_KEY
   endpos= leaf_page->buff + leaf_length;
   tmp_key.keyinfo= keyinfo;
   tmp_key.data=    keybuff;
+  next_buff= 0;
 
   if (!(key_start= _ma_get_last_key(&tmp_key, leaf_page, endpos)))
     DBUG_RETURN(-1);
@@ -597,9 +598,11 @@ static int del(MARIA_HA *info, MARIA_KEY
           /* underflow writes "next_page" to disk */
           ret_value= underflow(info, keyinfo, leaf_page, &next_page,
                                endpos);
-          if (ret_value == 0 && leaf_page->size >
-              share->max_index_block_size)
+          if (ret_value < 0)
+            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,
                                        share->max_index_block_size,
                                        (uchar*) 0, 0, 0,
@@ -632,6 +635,7 @@ static int del(MARIA_HA *info, MARIA_KEY
         goto err;
     }
     my_afree(next_buff);
+    DBUG_ASSERT(leaf_page->size <= share->max_index_block_size);
     DBUG_RETURN(ret_value);
   }
 
@@ -709,10 +713,14 @@ static int del(MARIA_HA *info, MARIA_KEY
                   KEY_OP_DEBUG_LOG_ADD_2))
     goto err;
 
+  DBUG_ASSERT(leaf_page->size <= share->max_index_block_size);
   DBUG_RETURN(new_leaf_length <=
               (info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
                (uint) keyinfo->underflow_block_length));
 err:
+  if (next_buff)
+    my_afree(next_buff);
+
   DBUG_RETURN(-1);
 } /* del */
 
@@ -731,9 +739,18 @@ static int del(MARIA_HA *info, MARIA_KEY
      leaf_page is saved to disk
      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
    @retval  0  ok
-   @retval  1  ok, but anc_buff did underflow
+   @retval  1  ok, but anc_page did underflow
    @retval -1  error
  */
 
@@ -1153,7 +1170,7 @@ static int underflow(MARIA_HA *info, MAR
     _ma_kpointer(info,leaf_key.data + leaf_key.data_length +
                  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_KEY("key_to_anc", &leaf_key);
     anc_end_pos= anc_buff + new_anc_length;
@@ -1191,6 +1208,7 @@ static int underflow(MARIA_HA *info, MAR
     bmove(leaf_buff+p_length+t_length, half_pos, tmp_length);
     (*keyinfo->store_key)(keyinfo,leaf_buff+p_length, &key_inserted);
     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->flag= page_flag;

=== modified file 'storage/maria/ma_open.c'
--- a/storage/maria/ma_open.c	2011-08-08 11:53:52 +0000
+++ b/storage/maria/ma_open.c	2011-08-15 13:39:53 +0000
@@ -563,21 +563,40 @@ MARIA_HA *maria_open(const char *name, i
 
     share->block_size= share->base.block_size;   /* Convenience */
     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;
       uint32 ftkey_nr= 1;
       for (i=0 ; i < keys ; i++)
       {
-        share->keyinfo[i].share= share;
-        disk_pos=_ma_keydef_read(disk_pos, &share->keyinfo[i]);
-        share->keyinfo[i].key_nr= i;
+        MARIA_KEYDEF *keyinfo= &share->keyinfo[i];
+        keyinfo->share= share;
+        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 + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
+                        disk_pos + keyinfo->keysegs * HA_KEYSEG_SIZE,
                         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->keyinfo[i].seg=pos;
-        for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
+        keyinfo->seg=pos;
+        for (j=0 ; j < keyinfo->keysegs; j++,pos++)
         {
           disk_pos=_ma_keyseg_read(disk_pos, pos);
           if (pos->type == HA_KEYTYPE_TEXT ||
@@ -595,25 +614,25 @@ MARIA_HA *maria_open(const char *name, i
           else if (pos->type == HA_KEYTYPE_BINARY)
             pos->charset= &my_charset_bin;
         }
-        if (share->keyinfo[i].flag & HA_SPATIAL)
+        if (keyinfo->flag & HA_SPATIAL)
         {
 #ifdef HAVE_SPATIAL
           uint sp_segs=SPDIMS*2;
-          share->keyinfo[i].seg=pos-sp_segs;
-          share->keyinfo[i].keysegs--;
+          keyinfo->seg=pos-sp_segs;
+          keyinfo->keysegs--;
           versioning= 0;
 #else
           my_errno=HA_ERR_UNSUPPORTED;
           goto err;
 #endif
         }
-        else if (share->keyinfo[i].flag & HA_FULLTEXT)
+        else if (keyinfo->flag & HA_FULLTEXT)
         {
           versioning= 0;
           DBUG_ASSERT(fulltext_keys);
           {
             uint k;
-            share->keyinfo[i].seg=pos;
+            keyinfo->seg=pos;
             for (k=0; k < FT_SEGS; k++)
             {
               *pos= ft_keysegs[k];
@@ -628,8 +647,7 @@ MARIA_HA *maria_open(const char *name, i
           }
           if (!share->ft2_keyinfo.seg)
           {
-            memcpy(&share->ft2_keyinfo, &share->keyinfo[i],
-                   sizeof(MARIA_KEYDEF));
+            memcpy(&share->ft2_keyinfo, keyinfo, sizeof(MARIA_KEYDEF));
             share->ft2_keyinfo.keysegs=1;
             share->ft2_keyinfo.flag=0;
             share->ft2_keyinfo.keylength=
@@ -639,10 +657,10 @@ MARIA_HA *maria_open(const char *name, i
             share->ft2_keyinfo.end=pos;
             setup_key_functions(& share->ft2_keyinfo);
           }
-          share->keyinfo[i].ftkey_nr= ftkey_nr++;
+          keyinfo->ftkey_nr= ftkey_nr++;
         }
-        setup_key_functions(share->keyinfo+i);
-        share->keyinfo[i].end=pos;
+        setup_key_functions(keyinfo);
+        keyinfo->end=pos;
         pos->type=HA_KEYTYPE_END;                       /* End */
         pos->length=share->base.rec_reflength;
         pos->null_bit=0;
@@ -686,10 +704,6 @@ MARIA_HA *maria_open(const char *name, i
                          share->base.null_bytes +
                          share->base.pack_bytes +
                          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;
 
     if (open_flags & HA_OPEN_COPY)
@@ -1580,7 +1594,6 @@ uchar *_ma_keydef_read(uchar *ptr, MARIA
    keydef->keylength    = mi_uint2korr(ptr);    ptr+= 2;
    keydef->minlength    = 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->parser       = &ft_default_parser;
    keydef->ftkey_nr     = 0;

=== modified file 'storage/maria/ma_page.c'
--- a/storage/maria/ma_page.c	2011-01-24 13:19:40 +0000
+++ b/storage/maria/ma_page.c	2011-08-15 13:39:53 +0000
@@ -193,6 +193,7 @@ my_bool _ma_write_keypage(MARIA_PAGE *pa
     nod_flag=    _ma_test_if_nod(share, buff);
 
     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));
 
     if (page->pos < share->base.keystart ||

=== modified file 'storage/maria/ma_write.c'
--- a/storage/maria/ma_write.c	2011-02-10 18:33:51 +0000
+++ b/storage/maria/ma_write.c	2011-08-15 13:39:53 +0000
@@ -1068,7 +1068,6 @@ int _ma_split_page(MARIA_HA *info, MARIA
 
   Returns pointer to start of 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
 */
 

=== modified file 'storage/maria/maria_def.h'
--- a/storage/maria/maria_def.h	2011-07-26 04:52:15 +0000
+++ b/storage/maria/maria_def.h	2011-08-15 13:39:53 +0000
@@ -740,7 +740,7 @@ struct st_maria_handler
   { 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 _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
 



More information about the commits mailing list