summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/mariabackup/fil_cur.cc5
-rw-r--r--extra/mariabackup/xtrabackup.cc10
-rw-r--r--storage/innobase/btr/btr0bulk.cc10
-rw-r--r--storage/innobase/btr/btr0cur.cc30
-rw-r--r--storage/innobase/buf/buf0buf.cc25
-rw-r--r--storage/innobase/buf/buf0dblwr.cc16
-rw-r--r--storage/innobase/buf/buf0dump.cc32
-rw-r--r--storage/innobase/buf/buf0flu.cc22
-rw-r--r--storage/innobase/buf/buf0rea.cc43
-rw-r--r--storage/innobase/dict/dict0crea.cc2
-rw-r--r--storage/innobase/dict/dict0dict.cc2
-rw-r--r--storage/innobase/dict/dict0stats_bg.cc2
-rw-r--r--storage/innobase/fil/fil0crypt.cc146
-rw-r--r--storage/innobase/fil/fil0fil.cc557
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc58
-rw-r--r--storage/innobase/fts/fts0opt.cc5
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/innobase/handler/i_s.cc5
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc8
-rw-r--r--storage/innobase/include/dict0mem.h7
-rw-r--r--storage/innobase/include/fil0fil.h315
-rw-r--r--storage/innobase/include/fsp0file.h8
-rw-r--r--storage/innobase/include/fsp0fsp.h4
-rw-r--r--storage/innobase/lock/lock0lock.cc2
-rw-r--r--storage/innobase/log/log0recv.cc18
-rw-r--r--storage/innobase/os/os0file.cc2
-rw-r--r--storage/innobase/row/row0uins.cc2
-rw-r--r--storage/innobase/row/row0umod.cc2
-rw-r--r--storage/innobase/srv/srv0srv.cc2
-rw-r--r--storage/innobase/srv/srv0start.cc2
-rw-r--r--storage/innobase/trx/trx0undo.cc4
31 files changed, 578 insertions, 770 deletions
diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc
index 7aa20b8700e..4f9e493b347 100644
--- a/extra/mariabackup/fil_cur.cc
+++ b/extra/mariabackup/fil_cur.cc
@@ -93,7 +93,6 @@ xb_fil_node_close_file(
mutex_enter(&fil_system.mutex);
ut_ad(node);
- ut_a(node->n_pending_flushes == 0);
ut_a(!node->being_extended);
if (!node->is_open()) {
@@ -406,7 +405,7 @@ xb_fil_cur_read(
retry_count = 10;
ret = XB_FIL_CUR_SUCCESS;
- fil_space_t *space = fil_space_t::get_for_io(cursor->space_id);
+ fil_space_t *space = fil_space_t::get(cursor->space_id);
if (!space) {
return XB_FIL_CUR_ERROR;
@@ -455,7 +454,7 @@ read_retry:
posix_fadvise(cursor->file, offset, to_read, POSIX_FADV_DONTNEED);
func_exit:
- space->release_for_io();
+ space->release();
return(ret);
}
diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc
index 39025862276..c05677b8810 100644
--- a/extra/mariabackup/xtrabackup.cc
+++ b/extra/mariabackup/xtrabackup.cc
@@ -3094,10 +3094,10 @@ xb_load_single_table_tablespace(
ut_a(space != NULL);
- space->add(file->filepath(), OS_FILE_CLOSED, 0, false, false);
- /* by opening the tablespace we forcing node and space objects
- in the cache to be populated with fields from space header */
- space->get_size();
+ space->add(file->filepath(), file->detach(), 0, false, false);
+ mutex_enter(&fil_system.mutex);
+ space->read_page0();
+ mutex_exit(&fil_system.mutex);
if (srv_operation == SRV_OPERATION_RESTORE_DELTA
|| xb_close_files) {
@@ -3402,7 +3402,7 @@ xb_load_tablespaces()
/** Destroy the tablespace memory cache. */
static void xb_data_files_close()
{
- fil_close_all_files();
+ fil_space_t::close_all();
buf_dblwr.close();
}
diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc
index f602e0d19a2..ee1bc20e1c9 100644
--- a/storage/innobase/btr/btr0bulk.cc
+++ b/storage/innobase/btr/btr0bulk.cc
@@ -60,12 +60,10 @@ PageBulk::init()
alloc_mtr.start();
m_index->set_modified(alloc_mtr);
- ulint n_reserved;
- bool success;
- success = fsp_reserve_free_extents(&n_reserved,
- m_index->table->space,
- 1, FSP_NORMAL, &alloc_mtr);
- if (!success) {
+ uint32_t n_reserved;
+ if (!fsp_reserve_free_extents(&n_reserved,
+ m_index->table->space,
+ 1, FSP_NORMAL, &alloc_mtr)) {
alloc_mtr.commit();
m_mtr.commit();
return(DB_OUT_OF_FILE_SPACE);
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index c280ed555fe..fdb56e34d7e 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -3318,20 +3318,16 @@ static void btr_cur_prefetch_siblings(const buf_block_t *block,
uint32_t prev= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_PREV));
uint32_t next= mach_read_from_4(my_assume_aligned<4>(page + FIL_PAGE_NEXT));
- if (prev != FIL_NULL)
- {
- ut_a(index->table->space->acquire_for_io());
+ if (prev == FIL_NULL);
+ else if (index->table->space->acquire())
buf_read_page_background(index->table->space,
page_id_t(block->page.id().space(), prev),
block->zip_size(), false);
- }
- if (next != FIL_NULL)
- {
- ut_a(index->table->space->acquire_for_io());
+ if (next == FIL_NULL);
+ else if (index->table->space->acquire())
buf_read_page_background(index->table->space,
page_id_t(block->page.id().space(), next),
block->zip_size(), false);
- }
}
/*************************************************************//**
@@ -3679,7 +3675,7 @@ btr_cur_pessimistic_insert(
dberr_t err;
bool inherit = false;
bool success;
- ulint n_reserved = 0;
+ uint32_t n_reserved = 0;
ut_ad(dtuple_check_typed(entry));
ut_ad(thr || !(~flags & (BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG)));
@@ -3711,7 +3707,7 @@ btr_cur_pessimistic_insert(
of the index tree, so that the insert will not fail because
of lack of space */
- ulint n_extents = cursor->tree_height / 16 + 3;
+ uint32_t n_extents = uint32_t(cursor->tree_height / 16 + 3);
success = fsp_reserve_free_extents(&n_reserved,
index->table->space,
@@ -4878,8 +4874,8 @@ btr_cur_pessimistic_update(
dberr_t err;
dberr_t optim_err;
roll_ptr_t roll_ptr;
- ibool was_first;
- ulint n_reserved = 0;
+ bool was_first;
+ uint32_t n_reserved = 0;
*offsets = NULL;
*big_rec = NULL;
@@ -5041,7 +5037,7 @@ btr_cur_pessimistic_update(
of the index tree, so that the update will not fail because
of lack of space */
- ulint n_extents = cursor->tree_height / 16 + 3;
+ uint32_t n_extents = uint32_t(cursor->tree_height / 16 + 3);
if (!fsp_reserve_free_extents(
&n_reserved, index->table->space, n_extents,
@@ -5643,7 +5639,7 @@ btr_cur_pessimistic_delete(
page_zip_des_t* page_zip;
dict_index_t* index;
rec_t* rec;
- ulint n_reserved = 0;
+ uint32_t n_reserved = 0;
bool success;
ibool ret = FALSE;
mem_heap_t* heap;
@@ -5672,7 +5668,7 @@ btr_cur_pessimistic_delete(
of the index tree, so that the node pointer updates will
not fail because of lack of space */
- ulint n_extents = cursor->tree_height / 32 + 1;
+ uint32_t n_extents = uint32_t(cursor->tree_height / 32 + 1);
success = fsp_reserve_free_extents(&n_reserved,
index->table->space,
@@ -7315,7 +7311,7 @@ btr_store_big_rec_extern_fields(
for (ulint blob_npages = 0;; ++blob_npages) {
buf_block_t* block;
const ulint commit_freq = 4;
- ulint r_extents;
+ uint32_t r_extents;
ut_ad(page_align(field_ref) == page_align(rec));
@@ -7588,7 +7584,7 @@ static void btr_check_blob_fil_page_type(const buf_block_t& block, bool read)
if (UNIV_LIKELY(type == FIL_PAGE_TYPE_BLOB))
return;
/* FIXME: take the tablespace as a parameter */
- if (fil_space_t *space= fil_space_acquire_silent(block.page.id().space()))
+ if (fil_space_t *space= fil_space_t::get(block.page.id().space()))
{
/* Old versions of InnoDB did not initialize FIL_PAGE_TYPE on BLOB
pages. Do not print anything about the type mismatch when reading
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 2046ffd4273..2cdd36a8b60 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -415,7 +415,7 @@ static bool buf_tmp_page_decrypt(byte* tmp_frame, byte* src_frame)
static bool buf_page_decrypt_after_read(buf_page_t *bpage,
const fil_node_t &node)
{
- ut_ad(node.space->pending_io());
+ ut_ad(node.space->referenced());
ut_ad(node.space->id == bpage->id().space());
const auto flags = node.space->flags;
@@ -475,7 +475,7 @@ decompress_with_slot:
slot->release();
ut_ad(!write_size
|| fil_page_type_validate(node.space, dst_frame));
- ut_ad(node.space->pending_io());
+ ut_ad(node.space->referenced());
return write_size != 0;
}
@@ -516,7 +516,7 @@ decrypt_failed:
goto decompress;
}
- ut_ad(node.space->pending_io());
+ ut_ad(node.space->referenced());
return true;
}
#endif /* !UNIV_INNOCHECKSUM */
@@ -2768,7 +2768,7 @@ buf_zip_decompress(
ulint size = page_zip_get_size(&block->page.zip);
/* The tablespace will not be found if this function is called
during IMPORT. */
- fil_space_t* space= fil_space_t::get_for_io(block->page.id().space());
+ fil_space_t* space= fil_space_t::get(block->page.id().space());
const unsigned key_version = mach_read_from_4(
frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL;
@@ -2805,7 +2805,7 @@ buf_zip_decompress(
if (page_zip_decompress(&block->page.zip,
block->frame, TRUE)) {
if (space) {
- space->release_for_io();
+ space->release();
}
return(TRUE);
}
@@ -2824,7 +2824,7 @@ buf_zip_decompress(
/* Copy to uncompressed storage. */
memcpy(block->frame, frame, block->zip_size());
if (space) {
- space->release_for_io();
+ space->release();
}
return(TRUE);
@@ -2848,7 +2848,7 @@ err_exit:
dict_set_corrupted_by_space(space);
}
- space->release_for_io();
+ space->release();
}
return(FALSE);
@@ -3160,10 +3160,10 @@ lookup:
asserting. */
if (page_id.space() == TRX_SYS_SPACE) {
} else if (page_id.space() == SRV_TMP_SPACE_ID) {
- } else if (fil_space_t* space= fil_space_t::get_for_io(
+ } else if (fil_space_t* space= fil_space_t::get(
page_id.space())) {
bool set = dict_set_corrupted_by_space(space);
- space->release_for_io();
+ space->release();
if (set) {
return NULL;
}
@@ -3374,8 +3374,7 @@ re_evict:
if (mode != BUF_GET_IF_IN_POOL
&& mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
} else if (!ibuf_debug) {
- } else if (fil_space_t* space
- = fil_space_t::get_for_io(page_id.space())) {
+ } else if (fil_space_t* space = fil_space_t::get(page_id.space())) {
/* Try to evict the block from the buffer pool, to use the
insert buffer (change buffer) as much as possible. */
@@ -3386,7 +3385,7 @@ re_evict:
/* Blocks cannot be relocated or enter or exit the
buf_pool while we are holding the buf_pool.mutex. */
const bool evicted = buf_LRU_free_page(&fix_block->page, true);
- space->release_for_io();
+ space->release();
if (evicted) {
hash_lock = buf_pool.page_hash.lock_get(fold);
@@ -4108,7 +4107,7 @@ after decryption normal page checksum does not match.
static dberr_t buf_page_check_corrupt(buf_page_t *bpage,
const fil_node_t &node)
{
- ut_ad(node.space->pending_io());
+ ut_ad(node.space->referenced());
byte* dst_frame = (bpage->zip.data) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc
index 6b1a32d8930..eb460af2de2 100644
--- a/storage/innobase/buf/buf0dblwr.cc
+++ b/storage/innobase/buf/buf0dblwr.cc
@@ -363,7 +363,7 @@ void buf_dblwr_t::recover()
continue;
}
- fil_space_t *space= fil_space_t::get_for_io(space_id);
+ fil_space_t *space= fil_space_t::get(space_id);
if (!space)
/* The tablespace that this page once belonged to does not exist */
@@ -379,7 +379,7 @@ void buf_dblwr_t::recover()
<< " is beyond the end of tablespace " << space->name
<< " (" << space->size << " pages)";
next_page:
- space->release_for_io();
+ space->release();
continue;
}
@@ -420,7 +420,7 @@ next_page:
/* Write the good page from the doublewrite buffer to the intended
position. */
- space->reacquire_for_io();
+ space->reacquire();
fio= space->io(IORequestWrite,
os_offset_t{page_id.page_no()} * physical_size,
physical_size, page);
@@ -506,10 +506,10 @@ static void buf_dblwr_check_page_lsn(const page_t* page, const fil_space_t& s)
static void buf_dblwr_check_page_lsn(const buf_page_t &b, const byte *page)
{
- if (fil_space_t *space= fil_space_t::get_for_io(b.id().space()))
+ if (fil_space_t *space= fil_space_t::get(b.id().space()))
{
buf_dblwr_check_page_lsn(page, *space);
- space->release_for_io();
+ space->release();
}
}
@@ -583,7 +583,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size)
}
#endif /* UNIV_DEBUG */
/* Write out the first block of the doublewrite buffer */
- ut_a(fil_system.sys_space->acquire_for_io());
+ ut_a(fil_system.sys_space->acquire());
fil_system.sys_space->io(IORequestWrite,
os_offset_t{block1.page_no()} <<
srv_page_size_shift,
@@ -593,7 +593,7 @@ bool buf_dblwr_t::flush_buffered_writes(const ulint size)
if (old_first_free > size)
{
/* Write out the second block of the doublewrite buffer. */
- ut_a(fil_system.sys_space->acquire_for_io());
+ ut_a(fil_system.sys_space->acquire());
fil_system.sys_space->io(IORequestWrite,
os_offset_t{block2.page_no()} <<
srv_page_size_shift,
@@ -687,7 +687,7 @@ void buf_dblwr_t::add_to_batch(fil_space_t *space, const IORequest &request,
ut_ad(request.bpage);
ut_ad(request.bpage->in_file());
ut_ad(space->id == request.bpage->id().space());
- ut_ad(space->pending_io());
+ ut_ad(space->referenced());
ut_ad(!srv_read_only_mode);
const ulint buf_size= 2 * block_size();
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 19a9e09e4a1..c62c0112e92 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -621,19 +621,11 @@ buf_load()
ulint last_check_time = 0;
ulint last_activity_cnt = 0;
- /* Avoid calling the expensive fil_space_acquire_silent() for each
+ /* Avoid calling the expensive fil_space_t::get() for each
page within the same tablespace. dump[] is sorted by (space, page),
so all pages from a given tablespace are consecutive. */
ulint cur_space_id = dump[0].space();
- fil_space_t* space = fil_space_acquire_silent(cur_space_id);
- if (space) {
- bool ok = space->acquire_for_io();
- space->release();
- if (!ok) {
- space = nullptr;
- }
- }
-
+ fil_space_t* space = fil_space_t::get(cur_space_id);
ulint zip_size = space ? space->zip_size() : 0;
PSI_stage_progress* pfs_stage_progress __attribute__((unused))
@@ -653,24 +645,16 @@ buf_load()
if (this_space_id != cur_space_id) {
if (space) {
- space->release_for_io();
+ space->release();
}
cur_space_id = this_space_id;
- space = fil_space_acquire_silent(cur_space_id);
+ space = fil_space_t::get(cur_space_id);
if (!space) {
continue;
}
- bool ok = space->acquire_for_io();
- space->release();
-
- if (!ok) {
- space = nullptr;
- continue;
- }
-
zip_size = space->zip_size();
}
@@ -684,17 +668,17 @@ buf_load()
}
if (space->is_stopping()) {
- space->release_for_io();
+ space->release();
space = nullptr;
continue;
}
- space->reacquire_for_io();
+ space->reacquire();
buf_read_page_background(space, dump[i], zip_size, true);
if (buf_load_abort_flag) {
if (space) {
- space->release_for_io();
+ space->release();
}
buf_load_abort_flag = false;
ut_free(dump);
@@ -722,7 +706,7 @@ buf_load()
}
if (space) {
- space->release_for_io();
+ space->release();
}
ut_free(dump);
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 25523ab53f1..f671aadeb4e 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -786,7 +786,7 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space)
(space == fil_system.temp_space));
ut_ad(space->purpose == FIL_TYPE_TABLESPACE ||
space->atomic_write_supported);
- ut_ad(space->pending_io());
+ ut_ad(space->referenced());
rw_lock_t *rw_lock;
@@ -854,7 +854,7 @@ static bool buf_flush_page(buf_page_t *bpage, bool lru, fil_space_t *space)
buf_release_freed_page(&block->page);
else
{
- space->reacquire_for_io();
+ space->reacquire();
ut_ad(status == buf_page_t::NORMAL || status == buf_page_t::INIT_ON_FLUSH);
size_t size, orig_size;
IORequest::Type type= lru ? IORequest::WRITE_LRU : IORequest::WRITE_ASYNC;
@@ -1029,7 +1029,7 @@ static void buf_flush_freed_pages(fil_space_t *space)
if (punch_hole)
{
- space->reacquire_for_io();
+ space->reacquire();
space->io(IORequest(IORequest::PUNCH_RANGE),
os_offset_t{range.first} * physical_size,
(range.last - range.first + 1) * physical_size,
@@ -1039,7 +1039,7 @@ static void buf_flush_freed_pages(fil_space_t *space)
{
for (os_offset_t i= range.first; i <= range.last; i++)
{
- space->reacquire_for_io();
+ space->reacquire();
space->io(IORequest(IORequest::WRITE_ASYNC),
i * physical_size, physical_size,
const_cast<byte*>(field_ref_zero));
@@ -1170,7 +1170,7 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max)
@retval nullptr if the pages for this tablespace should be discarded */
static fil_space_t *buf_flush_space(const uint32_t id)
{
- fil_space_t *space= fil_space_t::get_for_io(id);
+ fil_space_t *space= fil_space_t::get(id);
if (space)
buf_flush_freed_pages(space);
return space;
@@ -1261,7 +1261,7 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n)
if (last_space_id != space_id)
{
if (space)
- space->release_for_io();
+ space->release();
space= buf_flush_space(space_id);
last_space_id= space_id;
}
@@ -1270,7 +1270,7 @@ static void buf_flush_LRU_list_batch(ulint max, flush_counters_t *n)
}
else if (space->is_stopping())
{
- space->release_for_io();
+ space->release();
space= nullptr;
}
@@ -1298,7 +1298,7 @@ reacquire_mutex:
buf_pool.lru_hp.set(nullptr);
if (space)
- space->release_for_io();
+ space->release();
/* We keep track of all flushes happening as part of LRU flush. When
estimating the desired rate at which flush_list should be flushed,
@@ -1393,7 +1393,7 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn)
if (last_space_id != space_id)
{
if (space)
- space->release_for_io();
+ space->release();
space= buf_flush_space(space_id);
last_space_id= space_id;
}
@@ -1402,7 +1402,7 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn)
}
else if (space->is_stopping())
{
- space->release_for_io();
+ space->release();
space= nullptr;
}
@@ -1431,7 +1431,7 @@ reacquire_mutex:
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
if (space)
- space->release_for_io();
+ space->release();
if (scanned)
MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_BATCH_SCANNED,
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index daea53ec130..2f59f1ae4d5 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -288,7 +288,7 @@ buf_read_page_low(
<< page_id;
ut_ad(0);
nothing_read:
- space->release_for_io();
+ space->release();
return false;
}
@@ -358,7 +358,7 @@ nothing_read:
/* The i/o was already completed in space->io() */
*err = buf_page_read_complete(bpage, *fio.node);
- space->release_for_io();
+ space->release();
if (*err != DB_SUCCESS) {
return false;
@@ -402,7 +402,7 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf)
if (buf_pool.n_pend_reads > buf_pool.curr_size / BUF_READ_AHEAD_PEND_LIMIT)
return 0;
- fil_space_t* space= fil_space_acquire(page_id.space());
+ fil_space_t* space= fil_space_t::get(page_id.space());
if (!space)
return 0;
@@ -431,7 +431,7 @@ no_read_ahead:
return 0;
read_ahead:
- if (!space->acquire_for_io())
+ if (!space->acquire_if_not_stopped())
goto no_read_ahead;
/* Read all the suitable blocks within the area */
@@ -444,7 +444,7 @@ read_ahead:
if (space->is_stopping())
break;
dberr_t err;
- space->reacquire_for_io();
+ space->reacquire();
if (buf_read_page_low(&err, space, false, ibuf_mode, i, zip_size, false))
count++;
}
@@ -453,7 +453,6 @@ read_ahead:
DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u",
count, space->chain.start->name,
low.page_no()));
- space->release_for_io();
space->release();
/* Read ahead is considered one I/O operation for the purpose of
@@ -478,22 +477,13 @@ after decryption normal page checksum does not match.
@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
dberr_t buf_read_page(const page_id_t page_id, ulint zip_size)
{
- fil_space_t *space= fil_space_acquire(page_id.space());
+ fil_space_t *space= fil_space_t::get(page_id.space());
if (!space)
{
ib::info() << "trying to read page " << page_id
<< " in nonexisting or being-dropped tablespace";
return DB_TABLESPACE_DELETED;
}
- else if (!space->acquire_for_io())
- {
- ib::warn() << "unable to read " << page_id << " from tablespace "
- << space->name;
- space->release();
- return DB_PAGE_CORRUPTED;
- }
-
- space->release();
dberr_t err;
if (buf_read_page_low(&err, space, true, BUF_READ_ANY_PAGE,
@@ -607,22 +597,15 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
read-ahead, as that could break the ibuf page access order */
return 0;
- fil_space_t *space= fil_space_acquire(page_id.space());
+ fil_space_t *space= fil_space_t::get(page_id.space());
if (!space)
return 0;
- else
- {
- bool ok= space->acquire_for_io();
- space->release();
- if (!ok)
- return 0;
- }
if (high_1.page_no() > space->last_page_number())
{
/* The area is not whole. */
fail:
- space->release_for_io();
+ space->release();
return 0;
}
@@ -721,7 +704,7 @@ failed:
if (space->is_stopping())
break;
dberr_t err;
- space->reacquire_for_io();
+ space->reacquire();
count+= buf_read_page_low(&err, space, false, ibuf_mode, new_low, zip_size,
false);
}
@@ -730,7 +713,7 @@ failed:
DBUG_PRINT("ib_buf", ("random read-ahead %zu pages from %s: %u",
count, space->chain.start->name,
new_low.page_no()));
- space->release_for_io();
+ space->release();
/* Read ahead is considered one I/O operation for the purpose of
LRU policy decision. */
@@ -747,7 +730,7 @@ highest page number the last in the array
@param[in] n number of page numbers in the array */
void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n)
{
- fil_space_t* space = fil_space_t::get_for_io(space_id);
+ fil_space_t* space = fil_space_t::get(space_id);
if (!space) {
/* The tablespace is missing or unreadable: do nothing */
@@ -784,7 +767,7 @@ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n)
}
dberr_t err;
- space->reacquire_for_io();
+ space->reacquire();
buf_read_page_low(&err, space, false,
BUF_READ_ANY_PAGE, cur_page_id, zip_size,
true);
@@ -798,5 +781,5 @@ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n)
DBUG_PRINT("ib_buf", ("recovery read (%u pages) for %s", n,
space->chain.start->name));
- space->release_for_io();
+ space->release();
}
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index fb3247ecdcf..55e3191c228 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -948,7 +948,7 @@ void dict_drop_index_tree(btr_pcur_t* pcur, trx_t* trx, mtr_t* mtr)
ut_ad(len == 8);
- if (fil_space_t* s = fil_space_acquire_silent(space_id)) {
+ if (fil_space_t* s = fil_space_t::get(space_id)) {
/* Ensure that the tablespace file exists
in order to avoid a crash in buf_page_get_gen(). */
if (root_page_no < s->get_size()) {
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 52b77fd93a5..a4a660be584 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -884,7 +884,7 @@ is_unaccessible:
return nullptr;
}
- if (!fil_table_accessible(table))
+ if (!table->is_accessible())
goto is_unaccessible;
size_t db1_len, tbl1_len;
diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc
index 0b2e28b6476..bd7ae83b53a 100644
--- a/storage/innobase/dict/dict0stats_bg.cc
+++ b/storage/innobase/dict/dict0stats_bg.cc
@@ -358,7 +358,7 @@ next_table_id:
ut_ad(!table->is_temporary());
- if (!fil_table_accessible(table)) {
+ if (!table->is_accessible()) {
dict_table_close(table, TRUE, FALSE);
mutex_exit(&dict_sys.mutex);
goto next_table_id;
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index e73337a3bdd..73f87173485 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -633,7 +633,7 @@ byte* fil_space_encrypt(
return (src_frame);
}
- ut_ad(space->pending_io());
+ ut_ad(space->referenced());
return fil_encrypt_buf(space->crypt_data, space->id, offset,
src_frame, space->zip_size(),
@@ -846,7 +846,7 @@ fil_space_decrypt(
const ulint physical_size = space->physical_size();
ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted());
- ut_ad(space->pending_io());
+ ut_ad(space->referenced());
bool encrypted = fil_space_decrypt(space->id, space->crypt_data,
tmp_frame, physical_size,
@@ -1008,8 +1008,6 @@ fil_crypt_read_crypt_data(fil_space_t* space)
@return true if a recheck of tablespace is needed by encryption thread. */
static bool fil_crypt_start_encrypting_space(fil_space_t* space)
{
- bool recheck = false;
-
mutex_enter(&fil_crypt_threads_mutex);
fil_space_crypt_t *crypt_data = space->crypt_data;
@@ -1021,12 +1019,9 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space)
return false;
}
- if (crypt_data != NULL || fil_crypt_start_converting) {
- /* someone beat us to it */
- if (fil_crypt_start_converting) {
- recheck = true;
- }
+ const bool recheck = fil_crypt_start_converting;
+ if (recheck || crypt_data || space->is_stopping()) {
mutex_exit(&fil_crypt_threads_mutex);
return recheck;
}
@@ -1045,36 +1040,38 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space)
return false;
}
- crypt_data->type = CRYPT_SCHEME_UNENCRYPTED;
- crypt_data->min_key_version = 0; // all pages are unencrypted
- crypt_data->rotate_state.start_time = time(0);
- crypt_data->rotate_state.starting = true;
- crypt_data->rotate_state.active_threads = 1;
-
- mutex_enter(&fil_system.mutex);
- space->crypt_data = crypt_data;
- mutex_exit(&fil_system.mutex);
-
fil_crypt_start_converting = true;
mutex_exit(&fil_crypt_threads_mutex);
- do
- {
- mtr_t mtr;
- mtr.start();
- mtr.set_named_space(space);
+ mtr_t mtr;
+ mtr.start();
- /* 2 - get page 0 */
- dberr_t err = DB_SUCCESS;
- buf_block_t* block = buf_page_get_gen(
- page_id_t(space->id, 0), space->zip_size(),
- RW_X_LATCH, NULL, BUF_GET,
- __FILE__, __LINE__,
- &mtr, &err);
+ /* 2 - get page 0 */
+ dberr_t err = DB_SUCCESS;
+ if (buf_block_t* block = buf_page_get_gen(
+ page_id_t(space->id, 0), space->zip_size(),
+ RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED,
+ __FILE__, __LINE__, &mtr, &err)) {
+
+ crypt_data->type = CRYPT_SCHEME_1;
+ crypt_data->min_key_version = 0; // all pages are unencrypted
+ crypt_data->rotate_state.start_time = time(0);
+ crypt_data->rotate_state.starting = true;
+ crypt_data->rotate_state.active_threads = 1;
+
+ mutex_enter(&fil_system.mutex);
+ const bool stopping = space->is_stopping();
+ if (!stopping) {
+ space->crypt_data = crypt_data;
+ }
+ mutex_exit(&fil_system.mutex);
+ if (stopping) {
+ goto abort;
+ }
/* 3 - write crypt data to page 0 */
- crypt_data->type = CRYPT_SCHEME_1;
+ mtr.set_named_space(space);
crypt_data->write_page0(block, &mtr);
mtr.commit();
@@ -1094,19 +1091,18 @@ static bool fil_crypt_start_encrypting_space(fil_space_t* space)
mutex_exit(&crypt_data->mutex);
mutex_exit(&fil_crypt_threads_mutex);
- return recheck;
- } while (0);
-
- mutex_enter(&crypt_data->mutex);
- ut_a(crypt_data->rotate_state.active_threads == 1);
- crypt_data->rotate_state.active_threads = 0;
- mutex_exit(&crypt_data->mutex);
+ return false;
+ }
+abort:
+ mtr.commit();
mutex_enter(&fil_crypt_threads_mutex);
fil_crypt_start_converting = false;
mutex_exit(&fil_crypt_threads_mutex);
- return recheck;
+ crypt_data->~fil_space_crypt_t();
+ ut_free(crypt_data);
+ return false;
}
/** State of a rotation thread */
@@ -1479,7 +1475,7 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space,
while (it != end)
{
space= &*it;
- if (space->acquire())
+ if (space->acquire_if_not_stopped(true))
return space;
while (++it != end && (!UT_LIST_GET_LEN(it->chain) || it->is_stopping()));
}
@@ -1487,44 +1483,41 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space,
return NULL;
}
-/** Return the next tablespace.
-@param space previous tablespace (NULL to start from the beginning)
+/** Determine the next tablespace for encryption key rotation.
+@param space current tablespace (nullptr to start from the beginning)
@param recheck whether the removal condition needs to be rechecked after
-the encryption parameters were changed
+encryption parameters were changed
@param encrypt expected state of innodb_encrypt_tables
-@return pointer to the next tablespace (with n_pending_ops incremented)
-@retval NULL if this was the last */
-static fil_space_t *fil_space_next(fil_space_t *space, bool recheck,
- bool encrypt)
+@return the next tablespace
+@retval nullptr upon reaching the end of the iteration */
+inline fil_space_t *fil_space_t::next(fil_space_t *space, bool recheck,
+ bool encrypt)
{
mutex_enter(&fil_system.mutex);
if (!srv_fil_crypt_rotate_key_age)
space= fil_system.keyrotate_next(space, recheck, encrypt);
- else if (!space)
- {
- space= UT_LIST_GET_FIRST(fil_system.space_list);
- /* We can trust that space is not NULL because at least the
- system tablespace is always present and loaded first. */
- if (!space->acquire())
- goto next;
- }
else
{
- /* Move on to the next fil_space_t */
- space->release();
-next:
- space= UT_LIST_GET_NEXT(space_list, space);
-
- /* Skip abnormal tablespaces or those that are being created by
- fil_ibd_create(), or being dropped. */
- while (space &&
- (UT_LIST_GET_LEN(space->chain) == 0 ||
- space->is_stopping() || space->purpose != FIL_TYPE_TABLESPACE))
+ if (!space)
+ space= UT_LIST_GET_FIRST(fil_system.space_list);
+ else
+ {
+ /* Move on to the next fil_space_t */
+ space->release();
space= UT_LIST_GET_NEXT(space_list, space);
+ }
- if (space && !space->acquire())
- goto next;
+ for (; space; space= UT_LIST_GET_NEXT(space_list, space))
+ {
+ if (space->purpose != FIL_TYPE_TABLESPACE)
+ continue;
+ const uint32_t n= space->acquire_low();
+ if (UNIV_LIKELY(!(n & (STOPPING | CLOSING))))
+ break;
+ if (!(n & STOPPING) && space->prepare(true))
+ break;
+ }
}
mutex_exit(&fil_system.mutex);
@@ -1568,8 +1561,8 @@ static bool fil_crypt_find_space_to_rotate(
state->space = NULL;
}
- state->space = fil_space_next(state->space, *recheck,
- key_state->key_version != 0);
+ state->space = fil_space_t::next(state->space, *recheck,
+ key_state->key_version != 0);
while (!state->should_shutdown() && state->space) {
/* If there is no crypt data and we have not yet read
@@ -1587,8 +1580,8 @@ static bool fil_crypt_find_space_to_rotate(
return true;
}
- state->space = fil_space_next(state->space, *recheck,
- key_state->key_version != 0);
+ state->space = fil_space_t::next(state->space, *recheck,
+ key_state->key_version != 0);
}
if (state->space) {
@@ -2000,7 +1993,7 @@ fil_crypt_flush_space(
if (buf_block_t* block = buf_page_get_gen(
page_id_t(space->id, 0), space->zip_size(),
- RW_X_LATCH, NULL, BUF_GET,
+ RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err)) {
mtr.set_named_space(space);
crypt_data->write_page0(block, &mtr);
@@ -2240,15 +2233,12 @@ static void fil_crypt_rotation_list_fill()
if (space->purpose != FIL_TYPE_TABLESPACE
|| space->is_in_rotation_list
|| UT_LIST_GET_LEN(space->chain) == 0
- || !space->acquire()) {
+ || !space->acquire_if_not_stopped(true)) {
continue;
}
/* Ensure that crypt_data has been initialized. */
- if (!space->get_size()) {
- /* Page 0 was not loaded. Skip this tablespace. */
- goto next;
- }
+ ut_ad(space->size);
/* Skip ENCRYPTION!=DEFAULT tablespaces. */
if (space->crypt_data
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index ad9d2828467..1829bec8a73 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -64,10 +64,10 @@ inline bool fil_is_user_tablespace_id(ulint space_id)
!srv_is_undo_tablespace(space_id);
}
-/** Try to close a file.
-@return true if success, false if should retry later
-@param print_info if true, prints information why it cannot close a file */
-static bool fil_try_to_close_file(bool print_info)
+/** Try to close a file to adhere to the innodb_open_files limit.
+@param print_info whether to diagnose why a file cannot be closed
+@return whether a file was closed */
+bool fil_space_t::try_to_close(bool print_info)
{
ut_ad(mutex_own(&fil_system.mutex));
for (fil_space_t *space= UT_LIST_GET_FIRST(fil_system.space_list); space;
@@ -94,27 +94,15 @@ static bool fil_try_to_close_file(bool print_info)
if (!node->is_open())
continue;
- if (auto n= space->set_closing())
+ if (const auto n= space->set_closing())
{
if (print_info)
ib::info() << "Cannot close file " << node->name
- << " because of " << n << " pending operations";
- continue;
- }
-
- if (auto n= node->n_pending_flushes)
- {
- if (print_info)
- ib::info() << "Cannot close file " << node->name
- << ", because n_pending_flushes " << n;
- continue;
- }
-
- if (node->needs_flush)
- {
- if (print_info)
- ib::info() << "Cannot close file " << node->name
- << ", because is should be flushed first";
+ << " because of "
+ << (n & PENDING)
+ << ((n & NEEDS_FSYNC)
+ ? " pending operations and pending fsync"
+ : " pending operations");
continue;
}
@@ -210,7 +198,7 @@ const char* fil_path_to_mysql_datadir;
const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg" };
/** Number of pending tablespace flushes */
-ulint fil_n_pending_tablespace_flushes = 0;
+Atomic_counter<ulint> fil_n_pending_tablespace_flushes;
/** The tablespace memory cache. This variable is NULL before the module is
initialized. */
@@ -267,8 +255,7 @@ The caller should hold an InnoDB table lock or a MDL that prevents
the tablespace from being dropped during the operation,
or the caller should be in single-threaded crash recovery mode
(no user connections that could drop tablespaces).
-If this is not the case, fil_space_acquire() and fil_space_t::release()
-should be used instead.
+Normally, fil_space_t::get() should be used instead.
@param[in] id tablespace ID
@return tablespace, or NULL if not found */
fil_space_t*
@@ -281,30 +268,6 @@ fil_space_get(
return(space);
}
-/**********************************************************************//**
-Checks if all the file nodes in a space are flushed.
-@return true if all are flushed */
-static
-bool
-fil_space_is_flushed(
-/*=================*/
- fil_space_t* space) /*!< in: space */
-{
- ut_ad(mutex_own(&fil_system.mutex));
-
- for (const fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
- node != NULL;
- node = UT_LIST_GET_NEXT(chain, node)) {
-
- if (node->needs_flush) {
- ut_ad(srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC);
- return(false);
- }
- }
-
- return(true);
-}
-
/** Validate the compression algorithm for full crc32 format.
@param[in] space tablespace object
@return whether the compression algorithm support */
@@ -385,7 +348,12 @@ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle,
this->size += size;
UT_LIST_ADD_LAST(chain, node);
if (node->is_open()) {
- ++fil_system.n_open;
+ n_pending.fetch_and(~CLOSING, std::memory_order_relaxed);
+ if (++fil_system.n_open >= srv_max_n_open_files) {
+ reacquire();
+ try_to_close(true);
+ release();
+ }
}
mutex_exit(&fil_system.mutex);
@@ -422,7 +390,7 @@ static bool fil_node_open_file_low(fil_node_t *node)
/* The following call prints an error message */
if (os_file_get_last_error(true) == EMFILE + 100 &&
- fil_try_to_close_file(true))
+ fil_space_t::try_to_close(true))
continue;
ib::warn() << "Cannot open '" << node->name << "'.";
@@ -442,7 +410,7 @@ static bool fil_node_open_file_low(fil_node_t *node)
if (UNIV_LIKELY(!fil_system.freeze_space_list))
{
/* Move the file last in fil_system.space_list, so that
- fil_try_to_close_file() should close it as a last resort. */
+ fil_space_t::try_to_close() should close it as a last resort. */
UT_LIST_REMOVE(fil_system.space_list, node->space);
UT_LIST_ADD_LAST(fil_system.space_list, node->space);
}
@@ -463,11 +431,11 @@ static bool fil_node_open_file(fil_node_t *node)
srv_operation == SRV_OPERATION_RESTORE ||
srv_operation == SRV_OPERATION_RESTORE_DELTA);
ut_ad(node->space->purpose != FIL_TYPE_TEMPORARY);
- ut_ad(node->space->pending_io());
+ ut_ad(node->space->referenced());
for (ulint count= 0; fil_system.n_open >= srv_max_n_open_files; count++)
{
- if (fil_try_to_close_file(count > 1))
+ if (fil_space_t::try_to_close(count > 1))
count= 0;
else if (count >= 2)
{
@@ -512,98 +480,59 @@ pfs_os_file_t fil_node_t::detach()
void fil_node_t::prepare_to_close_or_detach()
{
ut_ad(mutex_own(&fil_system.mutex));
- ut_ad(space->is_closing());
- ut_ad(!space->pending_io());
+ ut_ad(space->is_ready_to_close() || srv_operation == SRV_OPERATION_BACKUP ||
+ srv_operation == SRV_OPERATION_RESTORE_DELTA);
ut_a(is_open());
- ut_a(n_pending_flushes == 0);
ut_a(!being_extended);
- ut_a(!needs_flush || space->purpose == FIL_TYPE_TEMPORARY ||
+ ut_a(space->is_ready_to_close() || space->purpose == FIL_TYPE_TEMPORARY ||
srv_fast_shutdown == 2 || !srv_was_started);
ut_a(fil_system.n_open > 0);
fil_system.n_open--;
}
-/** Flush any writes cached by the file system.
-@param[in,out] space tablespace
-@param[in] metadata whether to update file system metadata
-@return whether fil_system.mutex was released and reacquired */
-static bool fil_flush_low(fil_space_t* space, bool metadata = false)
+/** Flush any writes cached by the file system. */
+inline void fil_space_t::flush_low()
{
- ut_ad(mutex_own(&fil_system.mutex));
- ut_ad(!space->is_stopping());
-
- if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) {
- /* No need to flush. User has explicitly disabled
- buffering. */
- ut_ad(!space->is_in_unflushed_spaces);
- ut_ad(fil_space_is_flushed(space));
- ut_ad(space->n_pending_flushes == 0);
-
-#ifdef UNIV_DEBUG
- for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
- node != NULL;
- node = UT_LIST_GET_NEXT(chain, node)) {
- ut_ad(!node->needs_flush);
- ut_ad(node->n_pending_flushes == 0);
- }
-#endif /* UNIV_DEBUG */
-
- if (!metadata) return false;
- }
-
- bool reacquired = false;
- /* Prevent dropping of the space while we are flushing */
- space->n_pending_flushes++;
-
- for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
- node != NULL;
- node = UT_LIST_GET_NEXT(chain, node)) {
-
- if (!node->needs_flush) {
- continue;
- }
-
- ut_a(node->is_open());
-
- fil_n_pending_tablespace_flushes++;
-
-#ifdef _WIN32
- if (node->is_raw_disk) {
-
- goto skip_flush;
- }
-#endif /* _WIN32 */
-
- ut_a(node->is_open());
- node->n_pending_flushes++;
- node->needs_flush = false;
-
- mutex_exit(&fil_system.mutex);
-
- os_file_flush(node->handle);
- reacquired = true;
+ ut_ad(!mutex_own(&fil_system.mutex));
- mutex_enter(&fil_system.mutex);
+ uint32_t n= 0;
+ while (!n_pending.compare_exchange_strong(n, (n + 1) | NEEDS_FSYNC,
+ std::memory_order_acquire,
+ std::memory_order_relaxed))
+ {
+ if (n & STOPPING)
+ return;
+ if (!(n & NEEDS_FSYNC))
+ continue;
+ if (acquire_low() & STOPPING)
+ return;
+ break;
+ }
- node->n_pending_flushes--;
-#ifdef _WIN32
-skip_flush:
-#endif /* _WIN32 */
- if (!node->needs_flush) {
- if (space->is_in_unflushed_spaces
- && fil_space_is_flushed(space)) {
-
- fil_system.unflushed_spaces.remove(*space);
- space->is_in_unflushed_spaces = false;
- }
- }
+ fil_n_pending_tablespace_flushes++;
+ for (fil_node_t *node= UT_LIST_GET_FIRST(chain); node;
+ node= UT_LIST_GET_NEXT(chain, node))
+ {
+ ut_a(node->is_open());
+ IF_WIN(if (node->is_raw_disk) continue,);
+ os_file_flush(node->handle);
+ }
- fil_n_pending_tablespace_flushes--;
- }
+ if (is_in_unflushed_spaces)
+ {
+ mutex_enter(&fil_system.mutex);
+ if (is_in_unflushed_spaces)
+ {
+ is_in_unflushed_spaces= false;
+ fil_system.unflushed_spaces.remove(*this);
+ }
+ mutex_exit(&fil_system.mutex);
+ }
- space->n_pending_flushes--;
- return reacquired;
+ clear_flush();
+ release();
+ fil_n_pending_tablespace_flushes--;
}
/** Try to extend a tablespace.
@@ -624,7 +553,7 @@ fil_space_extend_must_retry(
ut_ad(UT_LIST_GET_LAST(space->chain) == node);
ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE);
ut_ad(node->space == space);
- ut_ad(space->pending_io());
+ ut_ad(space->referenced() || space->is_being_truncated);
*success = space->size >= size;
@@ -698,28 +627,35 @@ fil_space_extend_must_retry(
switch (space->id) {
case TRX_SYS_SPACE:
srv_sys_space.set_last_file_size(pages_in_MiB);
- fil_flush_low(space, true);
- return(false);
+ do_flush:
+ mutex_exit(&fil_system.mutex);
+ space->flush_low();
+ mutex_enter(&fil_system.mutex);
+ break;
default:
ut_ad(space->purpose == FIL_TYPE_TABLESPACE
|| space->purpose == FIL_TYPE_IMPORT);
if (space->purpose == FIL_TYPE_TABLESPACE
&& !space->is_being_truncated) {
- fil_flush_low(space, true);
+ goto do_flush;
}
- return(false);
+ break;
case SRV_TMP_SPACE_ID:
ut_ad(space->purpose == FIL_TYPE_TEMPORARY);
srv_tmp_space.set_last_file_size(pages_in_MiB);
- return(false);
+ break;
}
+
+ return false;
}
/** @return whether the file is usable for io() */
-ATTRIBUTE_COLD bool fil_space_t::prepare_for_io()
+ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex)
{
- ut_ad(pending_io());
- mutex_enter(&fil_system.mutex);
+ ut_ad(referenced());
+ if (!have_mutex)
+ mutex_enter(&fil_system.mutex);
+ ut_ad(mutex_own(&fil_system.mutex));
fil_node_t *node= UT_LIST_GET_LAST(chain);
ut_ad(!id || purpose == FIL_TYPE_TEMPORARY ||
node == UT_LIST_GET_FIRST(chain));
@@ -727,7 +663,7 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_for_io()
const bool is_open= node && (node->is_open() || fil_node_open_file(node));
if (!is_open)
- release_for_io();
+ release();
else if (auto desired_size= recv_size)
{
bool success;
@@ -761,9 +697,10 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_for_io()
}
else
clear:
- n_pending_ios.fetch_and(NOT_CLOSING);
+ n_pending.fetch_and(~CLOSING, std::memory_order_relaxed);
- mutex_exit(&fil_system.mutex);
+ if (!have_mutex)
+ mutex_exit(&fil_system.mutex);
return is_open;
}
@@ -774,28 +711,39 @@ clear:
bool fil_space_extend(fil_space_t *space, uint32_t size)
{
ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY);
- if (!space->acquire_for_io())
- return false;
-
- bool success;
-
- do
- mutex_enter(&fil_system.mutex);
- while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain),
- size, &success));
-
+ bool success= false;
+ const bool acquired= space->acquire();
+ mutex_enter(&fil_system.mutex);
+ if (acquired || space->is_being_truncated)
+ {
+ while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain),
+ size, &success))
+ mutex_enter(&fil_system.mutex);
+ }
mutex_exit(&fil_system.mutex);
- space->release_for_io();
+ if (acquired)
+ space->release();
return success;
}
/** Prepare to free a file from fil_system. */
-pfs_os_file_t fil_node_t::close_to_free(bool detach_handle)
+inline pfs_os_file_t fil_node_t::close_to_free(bool detach_handle)
{
ut_ad(mutex_own(&fil_system.mutex));
ut_a(magic_n == FIL_NODE_MAGIC_N);
ut_a(!being_extended);
+ if (is_open() &&
+ (space->n_pending.fetch_or(fil_space_t::CLOSING,
+ std::memory_order_acquire) &
+ fil_space_t::PENDING))
+ {
+ mutex_exit(&fil_system.mutex);
+ while (space->referenced())
+ os_thread_sleep(100);
+ mutex_enter(&fil_system.mutex);
+ }
+
while (is_open())
{
if (space->is_in_unflushed_spaces)
@@ -805,14 +753,6 @@ pfs_os_file_t fil_node_t::close_to_free(bool detach_handle)
fil_system.unflushed_spaces.remove(*space);
}
- if (n_pending_flushes || space->set_closing())
- {
- mutex_exit(&fil_system.mutex);
- os_thread_sleep(100);
- mutex_enter(&fil_system.mutex);
- continue;
- }
-
ut_a(!being_extended);
if (detach_handle)
{
@@ -875,7 +815,7 @@ std::vector<pfs_os_file_t> fil_system_t::detach(fil_space_t *space,
handles.push_back(handle);
}
- ut_ad(space->n_pending_flushes == 0);
+ ut_ad(!space->referenced());
return handles;
}
@@ -891,10 +831,10 @@ fil_space_free_low(
ut_ad(srv_fast_shutdown == 2 || !srv_was_started
|| space->max_lsn == 0);
- /* Wait for fil_space_t::release_for_io(); after
+ /* Wait for fil_space_t::release() after
fil_system_t::detach(), the tablespace cannot be found, so
- fil_space_t::get_for_io() would return NULL */
- while (space->pending_io()) {
+ fil_space_t::get() would return NULL */
+ while (space->referenced()) {
os_thread_sleep(100);
}
@@ -1001,7 +941,7 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
space->magic_n = FIL_SPACE_MAGIC_N;
space->crypt_data = crypt_data;
- space->n_pending_ios.store(CLOSING, std::memory_order_relaxed);
+ space->n_pending.store(CLOSING, std::memory_order_relaxed);
DBUG_LOG("tablespace",
"Created metadata for " << id << " name " << name);
@@ -1041,28 +981,10 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
return(NULL);
}
- if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT)
- && id > fil_system.max_assigned_id) {
- if (!fil_system.space_id_reuse_warned) {
- fil_system.space_id_reuse_warned = true;
-
- ib::warn() << "Allocated tablespace ID " << id
- << " for " << name << ", old maximum was "
- << fil_system.max_assigned_id;
- }
-
- fil_system.max_assigned_id = id;
- }
-
HASH_INSERT(fil_space_t, hash, &fil_system.spaces, id, space);
UT_LIST_ADD_LAST(fil_system.space_list, space);
- if (id < SRV_SPACE_ID_UPPER_BOUND && id > fil_system.max_assigned_id) {
-
- fil_system.max_assigned_id = id;
- }
-
switch (id) {
case 0:
ut_ad(!fil_system.sys_space);
@@ -1072,6 +994,18 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
ut_ad(!fil_system.temp_space);
fil_system.temp_space = space;
break;
+ default:
+ ut_ad(purpose != FIL_TYPE_TEMPORARY);
+ if (UNIV_LIKELY(id <= fil_system.max_assigned_id)) {
+ break;
+ }
+ if (!fil_system.space_id_reuse_warned) {
+ ib::warn() << "Allocated tablespace ID " << id
+ << " for " << name << ", old maximum was "
+ << fil_system.max_assigned_id;
+ }
+
+ fil_system.max_assigned_id = id;
}
/* Inform key rotation that there could be something
@@ -1157,9 +1091,13 @@ bool fil_space_t::read_page0()
return false;
ut_ad(!UT_LIST_GET_NEXT(chain, node));
- n_pending_ios.fetch_add(1, std::memory_order_acquire);
+ if (UNIV_UNLIKELY(acquire_low() & STOPPING))
+ {
+ ut_ad("this should not happen" == 0);
+ return false;
+ }
const bool ok= node->is_open() || fil_node_open_file(node);
- release_for_io();
+ release();
return ok;
}
@@ -1365,7 +1303,7 @@ void fil_system_t::close()
}
/** Close all tablespace files at shutdown */
-void fil_close_all_files()
+void fil_space_t::close_all()
{
if (!fil_system.is_initialised()) {
return;
@@ -1395,8 +1333,7 @@ next:
}
for (ulint count = 10000; count--; ) {
- if (!space->set_closing()
- && !node->n_pending_flushes) {
+ if (!space->set_closing()) {
node->close();
goto next;
}
@@ -1409,10 +1346,8 @@ next:
}
ib::error() << "File '" << node->name
- << "' has " << space->pending_io()
- << " operations and "
- << node->n_pending_flushes
- << " flushes";
+ << "' has " << space->referenced()
+ << " operations";
}
space = UT_LIST_GET_NEXT(space_list, space);
@@ -1460,7 +1395,7 @@ fil_write_flushed_lsn(
byte* buf;
ut_ad(!srv_read_only_mode);
- if (!fil_system.sys_space->acquire_for_io()) {
+ if (!fil_system.sys_space->acquire()) {
return DB_ERROR;
}
@@ -1484,64 +1419,29 @@ fil_write_flushed_lsn(
0, srv_page_size, buf);
fil_flush_file_spaces();
} else {
- fil_system.sys_space->release_for_io();
+ fil_system.sys_space->release();
}
aligned_free(buf);
return fio.err;
}
-/** Acquire a tablespace when it could be dropped concurrently.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@param[in] silent whether to silently ignore missing tablespaces
-@return the tablespace
-@retval NULL if missing or being deleted */
-fil_space_t* fil_space_acquire_low(ulint id, bool silent)
-{
- fil_space_t* space;
-
- mutex_enter(&fil_system.mutex);
-
- space = fil_space_get_by_id(id);
-
- if (space == NULL) {
- if (!silent) {
- ib::warn() << "Trying to access missing"
- " tablespace " << id;
- }
- } else if (!space->acquire()) {
- space = NULL;
- }
-
- mutex_exit(&fil_system.mutex);
-
- return(space);
-}
-
-/** Acquire a tablespace for reading or writing a block,
-when it could be dropped concurrently.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing */
-fil_space_t *fil_space_t::get_for_io(ulint id)
+/** Acquire a tablespace reference.
+@param id tablespace identifier
+@return tablespace
+@retval nullptr if the tablespace is missing or inaccessible */
+fil_space_t *fil_space_t::get(ulint id)
{
mutex_enter(&fil_system.mutex);
-
fil_space_t *space= fil_space_get_by_id(id);
-
- uint32_t f= space
- ? space->n_pending_ios.fetch_add(1, std::memory_order_relaxed)
- : 0;
-
+ const uint32_t n= space ? space->acquire_low() : 0;
mutex_exit(&fil_system.mutex);
- if ((f & CLOSING) && !space->prepare_for_io())
- {
- // FIXME: issue an error message!
+ if (n & STOPPING)
+ space= nullptr;
+
+ if ((n & CLOSING) && !space->prepare())
space= nullptr;
- }
return space;
}
@@ -1777,7 +1677,6 @@ fil_check_pending_io(
ulint count) /*!< in: number of attempts so far */
{
ut_ad(mutex_own(&fil_system.mutex));
- ut_ad(!space->referenced());
/* The following code must change when InnoDB supports
multiple datafiles per tablespace. */
@@ -1785,18 +1684,14 @@ fil_check_pending_io(
*node = UT_LIST_GET_FIRST(space->chain);
- const auto f = space->n_pending_flushes;
- const auto p = space->pending_io();
-
- if (f || p) {
+ if (const uint32_t p = space->referenced()) {
ut_a(!(*node)->being_extended);
/* Give a warning every 10 second, starting after 1 second */
if ((count % 500) == 50) {
ib::info() << "Trying to delete"
" tablespace '" << space->name
- << "' but there are " << f
- << " flushes and " << p
+ << "' but there are " << p
<< " pending i/o's on it.";
}
@@ -1824,13 +1719,14 @@ fil_check_pending_operations(
fil_space_t* sp = fil_space_get_by_id(id);
if (sp) {
- if (sp->crypt_data && sp->acquire()) {
+ sp->set_stopping(true);
+ if (sp->crypt_data) {
+ sp->reacquire();
mutex_exit(&fil_system.mutex);
fil_space_crypt_close_tablespace(sp);
mutex_enter(&fil_system.mutex);
sp->release();
}
- sp->set_stopping(true);
}
/* Check for pending operations. */
@@ -1927,27 +1823,6 @@ void fil_close_tablespace(ulint id)
ut_free(path);
}
-/** Determine whether a table can be accessed in operations that are
-not (necessarily) protected by meta-data locks.
-(Rollback would generally be protected, but rollback of
-FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
-but only by InnoDB table locks, which may be broken by
-lock_remove_all_on_table().)
-@param[in] table persistent table
-checked @return whether the table is accessible */
-bool fil_table_accessible(const dict_table_t* table)
-{
- if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) {
- return(false);
- }
-
- mutex_enter(&fil_system.mutex);
- bool accessible = table->space && !table->space->is_stopping();
- mutex_exit(&fil_system.mutex);
- ut_ad(accessible || dict_table_is_file_per_table(table));
- return accessible;
-}
-
/** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier
@param[in] if_exists whether to ignore missing tablespace
@@ -2313,7 +2188,7 @@ fil_rename_tablespace(
multiple datafiles per tablespace. */
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
node = UT_LIST_GET_FIRST(space->chain);
- ut_a(space->acquire());
+ space->reacquire();
mutex_exit(&fil_system.mutex);
@@ -2423,10 +2298,7 @@ fil_ibd_create(
file = os_file_create(
innodb_data_file_key, path,
OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT,
- OS_FILE_NORMAL,
- OS_DATA_FILE,
- srv_read_only_mode,
- &success);
+ OS_FILE_AIO, OS_DATA_FILE, srv_read_only_mode, &success);
if (!success) {
/* The following call will print an error message */
@@ -2452,7 +2324,7 @@ fil_ibd_create(
const bool is_compressed = fil_space_t::is_compressed(flags);
bool punch_hole = is_compressed;
-
+ fil_space_crypt_t* crypt_data = nullptr;
#ifdef _WIN32
if (is_compressed) {
os_file_set_sparse_win32(file);
@@ -2466,6 +2338,7 @@ fil_ibd_create(
err_exit:
os_file_close(file);
os_file_delete(innodb_data_file_key, path);
+ free(crypt_data);
return NULL;
}
@@ -2498,8 +2371,7 @@ err_exit:
/* Create crypt data if the tablespace is either encrypted or user has
requested it to remain unencrypted. */
- fil_space_crypt_t *crypt_data = (mode != FIL_ENCRYPTION_DEFAULT
- || srv_encrypt_tables)
+ crypt_data = (mode != FIL_ENCRYPTION_DEFAULT || srv_encrypt_tables)
? fil_space_create_crypt_data(mode, key_id)
: NULL;
@@ -2557,17 +2429,11 @@ err_exit:
}
}
- fil_space_t* space = fil_space_t::create(name, space_id, flags,
- FIL_TYPE_TABLESPACE,
- crypt_data, mode);
- if (!space) {
- free(crypt_data);
- *err = DB_ERROR;
- } else {
+ if (fil_space_t* space = fil_space_t::create(name, space_id, flags,
+ FIL_TYPE_TABLESPACE,
+ crypt_data, mode)) {
space->punch_hole = punch_hole;
- /* FIXME: Keep the file open! */
- fil_node_t* node = space->add(path, OS_FILE_CLOSED, size,
- false, true);
+ fil_node_t* node = space->add(path, file, size, false, true);
mtr_t mtr;
mtr.start();
mtr.log_file_op(FILE_CREATE, space_id, node->name);
@@ -2575,19 +2441,15 @@ err_exit:
node->find_metadata(file);
*err = DB_SUCCESS;
+ return space;
}
- os_file_close(file);
-
- if (*err != DB_SUCCESS) {
- if (has_data_dir) {
- RemoteDatafile::delete_link_file(name);
- }
-
- os_file_delete(innodb_data_file_key, path);
+ if (has_data_dir) {
+ RemoteDatafile::delete_link_file(name);
}
- return space;
+ *err = DB_ERROR;
+ goto err_exit;
}
/** Try to open a single-table tablespace and optionally check that the
@@ -2955,12 +2817,12 @@ skip_validate:
df_remote.close();
df_dict.close();
df_default.close();
- if (space->acquire_for_io()) {
+ if (space->acquire()) {
if (purpose != FIL_TYPE_IMPORT) {
fsp_flags_try_adjust(space, flags
& ~FSP_FLAGS_MEM_MASK);
}
- space->release_for_io();
+ space->release();
}
}
@@ -3464,36 +3326,19 @@ fil_report_invalid_page_access(const char *name,
inline void fil_node_t::complete_write()
{
ut_ad(!mutex_own(&fil_system.mutex));
- ut_ad(space->pending_io());
- if (space->purpose != FIL_TYPE_TEMPORARY && !space->is_stopping() &&
- srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC)
+ if (space->purpose != FIL_TYPE_TEMPORARY &&
+ srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC &&
+ space->set_needs_flush())
{
mutex_enter(&fil_system.mutex);
- if (!space->is_stopping())
+ if (!space->is_in_unflushed_spaces)
{
- needs_flush= true;
-
- if (!space->is_in_unflushed_spaces)
- {
- space->is_in_unflushed_spaces= true;
- fil_system.unflushed_spaces.push_front(*space);
- }
+ space->is_in_unflushed_spaces= true;
+ fil_system.unflushed_spaces.push_front(*space);
}
mutex_exit(&fil_system.mutex);
}
-#ifdef UNIV_DEBUG
- else
- {
- mutex_enter(&fil_system.mutex);
- if (!space->is_stopping())
- {
- ut_ad(!space->is_in_unflushed_spaces);
- ut_ad(!needs_flush);
- }
- mutex_exit(&fil_system.mutex);
- }
-#endif /* UNIV_DEBUG */
}
/** Read or write data.
@@ -3506,7 +3351,7 @@ inline void fil_node_t::complete_write()
fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
void *buf, buf_page_t *bpage)
{
- ut_ad(pending_io());
+ ut_ad(referenced());
ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
ut_ad(fil_validate_skip());
@@ -3524,7 +3369,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
if (type.type == IORequest::READ_ASYNC && is_stopping()
&& !is_being_truncated) {
- release_for_io();
+ release();
return {DB_TABLESPACE_DELETED, nullptr};
}
@@ -3540,7 +3385,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
node = UT_LIST_GET_NEXT(chain, node);
if (!node) {
if (type.type == IORequest::READ_ASYNC) {
- release_for_io();
+ release();
return {DB_ERROR, nullptr};
}
fil_report_invalid_page_access(name, offset,
@@ -3554,7 +3399,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
if (UNIV_UNLIKELY(node->size <= p)) {
if (type.type == IORequest::READ_ASYNC) {
- release_for_io();
+ release();
/* If we can tolerate the non-existent pages, we
should return with DB_ERROR and let caller decide
what to do. */
@@ -3594,7 +3439,7 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
release_sync_write:
node->complete_write();
release:
- release_for_io();
+ release();
}
ut_ad(fil_validate_skip());
}
@@ -3662,47 +3507,35 @@ write_completed:
}
}
- node->space->release_for_io();
-}
-
-/** Flush pending writes from the file system cache to the file */
-void fil_space_t::flush()
-{
- ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT);
- if (!is_stopping())
- {
- mutex_enter(&fil_system.mutex);
- if (!is_stopping())
- fil_flush_low(this);
- mutex_exit(&fil_system.mutex);
- }
+ node->space->release();
}
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS. */
void fil_flush_file_spaces()
{
- if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) {
- ut_d(mutex_enter(&fil_system.mutex));
- ut_ad(fil_system.unflushed_spaces.empty());
- ut_d(mutex_exit(&fil_system.mutex));
- return;
- }
+ if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC)
+ {
+ ut_d(mutex_enter(&fil_system.mutex));
+ ut_ad(fil_system.unflushed_spaces.empty());
+ ut_d(mutex_exit(&fil_system.mutex));
+ return;
+ }
rescan:
- mutex_enter(&fil_system.mutex);
+ mutex_enter(&fil_system.mutex);
- for (sized_ilist<fil_space_t, unflushed_spaces_tag_t>::iterator it
- = fil_system.unflushed_spaces.begin(),
- end = fil_system.unflushed_spaces.end();
- it != end; ++it) {
- if (!it->is_stopping() && fil_flush_low(&*it)) {
- mutex_exit(&fil_system.mutex);
- goto rescan;
- }
- }
+ for (fil_space_t &space : fil_system.unflushed_spaces)
+ {
+ if (space.needs_flush_not_stopping())
+ {
+ mutex_exit(&fil_system.mutex);
+ space.flush_low();
+ goto rescan;
+ }
+ }
- mutex_exit(&fil_system.mutex);
+ mutex_exit(&fil_system.mutex);
}
/** Functor to validate the file node list of a tablespace. */
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 7af8ee56893..ae8c557b24c 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -1641,7 +1641,7 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr,
{
fseg_inode_t* inode;
ib_id_t seg_id;
- ulint n_reserved;
+ uint32_t n_reserved;
DBUG_ENTER("fseg_create");
@@ -2196,7 +2196,7 @@ fseg_alloc_free_page_general(
fil_space_t* space;
buf_block_t* iblock;
buf_block_t* block;
- ulint n_reserved;
+ uint32_t n_reserved;
space_id = page_get_space_id(page_align(seg_header));
space = mtr_x_lock_space(space_id, mtr);
@@ -2308,64 +2308,64 @@ free pages available.
@return true if we were able to make the reservation */
bool
fsp_reserve_free_extents(
- ulint* n_reserved,
+ uint32_t* n_reserved,
fil_space_t* space,
- ulint n_ext,
+ uint32_t n_ext,
fsp_reserve_t alloc_type,
mtr_t* mtr,
uint32_t n_pages)
{
- ulint n_free_list_ext;
- ulint free_limit;
- ulint size;
- ulint n_free;
- ulint n_free_up;
ulint reserve;
size_t total_reserved = 0;
ut_ad(mtr);
*n_reserved = n_ext;
+ const uint32_t extent_size = FSP_EXTENT_SIZE;
+
mtr_x_lock_space(space, mtr);
- const ulint physical_size = space->physical_size();
+ const unsigned physical_size = space->physical_size();
buf_block_t* header = fsp_get_header(space, mtr);
try_again:
- size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + header->frame);
+ uint32_t size = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE
+ + header->frame);
ut_ad(size == space->size_in_header);
- if (size < FSP_EXTENT_SIZE && n_pages < FSP_EXTENT_SIZE / 2) {
+ if (size < extent_size && n_pages < extent_size / 2) {
/* Use different rules for small single-table tablespaces */
*n_reserved = 0;
return(fsp_reserve_free_pages(space, header, size,
mtr, n_pages));
}
- n_free_list_ext = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE
- + header->frame);
+ uint32_t n_free_list_ext = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE
+ + header->frame);
ut_ad(space->free_len == n_free_list_ext);
- free_limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT
- + header->frame);
+ uint32_t free_limit = mach_read_from_4(FSP_HEADER_OFFSET
+ + FSP_FREE_LIMIT
+ + header->frame);
ut_ad(space->free_limit == free_limit);
/* Below we play safe when counting free extents above the free limit:
some of them will contain extent descriptor pages, and therefore
will not be free extents */
+ uint32_t n_free_up;
+
if (size >= free_limit) {
- n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
+ n_free_up = (size - free_limit) / extent_size;
+ if (n_free_up) {
+ n_free_up--;
+ n_free_up -= n_free_up / (physical_size / extent_size);
+ }
} else {
ut_ad(alloc_type == FSP_BLOB);
n_free_up = 0;
}
- if (n_free_up > 0) {
- n_free_up--;
- n_free_up -= n_free_up / (physical_size / FSP_EXTENT_SIZE);
- }
-
- n_free = n_free_list_ext + n_free_up;
+ uint32_t n_free = n_free_list_ext + n_free_up;
switch (alloc_type) {
case FSP_NORMAL:
@@ -2373,7 +2373,7 @@ try_again:
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
code is duplicated in the function below! */
- reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
+ reserve = 2 + ((size / extent_size) * 2) / 200;
if (n_free <= reserve + n_ext) {
@@ -2383,7 +2383,7 @@ try_again:
case FSP_UNDO:
/* We reserve 0.5 % of the space size to cleaning operations */
- reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
+ reserve = 1 + ((size / extent_size) * 1) / 200;
if (n_free <= reserve + n_ext) {
@@ -2435,10 +2435,12 @@ fseg_free_page_low(
ut_ad(iblock->frame == page_align(seg_inode));
ut_d(space->modify_check(*mtr));
+ const uint32_t extent_size = FSP_EXTENT_SIZE;
+ ut_ad(ut_is_2pow(extent_size));
buf_block_t* xdes;
xdes_t* descr = xdes_get_descriptor(space, offset, &xdes, mtr);
- if (xdes_is_free(descr, offset % FSP_EXTENT_SIZE)) {
+ if (xdes_is_free(descr, offset & (extent_size - 1))) {
ib::fatal() << "InnoDB is trying to free page "
<< page_id_t(space->id, offset)
<< " though it is already marked as free in the"
@@ -2499,7 +2501,7 @@ fseg_free_page_low(
flst_add_last(iblock, static_cast<uint16_t>(FSEG_NOT_FULL
+ ioffset),
xdes, xoffset, mtr);
- not_full_n_used += FSP_EXTENT_SIZE - 1;
+ not_full_n_used += extent_size - 1;
} else {
ut_a(not_full_n_used > 0);
not_full_n_used--;
@@ -2507,7 +2509,7 @@ fseg_free_page_low(
mtr->write<4>(*iblock, p_not_full, not_full_n_used);
- const ulint bit = offset % FSP_EXTENT_SIZE;
+ const ulint bit = offset & (extent_size - 1);
xdes_set_free<true>(*xdes, descr, bit, mtr);
diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
index 20ba44a8d73..b0324bf7667 100644
--- a/storage/innobase/fts/fts0opt.cc
+++ b/storage/innobase/fts/fts0opt.cc
@@ -2389,7 +2389,7 @@ fts_optimize_table_bk(
dict_table_t* table = slot->table;
dberr_t error;
- if (fil_table_accessible(table)
+ if (table->is_accessible()
&& table->fts && table->fts->cache
&& table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) {
error = fts_optimize_table(table);
@@ -2799,8 +2799,7 @@ static void fts_optimize_sync_table(dict_table_t *table,
if (!sync_table)
return;
- if (sync_table->fts && sync_table->fts->cache &&
- fil_table_accessible(sync_table))
+ if (sync_table->fts && sync_table->fts->cache && sync_table->is_accessible())
{
fts_sync_table(sync_table, false);
if (process_message)
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 97cce77135b..b636592bb87 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -17481,7 +17481,7 @@ innodb_make_page_dirty(THD*, st_mysql_sys_var*, void*, const void* save)
mtr_t mtr;
uint space_id = *static_cast<const uint*>(save);
mysql_mutex_unlock(&LOCK_global_system_variables);
- fil_space_t* space = fil_space_acquire_silent(space_id);
+ fil_space_t* space = fil_space_t::get(space_id);
if (space == NULL) {
func_exit_no_space:
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index e7e66bb0e8d..b0dc115977e 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -6551,7 +6551,7 @@ i_s_dict_fill_sys_tablespaces(
memset(&file, 0xff, sizeof(file));
memset(&stat, 0x0, sizeof(stat));
- if (fil_space_t* s = fil_space_acquire_silent(space)) {
+ if (fil_space_t* s = fil_space_t::get(space)) {
const char *filepath = s->chain.start
? s->chain.start->name : NULL;
if (!filepath) {
@@ -7049,7 +7049,8 @@ i_s_tablespaces_encryption_fill_table(
for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list);
space; space = UT_LIST_GET_NEXT(space_list, space)) {
if (space->purpose == FIL_TYPE_TABLESPACE
- && space->acquire()) {
+ && !space->is_stopping()) {
+ space->reacquire();
mutex_exit(&fil_system.mutex);
if (int err = i_s_dict_fill_tablespaces_encryption(
thd, space, tables->table)) {
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index 9e9bc241828..5c9d7955c90 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -2300,7 +2300,7 @@ static void ibuf_read_merge_pages(const uint32_t* space_ids,
for (ulint i = 0; i < n_stored; i++) {
const ulint space_id = space_ids[i];
- fil_space_t* s = fil_space_t::get_for_io(space_id);
+ fil_space_t* s = fil_space_t::get(space_id);
if (!s) {
tablespace_deleted:
/* The tablespace was not found: remove all
@@ -2314,7 +2314,7 @@ tablespace_deleted:
}
const ulint zip_size = s->zip_size(), size = s->size;
- s->release_for_io();
+ s->release();
mtr_t mtr;
if (UNIV_LIKELY(page_nos[i] < size)) {
@@ -4028,7 +4028,7 @@ ibuf_restore_pos(
return true;
}
- if (fil_space_t* s = fil_space_acquire_silent(page_id.space())) {
+ if (fil_space_t* s = fil_space_t::get(page_id.space())) {
ib::error() << "ibuf cursor restoration fails!"
" ibuf record inserted to page "
<< page_id
@@ -4214,7 +4214,7 @@ ibuf_merge_or_delete_for_page(
fil_space_t* space;
if (update_ibuf_bitmap) {
- space = fil_space_acquire_silent(page_id.space());
+ space = fil_space_t::get(page_id.space());
if (UNIV_UNLIKELY(!space)) {
/* Do not try to read the bitmap page from the
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 1ae52dfbf5d..68eb417e531 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1806,6 +1806,13 @@ struct dict_table_t {
return(UNIV_LIKELY(!file_unreadable));
}
+ /** @return whether the table is accessible */
+ bool is_accessible() const
+ {
+ return UNIV_LIKELY(is_readable() && !corrupted && space)
+ && !space->is_stopping();
+ }
+
/** Check if a table name contains the string "/#sql"
which denotes temporary or intermediate tables in MariaDB. */
static bool is_temporary_name(const char* name)
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index 57e5c43199b..a980c21ead0 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -317,7 +317,7 @@ struct fil_io_t
{
/** error code */
dberr_t err;
- /** file; node->space->release_for_io() must follow IORequestRead call */
+ /** file; node->space->release() must follow IORequestRead call */
fil_node_t *node;
};
@@ -332,13 +332,14 @@ enum fil_encryption_t
FIL_ENCRYPTION_OFF
};
-struct fil_space_t : ilist_node<unflushed_spaces_tag_t>,
- ilist_node<rotation_list_tag_t>
+struct fil_space_t final :
+ ilist_node<unflushed_spaces_tag_t>, ilist_node<rotation_list_tag_t>
#else
-struct fil_space_t
+struct fil_space_t final
#endif
{
#ifndef UNIV_INNOCHECKSUM
+ friend fil_node_t;
ulint id; /*!< space id */
hash_node_t hash; /*!< hash chain node */
char* name; /*!< Tablespace name */
@@ -367,39 +368,27 @@ struct fil_space_t
/*!< recovered tablespace size in pages;
0 if no size change was read from the redo log,
or if the size change was implemented */
- ulint n_reserved_extents;
+ uint32_t n_reserved_extents;
/*!< number of reserved free extents for
ongoing operations like B-tree page split */
- ulint n_pending_flushes; /*!< this is positive when flushing
- the tablespace to disk; dropping of the
- tablespace is forbidden if this is positive */
private:
/** the committed size of the tablespace in pages */
Atomic_relaxed<uint32_t> committed_size;
- /** Number of pending buffer pool operations accessing the
- tablespace without holding a table lock or dict_operation_lock
- S-latch that would prevent the table (and tablespace) from being
- dropped. An example is encryption key rotation.
-
- The tablespace cannot be dropped while this is nonzero.
-
- The most significant bit contains the STOP_NEW_OPS flag. */
- Atomic_relaxed<uint32_t> n_pending_ops;
- /** Number of pending block read or write operations
- The tablespace object cannot be freed while this is nonzero,
- but it can be detached from fil_system.
-
- The most significant bit contains the CLOSING flag. */
- std::atomic<uint32_t> n_pending_ios;
-
- /** Flag in n_pending_ops that indicates that the tablespace is being
+ /** Number of pending operations on the file.
+ The tablespace cannot be freed while (n_pending & PENDING) != 0. */
+ std::atomic<uint32_t> n_pending;
+ /** Flag in n_pending that indicates that the tablespace is being
deleted, and no further operations should be performed */
- static constexpr uint32_t STOP_NEW_OPS= ~(~uint32_t(0) >> 1);
- /** Flag in n_pending_ios that indicates that the tablespace is a candidate
+ static constexpr uint32_t STOPPING= 1U << 31;
+ /** Flag in n_pending that indicates that the tablespace is a candidate
for being closed, and fil_node_t::is_open() can only be trusted after
acquiring fil_system.mutex and resetting the flag */
- static constexpr uint32_t CLOSING= STOP_NEW_OPS;
- static constexpr uint32_t NOT_CLOSING= ~CLOSING;
+ static constexpr uint32_t CLOSING= 1U << 30;
+ /** Flag in n_pending that indicates that the tablespace needs fsync().
+ This must be the least significant flag bit; @see release_flush() */
+ static constexpr uint32_t NEEDS_FSYNC= 1U << 29;
+ /** The reference count */
+ static constexpr uint32_t PENDING= ~(STOPPING | CLOSING | NEEDS_FSYNC);
public:
rw_lock_t latch; /*!< latch protecting the file space storage
allocation */
@@ -467,7 +456,7 @@ public:
@param[in] n_free_now current number of free extents
@param[in] n_to_reserve number of extents to reserve
@return whether the reservation succeeded */
- bool reserve_free_extents(ulint n_free_now, ulint n_to_reserve)
+ bool reserve_free_extents(uint32_t n_free_now, uint32_t n_to_reserve)
{
ut_ad(rw_lock_own(&latch, RW_LOCK_X));
if (n_reserved_extents + n_to_reserve > n_free_now) {
@@ -480,7 +469,7 @@ public:
/** Release the reserved free extents.
@param[in] n_reserved number of reserved extents */
- void release_free_extents(ulint n_reserved)
+ void release_free_extents(uint32_t n_reserved)
{
if (!n_reserved) return;
ut_ad(rw_lock_own(&latch, RW_LOCK_X));
@@ -513,70 +502,91 @@ public:
/** Close each file. Only invoked on fil_system.temp_space. */
void close();
- /** @return whether the tablespace is about to be dropped */
- bool is_stopping() const { return n_pending_ops & STOP_NEW_OPS; }
-
- /** @return number of references being held */
- size_t referenced() const { return n_pending_ops & ~STOP_NEW_OPS; }
-
/** Note that operations on the tablespace must stop or can resume */
inline void set_stopping(bool stopping);
+private:
MY_ATTRIBUTE((warn_unused_result))
- /** @return whether a tablespace reference was successfully acquired */
- bool acquire()
+ /** Try to acquire a tablespace reference.
+ @return the old reference count (if STOPPING is set, it was not acquired) */
+ uint32_t acquire_low()
{
uint32_t n= 0;
- while (!n_pending_ops.compare_exchange_strong(n, n + 1,
- std::memory_order_acquire,
- std::memory_order_relaxed))
- if (UNIV_UNLIKELY(n & STOP_NEW_OPS))
- return false;
- return true;
- }
- /** Release a tablespace reference.
- @return whether this was the last reference */
- bool release()
- {
- auto n= n_pending_ops.fetch_sub(1);
- ut_ad(n & ~STOP_NEW_OPS);
- return (n & ~STOP_NEW_OPS) == 1;
+ while (!n_pending.compare_exchange_strong(n, n + 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed) &&
+ !(n & STOPPING));
+ return n;
}
+public:
+ MY_ATTRIBUTE((warn_unused_result))
+ /** @return whether a tablespace reference was successfully acquired */
+ inline bool acquire_if_not_stopped(bool have_mutex= false);
MY_ATTRIBUTE((warn_unused_result))
/** Acquire a tablespace reference for I/O.
@return whether the file is usable */
- bool acquire_for_io()
+ bool acquire()
{
- return UNIV_LIKELY(!(n_pending_ios.fetch_add(1, std::memory_order_acquire)&
- CLOSING)) ||
- prepare_for_io();
+ uint32_t n= acquire_low();
+ if (UNIV_LIKELY(!(n & (STOPPING | CLOSING))))
+ return true;
+ return UNIV_LIKELY(!(n & STOPPING)) && prepare();
}
/** Acquire another tablespace reference for I/O. */
- inline void reacquire_for_io();
+ inline void reacquire();
- /** Release a tablespace reference for I/O. */
- void release_for_io()
+ /** Release a tablespace reference.
+ @return whether this was the last reference */
+ bool release()
{
- ut_d(uint32_t n=) n_pending_ios.fetch_sub(1, std::memory_order_release);
- ut_ad(n & NOT_CLOSING);
+ uint32_t n= n_pending.fetch_sub(1, std::memory_order_release);
+ ut_ad(n & PENDING);
+ return (n & PENDING) == 1;
}
- /** @return number of pending reads or writes */
- uint32_t pending_io() const
- { return n_pending_ios.load(std::memory_order_acquire) & NOT_CLOSING; }
+ /** Clear the NEEDS_FSYNC flag */
+ void clear_flush()
+ { n_pending.fetch_and(~NEEDS_FSYNC, std::memory_order_release); }
+
+private:
+ /** @return pending operations (and flags) */
+ uint32_t pending()const { return n_pending.load(std::memory_order_acquire); }
+public:
+ /** @return whether close() of the file handle has been requested */
+ bool is_closing() const { return pending() & CLOSING; }
+ /** @return whether the tablespace is going to be dropped */
+ bool is_stopping() const { return pending() & STOPPING; }
+ /** @return number of pending operations */
+ bool is_ready_to_close() const
+ { return (pending() & (PENDING | CLOSING)) == CLOSING; }
+ /** @return whether fsync() or similar is needed */
+ bool needs_flush() const { return pending() & NEEDS_FSYNC; }
+ /** @return whether fsync() or similar is needed, and the tablespace is
+ not being dropped */
+ bool needs_flush_not_stopping() const
+ { return (pending() & (NEEDS_FSYNC | STOPPING)) == NEEDS_FSYNC; }
+
+ uint32_t referenced() const { return pending() & PENDING; }
+private:
MY_ATTRIBUTE((warn_unused_result))
/** Prepare to close the file handle.
- @return number of pending operations */
+ @return number of pending operations, possibly with NEEDS_FSYNC flag */
uint32_t set_closing()
{
- return n_pending_ios.fetch_or(CLOSING, std::memory_order_acquire) &
- NOT_CLOSING;
+ return n_pending.fetch_or(CLOSING, std::memory_order_acquire) &
+ (PENDING | NEEDS_FSYNC);
}
- /** @return whether close() of the file handle has been requested */
- bool is_closing() const
- { return n_pending_ios.load(std::memory_order_acquire) & CLOSING; }
+
+public:
+ /** Try to close a file to adhere to the innodb_open_files limit.
+ @param print_info whether to diagnose why a file cannot be closed
+ @return whether a file was closed */
+ static bool try_to_close(bool print_info);
+
+ /** Close all tablespace files at shutdown */
+ static void close_all();
/** @return last_freed_lsn */
lsn_t get_last_freed_lsn() { return last_freed_lsn; }
@@ -587,6 +597,23 @@ public:
last_freed_lsn= lsn;
}
+ /** Note that the file will need fsync().
+ @return whether this needs to be added to fil_system.unflushed_spaces */
+ bool set_needs_flush()
+ {
+ uint32_t n= 1;
+ while (!n_pending.compare_exchange_strong(n, n | NEEDS_FSYNC,
+ std::memory_order_acquire,
+ std::memory_order_relaxed))
+ {
+ ut_ad(n & PENDING);
+ if (n & (NEEDS_FSYNC | STOPPING))
+ return false;
+ }
+
+ return true;
+ }
+
/** Clear all freed ranges for undo tablespace when InnoDB
encounters TRIM redo log record */
void clear_freed_ranges()
@@ -879,17 +906,19 @@ public:
fil_type_t purpose, fil_space_crypt_t *crypt_data,
fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT);
- /** Acquire a tablespace for reading or writing a block.
- @param id tablespace ID
- @return the tablespace, or nullptr if missing or inaccessible */
- static fil_space_t *get_for_io(ulint id);
+ MY_ATTRIBUTE((warn_unused_result))
+ /** Acquire a tablespace reference.
+ @param id tablespace identifier
+ @return tablespace
+ @retval nullptr if the tablespace is missing or inaccessible */
+ static fil_space_t *get(ulint id);
/** Add/remove the free page in the freed ranges list.
@param[in] offset page number to be added
@param[in] free true if page to be freed */
void free_page(uint32_t offset, bool add=true)
{
- std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
+ std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
if (add)
return freed_ranges.add_value(offset);
@@ -902,7 +931,7 @@ public:
/** Add the range of freed pages */
void add_free_ranges(range_set ranges)
{
- std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
+ std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
freed_ranges= std::move(ranges);
}
@@ -942,16 +971,28 @@ public:
@return status and file descriptor */
fil_io_t io(const IORequest &type, os_offset_t offset, size_t len,
void *buf, buf_page_t *bpage= nullptr);
- /** Flush pending writes from the file system cache to the file */
- void flush();
+ /** Flush pending writes from the file system cache to the file. */
+ inline void flush();
+ /** Flush pending writes from the file system cache to the file. */
+ void flush_low();
/** Read the first page of a data file.
@return whether the page was found valid */
bool read_page0();
+ /** Determine the next tablespace for encryption key rotation.
+ @param space current tablespace (nullptr to start from the beginning)
+ @param recheck whether the removal condition needs to be rechecked after
+ encryption parameters were changed
+ @param encrypt expected state of innodb_encrypt_tables
+ @return the next tablespace
+ @retval nullptr upon reaching the end of the iteration */
+ static inline fil_space_t *next(fil_space_t *space, bool recheck,
+ bool encrypt);
+
private:
/** @return whether the file is usable for io() */
- ATTRIBUTE_COLD bool prepare_for_io();
+ ATTRIBUTE_COLD bool prepare(bool have_mutex= false);
#endif /*!UNIV_INNOCHECKSUM */
};
@@ -960,7 +1001,8 @@ private:
#define FIL_SPACE_MAGIC_N 89472
/** File node of a tablespace or the log data space */
-struct fil_node_t {
+struct fil_node_t final
+{
/** tablespace containing this file */
fil_space_t* space;
/** file name; protected by fil_system.mutex and log_sys.mutex. */
@@ -980,12 +1022,8 @@ struct fil_node_t {
uint32_t init_size;
/** maximum size of the file in database pages (0 if unlimited) */
uint32_t max_size;
- /** count of pending flushes; is_open must be true if nonzero */
- ulint n_pending_flushes;
/** whether the file is currently being extended */
Atomic_relaxed<bool> being_extended;
- /** whether this file had writes after lasy fsync() */
- bool needs_flush;
/** link to other files in this tablespace */
UT_LIST_NODE_T(fil_node_t) chain;
@@ -1023,7 +1061,7 @@ struct fil_node_t {
/** Prepare to free a file from fil_system.
@param detach_handle whether to detach instead of closing a handle
@return detached handle or OS_FILE_CLOSED */
- pfs_os_file_t close_to_free(bool detach_handle= false);
+ inline pfs_os_file_t close_to_free(bool detach_handle= false);
/** Update the data structures on write completion */
inline void complete_write();
@@ -1036,13 +1074,6 @@ private:
/** Value of fil_node_t::magic_n */
#define FIL_NODE_MAGIC_N 89389
-inline void fil_space_t::reacquire_for_io()
-{
- ut_d(uint32_t n=) n_pending_ios.fetch_add(1, std::memory_order_relaxed);
- ut_ad(n & NOT_CLOSING);
- ut_ad(UT_LIST_GET_FIRST(chain)->is_open());
-}
-
inline void fil_space_t::set_imported()
{
ut_ad(purpose == FIL_TYPE_IMPORT);
@@ -1278,15 +1309,14 @@ inline uint16_t fil_page_get_type(const byte *page)
#ifndef UNIV_INNOCHECKSUM
/** Number of pending tablespace flushes */
-extern ulint fil_n_pending_tablespace_flushes;
+extern Atomic_counter<ulint> fil_n_pending_tablespace_flushes;
/** Look up a tablespace.
The caller should hold an InnoDB table lock or a MDL that prevents
the tablespace from being dropped during the operation,
or the caller should be in single-threaded crash recovery mode
(no user connections that could drop tablespaces).
-If this is not the case, fil_space_acquire() and fil_space_t::release()
-should be used instead.
+Normally, fil_space_t::get() should be used instead.
@param[in] id tablespace ID
@return tablespace, or NULL if not found */
fil_space_t*
@@ -1352,12 +1382,8 @@ public:
fil_space_t* temp_space; /*!< The innodb_temporary tablespace */
/** Map of fil_space_t::id to fil_space_t* */
hash_table_t spaces;
- sized_ilist<fil_space_t, unflushed_spaces_tag_t> unflushed_spaces;
- /*!< list of those
- tablespaces whose files contain
- unflushed writes; those spaces have
- at least one file node where
- needs_flush == true */
+ /** tablespaces for which fil_space_t::needs_flush() holds */
+ sized_ilist<fil_space_t, unflushed_spaces_tag_t> unflushed_spaces;
/** number of currently open files; protected by mutex */
ulint n_open;
ulint max_assigned_id;/*!< maximum space id in the existing
@@ -1400,12 +1426,44 @@ public:
/** The tablespace memory cache. */
extern fil_system_t fil_system;
+inline void fil_space_t::reacquire()
+{
+ ut_d(uint32_t n=) n_pending.fetch_add(1, std::memory_order_relaxed);
+ ut_d(if (mutex_own(&fil_system.mutex)) return);
+ ut_ad(n & PENDING);
+ ut_ad(UT_LIST_GET_FIRST(chain)->is_open());
+}
+
+inline bool fil_space_t::acquire_if_not_stopped(bool have_mutex)
+{
+ ut_ad(mutex_own(&fil_system.mutex) == have_mutex);
+ const uint32_t n= acquire_low();
+ if (UNIV_LIKELY(!(n & (STOPPING | CLOSING))))
+ return true;
+ return UNIV_LIKELY(!(n & CLOSING)) || prepare(have_mutex);
+}
+
/** Note that operations on the tablespace must stop or can resume */
inline void fil_space_t::set_stopping(bool stopping)
{
ut_ad(mutex_own(&fil_system.mutex));
- ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS);
- ut_ad(!(n & STOP_NEW_OPS) == stopping);
+ ut_d(auto n=) n_pending.fetch_xor(STOPPING, std::memory_order_relaxed);
+ ut_ad(!(n & STOPPING) == stopping);
+}
+
+/** Flush pending writes from the file system cache to the file. */
+inline void fil_space_t::flush()
+{
+ ut_ad(!mutex_own(&fil_system.mutex));
+
+ ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT);
+ if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC)
+ {
+ ut_ad(!is_in_unflushed_spaces);
+ ut_ad(!needs_flush());
+ }
+ else
+ flush_low();
}
/** @return the size in pages (0 if unreadable) */
@@ -1450,8 +1508,6 @@ fil_space_free(
void fil_space_set_recv_size_and_flags(ulint id, uint32_t size,
uint32_t flags);
-/** Close all tablespace files at shutdown */
-void fil_close_all_files();
/*******************************************************************//**
Sets the max tablespace id counter if the given number is bigger than the
previous value. */
@@ -1469,42 +1525,6 @@ fil_write_flushed_lsn(
lsn_t lsn)
MY_ATTRIBUTE((warn_unused_result));
-/** Acquire a tablespace when it could be dropped concurrently.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@param[in] silent whether to silently ignore missing tablespaces
-@return the tablespace
-@retval NULL if missing or being deleted */
-fil_space_t* fil_space_acquire_low(ulint id, bool silent)
- MY_ATTRIBUTE((warn_unused_result));
-
-/** Acquire a tablespace when it could be dropped concurrently.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing or being deleted or truncated */
-inline
-fil_space_t*
-fil_space_acquire(ulint id)
-{
- return (fil_space_acquire_low(id, false));
-}
-
-/** Acquire a tablespace that may not exist.
-Used by background threads that do not necessarily hold proper locks
-for concurrency control.
-@param[in] id tablespace ID
-@return the tablespace
-@retval NULL if missing or being deleted */
-inline
-fil_space_t*
-fil_space_acquire_silent(ulint id)
-{
- return (fil_space_acquire_low(id, true));
-}
-
/** Replay a file rename operation if possible.
@param[in] space_id tablespace identifier
@param[in] name old file name
@@ -1519,17 +1539,6 @@ fil_op_replay_rename(
const char* new_name)
MY_ATTRIBUTE((warn_unused_result));
-/** Determine whether a table can be accessed in operations that are
-not (necessarily) protected by meta-data locks.
-(Rollback would generally be protected, but rollback of
-FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
-but only by InnoDB table locks, which may be broken by
-lock_remove_all_on_table().)
-@param[in] table persistent table
-checked @return whether the table is accessible */
-bool fil_table_accessible(const dict_table_t* table)
- MY_ATTRIBUTE((warn_unused_result, nonnull));
-
/** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier
@param[in] if_exists whether to ignore missing tablespace
diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h
index 7a0687d4960..7db85e87ed0 100644
--- a/storage/innobase/include/fsp0file.h
+++ b/storage/innobase/include/fsp0file.h
@@ -268,6 +268,14 @@ public:
return(m_handle);
}
+ /** @return detached file handle */
+ pfs_os_file_t detach()
+ {
+ pfs_os_file_t detached = m_handle;
+ m_handle = OS_FILE_CLOSED;
+ return detached;
+ }
+
/** Get Datafile::m_order.
@return m_order */
ulint order() const
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 308b0916284..7245db39273 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -466,9 +466,9 @@ free pages available.
@return true if we were able to make the reservation */
bool
fsp_reserve_free_extents(
- ulint* n_reserved,
+ uint32_t* n_reserved,
fil_space_t* space,
- ulint n_ext,
+ uint32_t n_ext,
fsp_reserve_t alloc_type,
mtr_t* mtr,
uint32_t n_pages = 2);
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 71077e3f9fb..42ab5d061af 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -4949,7 +4949,7 @@ static void lock_rec_block_validate(const page_id_t page_id)
discard or rebuild a tablespace do hold an exclusive table
lock, which would conflict with any locks referring to the
tablespace from other transactions. */
- if (fil_space_t* space = fil_space_acquire(page_id.space())) {
+ if (fil_space_t* space = fil_space_t::get(page_id.space())) {
dberr_t err = DB_SUCCESS;
mtr_start(&mtr);
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 1fe5c70bcf7..8eeadc8e805 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -2060,14 +2060,14 @@ same_page:
const bool is_init= (b & 0x70) <= INIT_PAGE;
switch (*store) {
case STORE_IF_EXISTS:
- if (fil_space_t *space= fil_space_acquire_silent(space_id))
+ if (fil_space_t *space= fil_space_t::get(space_id))
{
const auto size= space->get_size();
- space->release();
- if (!size)
+ space->release();
+ if (!size)
continue;
- }
- else
+ }
+ else
continue;
/* fall through */
case STORE_YES:
@@ -2312,7 +2312,7 @@ static void recv_recover_page(buf_block_t* block, mtr_t& mtr,
if (fil_space_t* s = space
? space
- : fil_space_acquire(block->page.id().space())) {
+ : fil_space_t::get(block->page.id().space())) {
switch (a) {
case log_phys_t::APPLIED_TO_FSP_HEADER:
s->flags = mach_read_from_4(
@@ -2351,7 +2351,7 @@ static void recv_recover_page(buf_block_t* block, mtr_t& mtr,
fil_crypt_parse(s, b);
}
- if (s != space) {
+ if (!space) {
s->release();
}
}
@@ -2520,7 +2520,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id,
if (end_lsn < i.lsn)
DBUG_LOG("ib_log", "skip log for page " << page_id
<< " LSN " << end_lsn << " < " << i.lsn);
- else if (fil_space_t *space= fil_space_t::get_for_io(page_id.space()))
+ else if (fil_space_t *space= fil_space_t::get(page_id.space()))
{
mtr.start();
mtr.set_log_mode(MTR_LOG_NO_REDO);
@@ -2547,7 +2547,7 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id,
map::iterator r= p++;
recv_sys.pages.erase(r);
}
- space->release_for_io();
+ space->release();
}
return block;
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index cdf61f12ce4..0b9438d2a08 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -4170,7 +4170,7 @@ os_aio_print(FILE* file)
ULINTPF " OS file writes, "
ULINTPF " OS fsyncs\n",
log_sys.get_pending_flushes(),
- fil_n_pending_tablespace_flushes,
+ ulint{fil_n_pending_tablespace_flushes},
os_n_file_reads,
os_n_file_writes,
os_n_fsyncs);
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index 987c5b60f21..1529d8050db 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -401,7 +401,7 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked)
goto close_table;
}
- if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) {
+ if (UNIV_UNLIKELY(!node->table->is_accessible())) {
close_table:
/* Normally, tables should not disappear or become
unaccessible during ROLLBACK, because they should be
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index af35dc1af7f..f710f54d0c1 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -1235,7 +1235,7 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked)
ut_ad(!node->table->skip_alter_undo);
- if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) {
+ if (UNIV_UNLIKELY(!node->table->is_accessible())) {
close_table:
/* Normally, tables should not disappear or become
unaccessible during ROLLBACK, because they should be
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 44d33126e48..030acc72e63 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -697,7 +697,6 @@ static bool need_srv_free;
static void srv_init()
{
mutex_create(LATCH_ID_SRV_INNODB_MONITOR, &srv_innodb_monitor_mutex);
- srv_thread_pool_init();
if (!srv_read_only_mode) {
mutex_create(LATCH_ID_SRV_SYS_TASKS, &srv_sys.tasks_mutex);
@@ -761,6 +760,7 @@ void
srv_boot(void)
/*==========*/
{
+ srv_thread_pool_init();
sync_check_init();
trx_pool_init();
row_mysql_init();
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index d4ee4dc3c4b..78b7cbb635b 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2028,7 +2028,7 @@ void innodb_shutdown()
}
os_aio_free();
- fil_close_all_files();
+ fil_space_t::close_all();
/* Exit any remaining threads. */
ut_ad(!buf_page_cleaner_is_active);
srv_shutdown_threads();
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index e6ec441bdeb..1f3ce121c28 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -359,7 +359,7 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id,
dberr_t *err, mtr_t *mtr)
{
buf_block_t* block;
- ulint n_reserved;
+ uint32_t n_reserved;
bool success;
const ulint slot_no = trx_rsegf_undo_find_free(rseg_hdr);
@@ -551,7 +551,7 @@ buf_block_t* trx_undo_add_page(trx_undo_t* undo, mtr_t* mtr)
{
trx_rseg_t* rseg = undo->rseg;
buf_block_t* new_block = NULL;
- ulint n_reserved;
+ uint32_t n_reserved;
/* When we add a page to an undo log, this is analogous to
a pessimistic insert in a B-tree, and we must reserve the