summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-11-03 21:17:17 +0100
committerSergei Golubchik <serg@mariadb.org>2018-11-04 08:12:28 +0100
commitaf9649c722810eb1754953eb406a84ec876ce693 (patch)
tree20089193150bac2119ca6a0a8a31c7e92321241f
parent8a346f31b913daa011085afec2b2d38450c73e00 (diff)
downloadmariadb-git-af9649c722810eb1754953eb406a84ec876ce693.tar.gz
MDEV-17349 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed on concurrent SELECT and DELETE after RENAME from table with index on virtual column
Race condition. field->flags were copied from s->field->flags during field->clone(), early in open_table_from_share(). But s->field->flags were getting their PART_INDIRECT_KEY_FLAG bit much later in TABLE::mark_columns_used_by_virtual_fields() and only once per share. If two threads were executing the code between field->clone() and mark_columns_used_by_virtual_fields() at the same time, only one would get PART_INDIRECT_KEY_FLAG bits in field[].
-rw-r--r--mysql-test/suite/vcol/r/races.result16
-rw-r--r--mysql-test/suite/vcol/t/races.test22
-rw-r--r--sql/table.cc18
-rw-r--r--sql/table.h4
4 files changed, 57 insertions, 3 deletions
diff --git a/mysql-test/suite/vcol/r/races.result b/mysql-test/suite/vcol/r/races.result
new file mode 100644
index 00000000000..c46ed5ba2ef
--- /dev/null
+++ b/mysql-test/suite/vcol/r/races.result
@@ -0,0 +1,16 @@
+create table t1 (f text, vf tinytext as (f), key (vf(64))) engine=innodb;
+insert t1 (f) values ('foo');
+flush tables;
+connect con1,localhost,root,,test;
+set debug_sync='TABLE_after_field_clone WAIT_FOR go';
+delete from t1;
+connection default;
+select * from t1;
+f vf
+foo foo
+set debug_sync='now SIGNAL go';
+connection con1;
+disconnect con1;
+connection default;
+drop table t1;
+set debug_sync='reset';
diff --git a/mysql-test/suite/vcol/t/races.test b/mysql-test/suite/vcol/t/races.test
new file mode 100644
index 00000000000..1bf4e43dec9
--- /dev/null
+++ b/mysql-test/suite/vcol/t/races.test
@@ -0,0 +1,22 @@
+#
+# MDEV-17349 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed on concurrent SELECT and DELETE after RENAME from table with index on virtual column
+#
+source include/have_innodb.inc;
+source include/have_debug_sync.inc;
+create table t1 (f text, vf tinytext as (f), key (vf(64))) engine=innodb;
+insert t1 (f) values ('foo');
+flush tables;
+connect con1,localhost,root,,test;
+set debug_sync='TABLE_after_field_clone WAIT_FOR go';
+send delete from t1;
+connection default;
+let $wait_condition= select state like 'debug sync point%' from information_schema.processlist;
+source include/wait_condition.inc;
+select * from t1;
+set debug_sync='now SIGNAL go';
+connection con1;
+reap;
+disconnect con1;
+connection default;
+drop table t1;
+set debug_sync='reset';
diff --git a/sql/table.cc b/sql/table.cc
index f557799e7dd..2b278288784 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3013,6 +3013,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
uchar *record, *bitmaps;
Field **field_ptr;
uint8 save_context_analysis_only= thd->lex->context_analysis_only;
+ TABLE_SHARE::enum_v_keys check_set_initialized= share->check_set_initialized;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: %p", share->db.str,
share->table_name.str, outparam));
@@ -3116,6 +3117,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
(*field_ptr)= 0; // End marker
+ DEBUG_SYNC(thd, "TABLE_after_field_clone");
+
if (share->found_next_number_field)
outparam->found_next_number_field=
outparam->field[(uint) (share->found_next_number_field - share->field)];
@@ -3371,6 +3374,16 @@ partititon_err:
}
outparam->mark_columns_used_by_virtual_fields();
+ if (!check_set_initialized &&
+ share->check_set_initialized == TABLE_SHARE::V_KEYS)
+ {
+ // copy PART_INDIRECT_KEY_FLAG that was set meanwhile by *some* thread
+ for (uint i= 0 ; i < share->fields ; i++)
+ {
+ if (share->field[i]->flags & PART_INDIRECT_KEY_FLAG)
+ outparam->field[i]->flags|= PART_INDIRECT_KEY_FLAG;
+ }
+ }
if (share->table_category == TABLE_CATEGORY_LOG)
{
@@ -6708,6 +6721,7 @@ void TABLE::mark_columns_used_by_virtual_fields(void)
{
MY_BITMAP *save_read_set;
Field **vfield_ptr;
+ TABLE_SHARE::enum_v_keys v_keys= TABLE_SHARE::NO_V_KEYS;
/* If there is virtual fields are already initialized */
if (s->check_set_initialized)
@@ -6748,12 +6762,12 @@ void TABLE::mark_columns_used_by_virtual_fields(void)
if (bitmap_is_set(&tmp_set, i))
{
s->field[i]->flags|= PART_INDIRECT_KEY_FLAG;
- field[i]->flags|= PART_INDIRECT_KEY_FLAG;
+ v_keys= TABLE_SHARE::V_KEYS;
}
}
bitmap_clear_all(&tmp_set);
}
- s->check_set_initialized= 1;
+ s->check_set_initialized= v_keys;
if (s->tmp_table == NO_TMP_TABLE)
mysql_mutex_unlock(&s->LOCK_share);
}
diff --git a/sql/table.h b/sql/table.h
index 33b921cd946..4cd5c3ba5f3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -695,6 +695,9 @@ struct TABLE_SHARE
uint column_bitmap_size;
uchar frm_version;
+ enum enum_v_keys { NOT_INITIALIZED=0, NO_V_KEYS, V_KEYS };
+ enum_v_keys check_set_initialized;
+
bool use_ext_keys; /* Extended keys can be used */
bool null_field_first;
bool system; /* Set if system table (one record) */
@@ -705,7 +708,6 @@ struct TABLE_SHARE
bool table_creation_was_logged;
bool non_determinstic_insert;
bool vcols_need_refixing;
- bool check_set_initialized;
bool has_update_default_function;
ulong table_map_id; /* for row-based replication */