mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 19:37:16 +02:00
MDEV-23370 innodb_fts.innodb_fts_misc failed in buildbot, server crashed in dict_table_autoinc_destroy
This issue is caused by MDEV-22456ad6171b91c. Fix involves the backported version of 10.4 patch MDEV-227785f2628d1eeand few parts of MDEV-17441 (e9a5f288f2). dict_table_t::stats_latch_created: Removed dict_table_t::stats_latch: make value member and always lock it for simplicity even for stats cloned table. zip_pad_info_t::mutex_created: Removed zip_pad_info_t::mutex: make member value instead of pointer os0once.h: Removed dict_table_remove_from_cache_low(): Ensure that fts_free() is always called, even if dict_mem_table_free() is deferred until btr_search_lazy_free(). InnoDB would always zip_pad_info_t::mutex and dict_table_t::autoinc_mutex, even for tables are not in ROW_FORMAT=COMPRESSED nor include any AUTO_INCREMENT column.
This commit is contained in:
parent
987df9b37a
commit
3ba8f619e4
8 changed files with 68 additions and 399 deletions
|
|
@ -302,7 +302,7 @@ UNIV_INLINE
|
|||
void
|
||||
dict_table_autoinc_initialize(dict_table_t* table, ib_uint64_t value)
|
||||
{
|
||||
ut_ad(dict_table_autoinc_own(table));
|
||||
mysql_mutex_assert_owner(&table->autoinc_mutex);
|
||||
table->autoinc = value;
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +315,7 @@ UNIV_INLINE
|
|||
ib_uint64_t
|
||||
dict_table_autoinc_read(const dict_table_t* table)
|
||||
{
|
||||
ut_ad(dict_table_autoinc_own(table));
|
||||
mysql_mutex_assert_owner(&table->autoinc_mutex);
|
||||
return(table->autoinc);
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ UNIV_INLINE
|
|||
bool
|
||||
dict_table_autoinc_update_if_greater(dict_table_t* table, ib_uint64_t value)
|
||||
{
|
||||
ut_ad(dict_table_autoinc_own(table));
|
||||
mysql_mutex_assert_owner(&table->autoinc_mutex);
|
||||
|
||||
if (value > table->autoinc) {
|
||||
|
||||
|
|
@ -1524,25 +1524,6 @@ void
|
|||
dict_mutex_exit_for_mysql(void);
|
||||
/*===========================*/
|
||||
|
||||
/** Create a dict_table_t's stats latch or delay for lazy creation.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] table table whose stats latch to create
|
||||
@param[in] enabled if false then the latch is disabled
|
||||
and dict_table_stats_lock()/unlock() become noop on this table. */
|
||||
void
|
||||
dict_table_stats_latch_create(
|
||||
dict_table_t* table,
|
||||
bool enabled);
|
||||
|
||||
/** Destroy a dict_table_t's stats latch.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] table table whose stats latch to destroy */
|
||||
void
|
||||
dict_table_stats_latch_destroy(
|
||||
dict_table_t* table);
|
||||
|
||||
/** Lock the appropriate latch to protect a given table's statistics.
|
||||
@param[in] table table whose stats to lock
|
||||
@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ Created 1/8/1996 Heikki Tuuri
|
|||
#include "fts0fts.h"
|
||||
#include "buf0buf.h"
|
||||
#include "gis0type.h"
|
||||
#include "os0once.h"
|
||||
#include "fil0fil.h"
|
||||
#include <my_crypt.h>
|
||||
#include "fil0crypt.h"
|
||||
|
|
@ -299,21 +298,27 @@ parent table will fail, and user has to drop excessive foreign constraint
|
|||
before proceeds. */
|
||||
#define FK_MAX_CASCADE_DEL 15
|
||||
|
||||
/**********************************************************************//**
|
||||
Creates a table memory object.
|
||||
/** Creates a table memory object.
|
||||
@param[in] name table name
|
||||
@param[in] space space where the clustered index
|
||||
of the table is placed
|
||||
@param[in] n_cols total number of columns including
|
||||
virtual and non-virtual columns
|
||||
@param[in] n_v_cols number of virtual columns
|
||||
@param[in] flags table flags
|
||||
@param[in] flags2 table flags2
|
||||
@param[in] init_stats_latch whether to init the stats latch
|
||||
@return own: table object */
|
||||
dict_table_t*
|
||||
dict_mem_table_create(
|
||||
/*==================*/
|
||||
const char* name, /*!< in: table name */
|
||||
ulint space, /*!< in: space where the clustered index
|
||||
of the table is placed */
|
||||
ulint n_cols, /*!< in: total number of columns
|
||||
including virtual and non-virtual
|
||||
columns */
|
||||
ulint n_v_cols, /*!< in: number of virtual columns */
|
||||
ulint flags, /*!< in: table flags */
|
||||
ulint flags2); /*!< in: table flags2 */
|
||||
const char* name,
|
||||
ulint space,
|
||||
ulint n_cols,
|
||||
ulint n_v_cols,
|
||||
ulint flags,
|
||||
ulint flags2,
|
||||
bool init_stats_latch=true);
|
||||
|
||||
/****************************************************************//**
|
||||
Free a table memory object. */
|
||||
void
|
||||
|
|
@ -792,7 +797,7 @@ extern ulong zip_pad_max;
|
|||
an uncompressed page should be left as padding to avoid compression
|
||||
failures. This estimate is based on a self-adapting heuristic. */
|
||||
struct zip_pad_info_t {
|
||||
SysMutex* mutex; /*!< mutex protecting the info */
|
||||
mysql_mutex_t mutex; /*!< mutex protecting the info */
|
||||
ulint pad; /*!< number of bytes used as pad */
|
||||
ulint success;/*!< successful compression ops during
|
||||
current round */
|
||||
|
|
@ -800,9 +805,6 @@ struct zip_pad_info_t {
|
|||
current round */
|
||||
ulint n_rounds;/*!< number of currently successful
|
||||
rounds */
|
||||
volatile os_once::state_t
|
||||
mutex_created;
|
||||
/*!< Creation state of mutex member */
|
||||
};
|
||||
|
||||
/** Number of samples of data size kept when page compression fails for
|
||||
|
|
@ -1692,7 +1694,7 @@ struct dict_table_t {
|
|||
/** Statistics for query optimization. @{ */
|
||||
|
||||
/** Creation state of 'stats_latch'. */
|
||||
volatile os_once::state_t stats_latch_created;
|
||||
bool stats_latch_inited;
|
||||
|
||||
/** This latch protects:
|
||||
dict_table_t::stat_initialized,
|
||||
|
|
@ -1705,7 +1707,7 @@ struct dict_table_t {
|
|||
dict_table_t::indexes*::stat_n_leaf_pages.
|
||||
(*) Those are not always protected for
|
||||
performance reasons. */
|
||||
rw_lock_t* stats_latch;
|
||||
rw_lock_t stats_latch;
|
||||
|
||||
/** TRUE if statistics have been calculated the first time after
|
||||
database startup or table creation. */
|
||||
|
|
@ -1829,11 +1831,8 @@ struct dict_table_t {
|
|||
from a select. */
|
||||
lock_t* autoinc_lock;
|
||||
|
||||
/** Creation state of autoinc_mutex member */
|
||||
volatile os_once::state_t autoinc_mutex_created;
|
||||
|
||||
/** Mutex protecting the autoincrement counter. */
|
||||
ib_mutex_t* autoinc_mutex;
|
||||
mysql_mutex_t autoinc_mutex;
|
||||
|
||||
/** Autoinc counter value to give to the next inserted row. */
|
||||
ib_uint64_t autoinc;
|
||||
|
|
@ -1927,64 +1926,6 @@ struct dict_foreign_add_to_referenced_table {
|
|||
}
|
||||
};
|
||||
|
||||
/** Destroy the autoinc latch of the given table.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] table table whose stats latch to destroy */
|
||||
inline
|
||||
void
|
||||
dict_table_autoinc_destroy(
|
||||
dict_table_t* table)
|
||||
{
|
||||
if (table->autoinc_mutex_created == os_once::DONE
|
||||
&& table->autoinc_mutex != NULL) {
|
||||
mutex_free(table->autoinc_mutex);
|
||||
UT_DELETE(table->autoinc_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Request for lazy creation of the autoinc latch of a given table.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] table table whose autoinc latch is to be created. */
|
||||
inline
|
||||
void
|
||||
dict_table_autoinc_create_lazy(
|
||||
dict_table_t* table)
|
||||
{
|
||||
table->autoinc_mutex = NULL;
|
||||
table->autoinc_mutex_created = os_once::NEVER_DONE;
|
||||
}
|
||||
|
||||
/** Request a lazy creation of dict_index_t::zip_pad::mutex.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] index index whose zip_pad mutex is to be created */
|
||||
inline
|
||||
void
|
||||
dict_index_zip_pad_mutex_create_lazy(
|
||||
dict_index_t* index)
|
||||
{
|
||||
index->zip_pad.mutex = NULL;
|
||||
index->zip_pad.mutex_created = os_once::NEVER_DONE;
|
||||
}
|
||||
|
||||
/** Destroy the zip_pad_mutex of the given index.
|
||||
This function is only called from either single threaded environment
|
||||
or from a thread that has not shared the table object with other threads.
|
||||
@param[in,out] table table whose stats latch to destroy */
|
||||
inline
|
||||
void
|
||||
dict_index_zip_pad_mutex_destroy(
|
||||
dict_index_t* index)
|
||||
{
|
||||
if (index->zip_pad.mutex_created == os_once::DONE
|
||||
&& index->zip_pad.mutex != NULL) {
|
||||
mutex_free(index->zip_pad.mutex);
|
||||
UT_DELETE(index->zip_pad.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Release the zip_pad_mutex of a given index.
|
||||
@param[in,out] index index whose zip_pad_mutex is to be released */
|
||||
inline
|
||||
|
|
@ -1992,22 +1933,9 @@ void
|
|||
dict_index_zip_pad_unlock(
|
||||
dict_index_t* index)
|
||||
{
|
||||
mutex_exit(index->zip_pad.mutex);
|
||||
mysql_mutex_unlock(&index->zip_pad.mutex);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/** Check if the current thread owns the autoinc_mutex of a given table.
|
||||
@param[in] table the autoinc_mutex belongs to this table
|
||||
@return true, if the current thread owns the autoinc_mutex, false otherwise.*/
|
||||
inline
|
||||
bool
|
||||
dict_table_autoinc_own(
|
||||
const dict_table_t* table)
|
||||
{
|
||||
return(mutex_own(table->autoinc_mutex));
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/** Check whether the col is used in spatial index or regular index.
|
||||
@param[in] col column to check
|
||||
@return spatial status */
|
||||
|
|
|
|||
|
|
@ -1,118 +0,0 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
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
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**************************************************//**
|
||||
@file include/os0once.h
|
||||
A class that aids executing a given function exactly once in a multi-threaded
|
||||
environment.
|
||||
|
||||
Created Feb 20, 2014 Vasil Dimov
|
||||
*******************************************************/
|
||||
|
||||
#ifndef os0once_h
|
||||
#define os0once_h
|
||||
|
||||
#include "univ.i"
|
||||
#include "ut0ut.h"
|
||||
|
||||
/** Execute a given function exactly once in a multi-threaded environment
|
||||
or wait for the function to be executed by another thread.
|
||||
|
||||
Example usage:
|
||||
First the user must create a control variable of type os_once::state_t and
|
||||
assign it os_once::NEVER_DONE.
|
||||
Then the user must pass this variable, together with a function to be
|
||||
executed to os_once::do_or_wait_for_done().
|
||||
|
||||
Multiple threads can call os_once::do_or_wait_for_done() simultaneously with
|
||||
the same (os_once::state_t) control variable. The provided function will be
|
||||
called exactly once and when os_once::do_or_wait_for_done() returns then this
|
||||
function has completed execution, by this or another thread. In other words
|
||||
os_once::do_or_wait_for_done() will either execute the provided function or
|
||||
will wait for its execution to complete if it is already called by another
|
||||
thread or will do nothing if the function has already completed its execution
|
||||
earlier.
|
||||
|
||||
This mimics pthread_once(3), but unfortunatelly pthread_once(3) does not
|
||||
support passing arguments to the init_routine() function. We should use
|
||||
std::call_once() when we start compiling with C++11 enabled. */
|
||||
class os_once {
|
||||
public:
|
||||
/** Control variables' state type */
|
||||
typedef ib_uint32_t state_t;
|
||||
|
||||
/** Not yet executed. */
|
||||
static const state_t NEVER_DONE = 0;
|
||||
|
||||
/** Currently being executed by this or another thread. */
|
||||
static const state_t IN_PROGRESS = 1;
|
||||
|
||||
/** Finished execution. */
|
||||
static const state_t DONE = 2;
|
||||
|
||||
/** Call a given function or wait its execution to complete if it is
|
||||
already called by another thread.
|
||||
@param[in,out] state control variable
|
||||
@param[in] do_func function to call
|
||||
@param[in,out] do_func_arg an argument to pass to do_func(). */
|
||||
static
|
||||
void
|
||||
do_or_wait_for_done(
|
||||
volatile state_t* state,
|
||||
void (*do_func)(void*),
|
||||
void* do_func_arg)
|
||||
{
|
||||
int32 oldval = NEVER_DONE;
|
||||
|
||||
/* Avoid calling my_atomic_cas32() in the most common case. */
|
||||
if (*state == DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (my_atomic_cas32((int32*) state, &oldval, IN_PROGRESS)) {
|
||||
/* We are the first. Call the function. */
|
||||
|
||||
do_func(do_func_arg);
|
||||
|
||||
my_atomic_store32((int32*) state, DONE);
|
||||
} else {
|
||||
/* The state is not NEVER_DONE, so either it is
|
||||
IN_PROGRESS (somebody is calling the function right
|
||||
now or DONE (it has already been called and completed).
|
||||
Wait for it to become DONE. */
|
||||
for (;;) {
|
||||
const state_t s = *state;
|
||||
|
||||
switch (s) {
|
||||
case DONE:
|
||||
return;
|
||||
case IN_PROGRESS:
|
||||
break;
|
||||
case NEVER_DONE:
|
||||
/* fall through */
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
UT_RELAX_CPU();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* os0once_h */
|
||||
Loading…
Add table
Add a link
Reference in a new issue