#At file:///opt/local/work/5.0-41756/ based on revid:sergey.glukhov@stripped
2829 Konstantin Osipov 2009-10-30
A preview of the fix for
Bug#41756 "Strange error messages about locks from InnoDB".
Don't try to unlock rows unless certain that a) they were locked
b) they are not used.
An extended fix that counts locks.
added:
mysql-test/r/41756.result
mysql-test/t/41756-master.opt
mysql-test/t/41756.test
modified:
sql/item_subselect.cc
sql/records.cc
sql/sql_select.cc
sql/sql_select.h
sql/structs.h
=== added file 'mysql-test/r/41756.result'
--- a/mysql-test/r/41756.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/41756.result 2009-10-30 13:27:29 +0000
@@ -0,0 +1,20 @@
+#
+# Bug#41756 Strange error messages about locks from InnoDB
+#
+drop table if exists t1, t2;
+create table t1 (a int, b int primary key) engine=innodb;
+insert into t1 values (1,1), (null,2), (1,3), (1,4);
+create table t2 (a int, b int) engine=innodb;
+insert into t2 values (1,2), (1,2);
+select 1 from t1 natural join (select * from t2) as d for update;
+1
+commit;
+begin;
+select 1 from t1 natural join (select * from t2) as d for update;
+1
+#
+# Switching to connection con1
+delete from t1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+drop table t1, t2;
=== added file 'mysql-test/t/41756-master.opt'
--- a/mysql-test/t/41756-master.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/41756-master.opt 2009-10-30 13:27:29 +0000
@@ -0,0 +1,2 @@
+--innodb-locks-unsafe-for-binlog
+--innodb-lock-wait-timeout=1
=== added file 'mysql-test/t/41756.test'
--- a/mysql-test/t/41756.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/41756.test 2009-10-30 13:27:29 +0000
@@ -0,0 +1,29 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # Bug#41756 Strange error messages about locks from InnoDB
+--echo #
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+create table t1 (a int, b int primary key) engine=innodb;
+insert into t1 values (1,1), (null,2), (1,3), (1,4);
+create table t2 (a int, b int) engine=innodb;
+insert into t2 values (1,2), (1,2);
+select 1 from t1 natural join (select * from t2) as d for update;
+commit;
+begin;
+select 1 from t1 natural join (select * from t2) as d for update;
+connect (con1,localhost,root,,);
+--echo #
+--echo # Switching to connection con1
+connection con1;
+--error ER_LOCK_WAIT_TIMEOUT
+delete from t1;
+disconnect con1;
+connection default;
+commit;
+
+drop table t1, t2;
+
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2009-07-16 15:43:46 +0000
+++ b/sql/item_subselect.cc 2009-10-30 13:27:29 +0000
@@ -1844,6 +1844,7 @@ int subselect_single_select_engine::exec
item->reset_value_registration();
JOIN_TAB *changed_tabs[MAX_TABLES];
JOIN_TAB **last_changed_tab= changed_tabs;
+ void rr_unlock_row(st_join_table *tab);
if (item->have_guarded_conds())
{
/*
@@ -1869,6 +1870,7 @@ int subselect_single_select_engine::exec
tab->read_record.record= tab->table->record[0];
tab->read_record.thd= join->thd;
tab->read_record.ref_length= tab->table->file->ref_length;
+ tab->read_record.unlock_row= rr_unlock_row;
*(last_changed_tab++)= tab;
break;
}
=== modified file 'sql/records.cc'
--- a/sql/records.cc 2009-10-20 04:42:10 +0000
+++ b/sql/records.cc 2009-10-30 13:27:29 +0000
@@ -29,6 +29,7 @@ static int init_rr_cache(THD *thd, READ_
static int rr_cmp(uchar *a,uchar *b);
static int rr_index_first(READ_RECORD *info);
static int rr_index(READ_RECORD *info);
+void rr_unlock_row(st_join_table *tab);
/*
@@ -61,6 +62,7 @@ void init_read_record_idx(READ_RECORD *i
info->file= table->file;
info->record= table->record[0];
info->print_error= print_error;
+ info->unlock_row= rr_unlock_row;
table->status=0; /* And it's always found */
if (!table->file->inited)
@@ -135,6 +137,7 @@ void init_read_record(READ_RECORD *info,
}
info->select=select;
info->print_error=print_error;
+ info->unlock_row= rr_unlock_row;
info->ignore_not_found_rows= 0;
table->status=0; /* And it's always found */
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-10-21 09:04:08 +0000
+++ b/sql/sql_select.cc 2009-10-30 13:27:29 +0000
@@ -5357,7 +5357,9 @@ static bool create_ref_for_key(JOIN *joi
}
j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
j->ref.key_err=1;
+ j->ref.has_record= FALSE;
j->ref.null_rejecting= 0;
+ j->ref.use_count= 0;
keyuse=org_keyuse;
store_key **ref_key= j->ref.key_copy;
@@ -6157,6 +6159,23 @@ make_join_select(JOIN *join,SQL_SELECT *
DBUG_RETURN(0);
}
+static
+void
+join_read_key_unlock_row(st_join_table *tab)
+{
+ DBUG_ASSERT(tab->ref.use_count);
+ if (tab->ref.use_count)
+ tab->ref.use_count--;
+}
+
+
+void rr_unlock_row(st_join_table *tab)
+{
+ READ_RECORD *info= &tab->read_record;
+ info->file->unlock_row();
+}
+
+
static void
make_join_readinfo(JOIN *join, ulonglong options)
{
@@ -6172,6 +6191,7 @@ make_join_readinfo(JOIN *join, ulonglong
TABLE *table=tab->table;
tab->read_record.table= table;
tab->read_record.file=table->file;
+ tab->read_record.unlock_row= rr_unlock_row;
tab->next_select=sub_select; /* normal select */
/*
@@ -6215,6 +6235,7 @@ make_join_readinfo(JOIN *join, ulonglong
delete tab->quick;
tab->quick=0;
tab->read_first_record= join_read_key;
+ tab->read_record.unlock_row= join_read_key_unlock_row;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
@@ -10902,7 +10923,7 @@ evaluate_join_record(JOIN *join, JOIN_TA
return NESTED_LOOP_NO_MORE_ROWS;
}
else
- join_tab->read_record.file->unlock_row();
+ join_tab->read_record.unlock_row(join_tab);
}
else
{
@@ -10912,7 +10933,7 @@ evaluate_join_record(JOIN *join, JOIN_TA
*/
join->examined_rows++;
join->thd->row_count++;
- join_tab->read_record.file->unlock_row();
+ join_tab->read_record.unlock_row(join_tab);
}
return NESTED_LOOP_OK;
}
@@ -11265,12 +11286,23 @@ join_read_key(JOIN_TAB *tab)
table->status=STATUS_NOT_FOUND;
return -1;
}
+ /*
+ Moving away from the current record. Unlock the row
+ in the handler if it was not used.
+ */
+ if (tab->ref.has_record && tab->ref.use_count == 0)
+ tab->read_record.file->unlock_row();
error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND)
return report_error(table, error);
+
+ tab->ref.use_count= 1;
+ tab->ref.has_record= TRUE;
}
+ else if (table->status == 0)
+ tab->ref.use_count++;
table->null_row=0;
return table->status ? -1 : 0;
}
=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h 2009-07-16 12:19:22 +0000
+++ b/sql/sql_select.h 2009-10-30 13:27:29 +0000
@@ -53,6 +53,8 @@ class store_key;
typedef struct st_table_ref
{
bool key_err;
+ /** True if something was read into buffer in join_read_key. */
+ bool has_record;
uint key_parts; // num of ...
uint key_length; // length of key_buff
int key; // key no
@@ -78,8 +80,13 @@ typedef struct st_table_ref
*/
key_part_map null_rejecting;
table_map depend_map; // Table depends on these tables.
- byte *null_ref_key; // null byte position in the key_buf.
- // used for REF_OR_NULL optimization.
+ /* NULL byte position in the key_buf. Used for REF_OR_NULL optimization. */
+ byte *null_ref_key;
+ /*
+ The number of times the record associated with this key was used
+ in the join.
+ */
+ ha_rows use_count;
} TABLE_REF;
/*
=== modified file 'sql/structs.h'
--- a/sql/structs.h 2009-01-21 18:45:23 +0000
+++ b/sql/structs.h 2009-10-30 13:27:29 +0000
@@ -121,12 +121,16 @@ struct st_read_record; /* For referen
class SQL_SELECT;
class THD;
class handler;
+struct st_join_table;
+
+typedef void (*Unlock_row_func)(st_join_table *);
typedef struct st_read_record { /* Parameter to read_record */
struct st_table *table; /* Head-form */
handler *file;
struct st_table **forms; /* head and ref forms */
int (*read_record)(struct st_read_record *);
+ Unlock_row_func unlock_row;
THD *thd;
SQL_SELECT *select;
uint cache_records;
Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091030132729-hwwti0293rhotwq3.bundle
| Thread |
|---|
| • bzr commit into mysql-5.0 branch (kostja:2829) Bug#41756 | Konstantin Osipov | 30 Oct |