From: Date: June 24 2005 5:47pm Subject: bk commit into 4.1 tree (ingo:1.2317) BUG#10178 List-Archive: http://lists.mysql.com/internals/26411 X-Bug: 10178 Message-Id: Below is the list of changes that have just been committed into a local 4.1 repository of mydev. When mydev does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet 1.2317 05/06/24 17:47:09 ingo@stripped +4 -0 Bug#10178 - failure to find a row in heap table by concurrent UPDATEs Moved the key statistics update to info(). The table is not locked in open(). This made wrong stats possible. No test case for the test suite. This happens only with heavy concurrency. A test script is added to the bug report. sql/ha_heap.h 1.33 05/06/24 17:47:04 ingo@stripped +3 -1 Bug#10178 - failure to find a row in heap table by concurrent UPDATEs Added an element to track the validity of the key statistics. sql/ha_heap.cc 1.57 05/06/24 17:47:04 ingo@stripped +26 -5 Bug#10178 - failure to find a row in heap table by concurrent UPDATEs Moved the key statistics update to info(). The table is not locked in open(). This made wrong stats possible. mysql-test/t/heap_hash.test 1.9 05/06/24 17:47:04 ingo@stripped +2 -0 Bug#10178 - failure to find a row in heap table by concurrent UPDATEs Added a FLUSH TABLES to avoid statistics differences between normal and ps-protocol tests. mysql-test/r/heap_hash.result 1.13 05/06/24 17:47:04 ingo@stripped +12 -11 Bug#10178 - failure to find a row in heap table by concurrent UPDATEs Updated test results to reflect the new statistics behaviour. # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: ingo # Host: chilla.local # Root: /home/mydev/mysql-4.1-4100 --- 1.56/sql/ha_heap.cc Sun Jun 5 19:38:38 2005 +++ 1.57/sql/ha_heap.cc Fri Jun 24 17:47:04 2005 @@ -60,7 +60,15 @@ { /* Initialize variables for the opened table */ set_keys_for_scanning(); - update_key_stats(); + /* + We cannot run update_key_stats() here because we do not have a + lock on the table. The 'records' count might just be changed + temporarily at this moment and we might get wrong statistics (Bug + #10178). Instead we request for update. This will be done in + ha_heap::info(), which is always called before key statistics are + used. + */ + key_stats_ok= FALSE; } return (file ? 0 : 1); } @@ -112,6 +120,8 @@ } } records_changed= 0; + /* At the end of update_key_stats() we can proudly claim they are OK. */ + key_stats_ok= TRUE; } int ha_heap::write_row(byte * buf) @@ -125,7 +135,7 @@ res= heap_write(file,buf); if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -138,7 +148,7 @@ res= heap_update(file,old_data,new_data); if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -149,7 +159,7 @@ res= heap_delete(file,buf); if (!res && table->tmp_table == NO_TMP_TABLE && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -262,6 +272,13 @@ delete_length= info.deleted * info.reclength; if (flag & HA_STATUS_AUTO) auto_increment_value= info.auto_increment; + /* + If info() is called for the first time after open(), we will still + have to update the key statistics. Hoping that a table lock is now + in place. + */ + if (! key_stats_ok) + update_key_stats(); } int ha_heap::extra(enum ha_extra_function operation) @@ -273,7 +290,7 @@ { heap_clear(file); if (table->tmp_table == NO_TMP_TABLE) - update_key_stats(); + key_stats_ok= FALSE; return 0; } @@ -433,7 +450,11 @@ max_key->flag != HA_READ_AFTER_KEY) return HA_POS_ERROR; // Can only use exact keys else + { + /* Assert that info() did run. We need current statistics here. */ + DBUG_ASSERT(key_stats_ok); return key->rec_per_key[key->key_parts-1]; + } } --- 1.32/sql/ha_heap.h Tue May 24 21:21:11 2005 +++ 1.33/sql/ha_heap.h Fri Jun 24 17:47:04 2005 @@ -29,8 +29,10 @@ key_map btree_keys; /* number of records changed since last statistics update */ uint records_changed; + bool key_stats_ok; public: - ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {} + ha_heap(TABLE *table): handler(table), file(0), records_changed(0), + key_stats_ok(0) {} ~ha_heap() {} const char *table_type() const { return "HEAP"; } const char *index_type(uint inx) --- 1.12/mysql-test/r/heap_hash.result Tue Feb 8 21:44:49 2005 +++ 1.13/mysql-test/r/heap_hash.result Fri Jun 24 17:47:04 2005 @@ -231,18 +231,19 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a a 8 const 1 Using where insert into t1 select * from t1; +flush tables; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaab'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaac'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaad'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where flush tables; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra @@ -261,16 +262,16 @@ insert into t1 select * from t2; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaab'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaac'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaad'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where drop table t1, t2; create table t1 ( id int unsigned not null primary key auto_increment, @@ -345,15 +346,15 @@ show index from t3; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t3 1 a 1 a NULL NULL NULL NULL HASH -t3 1 a 2 b NULL 15 NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH show index from t3; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t3 1 a 1 a NULL NULL NULL NULL HASH -t3 1 a 2 b NULL 15 NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref heap_idx heap_idx 20 const 7 Using where -1 SIMPLE t3 ref a a 40 func,const 6 Using where +1 SIMPLE t3 ref a a 40 func,const 7 Using where drop table t1, t2, t3; create temporary table t1 ( a int, index (a) ) engine=memory; insert into t1 values (1),(2),(3),(4),(5); --- 1.8/mysql-test/t/heap_hash.test Tue Feb 8 21:44:49 2005 +++ 1.9/mysql-test/t/heap_hash.test Fri Jun 24 17:47:04 2005 @@ -169,6 +169,8 @@ explain select * from t1 where a='aaad'; insert into t1 select * from t1; +# avoid statistics differences between normal and ps-protocol tests +flush tables; explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaab'; explain select * from t1 where a='aaac';