mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-33049 Assertion `marked_for_write_or_computed()' failed in bool
Field_new_decimal::store_value(const my_decimal*, int*) Analysis ======== When rpl applier is unpacking a before row image, Field::reset() will be called before setting a field to null if null bit of the field is set in the row image. For Field_new_decimal::reset(), it calls Field_new_decimal::store_value() to reset the value. store_value() asserts that the field is in the write_set bitmap since it thinks the field is updating. But that is not true for the row image generated in FULL_NODUP mode. In the mode, the before image includes all fields and the after image includes only updated fields. Fix === In the case unpacking binlog row images, the assertion is meaningless. So the unpacking field is marked in write_set temporarily to avoid the assertion failure.
This commit is contained in:
parent
d136169e39
commit
be6d48fd53
3 changed files with 71 additions and 1 deletions
|
@ -4752,6 +4752,21 @@ include/diff_tables.inc [server_1:test.t, server_2:test.t, server_3:test.t]
|
|||
connection server_1;
|
||||
DROP TABLE t;
|
||||
include/rpl_sync.inc
|
||||
CREATE TABLE t1(c1 INT NOT NULL PRIMARY KEY, c2 varchar(10) DEFAULT NULL,
|
||||
c3 decimal(12,4) DEFAULT NULL);
|
||||
INSERT INTO t1(c1) VALUES (1);
|
||||
include/save_master_pos.inc
|
||||
UPDATE t1 SET c2 = 'c2';
|
||||
include/rpl_sync.inc
|
||||
FLUSH BINARY LOGS;
|
||||
UPDATE t1 SET c2 = "c2_new";
|
||||
# Use 'BINLOG' statement to apply the first update row event
|
||||
# BINLOG statement is same to slave applier, it should work well.
|
||||
# After 'BINLOG' statement c2's value should be "c2"
|
||||
SELECT * FROM t1;
|
||||
c1 c2 c3
|
||||
1 c2 NULL
|
||||
DROP TABLE t1;
|
||||
CON: 'server_1', IMG: 'FULL', RESTART SLAVE: 'N'
|
||||
connection server_1;
|
||||
SET SESSION binlog_row_image= 'FULL';
|
||||
|
|
|
@ -27,8 +27,41 @@
|
|||
-- let $row_img_test_script= include/rpl_row_img.test
|
||||
-- source include/rpl_row_img_general_loop.inc
|
||||
|
||||
################################################################################
|
||||
# MDEV-33049 Assertion `marked_for_write_or_computed()' failed in bool
|
||||
# Field_new_decimal::store_value(const my_decimal*, int*)
|
||||
#
|
||||
# In FULL_NODUP mode, the before image has all fields and the after image has
|
||||
# only updated fields. Crash happened when slave was unpacking a row event
|
||||
# if the new decimal field is null in the before image.
|
||||
################################################################################
|
||||
CREATE TABLE t1(c1 INT NOT NULL PRIMARY KEY, c2 varchar(10) DEFAULT NULL,
|
||||
c3 decimal(12,4) DEFAULT NULL);
|
||||
INSERT INTO t1(c1) VALUES (1);
|
||||
--source include/save_master_pos.inc
|
||||
--let $datadir= `SELECT @@datadir`
|
||||
|
||||
# It will generate a row event that c3 is only in before image and it is null.
|
||||
UPDATE t1 SET c2 = 'c2';
|
||||
|
||||
# the UPDATE will crash the slave without this fix.
|
||||
--source include/rpl_sync.inc
|
||||
|
||||
FLUSH BINARY LOGS;
|
||||
UPDATE t1 SET c2 = "c2_new";
|
||||
|
||||
--echo # Use 'BINLOG' statement to apply the first update row event
|
||||
--echo # BINLOG statement is same to slave applier, it should work well.
|
||||
--exec $MYSQL_BINLOG --start-position=$_master_pos $datadir$_master_file > $MYSQLTEST_VARDIR/tmp/binlog.sql
|
||||
--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/binlog.sql
|
||||
|
||||
--echo # After 'BINLOG' statement c2's value should be "c2"
|
||||
SELECT * FROM t1;
|
||||
|
||||
--remove_file $MYSQLTEST_VARDIR/tmp/binlog.sql
|
||||
DROP TABLE t1;
|
||||
|
||||
-- let $row_img_set=server_1:FULL:N,server_2:FULL:Y,server_3:FULL:Y
|
||||
-- source include/rpl_row_img_set.inc
|
||||
|
||||
|
||||
--source include/rpl_end.inc
|
||||
|
|
|
@ -201,7 +201,29 @@ static bool unpack_field(const table_def *tabledef, Field *f,
|
|||
the assertions triggered need to be
|
||||
addressed/revisited.
|
||||
*/
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
f->reset() may call store_value() to reset the value, for example
|
||||
Field_new_decimal. store_value() has below assertion:
|
||||
|
||||
DBUG_ASSERT(marked_for_write_or_computed());
|
||||
|
||||
It asserts write bitmap must be set. That caused an assertion
|
||||
failure for row images generated by FULL_NODUP mode.
|
||||
The assertion is meaningless for unpacking a row image, so
|
||||
the field is marked in write_set temporarily to avoid the
|
||||
assertion failure.
|
||||
*/
|
||||
bool was_not_set = !bitmap_is_set(f->table->write_set, f->field_index);
|
||||
if (was_not_set)
|
||||
bitmap_set_bit(f->table->write_set, f->field_index);
|
||||
#endif
|
||||
f->reset();
|
||||
#ifndef DBUG_OFF
|
||||
if (was_not_set)
|
||||
bitmap_clear_bit(f->table->write_set, f->field_index);
|
||||
#endif
|
||||
f->set_null();
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in a new issue