Merge 10.2 into 10.3

This commit is contained in:
Marko Mäkelä 2020-10-28 10:01:50 +02:00
commit a8de8f261d
122 changed files with 19102 additions and 2557 deletions

View file

@ -29,6 +29,7 @@ Created 2/23/1996 Heikki Tuuri
#include "dict0dict.h"
#include "btr0cur.h"
#include "buf0block_hint.h"
#include "btr0btr.h"
#include "gis0rtree.h"
@ -502,13 +503,10 @@ struct btr_pcur_t{
whether cursor was on, before, or after the old_rec record */
enum btr_pcur_pos_t rel_pos;
/** buffer block when the position was stored */
buf_block_t* block_when_stored;
buf::Block_hint block_when_stored;
/** the modify clock value of the buffer block when the cursor position
was stored */
ib_uint64_t modify_clock;
/** the withdraw clock value of the buffer pool when the cursor
position was stored */
ulint withdraw_clock;
/** btr_pcur_store_position() and btr_pcur_restore_position() state. */
enum pcur_pos_t pos_state;
/** PAGE_CUR_G, ... */
@ -528,9 +526,8 @@ struct btr_pcur_t{
btr_pcur_t() :
btr_cur(), latch_mode(0), old_stored(false), old_rec(NULL),
old_n_fields(0), rel_pos(btr_pcur_pos_t(0)),
block_when_stored(NULL),
modify_clock(0), withdraw_clock(0),
pos_state(BTR_PCUR_NOT_POSITIONED),
block_when_stored(),
modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED),
search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL),
old_rec_buf(NULL), buf_size(0)
{

View file

@ -0,0 +1,77 @@
/*****************************************************************************
Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Free Software Foundation.
This program is also distributed with certain software (including but not
limited to OpenSSL) that is licensed under separate terms, as designated in a
particular file or component or in included license documentation. The authors
of MySQL hereby grant you an additional permission to link the program and
your derivative works with the separately licensed software that they have
included with MySQL.
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, version 2.0,
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 St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#pragma once
#include "buf0buf.h"
namespace buf {
class Block_hint {
public:
Block_hint():m_block(NULL),m_page_id(0,0) {}
/** Stores the pointer to the block, which is currently buffer-fixed.
@param block a pointer to a buffer-fixed block to be stored */
inline void store(buf_block_t *block)
{
ut_ad(block->page.buf_fix_count);
m_block= block;
m_page_id= block->page.id;
}
/** Clears currently stored pointer. */
inline void clear() { m_block= NULL; }
/** Invoke f on m_block(which may be null)
@param f The function to be executed. It will be passed the pointer.
If you wish to use the block pointer subsequently,
you need to ensure you buffer-fix it before returning from f.
@return the return value of f
*/
template <typename F>
bool run_with_hint(const F &f)
{
buffer_fix_block_if_still_valid();
/* m_block could be changed during f() call, so we use local
variable to remember which block we need to unfix */
buf_block_t *block= m_block;
bool res= f(block);
if (block)
buf_block_buf_fix_dec(block);
return res;
}
buf_block_t *block() const { return m_block; }
private:
/** The block pointer stored by store(). */
buf_block_t *m_block;
/** If m_block is non-null, the m_block->page.id at time it was stored. */
page_id_t m_page_id;
/** A helper function which checks if m_block is not a dangling pointer and
still points to block with page with m_page_id and if so, buffer-fixes it,
otherwise clear()s it */
void buffer_fix_block_if_still_valid();
};
} // namespace buf

View file

@ -101,10 +101,6 @@ extern buf_pool_t* buf_pool_ptr; /*!< The buffer pools
extern volatile bool buf_pool_withdrawing; /*!< true when withdrawing buffer
pool pages might cause page relocation */
extern volatile ulint buf_withdraw_clock; /*!< the clock is incremented
every time a pointer to a page may
become obsolete */
# ifdef UNIV_DEBUG
extern my_bool buf_disable_resize_buffer_pool_debug; /*!< if TRUE, resizing
buffer pool is not allowed. */
@ -1373,14 +1369,6 @@ buf_get_nth_chunk_block(
ulint n, /*!< in: nth chunk in the buffer pool */
ulint* chunk_size); /*!< in: chunk size */
/** Verify the possibility that a stored page is not in buffer pool.
@param[in] withdraw_clock withdraw clock when stored the page
@retval true if the page might be relocated */
UNIV_INLINE
bool
buf_pool_is_obsolete(
ulint withdraw_clock);
/** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit,
if needed.
@param[in] size size in bytes
@ -2207,6 +2195,11 @@ struct buf_pool_t{
buf_tmp_array_t* tmp_arr;
/*!< Array for temporal memory
used in compression and encryption */
/** Determine if a pointer belongs to a buf_block_t.
It can be a pointer to the buf_block_t itself or a member of it.
@param ptr a pointer that will not be dereferenced
@return whether the ptr belongs to a buf_block_t struct */
inline bool is_block_field(const void *ptr) const;
#if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN
# error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN"

View file

@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2014, 2019, MariaDB Corporation.
Copyright (c) 2014, 2020, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@ -54,6 +54,25 @@ struct buf_chunk_t{
}
};
bool buf_pool_t::is_block_field(const void *ptr) const
{
const buf_chunk_t* chunk= chunks;
const buf_chunk_t *const echunk= chunk + ut_min(n_chunks,
n_chunks_new);
/* TODO: protect chunks with a mutex (the older pointer will
currently remain during resize()) */
while (chunk < echunk)
{
if (ptr >= reinterpret_cast<const void*>(chunk->blocks) &&
ptr < reinterpret_cast<const void*>(
chunk->blocks + chunk->size))
return true;
chunk++;
}
return false;
}
/*********************************************************************//**
Gets the current size of buffer buf_pool in bytes.
@return size in bytes */
@ -1056,8 +1075,6 @@ buf_block_buf_fix_dec(
/*==================*/
buf_block_t* block) /*!< in/out: block to bufferunfix */
{
buf_block_unfix(block);
#ifdef UNIV_DEBUG
/* No debug latch is acquired if block belongs to system temporary.
Debug latch is not of much help if access to block is single
@ -1066,6 +1083,8 @@ buf_block_buf_fix_dec(
rw_lock_s_unlock(&block->debug_latch);
}
#endif /* UNIV_DEBUG */
buf_block_unfix(block);
}
/** Returns the buffer pool instance given a page id.
@ -1439,18 +1458,6 @@ buf_page_get_frame(
}
}
/** Verify the possibility that a stored page is not in buffer pool.
@param[in] withdraw_clock withdraw clock when stored the page
@retval true if the page might be relocated */
UNIV_INLINE
bool
buf_pool_is_obsolete(
ulint withdraw_clock)
{
return(UNIV_UNLIKELY(buf_pool_withdrawing
|| buf_withdraw_clock != withdraw_clock));
}
/** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit,
if needed.
@param[in] size size in bytes

View file

@ -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) {
@ -1468,25 +1468,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 */

View file

@ -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 "fil0crypt.h"
#include <set>
@ -296,20 +295,25 @@ 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.
/** Create a table memory object.
@param name table name
@param space tablespace
@param n_cols total number of columns (both virtual and non-virtual)
@param n_v_cols number of virtual columns
@param flags table flags
@param flags2 table flags2
@param 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 */
fil_space_t* space, /*!< in: tablespace */
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,
fil_space_t* space,
ulint n_cols,
ulint n_v_cols,
ulint flags,
ulint flags2,
bool init_stats_latch=true);
/****************************************************************//**
Free a table memory object. */
void
@ -812,7 +816,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 */
@ -820,9 +824,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
@ -1864,7 +1865,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,
@ -1877,7 +1878,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. */
@ -2001,11 +2002,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;
@ -2112,64 +2110,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
@ -2177,22 +2117,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 */

View file

@ -170,10 +170,10 @@ mtr_t::release_block_at_savepoint(
ut_a(slot->object == block);
buf_block_unfix(reinterpret_cast<buf_block_t*>(block));
buf_page_release_latch(block, slot->type);
buf_block_unfix(reinterpret_cast<buf_block_t*>(block));
slot->object = NULL;
}

View file

@ -1,120 +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"
#include "my_cpu.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;
}
MY_RELAX_CPU();
}
}
}
};
#endif /* os0once_h */

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation.
Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1119,7 +1119,7 @@ public:
}
/** @return number of committed transactions waiting for purge */
ulint history_size() const
uint32 history_size() const
{
return uint32(my_atomic_load32(&const_cast<trx_sys_t*>(this)
->rseg_history_len));

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2018, MariaDB Corporation.
Copyright (c) 2017, 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -366,8 +366,6 @@ struct trx_undo_t {
(IB_ID_MAX if the undo log is empty) */
buf_block_t* guess_block; /*!< guess for the buffer block where
the top page might reside */
ulint withdraw_clock; /*!< the withdraw clock value of the
buffer pool when guess_block was stored */
/** @return whether the undo log is empty */
bool empty() const { return top_undo_no == IB_ID_MAX; }