mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
ff16609374
There is a race condition related to the variable srv_stats.n_lock_wait_current_count, which is only incremented and decremented by the function lock_wait_suspend_thread(), The incrementing is protected by lock_sys->wait_mutex, but the decrementing does not appear to be protected by anything. This mismatch could allow the counter to be corrupted when a transactional InnoDB table or record lock wait is terminating roughly at the same time with the start of a wait on a (possibly different) lock. ib_counter_t: Remove some unused methods. Prevent instantiation for N=1. Add an inc() method that takes a slot index as a parameter. single_indexer_t: Remove. simple_counter<typename Type, bool atomic=false>: A new counter wrapper. Optionally use atomic memory operations for modifying the counter. Aligned to the cache line size. lsn_ctr_1_t, ulint_ctr_1_t, int64_ctr_1_t: Define as simple_counter<Type>. These counters are either only incremented (and we do not care about losing some increment operations), or the increment/decrement operations are protected by some mutex. srv_stats_t::os_log_pending_writes: Document that the number is protected by log_sys->mutex. srv_stats_t::n_lock_wait_current_count: Use simple_counter<ulint, true>, that is, atomic inc() and dec() operations. lock_wait_suspend_thread(): Release the mutexes before incrementing the counters. Avoid acquiring the lock mutex if the lock wait has already been resolved. Atomically increment and decrement srv_stats.n_lock_wait_current_count. row_insert_for_mysql(), row_update_for_mysql(), row_update_cascade_for_mysql(): Use the inc() method with the trx->id as the slot index. This is a non-functional change, just using inc() instead of add(1). buf_LRU_get_free_block(): Replace the method add(index, n) with inc(). There is no slot index in the simple_counter.
149 lines
4.3 KiB
C++
149 lines
4.3 KiB
C++
/*****************************************************************************
|
|
|
|
Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2017, 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, Suite 500, Boston, MA 02110-1335 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
/**************************************************//**
|
|
@file include/ut0counter.h
|
|
|
|
Counter utility class
|
|
|
|
Created 2012/04/12 by Sunny Bains
|
|
*******************************************************/
|
|
|
|
#ifndef UT0COUNTER_H
|
|
#define UT0COUNTER_H
|
|
|
|
#include "univ.i"
|
|
#include <string.h>
|
|
#include "os0thread.h"
|
|
#include "os0sync.h"
|
|
|
|
/** Default number of slots to use in ib_counter_t */
|
|
#define IB_N_SLOTS 64
|
|
|
|
/** Get the offset into the counter array. */
|
|
template <typename Type, int N>
|
|
struct generic_indexer_t {
|
|
/** @return offset within m_counter */
|
|
size_t offset(size_t index) const UNIV_NOTHROW {
|
|
return(((index % N) + 1) * (CACHE_LINE_SIZE / sizeof(Type)));
|
|
}
|
|
};
|
|
|
|
#ifdef HAVE_SCHED_GETCPU
|
|
#include <utmpx.h>
|
|
/** Use the cpu id to index into the counter array. If it fails then
|
|
use the thread id. */
|
|
template <typename Type, int N>
|
|
struct get_sched_indexer_t : public generic_indexer_t<Type, N> {
|
|
/* @return result from sched_getcpu(), the thread id if it fails. */
|
|
size_t get_rnd_index() const UNIV_NOTHROW {
|
|
|
|
size_t cpu = sched_getcpu();
|
|
if (cpu == -1) {
|
|
cpu = (lint) os_thread_get_curr_id();
|
|
}
|
|
|
|
return(cpu);
|
|
}
|
|
};
|
|
#endif /* HAVE_SCHED_GETCPU */
|
|
|
|
/** Use the thread id to index into the counter array. */
|
|
template <typename Type, int N>
|
|
struct thread_id_indexer_t : public generic_indexer_t<Type, N> {
|
|
/* @return a random number, currently we use the thread id. Where
|
|
thread id is represented as a pointer, it may not work as
|
|
effectively. */
|
|
size_t get_rnd_index() const UNIV_NOTHROW {
|
|
return((lint) os_thread_get_curr_id());
|
|
}
|
|
|
|
/** @return a random offset to the array */
|
|
size_t get_rnd_offset() const UNIV_NOTHROW
|
|
{
|
|
return(generic_indexer_t<Type, N>::offset(get_rnd_index()));
|
|
}
|
|
};
|
|
|
|
/** Class for using fuzzy counters. The counter is not protected by any
|
|
mutex and the results are not guaranteed to be 100% accurate but close
|
|
enough. Creates an array of counters and separates each element by the
|
|
CACHE_LINE_SIZE bytes */
|
|
template <
|
|
typename Type,
|
|
int N = IB_N_SLOTS,
|
|
template<typename, int> class Indexer = thread_id_indexer_t>
|
|
struct MY_ALIGNED(CACHE_LINE_SIZE) ib_counter_t
|
|
{
|
|
#ifdef UNIV_DEBUG
|
|
~ib_counter_t()
|
|
{
|
|
size_t n = (CACHE_LINE_SIZE / sizeof(Type));
|
|
|
|
/* Check that we aren't writing outside our defined bounds. */
|
|
for (size_t i = 0; i < UT_ARR_SIZE(m_counter); i += n) {
|
|
for (size_t j = 1; j < n - 1; ++j) {
|
|
ut_ad(m_counter[i + j] == 0);
|
|
}
|
|
}
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/** Increment the counter by 1. */
|
|
void inc() UNIV_NOTHROW { add(1); }
|
|
|
|
/** Increment the counter by 1.
|
|
@param[in] index a reasonably thread-unique identifier */
|
|
void inc(size_t index) UNIV_NOTHROW { add(index, 1); }
|
|
|
|
/** Add to the counter.
|
|
@param[in] n amount to be added */
|
|
void add(Type n) UNIV_NOTHROW { add(m_policy.get_rnd_offset(), n); }
|
|
|
|
/** Add to the counter.
|
|
@param[in] index a reasonably thread-unique identifier
|
|
@param[in] n amount to be added */
|
|
void add(size_t index, Type n) UNIV_NOTHROW {
|
|
size_t i = m_policy.offset(index);
|
|
|
|
ut_ad(i < UT_ARR_SIZE(m_counter));
|
|
|
|
m_counter[i] += n;
|
|
}
|
|
|
|
/* @return total value - not 100% accurate, since it is not atomic. */
|
|
operator Type() const UNIV_NOTHROW {
|
|
Type total = 0;
|
|
|
|
for (size_t i = 0; i < N; ++i) {
|
|
total += m_counter[m_policy.offset(i)];
|
|
}
|
|
|
|
return(total);
|
|
}
|
|
|
|
private:
|
|
/** Indexer into the array */
|
|
Indexer<Type, N>m_policy;
|
|
|
|
/** Slot 0 is unused. */
|
|
Type m_counter[(N + 1) * (CACHE_LINE_SIZE / sizeof(Type))];
|
|
};
|
|
|
|
#endif /* UT0COUNTER_H */
|