Commit 92b5a8bb authored by Monty's avatar Monty

MDEV-17665 Assertion `!share and other errors on concurrent Aria operations

Fixes also:
MDEV-22674 Server crash in compare_bin ... restore_table_state_after_repair

The bug was that the 'can_enable_index' variable in MyISAM and Aria was
not properly set and reset for bulk insert.
Because of this, insert...select was trying to recreate indexes while
another thread was using it, causing crashes in page cache.
parent 8819b5ee
...@@ -104,3 +104,63 @@ DROP TABLE t1; ...@@ -104,3 +104,63 @@ DROP TABLE t1;
# #
# End of 10.2 test # End of 10.2 test
# #
#
# MDEV-17665 Assertion `!share || share->page_type == PAGECACHE_LSN_PAGE',
# `type != PAGECACHE_READ_UNKNOWN_PAGE' and similar ones upon concurrent
# Aria operations
#
CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, KEY(a)) ENGINE=Aria;
ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100;
connect con1,localhost,root,,test;
connect con2,localhost,root,,test;
INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100;
connection con1;
FLUSH TABLES;
connection default;
INSERT INTO t1 SELECT 1;
ERROR 21S01: Column count doesn't match value count at row 1
connection con2;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
disconnect con2;
connection con1;
disconnect con1;
connection default;
DROP TABLE t1;
#
# MDEV-22674 Server crash in compare_bin, ASAN heap-buffer-overflow in
# _ma_dpointer, Assertion `!info->s->have_versioning ||
# info->s->lock_key_trees' failed in restore_table_state_after_repair
#
CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria;
INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1);
connect con1,localhost,root,,test;
ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 (id) SELECT b FROM t2;
connection default;
INSERT INTO t1 SELECT a FROM t2;
ERROR 21S01: Column count doesn't match value count at row 1
connection con1;
ERROR 42S22: Unknown column 'b' in 'field list'
disconnect con1;
connection default;
drop table t1, t2;
# This is also in MDEV-22674
CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria;
INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1);
ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 (id) SELECT b FROM t2;
ERROR 42S22: Unknown column 'b' in 'field list'
INSERT INTO t1 SELECT a FROM t2;
ERROR 21S01: Column count doesn't match value count at row 1
SELECT COUNT(*) FROM t1;
COUNT(*)
500
DROP TABLE t1,t2;
#
# End of 10.4 test
#
# Testing of potential problems in Aria and alter table # Testing of potential problems in Aria and alter table
-- source include/have_maria.inc -- source include/have_maria.inc
-- source include/have_innodb.inc
-- source include/have_sequence.inc
drop table if exists t1; drop table if exists t1;
...@@ -90,3 +92,85 @@ DROP TABLE t1; ...@@ -90,3 +92,85 @@ DROP TABLE t1;
--echo # --echo #
--echo # End of 10.2 test --echo # End of 10.2 test
--echo # --echo #
--echo #
--echo # MDEV-17665 Assertion `!share || share->page_type == PAGECACHE_LSN_PAGE',
--echo # `type != PAGECACHE_READ_UNKNOWN_PAGE' and similar ones upon concurrent
--echo # Aria operations
--echo #
CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, KEY(a)) ENGINE=Aria;
ALTER TABLE t1 DISABLE KEYS;
INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100;
--connect (con1,localhost,root,,test)
--connect (con2,localhost,root,,test)
--send
INSERT INTO t1 SELECT seq, seq FROM seq_1_to_100;
--connection con1
--send
FLUSH TABLES;
--connection default
--error ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO t1 SELECT 1;
# Cleanup
--connection con2
--error ER_DUP_ENTRY
--reap
--disconnect con2
--connection con1
--reap
--disconnect con1
--connection default
DROP TABLE t1;
--echo #
--echo # MDEV-22674 Server crash in compare_bin, ASAN heap-buffer-overflow in
--echo # _ma_dpointer, Assertion `!info->s->have_versioning ||
--echo # info->s->lock_key_trees' failed in restore_table_state_after_repair
--echo #
CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria;
INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1);
--connect (con1,localhost,root,,test)
ALTER TABLE t1 DISABLE KEYS;
--send
INSERT INTO t1 (id) SELECT b FROM t2;
--connection default
--error ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO t1 SELECT a FROM t2;
# Cleanup
--connection con1
--error ER_BAD_FIELD_ERROR
--reap
--disconnect con1
--connection default
drop table t1, t2;
--echo # This is also in MDEV-22674
CREATE TABLE t1 (id INT, d DATETIME, PRIMARY KEY(d,id),INDEX(d)) ENGINE=Aria;
INSERT INTO t1 SELECT seq, NOW() FROM seq_1_to_500;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
INSERT INTO t2 VALUES (1);
ALTER TABLE t1 DISABLE KEYS;
--error ER_BAD_FIELD_ERROR
INSERT INTO t1 (id) SELECT b FROM t2;
--error ER_WRONG_VALUE_COUNT_ON_ROW
INSERT INTO t1 SELECT a FROM t2;
SELECT COUNT(*) FROM t1;
DROP TABLE t1,t2;
--echo #
--echo # End of 10.4 test
--echo #
...@@ -31,6 +31,9 @@ insert into t1 select * from t2; ...@@ -31,6 +31,9 @@ insert into t1 select * from t2;
show engine aria logs; show engine aria logs;
Type Name Status Type Name Status
Aria Size 24576 aria_log.00000001 unknown Aria Size 24576 aria_log.00000001 unknown
select count(*) from t1;
count(*)
65
connection default; connection default;
connection admin; connection admin;
* shut down mysqld, removed logs, restarted it * shut down mysqld, removed logs, restarted it
...@@ -40,6 +43,9 @@ insert into t1 select * from t2; ...@@ -40,6 +43,9 @@ insert into t1 select * from t2;
show engine aria logs; show engine aria logs;
Type Name Status Type Name Status
Aria Size 16384 aria_log.00000001 unknown Aria Size 16384 aria_log.00000001 unknown
select count(*) from t1;
count(*)
64
drop table t1; drop table t1;
connection default; connection default;
connection admin; connection admin;
......
...@@ -48,6 +48,7 @@ insert into t1 values('a'); ...@@ -48,6 +48,7 @@ insert into t1 values('a');
insert into t1 select * from t2; insert into t1 select * from t2;
--replace_regex /; .+aria_log/aria_log/ --replace_regex /; .+aria_log/aria_log/
show engine aria logs; show engine aria logs;
select count(*) from t1;
# optimization because table is empty # optimization because table is empty
-- source include/maria_empty_logs.inc -- source include/maria_empty_logs.inc
...@@ -55,6 +56,7 @@ truncate table t1; ...@@ -55,6 +56,7 @@ truncate table t1;
insert into t1 select * from t2; insert into t1 select * from t2;
--replace_regex /; .+aria_log/aria_log/ --replace_regex /; .+aria_log/aria_log/
show engine aria logs; show engine aria logs;
select count(*) from t1;
drop table t1; drop table t1;
......
...@@ -10614,6 +10614,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ...@@ -10614,6 +10614,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
bool make_versioned= !from->versioned() && to->versioned(); bool make_versioned= !from->versioned() && to->versioned();
bool make_unversioned= from->versioned() && !to->versioned(); bool make_unversioned= from->versioned() && !to->versioned();
bool keep_versioned= from->versioned() && to->versioned(); bool keep_versioned= from->versioned() && to->versioned();
bool bulk_insert_started= 0;
Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL; Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL;
MYSQL_TIME query_start; MYSQL_TIME query_start;
DBUG_ENTER("copy_data_between_tables"); DBUG_ENTER("copy_data_between_tables");
...@@ -10652,6 +10653,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ...@@ -10652,6 +10653,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE); to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE);
to->file->ha_start_bulk_insert(from->file->stats.records, to->file->ha_start_bulk_insert(from->file->stats.records,
ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT);
bulk_insert_started= 1;
List_iterator<Create_field> it(create); List_iterator<Create_field> it(create);
Create_field *def; Create_field *def;
copy_end=copy; copy_end=copy;
...@@ -10914,6 +10916,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ...@@ -10914,6 +10916,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->print_error(my_errno,MYF(0)); to->file->print_error(my_errno,MYF(0));
error= 1; error= 1;
} }
bulk_insert_started= 0;
if (!ignore) if (!ignore)
to->file->extra(HA_EXTRA_END_ALTER_COPY); to->file->extra(HA_EXTRA_END_ALTER_COPY);
...@@ -10927,7 +10930,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ...@@ -10927,7 +10930,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
error= 1; error= 1;
err: err:
/* Free resources */ if (bulk_insert_started)
(void) to->file->ha_end_bulk_insert();
/* Free resources */
if (init_read_record_done) if (init_read_record_done)
end_read_record(&info); end_read_record(&info);
delete [] copy; delete [] copy;
......
...@@ -1025,7 +1025,7 @@ int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | ...@@ -1025,7 +1025,7 @@ int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT | HA_CAN_VIRTUAL_COLUMNS | HA_CAN_EXPORT |
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
HA_CAN_TABLES_WITHOUT_ROLLBACK), HA_CAN_TABLES_WITHOUT_ROLLBACK),
can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE) can_enable_indexes(0), bulk_insert_single_undo(BULK_INSERT_NONE)
{} {}
...@@ -2089,6 +2089,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) ...@@ -2089,6 +2089,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags)
DBUG_ENTER("ha_maria::start_bulk_insert"); DBUG_ENTER("ha_maria::start_bulk_insert");
THD *thd= table->in_use; THD *thd= table->in_use;
MARIA_SHARE *share= file->s; MARIA_SHARE *share= file->s;
bool index_disabled= 0;
DBUG_PRINT("info", ("start_bulk_insert: rows %lu", (ulong) rows)); DBUG_PRINT("info", ("start_bulk_insert: rows %lu", (ulong) rows));
/* don't enable row cache if too few rows */ /* don't enable row cache if too few rows */
...@@ -2152,6 +2153,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) ...@@ -2152,6 +2153,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags)
{ {
/* Internal table; If we get a duplicate something is very wrong */ /* Internal table; If we get a duplicate something is very wrong */
file->update|= HA_STATE_CHANGED; file->update|= HA_STATE_CHANGED;
index_disabled= share->base.keys > 0;
maria_clear_all_keys_active(file->s->state.key_map); maria_clear_all_keys_active(file->s->state.key_map);
} }
else else
...@@ -2179,6 +2181,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) ...@@ -2179,6 +2181,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags)
table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH) table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH)
{ {
maria_clear_key_active(share->state.key_map, i); maria_clear_key_active(share->state.key_map, i);
index_disabled= 1;
file->update|= HA_STATE_CHANGED; file->update|= HA_STATE_CHANGED;
file->create_unique_index_by_sort= all_keys; file->create_unique_index_by_sort= all_keys;
} }
...@@ -2208,6 +2211,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags) ...@@ -2208,6 +2211,7 @@ void ha_maria::start_bulk_insert(ha_rows rows, uint flags)
rows); rows);
} }
} }
can_enable_indexes= index_disabled;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2246,7 +2250,6 @@ int ha_maria::end_bulk_insert() ...@@ -2246,7 +2250,6 @@ int ha_maria::end_bulk_insert()
if (bulk_insert_single_undo != BULK_INSERT_NONE) if (bulk_insert_single_undo != BULK_INSERT_NONE)
{ {
DBUG_ASSERT(can_enable_indexes);
/* /*
Table was transactional just before start_bulk_insert(). Table was transactional just before start_bulk_insert().
No need to flush pages if we did a repair (which already flushed). No need to flush pages if we did a repair (which already flushed).
...@@ -2257,6 +2260,7 @@ int ha_maria::end_bulk_insert() ...@@ -2257,6 +2260,7 @@ int ha_maria::end_bulk_insert()
first_error= first_error ? first_error : error; first_error= first_error ? first_error : error;
bulk_insert_single_undo= BULK_INSERT_NONE; // Safety bulk_insert_single_undo= BULK_INSERT_NONE; // Safety
} }
can_enable_indexes= 0;
DBUG_RETURN(first_error); DBUG_RETURN(first_error);
} }
......
...@@ -726,7 +726,7 @@ ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) ...@@ -726,7 +726,7 @@ ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | HA_CAN_REPAIR | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT | HA_CAN_REPAIR |
HA_CAN_TABLES_WITHOUT_ROLLBACK), HA_CAN_TABLES_WITHOUT_ROLLBACK),
can_enable_indexes(1) can_enable_indexes(0)
{} {}
handler *ha_myisam::clone(const char *name __attribute__((unused)), handler *ha_myisam::clone(const char *name __attribute__((unused)),
...@@ -1729,6 +1729,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) ...@@ -1729,6 +1729,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags)
THD *thd= table->in_use; THD *thd= table->in_use;
ulong size= MY_MIN(thd->variables.read_buff_size, ulong size= MY_MIN(thd->variables.read_buff_size,
(ulong) (table->s->avg_row_length*rows)); (ulong) (table->s->avg_row_length*rows));
bool index_disabled= 0;
DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu", DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
(ulong) rows, size)); (ulong) rows, size));
...@@ -1752,6 +1753,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) ...@@ -1752,6 +1753,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags)
if (file->open_flag & HA_OPEN_INTERNAL_TABLE) if (file->open_flag & HA_OPEN_INTERNAL_TABLE)
{ {
file->update|= HA_STATE_CHANGED; file->update|= HA_STATE_CHANGED;
index_disabled= file->s->base.keys > 0;
mi_clear_all_keys_active(file->s->state.key_map); mi_clear_all_keys_active(file->s->state.key_map);
} }
else else
...@@ -1782,6 +1784,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) ...@@ -1782,6 +1784,7 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags)
table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH) table->key_info[i].algorithm != HA_KEY_ALG_LONG_HASH)
{ {
mi_clear_key_active(share->state.key_map, i); mi_clear_key_active(share->state.key_map, i);
index_disabled= 1;
file->update|= HA_STATE_CHANGED; file->update|= HA_STATE_CHANGED;
file->create_unique_index_by_sort= all_keys; file->create_unique_index_by_sort= all_keys;
} }
...@@ -1789,12 +1792,15 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags) ...@@ -1789,12 +1792,15 @@ void ha_myisam::start_bulk_insert(ha_rows rows, uint flags)
} }
} }
else else
{
if (!file->bulk_insert && if (!file->bulk_insert &&
(!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)) (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
{ {
mi_init_bulk_insert(file, (size_t) thd->variables.bulk_insert_buff_size, mi_init_bulk_insert(file, (size_t) thd->variables.bulk_insert_buff_size,
rows); rows);
} }
}
can_enable_indexes= index_disabled;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1846,6 +1852,7 @@ int ha_myisam::end_bulk_insert() ...@@ -1846,6 +1852,7 @@ int ha_myisam::end_bulk_insert()
file->s->state.changed&= ~(STATE_CRASHED|STATE_CRASHED_ON_REPAIR); file->s->state.changed&= ~(STATE_CRASHED|STATE_CRASHED_ON_REPAIR);
} }
} }
can_enable_indexes= 0;
} }
DBUG_PRINT("exit", ("first_error: %d", first_error)); DBUG_PRINT("exit", ("first_error: %d", first_error));
DBUG_RETURN(first_error); DBUG_RETURN(first_error);
......
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