mariadb/storage/innobase/include/que0que.h
Marko Mäkelä 82b7c561b7 MDEV-24258 Merge dict_sys.mutex into dict_sys.latch
In the parent commit, dict_sys.latch could theoretically have been
replaced with a mutex. But, we can do better and merge dict_sys.mutex
into dict_sys.latch. Generally, every occurrence of dict_sys.mutex_lock()
will be replaced with dict_sys.lock().

The PERFORMANCE_SCHEMA instrumentation for dict_sys_mutex
will be removed along with dict_sys.mutex. The dict_sys.latch
will remain instrumented as dict_operation_lock.

Some use of dict_sys.lock() will be replaced with dict_sys.freeze(),
which we will reintroduce for the new shared mode. Most notably,
concurrent table lookups are possible as long as the tables are present
in the dict_sys cache. In particular, this will allow more concurrency
among InnoDB purge workers.

Because dict_sys.mutex will no longer 'throttle' the threads that purge
InnoDB transaction history, a performance degradation may be observed
unless innodb_purge_threads=1.

The table cache eviction policy will become FIFO-like,
similar to what happened to fil_system.LRU
in commit 45ed9dd957.
The name of the list dict_sys.table_LRU will become somewhat misleading;
that list contains tables that may be evicted, even though the
eviction policy no longer is least-recently-used but first-in-first-out.
(Note: Tables can never be evicted as long as locks exist on them or
the tables are in use by some thread.)

As demonstrated by the test perfschema.sxlock_func, there
will be less contention on dict_sys.latch, because some previous
use of exclusive latches will be replaced with shared latches.

fts_parse_sql_no_dict_lock(): Replaced with pars_sql().

fts_get_table_name_prefix(): Merged to fts_optimize_create().

dict_stats_update_transient_for_index(): Deduplicated some code.

ha_innobase::info_low(), dict_stats_stop_bg(): Use a combination
of dict_sys.latch and table->stats_mutex_lock() to cover the
changes of BG_STAT_SHOULD_QUIT, because the flag is being read
in dict_stats_update_persistent() while not holding dict_sys.latch.

row_discard_tablespace_for_mysql(): Protect stats_bg_flag by
exclusive dict_sys.latch, like most other code does.

row_quiesce_table_has_fts_index(): Remove unnecessary mutex
acquisition. FLUSH TABLES...FOR EXPORT is protected by MDL.

row_import::set_root_by_heuristic(): Remove unnecessary mutex
acquisition. ALTER TABLE...IMPORT TABLESPACE is protected by MDL.

row_ins_sec_index_entry_low(): Replace a call
to dict_set_corrupted_index_cache_only(). Reads of index->type
were not really protected by dict_sys.mutex, and writes
(flagging an index corrupted) should be extremely rare.

dict_stats_process_entry_from_defrag_pool(): Only freeze the dictionary,
do not lock it exclusively.

dict_stats_wait_bg_to_stop_using_table(), DICT_BG_YIELD: Remove trx.
We can simply invoke dict_sys.unlock() and dict_sys.lock() directly.

dict_acquire_mdl_shared()<trylock=false>: Assert that dict_sys.latch is
only held in shared more, not exclusive mode. Only acquire it in
exclusive mode if the table needs to be loaded to the cache.

dict_sys_t::acquire(): Remove. Relocating elements in dict_sys.table_LRU
would require holding an exclusive latch, which we want to avoid
for performance reasons.

dict_sys_t::allow_eviction(): Add the table first to dict_sys.table_LRU,
to compensate for the removal of dict_sys_t::acquire(). This function
is only invoked by INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS.

dict_table_open_on_id(), dict_table_open_on_name(): If dict_locked=false,
try to acquire dict_sys.latch in shared mode. Only acquire the latch in
exclusive mode if the table is not found in the cache.

Reviewed by: Thirunarayanan Balathandayuthapani
2021-08-31 13:51:35 +03:00

317 lines
11 KiB
C

/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2021, 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
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/que0que.h
Query graph
Created 5/27/1996 Heikki Tuuri
*******************************************************/
#ifndef que0que_h
#define que0que_h
#include "data0data.h"
#include "trx0trx.h"
#include "trx0roll.h"
#include "srv0srv.h"
#include "que0types.h"
#include "row0types.h"
#include "pars0types.h"
/***********************************************************************//**
Creates a query graph fork node.
@return own: fork node */
que_fork_t *que_fork_create(mem_heap_t* heap);
/***********************************************************************//**
Gets the first thr in a fork. */
UNIV_INLINE
que_thr_t*
que_fork_get_first_thr(
/*===================*/
que_fork_t* fork); /*!< in: query fork */
/***********************************************************************//**
Gets the child node of the first thr in a fork. */
UNIV_INLINE
que_node_t*
que_fork_get_child(
/*===============*/
que_fork_t* fork); /*!< in: query fork */
/***********************************************************************//**
Sets the parent of a graph node. */
UNIV_INLINE
void
que_node_set_parent(
/*================*/
que_node_t* node, /*!< in: graph node */
que_node_t* parent);/*!< in: parent */
/** Creates a query graph thread node.
@param[in] parent parent node, i.e., a fork node
@param[in] heap memory heap where created
@param[in] prebuilt row prebuilt structure
@return own: query thread node */
que_thr_t*
que_thr_create(
que_fork_t* parent,
mem_heap_t* heap,
row_prebuilt_t* prebuilt);
/**********************************************************************//**
Frees a query graph, but not the heap where it was created. Does not free
explicit cursor declarations, they are freed in que_graph_free. */
void
que_graph_free_recursive(
/*=====================*/
que_node_t* node); /*!< in: query graph node */
/**********************************************************************//**
Frees a query graph. */
void
que_graph_free(
/*===========*/
que_t* graph); /*!< in: query graph; we assume that the memory
heap where this graph was created is private
to this graph: if not, then use
que_graph_free_recursive and free the heap
afterwards! */
/**********************************************************************//**
Run a query thread. Handles lock waits. */
void
que_run_threads(
/*============*/
que_thr_t* thr); /*!< in: query thread */
/**********************************************************************//**
Starts execution of a command in a query fork. Picks a query thread which
is not in the QUE_THR_RUNNING state and moves it to that state. If none
can be chosen, a situation which may arise in parallelized fetches, NULL
is returned.
@return a query thread of the graph moved to QUE_THR_RUNNING state, or
NULL; the query thread should be executed by que_run_threads by the
caller */
que_thr_t*
que_fork_start_command(
/*===================*/
que_fork_t* fork); /*!< in: a query fork */
/***********************************************************************//**
Gets the trx of a query thread. */
UNIV_INLINE
trx_t*
thr_get_trx(
/*========*/
que_thr_t* thr); /*!< in: query thread */
/***********************************************************************//**
Gets the type of a graph node. */
UNIV_INLINE
ulint
que_node_get_type(
/*==============*/
const que_node_t* node); /*!< in: graph node */
/***********************************************************************//**
Gets pointer to the value data type field of a graph node. */
UNIV_INLINE
dtype_t*
que_node_get_data_type(
/*===================*/
que_node_t* node); /*!< in: graph node */
/***********************************************************************//**
Gets pointer to the value dfield of a graph node. */
UNIV_INLINE
dfield_t*
que_node_get_val(
/*=============*/
que_node_t* node); /*!< in: graph node */
/***********************************************************************//**
Gets the value buffer size of a graph node.
@return val buffer size, not defined if val.data == NULL in node */
UNIV_INLINE
ulint
que_node_get_val_buf_size(
/*======================*/
que_node_t* node); /*!< in: graph node */
/***********************************************************************//**
Sets the value buffer size of a graph node. */
UNIV_INLINE
void
que_node_set_val_buf_size(
/*======================*/
que_node_t* node, /*!< in: graph node */
ulint size); /*!< in: size */
/*********************************************************************//**
Gets the next list node in a list of query graph nodes. */
UNIV_INLINE
que_node_t*
que_node_get_next(
/*==============*/
que_node_t* node); /*!< in: node in a list */
/*********************************************************************//**
Gets the parent node of a query graph node.
@return parent node or NULL */
UNIV_INLINE
que_node_t*
que_node_get_parent(
/*================*/
que_node_t* node); /*!< in: node */
/****************************************************************//**
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
given node, or NULL if the node is not within a loop.
@return containing loop node, or NULL. */
que_node_t*
que_node_get_containing_loop_node(
/*==============================*/
que_node_t* node); /*!< in: node */
/*********************************************************************//**
Catenates a query graph node to a list of them, possible empty list.
@return one-way list of nodes */
UNIV_INLINE
que_node_t*
que_node_list_add_last(
/*===================*/
que_node_t* node_list, /*!< in: node list, or NULL */
que_node_t* node); /*!< in: node */
/*************************************************************************
Get the last node from the list.*/
UNIV_INLINE
que_node_t*
que_node_list_get_last(
/*===================*/
/* out: node last node from list.*/
que_node_t* node_list); /* in: node list, or NULL */
/*********************************************************************//**
Gets a query graph node list length.
@return length, for NULL list 0 */
UNIV_INLINE
ulint
que_node_list_get_len(
/*==================*/
que_node_t* node_list); /*!< in: node list, or NULL */
/*********************************************************************//**
Evaluate the given SQL
@return error code or DB_SUCCESS */
dberr_t
que_eval_sql(
/*=========*/
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql, /*!< in: SQL string */
bool lock_dict,
/*!< in: whether to acquire/release
dict_sys.latch around call to pars_sql(). */
trx_t* trx); /*!< in: trx */
/**********************************************************************//**
Round robin scheduler.
@return a query thread of the graph moved to QUE_THR_RUNNING state, or
NULL; the query thread should be executed by que_run_threads by the
caller */
que_thr_t*
que_fork_scheduler_round_robin(
/*===========================*/
que_fork_t* fork, /*!< in: a query fork */
que_thr_t* thr); /*!< in: current pos */
/** Query thread states */
enum que_thr_state_t {
/** in selects this means that the thread is at the end of its
result set (or start, in case of a scroll cursor); in other
statements, this means the thread has done its task */
QUE_THR_COMPLETED,
QUE_THR_RUNNING
};
/** Query thread lock states */
enum que_thr_lock_t {
QUE_THR_LOCK_NOLOCK,
QUE_THR_LOCK_ROW,
QUE_THR_LOCK_TABLE
};
/* Query graph query thread node: the fields are protected by the
trx_t::mutex with the exceptions named below */
struct que_thr_t{
que_common_t common; /*!< type: QUE_NODE_THR */
que_node_t* child; /*!< graph child node */
que_t* graph; /*!< graph where this node belongs */
que_thr_state_t state; /*!< state of the query thread */
/*------------------------------*/
/* The following fields are private to the OS thread executing the
query thread, and are not protected by any mutex: */
que_node_t* run_node; /*!< pointer to the node where the
subgraph down from this node is
currently executed */
que_node_t* prev_node; /*!< pointer to the node from which
the control came */
ulint resource; /*!< resource usage of the query thread
thus far */
ulint lock_state; /*!< lock state of thread (table or
row) */
/*------------------------------*/
/* The following fields are links for the various lists that
this type can be on. */
UT_LIST_NODE_T(que_thr_t)
thrs; /*!< list of thread nodes of the fork
node */
UT_LIST_NODE_T(que_thr_t)
queue; /*!< list of runnable thread nodes in
the server task queue */
ulint fk_cascade_depth; /*!< maximum cascading call depth
supported for foreign key constraint
related delete/updates */
row_prebuilt_t* prebuilt; /*!< prebuilt structure processed by
the query thread */
};
/* Query graph fork node: its fields are protected by the query thread mutex */
struct que_fork_t{
que_common_t common; /*!< type: QUE_NODE_FORK */
que_t* graph; /*!< query graph of this node */
trx_t* trx; /*!< transaction: this is set only in
the root node */
ulint state; /*!< state of the fork node */
que_thr_t* caller; /*!< pointer to a possible calling query
thread */
UT_LIST_BASE_NODE_T(que_thr_t)
thrs; /*!< list of query threads */
/*------------------------------*/
/* The fields in this section are defined only in the root node */
sym_tab_t* sym_tab; /*!< symbol table of the query,
generated by the parser, or NULL
if the graph was created 'by hand' */
pars_info_t* info; /*!< info struct, or NULL */
sel_node_t* last_sel_node; /*!< last executed select node, or NULL
if none */
UT_LIST_NODE_T(que_fork_t)
graphs; /*!< list of query graphs of a session
or a stored procedure */
/*------------------------------*/
mem_heap_t* heap; /*!< memory heap where the fork was
created */
};
/* Query fork (or graph) states */
#define QUE_FORK_ACTIVE 1
#define QUE_FORK_COMMAND_WAIT 2
/* Flag which is ORed to control structure statement node types */
#define QUE_NODE_CONTROL_STAT 1024
#include "que0que.ic"
#endif