1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/*****************************************************************************
Copyright (c) 2007, 2025, Oracle and/or its affiliates.
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 designed to work 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 either included with
the program or referenced in the documentation.
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
*****************************************************************************/
/** @file include/lock0iter.h
Lock queue iterator type and function prototypes.
Created July 16, 2007 Vasil Dimov
*******************************************************/
#ifndef lock0iter_h
#define lock0iter_h
#include "dict0types.h"
#include "lock0types.h"
#include "univ.i"
namespace locksys {
/** Calls visitor for each lock_t object which is a reason that wait_lock has to
wait. It is assumed that the wait_lock is waiting, and the caller has latched
the shard which contains the wait_lock
@param[in] wait_lock the waiting lock
@param[in] visitor a function to be called for each lock, s.t.
locksys::has_to_wait(wait_lock, lock) is true.
To stop iteration the visitor can return true, in which
case the lock for which it happened will be returned.
@return the first lock for which visitor returned true (in which case the search
ends) or nullptr if visitor never returned true (so all waiters were visited).*/
// TODO: this should use ut0function_reference.h or std::function_ref
const lock_t *find_blockers(const lock_t &wait_lock,
std::function<bool(const lock_t &)> visitor);
/** A helper method to access dict_table_t::locks list in a way which is
safe against the case another thread is trying to drop or truncate the table.
The main challenge it solves is how to do that without acquiring an MDL.
@param[in] table_id The id of the table, locks of which we want to visit
@param[in] visitor The visitor function which will be called for each lock
on the table.
It might be not called at all, in case the table is no
longer found in the hash, or has no locks.
If it is called, then it is called under protection of
shard mutex for this table_id.
To stop iteration the visitor can return true.
*/
void find_on_table(const table_id_t table_id,
std::function<bool(const lock_t &)> visitor);
} // namespace locksys
/** Iterates over all locks in the lock sys in a manner which guarantees that
all locks from the same lock queue are processed in a single critical section.*/
class All_locks_iterator {
public:
/** Processes a batch of one or more non-empty lock queues, calling the
provided function f for each lock in the queue, making sure that the queue is
not being modified during processing it.
Please note, that this means that the locks from a single lock queue visited
by f() present a consistent snapshot of this queue, however locks which reside
in different queues, may be inconsistent with each other, as they are observed
at different "times".
Also, this iterator does not guarantee reporting all locks in case the
lock-sys is being resized in parallel by lock_sys_resize() - resizing causes
the iterator to stop processing to avoid double-reporting.
@return true iff the iterator is done, and calling it again will not provide
any further results */
bool iterate_over_next_batch(
const std::function<void(const lock_t &lock)> &f);
private:
/** This iterator moves through the following stages, where the move to next
stage occurs when all locks from previous stage were reported. */
enum class stage_t {
/** iterator was just created (which does not cost much) */
NOT_STARTED,
/** iterating over LOCK_TABLE locks for tables from m_table_ids */
TABLE_LOCKS,
/** iterating over LOCK_PRDT_PAGE in lock_sys->prdt_page_hash */
PRDT_PAGE_LOCKS,
/** iterating over LOCK_PREDICATE locks in lock_sys->prdt_hash */
PRDT_LOCKS,
/** iterating over other (non-predicate) LOCK_RECORD locks in
lock_sys->rec_hash */
REC_LOCKS,
/** finished iterating, nothing more to see */
DONE,
};
/** The current stage this iterator is in. */
stage_t m_stage{stage_t::NOT_STARTED};
/** List of ids of all tables found in dict sys which are candidates for
inspection in TABLE_LOCKS stage */
std::vector<table_id_t> m_table_ids;
/** Tracks progress within a single stage: index of table in m_table_ids for
the TABLE_LOCKS stage, and cell of the hash_table for record locks.
It is reset to 0 at the beginning of each stage. */
size_t m_bucket_id{0};
/** The value of lock_sys->n_resizes is stored in this field at the begging
of stages involving iterating over lock sys hash tables so that we can spot
if the hash table got resized during our iteration and invalidate the iterator
*/
uint32_t m_lock_sys_n_resizes_at_the_beginning{0};
private:
/** Helper function for TABLE_LOCKS stage.
Calls f for all locks associated with m_table_ids[m_bucket_id].
@param[in] f function to apply to each lock
@return true iff it succeeded */
template <typename F>
bool iterate_over_current_table(F &&f);
/** Helper function for PRDT_PAGE_LOCKS, PRDT_LOCKS and REC_LOCKS stages.
Calls f for all locks associated with hash_table m_bucket_id-th cell.
@param[in] hash_table hash_table to inspect
@param[in] f function to apply to each lock
@return true iff it succeeded */
template <typename F>
bool iterate_over_current_cell(struct Locks_hashtable &hash_table, F &&f);
};
#endif /* lock0iter_h */
|