Commit 1cda462f authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.3 into 10.4

parents c9cf6b13 a7dd7c89
...@@ -48,6 +48,8 @@ template <typename Type> class Atomic_relaxed ...@@ -48,6 +48,8 @@ template <typename Type> class Atomic_relaxed
{ return m.fetch_add(i, o); } { return m.fetch_add(i, o); }
Type fetch_sub(const Type i, std::memory_order o= std::memory_order_relaxed) Type fetch_sub(const Type i, std::memory_order o= std::memory_order_relaxed)
{ return m.fetch_sub(i, o); } { return m.fetch_sub(i, o); }
Type fetch_xor(const Type i, std::memory_order o= std::memory_order_relaxed)
{ return m.fetch_xor(i, o); }
bool compare_exchange_strong(Type& i1, const Type i2, bool compare_exchange_strong(Type& i1, const Type i2,
std::memory_order o1= std::memory_order_relaxed, std::memory_order o1= std::memory_order_relaxed,
std::memory_order o2= std::memory_order_relaxed) std::memory_order o2= std::memory_order_relaxed)
......
...@@ -1617,12 +1617,15 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space, ...@@ -1617,12 +1617,15 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space,
} }
} }
if (it == end) while (it != end)
return NULL; {
space= &*it; space= &*it;
space->acquire(); if (space->acquire())
return space; return space;
while (++it != end && (!UT_LIST_GET_LEN(it->chain) || it->is_stopping()));
}
return NULL;
} }
/** Return the next tablespace. /** Return the next tablespace.
...@@ -1644,12 +1647,14 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck, ...@@ -1644,12 +1647,14 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck,
space= UT_LIST_GET_FIRST(fil_system.space_list); space= UT_LIST_GET_FIRST(fil_system.space_list);
/* We can trust that space is not NULL because at least the /* We can trust that space is not NULL because at least the
system tablespace is always present and loaded first. */ system tablespace is always present and loaded first. */
space->acquire(); if (!space->acquire())
goto next;
} }
else else
{ {
/* Move on to the next fil_space_t */ /* Move on to the next fil_space_t */
space->release(); space->release();
next:
space= UT_LIST_GET_NEXT(space_list, space); space= UT_LIST_GET_NEXT(space_list, space);
/* Skip abnormal tablespaces or those that are being created by /* Skip abnormal tablespaces or those that are being created by
...@@ -1659,8 +1664,8 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck, ...@@ -1659,8 +1664,8 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck,
space->is_stopping() || space->purpose != FIL_TYPE_TABLESPACE)) space->is_stopping() || space->purpose != FIL_TYPE_TABLESPACE))
space= UT_LIST_GET_NEXT(space_list, space); space= UT_LIST_GET_NEXT(space_list, space);
if (space) if (space && !space->acquire())
space->acquire(); goto next;
} }
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
...@@ -2529,31 +2534,27 @@ static void fil_crypt_rotation_list_fill() ...@@ -2529,31 +2534,27 @@ static void fil_crypt_rotation_list_fill()
space = UT_LIST_GET_NEXT(space_list, space)) { space = UT_LIST_GET_NEXT(space_list, space)) {
if (space->purpose != FIL_TYPE_TABLESPACE if (space->purpose != FIL_TYPE_TABLESPACE
|| space->is_in_rotation_list || space->is_in_rotation_list
|| space->is_stopping() || UT_LIST_GET_LEN(space->chain) == 0
|| UT_LIST_GET_LEN(space->chain) == 0) { || !space->acquire()) {
continue; continue;
} }
/* Ensure that crypt_data has been initialized. */ /* Ensure that crypt_data has been initialized. */
if (!space->size) { if (!space->size) {
/* Protect the tablespace while we may
release fil_system.mutex. */
ut_d(space->acquire());
ut_d(const fil_space_t* s=) ut_d(const fil_space_t* s=)
fil_system.read_page0(space->id); fil_system.read_page0(space->id);
ut_ad(!s || s == space); ut_ad(!s || s == space);
ut_d(space->release());
if (!space->size) { if (!space->size) {
/* Page 0 was not loaded. /* Page 0 was not loaded.
Skip this tablespace. */ Skip this tablespace. */
continue; goto next;
} }
} }
/* Skip ENCRYPTION!=DEFAULT tablespaces. */ /* Skip ENCRYPTION!=DEFAULT tablespaces. */
if (space->crypt_data if (space->crypt_data
&& !space->crypt_data->is_default_encryption()) { && !space->crypt_data->is_default_encryption()) {
continue; goto next;
} }
if (srv_encrypt_tables) { if (srv_encrypt_tables) {
...@@ -2561,19 +2562,21 @@ static void fil_crypt_rotation_list_fill() ...@@ -2561,19 +2562,21 @@ static void fil_crypt_rotation_list_fill()
innodb_encrypt_tables!=OFF */ innodb_encrypt_tables!=OFF */
if (space->crypt_data if (space->crypt_data
&& space->crypt_data->min_key_version) { && space->crypt_data->min_key_version) {
continue; goto next;
} }
} else { } else {
/* Skip unencrypted tablespaces if /* Skip unencrypted tablespaces if
innodb_encrypt_tables=OFF */ innodb_encrypt_tables=OFF */
if (!space->crypt_data if (!space->crypt_data
|| !space->crypt_data->min_key_version) { || !space->crypt_data->min_key_version) {
continue; goto next;
} }
} }
fil_system.rotation_list.push_back(*space); fil_system.rotation_list.push_back(*space);
space->is_in_rotation_list = true; space->is_in_rotation_list = true;
next:
space->release();
} }
} }
......
...@@ -658,8 +658,7 @@ fil_try_to_close_file_in_LRU( ...@@ -658,8 +658,7 @@ fil_try_to_close_file_in_LRU(
static void fil_flush_low(fil_space_t* space, bool metadata = false) static void fil_flush_low(fil_space_t* space, bool metadata = false)
{ {
ut_ad(mutex_own(&fil_system.mutex)); ut_ad(mutex_own(&fil_system.mutex));
ut_ad(space); ut_ad(!space->is_stopping());
ut_ad(!space->stop_new_ops);
if (fil_buffering_disabled(space)) { if (fil_buffering_disabled(space)) {
...@@ -1869,10 +1868,8 @@ fil_space_t* fil_space_acquire_low(ulint id, bool silent) ...@@ -1869,10 +1868,8 @@ fil_space_t* fil_space_acquire_low(ulint id, bool silent)
ib::warn() << "Trying to access missing" ib::warn() << "Trying to access missing"
" tablespace " << id; " tablespace " << id;
} }
} else if (space->is_stopping()) { } else if (!space->acquire()) {
space = NULL; space = NULL;
} else {
space->acquire();
} }
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
...@@ -2156,11 +2153,11 @@ static ulint fil_check_pending_ops(const fil_space_t* space, ulint count) ...@@ -2156,11 +2153,11 @@ static ulint fil_check_pending_ops(const fil_space_t* space, ulint count)
{ {
ut_ad(mutex_own(&fil_system.mutex)); ut_ad(mutex_own(&fil_system.mutex));
if (space == NULL) { if (!space) {
return 0; return 0;
} }
if (ulint n_pending_ops = space->n_pending_ops) { if (auto n_pending_ops = space->referenced()) {
/* Give a warning every 10 second, starting after 1 second */ /* Give a warning every 10 second, starting after 1 second */
if ((count % 500) == 50) { if ((count % 500) == 50) {
...@@ -2249,14 +2246,13 @@ fil_check_pending_operations( ...@@ -2249,14 +2246,13 @@ fil_check_pending_operations(
fil_space_t* sp = fil_space_get_by_id(id); fil_space_t* sp = fil_space_get_by_id(id);
if (sp) { if (sp) {
sp->stop_new_ops = true; if (sp->crypt_data && sp->acquire()) {
if (sp->crypt_data) {
sp->acquire();
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
fil_space_crypt_close_tablespace(sp); fil_space_crypt_close_tablespace(sp);
mutex_enter(&fil_system.mutex); mutex_enter(&fil_system.mutex);
sp->release(); sp->release();
} }
sp->set_stopping(true);
} }
/* Check for pending operations. */ /* Check for pending operations. */
...@@ -2777,7 +2773,7 @@ fil_rename_tablespace( ...@@ -2777,7 +2773,7 @@ fil_rename_tablespace(
multiple datafiles per tablespace. */ multiple datafiles per tablespace. */
ut_a(UT_LIST_GET_LEN(space->chain) == 1); ut_a(UT_LIST_GET_LEN(space->chain) == 1);
node = UT_LIST_GET_FIRST(space->chain); node = UT_LIST_GET_FIRST(space->chain);
space->n_pending_ops++; ut_a(space->acquire());
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
...@@ -2799,8 +2795,7 @@ fil_rename_tablespace( ...@@ -2799,8 +2795,7 @@ fil_rename_tablespace(
/* log_sys.mutex is above fil_system.mutex in the latching order */ /* log_sys.mutex is above fil_system.mutex in the latching order */
ut_ad(log_mutex_own()); ut_ad(log_mutex_own());
mutex_enter(&fil_system.mutex); mutex_enter(&fil_system.mutex);
ut_ad(space->n_pending_ops); space->release();
space->n_pending_ops--;
ut_ad(space->name == old_space_name); ut_ad(space->name == old_space_name);
ut_ad(node->name == old_file_name); ut_ad(node->name == old_file_name);
bool success; bool success;
...@@ -4133,7 +4128,7 @@ fil_io( ...@@ -4133,7 +4128,7 @@ fil_io(
if (space == NULL if (space == NULL
|| (req_type.is_read() || (req_type.is_read()
&& !sync && !sync
&& space->stop_new_ops && space->is_stopping()
&& !space->is_being_truncated)) { && !space->is_being_truncated)) {
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
...@@ -4733,7 +4728,7 @@ fil_space_validate_for_mtr_commit( ...@@ -4733,7 +4728,7 @@ fil_space_validate_for_mtr_commit(
fil_space_acquire() before mtr_start() and fil_space_acquire() before mtr_start() and
fil_space_t::release() after mtr_commit(). This is why fil_space_t::release() after mtr_commit(). This is why
n_pending_ops should not be zero if stop_new_ops is set. */ n_pending_ops should not be zero if stop_new_ops is set. */
ut_ad(!space->stop_new_ops ut_ad(!space->is_stopping()
|| space->is_being_truncated /* fil_truncate_prepare() */ || space->is_being_truncated /* fil_truncate_prepare() */
|| space->referenced()); || space->referenced());
} }
...@@ -4949,23 +4944,3 @@ fil_space_get_block_size(const fil_space_t* space, unsigned offset) ...@@ -4949,23 +4944,3 @@ fil_space_get_block_size(const fil_space_t* space, unsigned offset)
return block_size; return block_size;
} }
/*******************************************************************//**
Returns the table space by a given id, NULL if not found. */
fil_space_t*
fil_space_found_by_id(
/*==================*/
ulint id) /*!< in: space id */
{
fil_space_t* space = NULL;
mutex_enter(&fil_system.mutex);
space = fil_space_get_by_id(id);
/* Not found if space is being deleted */
if (space && space->stop_new_ops) {
space = NULL;
}
mutex_exit(&fil_system.mutex);
return space;
}
...@@ -8576,8 +8576,7 @@ i_s_tablespaces_encryption_fill_table( ...@@ -8576,8 +8576,7 @@ i_s_tablespaces_encryption_fill_table(
for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list);
space; space = UT_LIST_GET_NEXT(space_list, space)) { space; space = UT_LIST_GET_NEXT(space_list, space)) {
if (space->purpose == FIL_TYPE_TABLESPACE if (space->purpose == FIL_TYPE_TABLESPACE
&& !space->is_stopping()) { && space->acquire()) {
space->acquire();
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
if (int err = i_s_dict_fill_tablespaces_encryption( if (int err = i_s_dict_fill_tablespaces_encryption(
thd, space, tables->table)) { thd, space, tables->table)) {
...@@ -8850,8 +8849,7 @@ i_s_tablespaces_scrubbing_fill_table( ...@@ -8850,8 +8849,7 @@ i_s_tablespaces_scrubbing_fill_table(
for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list);
space; space = UT_LIST_GET_NEXT(space_list, space)) { space; space = UT_LIST_GET_NEXT(space_list, space)) {
if (space->purpose == FIL_TYPE_TABLESPACE if (space->purpose == FIL_TYPE_TABLESPACE
&& !space->is_stopping()) { && space->acquire()) {
space->acquire();
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
if (int err = i_s_dict_fill_tablespaces_scrubbing( if (int err = i_s_dict_fill_tablespaces_scrubbing(
thd, space, tables->table)) { thd, space, tables->table)) {
......
...@@ -102,15 +102,6 @@ struct fil_space_t ...@@ -102,15 +102,6 @@ struct fil_space_t
/** Log sequence number of the latest MLOG_INDEX_LOAD record /** Log sequence number of the latest MLOG_INDEX_LOAD record
that was found while parsing the redo log */ that was found while parsing the redo log */
lsn_t enable_lsn; lsn_t enable_lsn;
/** set when an .ibd file is about to be deleted,
or an undo tablespace is about to be truncated.
When this is set following new ops are not allowed:
* read IO request
* ibuf merge
* file flush
Note that we can still possibly have new write operations
because we don't check this flag when doing flush batches. */
bool stop_new_ops;
/** whether undo tablespace truncation is in progress */ /** whether undo tablespace truncation is in progress */
bool is_being_truncated; bool is_being_truncated;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
...@@ -142,14 +133,22 @@ struct fil_space_t ...@@ -142,14 +133,22 @@ struct fil_space_t
ulint n_pending_flushes; /*!< this is positive when flushing ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the the tablespace to disk; dropping of the
tablespace is forbidden if this is positive */ tablespace is forbidden if this is positive */
/** Number of pending buffer pool operations accessing the tablespace private:
without holding a table lock or dict_sys.latch S-latch /** Number of pending buffer pool operations accessing the
that would prevent the table (and tablespace) from being 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 change buffer merge. dropped. An example is change buffer merge.
The tablespace cannot be dropped while this is nonzero,
or while fil_node_t::n_pending is nonzero. The tablespace cannot be dropped while this is nonzero, or while
Protected by fil_system.mutex and std::atomic. */ fil_node_t::n_pending is nonzero.
std::atomic<ulint> n_pending_ops;
The most significant bit contains the STOP_NEW_OPS flag. */
Atomic_relaxed<size_t> n_pending_ops;
/** Flag in n_pending_ops that indicates that the tablespace is being
deleted, and no further operations should be performed */
static const size_t STOP_NEW_OPS= ~(~size_t(0) >> 1);
public:
/** Number of pending block read or write operations /** Number of pending block read or write operations
(when a write is imminent or a read has recently completed). (when a write is imminent or a read has recently completed).
The tablespace object cannot be freed while this is nonzero, The tablespace object cannot be freed while this is nonzero,
...@@ -183,9 +182,6 @@ struct fil_space_t ...@@ -183,9 +182,6 @@ struct fil_space_t
ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
/** @return whether the tablespace is about to be dropped */
bool is_stopping() const { return stop_new_ops; }
/** Clamp a page number for batched I/O, such as read-ahead. /** Clamp a page number for batched I/O, such as read-ahead.
@param offset page number limit @param offset page number limit
@return offset clamped to the tablespace size */ @return offset clamped to the tablespace size */
...@@ -270,18 +266,43 @@ struct fil_space_t ...@@ -270,18 +266,43 @@ struct fil_space_t
/** Close each file. Only invoked on fil_system.temp_space. */ /** Close each file. Only invoked on fil_system.temp_space. */
void close(); void close();
/** Acquire a tablespace reference. */ /** @return whether the tablespace is about to be dropped */
void acquire() { n_pending_ops++; } 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 */
void set_stopping(bool stopping)
{
ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS);
ut_ad(!(n & STOP_NEW_OPS) == stopping);
}
MY_ATTRIBUTE((warn_unused_result))
/** @return whether a tablespace reference was successfully acquired */
bool acquire()
{
size_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. /** Release a tablespace reference.
@return whether this was the last reference */ @return whether this was the last reference */
bool release() { auto n= n_pending_ops--; ut_ad(n); return n == 1; } bool release()
/** @return whether references are being held */ {
bool referenced() const { return n_pending_ops; } auto n= n_pending_ops.fetch_sub(1);
ut_ad(n & ~STOP_NEW_OPS);
return (n & ~STOP_NEW_OPS) == 1;
}
/** Acquire a tablespace reference for I/O. */ /** Acquire a tablespace reference for I/O. */
void acquire_for_io() { n_pending_ios++; } void acquire_for_io() { n_pending_ios++; }
/** Release a tablespace reference for I/O. */ /** Release a tablespace reference for I/O. */
void release_for_io() { ut_ad(pending_io()); n_pending_ios--; } void release_for_io() { ut_d(auto n=) n_pending_ios--; ut_ad(n); }
/** @return whether I/O is pending */ /** @return whether I/O is pending */
bool pending_io() const { return n_pending_ios; } bool pending_io() const { return n_pending_ios; }
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */
......
...@@ -776,12 +776,12 @@ static void trx_purge_truncate_history() ...@@ -776,12 +776,12 @@ static void trx_purge_truncate_history()
/* This is only executed by srv_purge_coordinator_thread. */ /* This is only executed by srv_purge_coordinator_thread. */
export_vars.innodb_undo_truncations++; export_vars.innodb_undo_truncations++;
/* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */ /* In MDEV-8319 (10.5) we will PUNCH_HOLE the garbage
(with write-ahead logging). */
mutex_enter(&fil_system.mutex); mutex_enter(&fil_system.mutex);
ut_ad(&space == purge_sys.truncate.current); ut_ad(&space == purge_sys.truncate.current);
ut_ad(space.stop_new_ops);
ut_ad(space.is_being_truncated); ut_ad(space.is_being_truncated);
purge_sys.truncate.current->stop_new_ops = false; purge_sys.truncate.current->set_stopping(false);
purge_sys.truncate.current->is_being_truncated = false; purge_sys.truncate.current->is_being_truncated = false;
mutex_exit(&fil_system.mutex); mutex_exit(&fil_system.mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment