diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-11-03 21:17:17 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-11-04 08:12:28 +0100 |
commit | af9649c722810eb1754953eb406a84ec876ce693 (patch) | |
tree | 20089193150bac2119ca6a0a8a31c7e92321241f | |
parent | 8a346f31b913daa011085afec2b2d38450c73e00 (diff) | |
download | mariadb-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.result | 16 | ||||
-rw-r--r-- | mysql-test/suite/vcol/t/races.test | 22 | ||||
-rw-r--r-- | sql/table.cc | 18 | ||||
-rw-r--r-- | sql/table.h | 4 |
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 */ |