diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-09-09 15:00:21 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-09-09 15:00:21 +0300 |
commit | 66ae50a564f1d145d36f7de8dc266ce9266acf26 (patch) | |
tree | 7fe24cde51d4a3f53a4b7a67d48c168016f3dc10 | |
parent | 9b688471274868ff94115fd6e4255ee01befedad (diff) | |
parent | 7e07e38cf687ccd7fa3bd3a35c1eb7e4b307ca5f (diff) | |
download | mariadb-git-66ae50a564f1d145d36f7de8dc266ce9266acf26.tar.gz |
Merge 10.3 into 10.4
-rw-r--r-- | mysql-test/suite/innodb/r/foreign_key.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/foreign_key.test | 13 | ||||
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 10 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 104 | ||||
-rw-r--r-- | storage/innobase/buf/buf0dblwr.cc | 10 | ||||
-rw-r--r-- | storage/innobase/dict/dict0boot.cc | 4 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 6 | ||||
-rw-r--r-- | storage/innobase/fsp/fsp0fsp.cc | 131 | ||||
-rw-r--r-- | storage/innobase/include/fsp0fsp.h | 30 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 4 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 1 | ||||
-rw-r--r-- | storage/innobase/mtr/mtr0mtr.cc | 26 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 63 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rseg.cc | 2 | ||||
-rw-r--r-- | storage/innobase/trx/trx0sys.cc | 2 | ||||
-rw-r--r-- | storage/innobase/trx/trx0undo.cc | 2 |
16 files changed, 257 insertions, 162 deletions
diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 901008753f6..bd40f98ef65 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -740,6 +740,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 bbda93d160a..9207fce6525 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 1f104e59db8..04aaccec84e 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1087,8 +1087,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); @@ -1118,7 +1117,7 @@ btr_create( flst_init(block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); } else { - block = fseg_create(space, 0, + block = fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); if (block == NULL) { @@ -1127,8 +1126,9 @@ 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 51b67237f22..b13ac2ef2ac 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5588,14 +5588,13 @@ buf_page_create( { buf_frame_t* frame; buf_block_t* block; - buf_block_t* free_block = NULL; buf_pool_t* buf_pool = buf_pool_get(page_id); rw_lock_t* hash_lock; ut_ad(mtr->is_active()); ut_ad(page_id.space() != 0 || !zip_size); - - free_block = buf_LRU_get_free_block(buf_pool); +loop: + buf_block_t *free_block = buf_LRU_get_free_block(buf_pool); buf_pool_mutex_enter(buf_pool); @@ -5604,22 +5603,68 @@ buf_page_create( block = (buf_block_t*) buf_page_hash_get_low(buf_pool, page_id); - if (block + if (UNIV_LIKELY_NULL(block) && buf_page_in_file(&block->page) && !buf_pool_watch_is_sentinel(buf_pool, &block->page)) { ut_d(block->page.file_page_was_freed = FALSE); - #ifdef BTR_CUR_HASH_ADAPT - bool drop_hash_entry = - (block->page.state == BUF_BLOCK_FILE_PAGE - && block->index); - - if (drop_hash_entry) { - /* Avoid a hang if I/O is going on. Release - the buffer pool mutex and page hash lock - and wait for I/O to complete */ - while (buf_block_get_io_fix(block) != BUF_IO_NONE) { - block->fix(); + const dict_index_t *drop_hash_entry= nullptr; +#endif + switch (const auto page_state= buf_block_get_state(block)) { + default: + ut_ad(0); + break; + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + buf_block_init_low(free_block); + mutex_enter(&buf_pool->zip_mutex); + + buf_page_mutex_enter(free_block); + if (buf_page_get_io_fix(&block->page) != BUF_IO_NONE) { + mutex_exit(&buf_pool->zip_mutex); + rw_lock_x_unlock(hash_lock); + buf_LRU_block_free_non_file_page(free_block); + buf_pool_mutex_exit(buf_pool); + buf_page_mutex_exit(free_block); + + goto loop; + } + + rw_lock_x_lock(&free_block->lock); + + buf_relocate(&block->page, &free_block->page); + if (page_state == BUF_BLOCK_ZIP_DIRTY) { + ut_ad(block->page.in_flush_list); + ut_ad(block->page.oldest_modification > 0); + buf_flush_relocate_on_flush_list( + &block->page, &free_block->page); + } else { + ut_ad(block->page.oldest_modification == 0); + ut_ad(!block->page.in_flush_list); +#ifdef UNIV_DEBUG + UT_LIST_REMOVE( + buf_pool->zip_clean, &block->page); +#endif + } + + free_block->page.state = BUF_BLOCK_FILE_PAGE; + mutex_exit(&buf_pool->zip_mutex); + free_block->lock_hash_val = lock_rec_hash( + page_id.space(), page_id.page_no()); + buf_unzip_LRU_add_block(free_block, false); + buf_page_free_descriptor(&block->page); + block = free_block; + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + buf_page_mutex_exit(free_block); + free_block = nullptr; + break; + case BUF_BLOCK_FILE_PAGE: + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + const uint32_t num_fix_count= mtr->get_fix_count(block) + + 1; + while (buf_block_get_io_fix(block) != BUF_IO_NONE + || (num_fix_count + != block->page.buf_fix_count)) { buf_pool_mutex_exit(buf_pool); rw_lock_x_unlock(hash_lock); @@ -5627,31 +5672,30 @@ buf_page_create( buf_pool_mutex_enter(buf_pool); rw_lock_x_lock(hash_lock); - block->unfix(); } + rw_lock_x_lock(&block->lock); - } +#ifdef BTR_CUR_HASH_ADAPT + drop_hash_entry = block->index; #endif + break; + } /* Page can be found in buf_pool */ buf_pool_mutex_exit(buf_pool); rw_lock_x_unlock(hash_lock); - buf_block_free(free_block); + if (free_block) { + buf_block_free(free_block); + } + #ifdef BTR_CUR_HASH_ADAPT - if (drop_hash_entry) { + if (UNIV_LIKELY_NULL(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()) { - return buf_page_get_with_no_latch(page_id, zip_size, - mtr); - } + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); - mutex_exit(&recv_sys.mutex); - block = buf_page_get_with_no_latch(page_id, zip_size, mtr); - mutex_enter(&recv_sys.mutex); return block; } @@ -5666,6 +5710,8 @@ buf_page_create( buf_page_init(buf_pool, page_id, zip_size, block); + rw_lock_x_lock(&block->lock); + rw_lock_x_unlock(hash_lock); /* The block must be put to the LRU list */ @@ -5683,7 +5729,6 @@ buf_page_create( by IO-fixing and X-latching the block. */ buf_page_set_io_fix(&block->page, BUF_IO_READ); - rw_lock_x_lock(&block->lock); buf_page_mutex_exit(block); /* buf_pool->mutex may be released and reacquired by @@ -5705,12 +5750,11 @@ buf_page_create( buf_unzip_LRU_add_block(block, FALSE); buf_page_set_io_fix(&block->page, BUF_IO_NONE); - rw_lock_x_unlock(&block->lock); } buf_pool_mutex_exit(buf_pool); - mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); buf_page_set_accessed(&block->page); diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index dde718da35b..f6da4d2d8e4 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -170,6 +170,7 @@ buf_dblwr_create() { buf_block_t* block2; buf_block_t* new_block; + buf_block_t* trx_sys_block; byte* doublewrite; byte* fseg_header; ulint page_no; @@ -205,9 +206,12 @@ start_again: } } - block2 = fseg_create(fil_system.sys_space, TRX_SYS_PAGE_NO, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_FSEG, &mtr); + trx_sys_block = buf_page_get(page_id_t(TRX_SYS_SPACE, TRX_SYS_PAGE_NO), + 0, RW_X_LATCH, &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 0055ca6ef17..29db56599e2 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2019, MariaDB Corporation. +Copyright (c) 2016, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -142,7 +142,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(DICT_HDR_PAGE_NO == block->page.id.page_no()); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d5b1e3f7e24..411abdcd494 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -6047,7 +6047,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 29fc5fa37bd..c87273b87ec 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -112,7 +112,6 @@ to 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. If init_mtr != mtr, but the page is @@ -130,7 +129,6 @@ fseg_alloc_free_page_low( fseg_inode_t* seg_inode, ulint hint, byte direction, - rw_lock_type_t rw_latch, mtr_t* mtr, mtr_t* init_mtr #ifdef UNIV_DEBUG @@ -196,7 +194,9 @@ xdes_set_bit( ulint bit_index; ulint descr_byte; - ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr_memo_contains_page( + mtr, descr, + MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT)); ut_ad(offset < FSP_EXTENT_SIZE); @@ -323,7 +323,9 @@ xdes_set_state( ut_ad(descr && mtr); ut_ad(state >= XDES_FREE); ut_ad(state <= XDES_FSEG); - ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr_memo_contains_page( + mtr, descr, + MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX)); mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr); } @@ -357,9 +359,10 @@ xdes_init( xdes_t* descr, /*!< in: descriptor */ mtr_t* mtr) /*!< in/out: mini-transaction */ { - ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_SX_FIX)); - mlog_memset(descr + XDES_BITMAP, XDES_SIZE - XDES_BITMAP, 0xff, mtr); - xdes_set_state(descr, XDES_FREE, mtr); + ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); + mlog_memset(descr + XDES_BITMAP, XDES_SIZE - XDES_BITMAP, 0xff, mtr); + xdes_set_state(descr, XDES_FREE, mtr); } /** Get pointer to a the extent descriptor of a page. @@ -387,7 +390,8 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; ut_ad(mtr_memo_contains(mtr, space, MTR_MEMO_SPACE_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_SX_FIX) + || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -628,7 +632,6 @@ void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) mtr_x_lock_space(space, mtr); buf_block_t* block = buf_page_create(page_id, zip_size, mtr); - buf_page_get(page_id, zip_size, RW_SX_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); space->size_in_header = size; @@ -965,9 +968,6 @@ fsp_fill_free_list( block = buf_page_create( page_id, zip_size, mtr); - buf_page_get( - page_id, zip_size, RW_SX_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -985,9 +985,6 @@ fsp_fill_free_list( block = buf_page_create( page_id, zip_size, mtr); - buf_page_get( - page_id, zip_size, RW_SX_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -1130,7 +1127,6 @@ not previously x-latched. It is assumed that the block has been x-latched only by mtr, and freed in mtr in that case. @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 of the allocation @param[in,out] init_mtr mini-transaction for initializing the page @return block, initialized if init_mtr==mtr @@ -1140,39 +1136,17 @@ buf_block_t* fsp_page_create( fil_space_t* space, page_no_t offset, - rw_lock_type_t rw_latch, mtr_t* mtr, mtr_t* init_mtr) { buf_block_t* block = buf_page_create(page_id_t(space->id, offset), space->zip_size(), init_mtr); - ut_d(bool latched = mtr_memo_contains_flagged(mtr, block, - MTR_MEMO_PAGE_X_FIX - | MTR_MEMO_PAGE_SX_FIX)); - - ut_ad(rw_latch == RW_X_LATCH || rw_latch == RW_SX_LATCH); - - /* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */ - if (rw_latch == RW_X_LATCH) { - rw_lock_x_lock(&block->lock); - } else { - rw_lock_sx_lock(&block->lock); - } - - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - mtr_memo_push(init_mtr, block, rw_latch == RW_X_LATCH - ? MTR_MEMO_PAGE_X_FIX : MTR_MEMO_PAGE_SX_FIX); - if (init_mtr == mtr - || (rw_latch == RW_X_LATCH - ? rw_lock_get_x_lock_count(&block->lock) == 1 - : rw_lock_get_sx_lock_count(&block->lock) == 1)) { - + || rw_lock_get_x_lock_count(&block->lock) == 1) { /* Initialize the page, unless it was already - SX-latched in mtr. (In this case, we would want to + latched in mtr. (In this case, we would want to allocate another page that has not been freed in mtr.) */ - ut_ad(init_mtr == mtr || !latched); fsp_init_file_page(space, block, init_mtr); } @@ -1183,7 +1157,6 @@ fsp_page_create( 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) @@ -1196,7 +1169,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) { @@ -1286,7 +1258,7 @@ fsp_alloc_free_page( } fsp_alloc_from_free_frag(header, descr, free, mtr); - return fsp_page_create(space, page_no, rw_latch, mtr, init_mtr); + return fsp_page_create(space, page_no, mtr, init_mtr); } /** Frees a single page of a space. @@ -1525,15 +1497,14 @@ fsp_alloc_seg_inode_page( ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET); ut_ad(page_get_space_id(page_align(space_header)) == space->id); - block = fsp_alloc_free_page(space, 0, RW_SX_LATCH, mtr, mtr); - - if (block == NULL) { + 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); mlog_write_ulint(block->frame + FIL_PAGE_TYPE, FIL_PAGE_INODE, MLOG_2BYTES, mtr); @@ -1844,53 +1815,44 @@ fseg_get_n_frag_pages( 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) { fsp_header_t* space_header; fseg_inode_t* inode; ib_id_t seg_id; - buf_block_t* block = 0; /* remove warning */ fseg_header_t* header = 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) { header = byte_offset + buf_block_get_frame(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); @@ -1931,9 +1893,8 @@ fseg_create( mlog_memset(inode + FSEG_FRAG_ARR, FSEG_FRAG_SLOT_SIZE * FSEG_FRAG_ARR_N_SLOTS, 0xff, mtr); - if (page == 0) { - block = fseg_alloc_free_page_low(space, - inode, 0, FSP_UP, RW_SX_LATCH, + if (!block) { + block = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr, mtr #ifdef UNIV_DEBUG , has_done_reservation @@ -1949,7 +1910,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); header = byte_offset + buf_block_get_frame(block); mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE, @@ -2161,7 +2122,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. If init_mtr != mtr, but the page is @@ -2179,7 +2139,6 @@ fseg_alloc_free_page_low( fseg_inode_t* seg_inode, ulint hint, byte direction, - rw_lock_type_t rw_latch, mtr_t* mtr, mtr_t* init_mtr #ifdef UNIV_DEBUG @@ -2320,11 +2279,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, mtr); @@ -2399,7 +2358,7 @@ got_hinted_page: fseg_mark_page_used(seg_inode, ret_page, ret_descr, mtr); } - return fsp_page_create(space, ret_page, rw_latch, mtr, init_mtr); + return fsp_page_create(space, ret_page, mtr, init_mtr); } /**********************************************************************//** @@ -2455,7 +2414,7 @@ fseg_alloc_free_page_general( block = fseg_alloc_free_page_low(space, inode, hint, direction, - RW_X_LATCH, mtr, init_mtr + mtr, init_mtr #ifdef UNIV_DEBUG , has_done_reservation #endif /* UNIV_DEBUG */ @@ -3140,7 +3099,7 @@ fseg_print_low( ulint page_no; ib_id_t seg_id; - ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); space = page_get_space_id(page_align(inode)); page_no = page_get_page_no(page_align(inode)); diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 8e1acfe1805..772577ed20c 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -359,26 +359,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); /**********************************************************************//** Calculates the number of pages reserved by a segment, and how many pages are diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index aa119bf72d5..a7d0af02986 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -426,6 +426,10 @@ struct mtr_t { static inline bool is_block_dirtied(const buf_block_t* block) MY_ATTRIBUTE((warn_unused_result)); + /** 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); private: /** Prepare to write the mini-transaction log to the redo log buffer. @return number of bytes to write in finish_write() */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index bc116fec152..c9035ee8b79 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2242,7 +2242,6 @@ init_fail: { 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, recv_addr, &i); ut_ad(mtr.has_committed()); } diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 235c2807b60..15d7cc4b5a4 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -308,6 +308,24 @@ struct DebugCheck { }; #endif +/** 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) + ut_d(if (slot->type != MTR_MEMO_MODIFY)) + num_fix++; + return true; + } +}; + /** Release a resource acquired by the mini-transaction. */ struct ReleaseBlocks { /** Release specific object */ @@ -735,6 +753,14 @@ inline lsn_t mtr_t::finish_write(ulint len) return start_lsn; } +uint32_t mtr_t::get_fix_count(const buf_block_t *block) +{ + Iterate<FindBlock> iteration((FindBlock(block))); + if (m_memo.for_each_block(iteration)) + return iteration.functor.num_fix; + return 0; +} + #ifdef UNIV_DEBUG /** Check if memo contains the given item. @return true if contains */ diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 917e36b8534..26a6d608ad7 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -3175,20 +3175,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); }; /*********************************************************************//** @@ -3388,8 +3414,18 @@ 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; + + lsn_t lsn = bpage.newest_modification; + if (!lsn) { + 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( @@ -3401,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 { @@ -3411,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 4ca140d4f30..3e29ad838c9 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -312,7 +312,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 632ad7f61c8..87e85b85939 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -160,7 +160,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 54e3f4de467..da219cf6139 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -526,7 +526,7 @@ trx_undo_seg_create(fil_space_t* space, trx_rsegf_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); |