Commit af9649c7 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-17349 Assertion `!table || (!table->read_set ||...

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[].
parent 8a346f31
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';
#
# 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';
......@@ -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 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
}
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);
}
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment