diff options
22 files changed, 300 insertions, 180 deletions
diff --git a/mysql-test/suite/galera_sr/r/GCF-597.result b/mysql-test/suite/galera_sr/r/GCF-597.result index 7afca229251..52b13ba3268 100644 --- a/mysql-test/suite/galera_sr/r/GCF-597.result +++ b/mysql-test/suite/galera_sr/r/GCF-597.result @@ -15,7 +15,13 @@ INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; connection node_2; ROLLBACK; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction DROP TABLE t1; +disconnect node_1a; +disconnect node_2a; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result index 82f41a2faaa..c775cd854a7 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result @@ -17,17 +17,25 @@ SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT COUNT(*) AS EXPECT_0 FROM t1; EXPECT_0 0 -SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; -EXPECT_0 -0 INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3; SELECT COUNT(*) AS EXPECT_1000 FROM t1; EXPECT_1000 1000 -connection node_1a; +connection node_1; SET GLOBAL wsrep_sync_wait=15; SELECT COUNT(*) AS EXPECT_1000 FROM t1; EXPECT_1000 1000 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 +connection node_2; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 +connection node_1; DROP TABLE t1; DROP TABLE ten; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result index d14de27d2b7..eab6110afb1 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result @@ -2,9 +2,9 @@ connection node_2; connection node_1; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; connection node_2; -SELECT COUNT(*) = 0 FROM t1; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_0 FROM t1; +EXPECT_0 +0 connection node_1; CREATE TABLE t2 (f1 INTEGER); connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; @@ -39,16 +39,16 @@ INSERT INTO t1 VALUES (13); INSERT INTO t1 VALUES (14); INSERT INTO t1 VALUES (15); COMMIT; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 connection node_2; -SELECT COUNT(*) = 15 FROM t1; -COUNT(*) = 15 -1 -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_15 FROM t1; +EXPECT_15 +15 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 connection node_1; DROP TABLE t1; DROP TABLE t2; diff --git a/mysql-test/suite/galera_sr/t/GCF-597.test b/mysql-test/suite/galera_sr/t/GCF-597.test index d3d80ffc4f8..9c86e598154 100644 --- a/mysql-test/suite/galera_sr/t/GCF-597.test +++ b/mysql-test/suite/galera_sr/t/GCF-597.test @@ -22,8 +22,21 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1a +--let $wait_condition = SELECT COUNT(*) = 5 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +--let $wait_condition = SELECT COUNT(*) = 5 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + --connection node_2 --error ER_LOCK_DEADLOCK ROLLBACK; -DROP TABLE t1;
\ No newline at end of file +DROP TABLE t1; + +--disconnect node_1a +--disconnect node_2a diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test index 5282baed86d..8bce5f6bc36 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test @@ -33,18 +33,27 @@ SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # Confirm that the kill caused the updates made so far to be removed --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM t1 +--source include/wait_condition.inc SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT COUNT(*) AS EXPECT_0 FROM t1; -SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; # Confirm that the transaction can be reissued in its entirety on the slave without a conflict INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3; SELECT COUNT(*) AS EXPECT_1000 FROM t1; ---connection node_1a +--connection node_1 SET GLOBAL wsrep_sync_wait=15; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; + +--connection node_2 SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +--connection node_1 DROP TABLE t1; DROP TABLE ten; diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test index a76a03e49b9..cbf7213c69f 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test @@ -13,12 +13,17 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; # Block node #2's applier before table t1's inserts have come into play --connection node_2 -SELECT COUNT(*) = 0 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1' +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_0 FROM t1; --connection node_1 CREATE TABLE t2 (f1 INTEGER); --connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + LOCK TABLE t2 WRITE; --connection node_1 @@ -39,11 +44,8 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); ---sleep 2 - --connection node_2 --source include/kill_galera.inc ---sleep 1 --connection node_1 INSERT INTO t1 VALUES (6); @@ -54,8 +56,6 @@ INSERT INTO t1 VALUES (10); --connection node_2 --source include/start_mysqld.inc ---sleep 1 - --source include/wait_until_connected_again.inc --source include/galera_wait_ready.inc @@ -67,12 +67,17 @@ INSERT INTO t1 VALUES (14); INSERT INTO t1 VALUES (15); COMMIT; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; +--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; --connection node_2 ---sleep 5 -SELECT COUNT(*) = 15 FROM t1; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; +--let $wait_condition = SELECT COUNT(*) = 15 FROM t1 +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_15 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; --connection node_1 diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 936c7bab54f..aadfc338501 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -736,6 +736,17 @@ t2 CREATE TABLE `t2` ( CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; ERROR 42S01: Table 't2' already exists DROP TABLE t2, t1; +# +# MDEV-23685 SIGSEGV on ADD FOREIGN KEY after failed attempt +# to create unique key on virtual column +# +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, b INT AS (a)) ENGINE=InnODB; +INSERT INTO t1 (pk,a) VALUES (1,10),(2,10); +ALTER TABLE t1 ADD UNIQUE INDEX ind9 (b), LOCK=SHARED; +ERROR 23000: Duplicate entry '10' for key 'ind9' +SET FOREIGN_KEY_CHECKS= 0; +ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (pk); +DROP TABLE t1; # End of 10.2 tests CREATE TABLE t1 (a GEOMETRY, INDEX(a(8)), FOREIGN KEY (a) REFERENCES x (xx)) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 3d4c7c5004d..c1713cb9742 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -720,6 +720,19 @@ SHOW CREATE TABLE t2; CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; DROP TABLE t2, t1; +--echo # +--echo # MDEV-23685 SIGSEGV on ADD FOREIGN KEY after failed attempt +--echo # to create unique key on virtual column +--echo # +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, b INT AS (a)) ENGINE=InnODB; + +INSERT INTO t1 (pk,a) VALUES (1,10),(2,10); +--error ER_DUP_ENTRY +ALTER TABLE t1 ADD UNIQUE INDEX ind9 (b), LOCK=SHARED; +SET FOREIGN_KEY_CHECKS= 0; +ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (pk); +DROP TABLE t1; + --echo # End of 10.2 tests # MDEV-21792 Server aborts upon attempt to create foreign key on spatial field diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 40684e95615..8ed25db8cb7 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1025,8 +1025,7 @@ btr_create( if (UNIV_UNLIKELY(type & DICT_IBUF)) { /* Allocate first the ibuf header page */ buf_block_t* ibuf_hdr_block = fseg_create( - space, 0, - IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); + space, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); if (ibuf_hdr_block == NULL) { return(FIL_NULL); @@ -1056,8 +1055,8 @@ btr_create( flst_init(block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); } else { - block = fseg_create(space, 0, - PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); + block = fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_TOP, + mtr); if (block == NULL) { return(FIL_NULL); @@ -1065,8 +1064,8 @@ btr_create( buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - if (!fseg_create(space, block->page.id().page_no(), - PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { + if (!fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr, + false, block)) { /* Not enough space for new segment, free root segment before return. */ btr_free_root(block, mtr); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 5977271dc20..4094c24fac2 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3823,6 +3823,7 @@ buf_page_create(fil_space_t *space, uint32_t offset, ut_ad(page_id.space() != 0 || !zip_size); space->free_page(offset, false); +loop: buf_block_t *free_block= buf_LRU_get_free_block(false); free_block->initialise(page_id, zip_size, 1); @@ -3837,35 +3838,71 @@ buf_page_create(fil_space_t *space, uint32_t offset, !buf_pool.watch_is_sentinel(block->page)) { #ifdef BTR_CUR_HASH_ADAPT - const bool drop_hash_entry= block->page.state() == BUF_BLOCK_FILE_PAGE && - UNIV_LIKELY_NULL(block->index); - if (UNIV_UNLIKELY(drop_hash_entry)) + const dict_index_t *drop_hash_entry= nullptr; +#endif + switch (block->page.state()) { + default: + ut_ad(0); + break; + case BUF_BLOCK_FILE_PAGE: + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + { + const auto num_fix_count= mtr->get_fix_count(block) + 1; + while (block->page.io_fix() != BUF_IO_NONE || + num_fix_count != block->page.buf_fix_count()) + { + mutex_exit(&buf_pool.mutex); + os_thread_yield(); + mutex_enter(&buf_pool.mutex); + } + } rw_lock_x_lock(&block->lock); -#endif /* BTR_CUR_HASH_ADAPT */ +#ifdef BTR_CUR_HASH_ADAPT + drop_hash_entry= block->index; +#endif + buf_LRU_block_free_non_file_page(free_block); + break; + case BUF_BLOCK_ZIP_PAGE: + page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); + hash_lock->write_lock(); + if (block->page.io_fix() != BUF_IO_NONE) + { + hash_lock->write_unlock(); + buf_LRU_block_free_non_file_page(block); + mutex_exit(&buf_pool.mutex); + goto loop; + } + + rw_lock_x_lock(&free_block->lock); + buf_relocate(&block->page, &free_block->page); + + if (block->page.oldest_modification() > 0) + buf_flush_relocate_on_flush_list(&block->page, &free_block->page); +#ifdef UNIV_DEBUG + else + UT_LIST_REMOVE(buf_pool.zip_clean, &block->page); +#endif + + free_block->page.set_state(BUF_BLOCK_FILE_PAGE); + free_block->lock_hash_val= lock_rec_hash( + page_id.space(), page_id.page_no()); + buf_unzip_LRU_add_block(free_block, FALSE); + hash_lock->write_unlock(); + buf_page_free_descriptor(&block->page); + block= free_block; + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + break; + } - /* Page can be found in buf_pool */ - buf_LRU_block_free_non_file_page(free_block); mutex_exit(&buf_pool.mutex); #ifdef BTR_CUR_HASH_ADAPT - if (UNIV_UNLIKELY(drop_hash_entry)) - { + if (drop_hash_entry) btr_search_drop_page_hash_index(block); - rw_lock_x_unlock(&block->lock); - } #endif /* BTR_CUR_HASH_ADAPT */ - if (!recv_recovery_is_on()) - /* FIXME: Remove the redundant lookup and avoid - the unnecessary invocation of buf_zip_decompress(). - We may have to convert buf_page_t to buf_block_t, - but we are going to initialize the page. */ - return buf_page_get_gen(page_id, zip_size, RW_NO_LATCH, - block, BUF_GET_POSSIBLY_FREED, - __FILE__, __LINE__, mtr); - mutex_exit(&recv_sys.mutex); - block= buf_page_get_with_no_latch(page_id, zip_size, mtr); - mutex_enter(&recv_sys.mutex); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); + return block; } @@ -3889,13 +3926,13 @@ buf_page_create(fil_space_t *space, uint32_t offset, ut_d(block->page.in_page_hash= true); HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, &block->page); + rw_lock_x_lock(&block->lock); if (UNIV_UNLIKELY(zip_size)) { /* Prevent race conditions during buf_buddy_alloc(), which may release and reacquire buf_pool.mutex, by IO-fixing and X-latching the block. */ block->page.set_io_fix(BUF_IO_READ); - rw_lock_x_lock(&block->lock); hash_lock->write_unlock(); /* buf_pool.mutex may be released and reacquired by @@ -3911,14 +3948,13 @@ buf_page_create(fil_space_t *space, uint32_t offset, buf_unzip_LRU_add_block(block, FALSE); block->page.set_io_fix(BUF_IO_NONE); - rw_lock_x_unlock(&block->lock); } else hash_lock->write_unlock(); mutex_exit(&buf_pool.mutex); - mtr->memo_push(block, MTR_MEMO_BUF_FIX); + mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); block->page.set_accessed(); buf_pool.stat.n_pages_created++; diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 516aeef1002..4b2822bf865 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -166,9 +166,9 @@ start_again: } } - block2 = fseg_create(fil_system.sys_space, TRX_SYS_PAGE_NO, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_FSEG, &mtr); + block2 = fseg_create(fil_system.sys_space, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG, + &mtr, false, trx_sys_block); if (block2 == NULL) { too_small: diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 833f2621de6..359684416ed 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -134,7 +134,7 @@ dict_hdr_create( /* Create the dictionary header file block in a new, allocated file segment in the system tablespace */ - block = fseg_create(fil_system.sys_space, 0, + block = fseg_create(fil_system.sys_space, DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); ut_a(block->page.id() == page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO)); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 097c907a826..d9338af1327 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -5027,7 +5027,11 @@ dict_foreign_qualify_index( return(false); } - if (index->type & (DICT_SPATIAL | DICT_FTS)) { + if (index->type & (DICT_SPATIAL | DICT_FTS | DICT_CORRUPT)) { + return false; + } + + if (index->online_status >= ONLINE_INDEX_ABORTED) { return false; } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index a2a6335a17a..6ac57ca395c 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -101,7 +101,6 @@ minimize file space fragmentation. @param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mtr or another mini-transaction in which the page should be initialized. @@ -114,7 +113,6 @@ fseg_alloc_free_page_low( buf_block_t* iblock, ulint hint, byte direction, - rw_lock_type_t rw_latch, #ifdef UNIV_DEBUG bool has_done_reservation, /*!< whether the space has already been reserved */ @@ -147,7 +145,8 @@ template<bool free> inline void xdes_set_free(const buf_block_t &block, xdes_t *descr, ulint offset, mtr_t *mtr) { - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); ut_ad(offset < FSP_EXTENT_SIZE); ut_ad(page_align(descr) == block.frame); compile_time_assert(XDES_BITS_PER_PAGE == 2); @@ -218,7 +217,8 @@ inline void xdes_set_state(const buf_block_t &block, xdes_t *descr, ut_ad(descr && mtr); ut_ad(state >= XDES_FREE); ut_ad(state <= XDES_FSEG); - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); ut_ad(page_align(descr) == block.frame); ut_ad(mach_read_from_4(descr + XDES_STATE) <= XDES_FSEG); mtr->write<1>(block, XDES_STATE + 3 + descr, state); @@ -245,7 +245,8 @@ xdes_get_state( Inits an extent descriptor to the free and clean state. */ inline void xdes_init(const buf_block_t &block, xdes_t *descr, mtr_t *mtr) { - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); mtr->memset(&block, uint16_t(descr - block.frame) + XDES_BITMAP, XDES_SIZE - XDES_BITMAP, 0xff); xdes_set_state(block, descr, XDES_FREE, mtr); @@ -320,7 +321,8 @@ xdes_get_descriptor_with_space_hdr( ulint size; ulint descr_page_no; ut_ad(mtr->memo_contains(*space)); - ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX + | MTR_MEMO_PAGE_X_FIX)); /* Read free limit and space size */ limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + header->frame); @@ -553,9 +555,7 @@ void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) mtr_x_lock_space(space, mtr); - const auto savepoint = mtr->get_savepoint(); buf_block_t* block = buf_page_create(space, 0, zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); space->size_in_header = size; @@ -874,11 +874,9 @@ fsp_fill_free_list( pages should be ignored. */ if (i > 0) { - const auto savepoint = mtr->get_savepoint(); block= buf_page_create( space, static_cast<uint32_t>(i), zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -888,13 +886,11 @@ fsp_fill_free_list( } if (space->purpose != FIL_TYPE_TEMPORARY) { - const auto savepoint = mtr->get_savepoint(); block = buf_page_create( space, static_cast<uint32_t>( i + FSP_IBUF_BITMAP_OFFSET), zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -1040,46 +1036,22 @@ fsp_alloc_from_free_frag(buf_block_t *header, buf_block_t *xdes, xdes_t *descr, /** Gets a buffer block for an allocated page. @param[in,out] space tablespace @param[in] offset page number of the allocated page -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @return block, initialized */ static buf_block_t* -fsp_page_create( - fil_space_t* space, - page_no_t offset, - rw_lock_type_t rw_latch, - mtr_t* mtr) +fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) { - buf_block_t* block = buf_page_create( - space, static_cast<uint32_t>(offset), - space->zip_size(), mtr); - - /* The latch may already have been acquired, so we cannot invoke - mtr_t::x_latch_at_savepoint() or mtr_t::sx_latch_at_savepoint(). */ - mtr_memo_type_t memo; - - if (rw_latch == RW_X_LATCH) { - rw_lock_x_lock(&block->lock); - memo = MTR_MEMO_PAGE_X_FIX; - } else { - ut_ad(rw_latch == RW_SX_LATCH); - rw_lock_sx_lock(&block->lock); - memo = MTR_MEMO_PAGE_SX_FIX; - } - - mtr_memo_push(mtr, block, memo); - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - fsp_init_file_page(space, block, mtr); - - return(block); + buf_block_t *block= buf_page_create(space, static_cast<uint32_t>(offset), + space->zip_size(), mtr); + fsp_init_file_page(space, block, mtr); + return block; } /** Allocates a single free page from a space. The page is marked as used. @param[in,out] space tablespace @param[in] hint hint of which page would be desirable -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mini-transaction in which the page should be initialized (may be the same as mtr) @@ -1089,7 +1061,6 @@ buf_block_t* fsp_alloc_free_page( fil_space_t* space, ulint hint, - rw_lock_type_t rw_latch, mtr_t* mtr, mtr_t* init_mtr) { @@ -1184,7 +1155,7 @@ fsp_alloc_free_page( } fsp_alloc_from_free_frag(block, xdes, descr, free, mtr); - return fsp_page_create(space, page_no, rw_latch, init_mtr); + return fsp_page_create(space, page_no, init_mtr); } /** Frees a single page of a space. @@ -1376,13 +1347,13 @@ bool fsp_alloc_seg_inode_page(fil_space_t *space, buf_block_t *header, mtr_t *mtr) { ut_ad(header->page.id().space() == space->id); - buf_block_t *block= fsp_alloc_free_page(space, 0, RW_SX_LATCH, mtr, mtr); + buf_block_t *block= fsp_alloc_free_page(space, 0, mtr, mtr); if (!block) return false; buf_block_dbg_add_level(block, SYNC_FSP_PAGE); - ut_ad(rw_lock_get_sx_lock_count(&block->lock) == 1); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); mtr->write<2>(*block, block->frame + FIL_PAGE_TYPE, FIL_PAGE_INODE); @@ -1650,48 +1621,40 @@ static ulint fseg_get_n_frag_pages(const fseg_inode_t *inode) return(count); } -/**********************************************************************//** -Creates a new segment. -@return the block where the segment header is placed, x-latched, NULL -if could not create segment because of lack of space */ +/** Create a new segment. +@param space tablespace +@param byte_offset byte offset of the created segment header +@param mtr mini-transaction +@param has_done_reservation whether fsp_reserve_free_extents() was invoked +@param block block where segment header is placed, + or NULL to allocate an additional page for that +@return the block where the segment header is placed, x-latched +@retval NULL if could not create segment because of lack of space */ buf_block_t* -fseg_create( - fil_space_t* space, /*!< in,out: tablespace */ - ulint page, /*!< in: page where the segment header is placed: if - this is != 0, the page must belong to another segment, - if this is 0, a new page will be allocated and it - will belong to the created segment */ - ulint byte_offset, /*!< in: byte offset of the created segment header - on the page */ - mtr_t* mtr, - bool has_done_reservation) /*!< in: whether the caller - has already done the reservation for the pages with - fsp_reserve_free_extents (at least 2 extents: one for - the inode and the other for the segment) then there is - no need to do the check for this individual - operation */ +fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, + bool has_done_reservation, buf_block_t *block) { fseg_inode_t* inode; ib_id_t seg_id; - buf_block_t* block = 0; /* remove warning */ ulint n_reserved; DBUG_ENTER("fseg_create"); ut_ad(mtr); + ut_ad(byte_offset >= FIL_PAGE_DATA); ut_ad(byte_offset + FSEG_HEADER_SIZE <= srv_page_size - FIL_PAGE_DATA_END); mtr_x_lock_space(space, mtr); ut_d(space->modify_check(*mtr)); - if (page != 0) { - block = buf_page_get(page_id_t(space->id, page), - space->zip_size(), - RW_SX_LATCH, mtr); + if (block) { + ut_ad(block->page.id().space() == space->id); + if (!space->full_crc32()) { - fil_block_check_type(*block, space->id == TRX_SYS_SPACE - && page == TRX_SYS_PAGE_NO + fil_block_check_type(*block, block->page.id() + == page_id_t(TRX_SYS_SPACE, + TRX_SYS_PAGE_NO) ? FIL_PAGE_TYPE_TRX_SYS : FIL_PAGE_TYPE_SYS, mtr); @@ -1734,10 +1697,9 @@ fseg_create( mtr->memset(iblock, uint16_t(inode - iblock->frame) + FSEG_FRAG_ARR, FSEG_FRAG_SLOT_SIZE * FSEG_FRAG_ARR_N_SLOTS, 0xff); - if (page == 0) { + if (!block) { block = fseg_alloc_free_page_low(space, inode, iblock, 0, FSP_UP, - RW_SX_LATCH, #ifdef UNIV_DEBUG has_done_reservation, #endif /* UNIV_DEBUG */ @@ -1752,7 +1714,7 @@ fseg_create( goto funct_exit; } - ut_ad(rw_lock_get_sx_lock_count(&block->lock) == 1); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); ut_ad(!fil_page_get_type(block->frame)); mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->frame, FIL_PAGE_TYPE_SYS); @@ -1957,7 +1919,6 @@ minimize file space fragmentation. @param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mtr or another mini-transaction in which the page should be initialized. @@ -1970,7 +1931,6 @@ fseg_alloc_free_page_low( buf_block_t* iblock, ulint hint, byte direction, - rw_lock_type_t rw_latch, #ifdef UNIV_DEBUG bool has_done_reservation, /*!< whether the space has already been reserved */ @@ -2111,11 +2071,11 @@ take_hinted_page: /* 6. We allocate an individual page from the space ===================================================*/ buf_block_t* block = fsp_alloc_free_page( - space, hint, rw_latch, mtr, init_mtr); + space, hint, mtr, init_mtr); - ut_ad(!has_done_reservation || block != NULL); + ut_ad(!has_done_reservation || block); - if (block != NULL) { + if (block) { /* Put the page in the fragment page array of the segment */ n = fseg_find_free_frag_page_slot(seg_inode); @@ -2192,7 +2152,7 @@ got_hinted_page: xdes, mtr); } - return fsp_page_create(space, ret_page, rw_latch, init_mtr); + return fsp_page_create(space, ret_page, init_mtr); } /**********************************************************************//** @@ -2243,7 +2203,6 @@ fseg_alloc_free_page_general( block = fseg_alloc_free_page_low(space, inode, iblock, hint, direction, - RW_X_LATCH, #ifdef UNIV_DEBUG has_done_reservation, #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index e5bc4c8a6ed..31c66cb57ea 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -362,26 +362,18 @@ fsp_header_init_fields( void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) MY_ATTRIBUTE((nonnull)); -/**********************************************************************//** -Creates a new segment. -@return the block where the segment header is placed, x-latched, NULL -if could not create segment because of lack of space */ +/** Create a new segment. +@param space tablespace +@param byte_offset byte offset of the created segment header +@param mtr mini-transaction +@param has_done_reservation whether fsp_reserve_free_extents() was invoked +@param block block where segment header is placed, + or NULL to allocate an additional page for that +@return the block where the segment header is placed, x-latched +@retval NULL if could not create segment because of lack of space */ buf_block_t* -fseg_create( - fil_space_t* space, /*!< in,out: tablespace */ - ulint page, /*!< in: page where the segment header is placed: if - this is != 0, the page must belong to another segment, - if this is 0, a new page will be allocated and it - will belong to the created segment */ - ulint byte_offset, /*!< in: byte offset of the created segment header - on the page */ - mtr_t* mtr, - bool has_done_reservation = false); /*!< in: whether the caller - has already done the reservation for the pages with - fsp_reserve_free_extents (at least 2 extents: one for - the inode and the other for the segment) then there is - no need to do the check for this individual - operation */ +fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, + bool has_done_reservation= false, buf_block_t *block= NULL); /** Calculate the number of pages reserved by a segment, and how many pages are currently used. diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 599da234904..4487bf94e01 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -591,6 +591,11 @@ public: m_freed_pages->add_value(id.page_no()); } + /** Determine the added buffer fix count of a block. + @param block block to be checked + @return number of buffer count added by this mtr */ + uint32_t get_fix_count(const buf_block_t *block) const; + private: /** Log a write of a byte string to a page. @param block buffer page diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 46830db1323..292060adced 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2592,7 +2592,6 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, ut_ad(&recs == &p->second); i.created= true; buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); - mtr.x_latch_at_savepoint(0, block); recv_recover_page(block, mtr, p, space, &i); ut_ad(mtr.has_committed()); recs.log.clear(); diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 94a88bd3f83..17b524f610f 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -702,6 +702,31 @@ inline lsn_t mtr_t::finish_write(ulint len) return start_lsn; } +/** Find buffer fix count of the given block acquired by the +mini-transaction */ +struct FindBlock +{ + int32_t num_fix; + const buf_block_t *const block; + + FindBlock(const buf_block_t *block_buf): num_fix(0), block(block_buf) {} + + bool operator()(const mtr_memo_slot_t* slot) + { + if (slot->object == block) + num_fix++; + return true; + } +}; + +uint32_t mtr_t::get_fix_count(const buf_block_t *block) const +{ + Iterate<FindBlock> iteration((FindBlock(block))); + if (m_memo.for_each_block(iteration)) + return iteration.functor.num_fix; + return 0; +} + #ifdef UNIV_DEBUG /** Check if we are holding an rw-latch in this mini-transaction @param lock latch to search for diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 8e171f9bf20..239544c453e 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -3178,20 +3178,46 @@ row_sel_build_prev_vers_for_mysql( return(err); } -/** Helper class to cache clust_rec and old_ver */ +/** Helper class to cache clust_rec and old_vers */ class Row_sel_get_clust_rec_for_mysql { - const rec_t *cached_clust_rec; - rec_t *cached_old_vers; + const rec_t *cached_clust_rec; + rec_t *cached_old_vers; + lsn_t cached_lsn; + page_id_t cached_page_id; -public: - Row_sel_get_clust_rec_for_mysql() : - cached_clust_rec(NULL), cached_old_vers(NULL) {} +#ifdef UNIV_DEBUG + void check_eq(const dict_index_t *index, const rec_offs *offsets) const + { + rec_offs vers_offs[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS]; + rec_offs_init(vers_offs); + mem_heap_t *heap= nullptr; + + ut_ad(rec_offs_validate(cached_clust_rec, index, offsets)); + ut_ad(index->first_user_field() <= rec_offs_n_fields(offsets)); + ut_ad(vers_offs == rec_get_offsets(cached_old_vers, index, vers_offs, true, + index->db_trx_id(), &heap)); + ut_ad(!heap); + for (auto n= index->db_trx_id(); n--; ) + { + const dict_col_t *col= dict_index_get_nth_col(index, n); + ulint len1, len2; + const byte *b1= rec_get_nth_field(cached_clust_rec, offsets, n, &len1); + const byte *b2= rec_get_nth_field(cached_old_vers, vers_offs, n, &len2); + ut_ad(!cmp_data_data(col->mtype, col->prtype, b1, len1, b2, len2)); + } + } +#endif - dberr_t operator()(row_prebuilt_t *prebuilt, dict_index_t *sec_index, - const rec_t *rec, que_thr_t *thr, const rec_t **out_rec, - rec_offs **offsets, mem_heap_t **offset_heap, - dtuple_t **vrow, mtr_t *mtr); +public: + Row_sel_get_clust_rec_for_mysql() : + cached_clust_rec(NULL), cached_old_vers(NULL), cached_lsn(0), + cached_page_id(page_id_t(0,0)) {} + + dberr_t operator()(row_prebuilt_t *prebuilt, dict_index_t *sec_index, + const rec_t *rec, que_thr_t *thr, const rec_t **out_rec, + rec_offs **offsets, mem_heap_t **offset_heap, + dtuple_t **vrow, mtr_t *mtr); }; /*********************************************************************//** @@ -3391,8 +3417,15 @@ Row_sel_get_clust_rec_for_mysql::operator()( && !lock_clust_rec_cons_read_sees( clust_rec, clust_index, *offsets, &trx->read_view)) { + const buf_page_t& bpage = btr_pcur_get_block( + prebuilt->clust_pcur)->page; + + const lsn_t lsn = mach_read_from_8( + page_align(clust_rec) + FIL_PAGE_LSN); - if (clust_rec != cached_clust_rec) { + if (lsn != cached_lsn + || bpage.id() != cached_page_id + || clust_rec != cached_clust_rec) { /* The following call returns 'offsets' associated with 'old_vers' */ err = row_sel_build_prev_vers_for_mysql( @@ -3404,6 +3437,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( goto err_exit; } + cached_lsn = lsn; + cached_page_id = bpage.id(); cached_clust_rec = clust_rec; cached_old_vers = old_vers; } else { @@ -3414,7 +3449,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( version of clust_rec and its old version old_vers. Re-calculate the offsets for old_vers. */ - if (old_vers != NULL) { + if (old_vers) { + ut_d(check_eq(clust_index, *offsets)); *offsets = rec_get_offsets( old_vers, clust_index, *offsets, true, ULINT_UNDEFINED, offset_heap); diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index b90ad9b73c8..fb58687beab 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -316,7 +316,7 @@ trx_rseg_header_create( ut_ad(!sys_header == (space == fil_system.temp_space)); /* Allocate a new file segment for the rollback segment */ - block = fseg_create(space, 0, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); + block = fseg_create(space, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); if (block == NULL) { /* No space left */ diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 7144ccff6f5..a3ada6636fd 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -158,7 +158,7 @@ trx_sysf_create( compile_time_assert(TRX_SYS_SPACE == 0); /* Create the trx sys file block in a new allocated file segment */ - block = fseg_create(fil_system.sys_space, 0, + block = fseg_create(fil_system.sys_space, TRX_SYS + TRX_SYS_FSEG_HEADER, mtr); buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER); diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 9ec219870c4..ae3224a29a6 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -383,7 +383,7 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, } /* Allocate a new file segment for the undo log */ - block = fseg_create(space, 0, TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, + block = fseg_create(space, TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, mtr, true); space->release_free_extents(n_reserved); |