Commit a1267724 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26293 InnoDB: Failing assertion: space->is_ready_to_close() ...

fil_space_t::acquire_low(): Introduce a parameter that specifies
which flags should be avoided. At all times, referenced() must not
be incremented if the STOPPING flag is set. When fil_system.mutex
is not being held by the current thread, the reference must not be
incremented if the CLOSING flag is set (unless NEEDS_FSYNC is set,
in fil_space_t::flush()).

fil_space_t::acquire(): Invoke acquire_low(STOPPING | CLOSING).
In this way, the reference count cannot be incremented after
fil_space_t::try_to_close() invoked fil_space_t::set_closing().

If the CLOSING flag was set, we must retry acquire_low() after
acquiring fil_system.mutex.

fil_space_t::prepare_acquired(): Replaces prepare(true).

fil_space_t::acquire_and_prepare(): Replaces prepare().
This basically retries fil_space_t::acquire() after
acquiring fil_system.mutex.
parent afe607df
/***************************************************************************** /*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
Copyright (c) 2014, 2021, MariaDB Corporation. Copyright (c) 2014, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -1456,7 +1456,7 @@ inline bool fil_space_t::acquire_if_not_stopped() ...@@ -1456,7 +1456,7 @@ inline bool fil_space_t::acquire_if_not_stopped()
return true; return true;
if (UNIV_UNLIKELY(n & STOPPING)) if (UNIV_UNLIKELY(n & STOPPING))
return false; return false;
return UNIV_LIKELY(!(n & CLOSING)) || prepare(true); return UNIV_LIKELY(!(n & CLOSING)) || prepare_acquired();
} }
bool fil_crypt_must_default_encrypt() bool fil_crypt_must_default_encrypt()
...@@ -1567,7 +1567,7 @@ inline fil_space_t *fil_space_t::next(fil_space_t *space, bool recheck, ...@@ -1567,7 +1567,7 @@ inline fil_space_t *fil_space_t::next(fil_space_t *space, bool recheck,
const uint32_t n= space->acquire_low(); const uint32_t n= space->acquire_low();
if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) if (UNIV_LIKELY(!(n & (STOPPING | CLOSING))))
break; break;
if (!(n & STOPPING) && space->prepare(true)) if (!(n & STOPPING) && space->prepare_acquired())
break; break;
} }
} }
......
...@@ -665,11 +665,9 @@ fil_space_extend_must_retry( ...@@ -665,11 +665,9 @@ fil_space_extend_must_retry(
} }
/** @return whether the file is usable for io() */ /** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) ATTRIBUTE_COLD bool fil_space_t::prepare_acquired()
{ {
ut_ad(referenced()); ut_ad(referenced());
if (!have_mutex)
mutex_enter(&fil_system.mutex);
ut_ad(mutex_own(&fil_system.mutex)); ut_ad(mutex_own(&fil_system.mutex));
fil_node_t *node= UT_LIST_GET_LAST(chain); fil_node_t *node= UT_LIST_GET_LAST(chain);
ut_ad(!id || purpose == FIL_TYPE_TEMPORARY || ut_ad(!id || purpose == FIL_TYPE_TEMPORARY ||
...@@ -714,8 +712,16 @@ ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) ...@@ -714,8 +712,16 @@ ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex)
clear: clear:
n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); n_pending.fetch_and(~CLOSING, std::memory_order_relaxed);
if (!have_mutex) return is_open;
mutex_exit(&fil_system.mutex); }
/** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool fil_space_t::acquire_and_prepare()
{
mutex_enter(&fil_system.mutex);
const auto flags= acquire_low() & (STOPPING | CLOSING);
const bool is_open= !flags || (flags == CLOSING && prepare_acquired());
mutex_exit(&fil_system.mutex);
return is_open; return is_open;
} }
...@@ -1488,13 +1494,13 @@ fil_space_t *fil_space_t::get(ulint id) ...@@ -1488,13 +1494,13 @@ fil_space_t *fil_space_t::get(ulint id)
mutex_enter(&fil_system.mutex); mutex_enter(&fil_system.mutex);
fil_space_t *space= fil_space_get_by_id(id); fil_space_t *space= fil_space_get_by_id(id);
const uint32_t n= space ? space->acquire_low() : 0; const uint32_t n= space ? space->acquire_low() : 0;
mutex_exit(&fil_system.mutex);
if (n & STOPPING) if (n & STOPPING)
space= nullptr; space= nullptr;
else if ((n & CLOSING) && !space->prepare()) else if ((n & CLOSING) && !space->prepare_acquired())
space= nullptr; space= nullptr;
mutex_exit(&fil_system.mutex);
return space; return space;
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2021, MariaDB Corporation. Copyright (c) 2013, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -507,15 +507,16 @@ struct fil_space_t final ...@@ -507,15 +507,16 @@ struct fil_space_t final
private: private:
MY_ATTRIBUTE((warn_unused_result)) MY_ATTRIBUTE((warn_unused_result))
/** Try to acquire a tablespace reference. /** Try to acquire a tablespace reference (increment referenced()).
@return the old reference count (if STOPPING is set, it was not acquired) */ @param avoid when these flags are set, nothing will be acquired
uint32_t acquire_low() @return the old reference count */
uint32_t acquire_low(uint32_t avoid= STOPPING)
{ {
uint32_t n= 0; uint32_t n= 0;
while (!n_pending.compare_exchange_strong(n, n + 1, while (!n_pending.compare_exchange_strong(n, n + 1,
std::memory_order_acquire, std::memory_order_acquire,
std::memory_order_relaxed) && std::memory_order_relaxed) &&
!(n & STOPPING)); !(n & avoid));
return n; return n;
} }
public: public:
...@@ -529,10 +530,8 @@ struct fil_space_t final ...@@ -529,10 +530,8 @@ struct fil_space_t final
@return whether the file is usable */ @return whether the file is usable */
bool acquire() bool acquire()
{ {
uint32_t n= acquire_low(); const auto flags= acquire_low(STOPPING | CLOSING) & (STOPPING | CLOSING);
if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) return UNIV_LIKELY(!flags) || (flags == CLOSING && acquire_and_prepare());
return true;
return UNIV_LIKELY(!(n & STOPPING)) && prepare();
} }
/** Acquire another tablespace reference for I/O. */ /** Acquire another tablespace reference for I/O. */
...@@ -999,7 +998,9 @@ struct fil_space_t final ...@@ -999,7 +998,9 @@ struct fil_space_t final
private: private:
/** @return whether the file is usable for io() */ /** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool prepare(bool have_mutex= false); ATTRIBUTE_COLD bool prepare_acquired();
/** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool acquire_and_prepare();
#endif /*!UNIV_INNOCHECKSUM */ #endif /*!UNIV_INNOCHECKSUM */
}; };
......
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