forked from percona/percona-xtrabackup
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug#30050452: CRASH WHEN EXECUTING "SELECT SLEEP(10)" THROUGH CURSOR …
…(WITH THREAD-POOL) Problem: * TempTable segfaults in certain scenarios when ThreadPool (TP) plugin is used. * Cursor-protocol only accentuates the crash condition more. Analysis: * TempTable implements two of its critical parts through the means of thread-local variables, namely its data-backend (storage for tables) and custom memory allocator. * This becomes a design and functional issue as soon as MySQL server is run with the ThreadPool (TP) plugin because presence of that plugin will change the traditional thread-handling MySQL model, which is 1-thread-per-client-connection, to the alternative model where this assumption no longer holds and code relying on such assumption automatically becomes broken. * In particular, TP plugin will not be allocating a new thread for each new connection arriving but instead it will pick a thread from pre-allocated pool of threads and assign one to the statement execution engine. * In practice, this means that it is possible that statements within one client connection are now served with a multitude of different threads (but not simultaneously), which with traditional thread-handling model, such condition was not possible (it was always the same thread). * Furthermore, cursor-protocol makes it possible that even an execution of a single statement within one client connection is served by different threads. * E.g. Cursor-protocol enables fetching the result set of a query (data) in chunks. And TP plugin makes a situation possible where each chunk is fetched from a different thread. * TL;DR thread-local-storage variables cannot really co-exist with TP plugin in their natural form. Solution: * Replace TempTable parts which are implemented in terms of thread-local-storage variables with a solution which: * Is functionally correct in both cases, with and without TP plugin running. * Does not sacrifice the overall performance at any rate. * Does not lock the design but keeps the door open for future advancements (e.g. more control over memory consumption). * Basic idea is to: * Organize data-backend (table-storage) into shards * Ditto for shared-blocks (custom memory allocator external state) * Use unique connection identifier to map between connections and their corresponding shards Addendum: * This patch also fixes some other issues which have been reported but which are directly or indirectly caused by the same limitation in design: * BUG #30050420 CRASHES WHEN CLOSING CONNECTION WITH UNCLOSED CURSOR (WITH THREAD-POOL) * BUG #31116036 TEMPTABLE WASTES 1MB FOR EACH CONNECTION IN THREAD CACHE * BUG #31471863 TEMPTABLE ENGINE USES MUCH MORE MEMORY THAN MEMORY ENGINE FOR TEMPORARY TABLE Reviewed-by: Pawel Olchawa <[email protected]> RB: 24497
- Loading branch information
Jusufadis Bakamovic
committed
Jun 10, 2020
1 parent
6875535
commit 6653b43
Showing
22 changed files
with
1,408 additions
and
319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* Copyright (c) 2020, 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, 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 */ | ||
|
||
/** @file storage/temptable/include/temptable/kv_store.h | ||
TempTable key-value store implementation. */ | ||
|
||
#ifndef TEMPTABLE_KV_STORE_H | ||
#define TEMPTABLE_KV_STORE_H | ||
|
||
#include <shared_mutex> | ||
#include <string> | ||
#include <unordered_map> | ||
|
||
#include "storage/temptable/include/temptable/constants.h" | ||
#include "storage/temptable/include/temptable/kv_store_logger.h" | ||
|
||
namespace temptable { | ||
|
||
/** Forward-declarations. */ | ||
class Table; | ||
|
||
/** Key-value store, a convenience wrapper class which models a thread-safe | ||
* dictionary type. | ||
* | ||
* Thread-safety is accomplished by using a `Lock` which can be any of the usual | ||
* mutual exclusive algorithms from C++ thread-support library or any other | ||
* which satisfy C++ concurrency named requirements. E.g. mutex, timed_mutex, | ||
* recursive_mutex, recursive_timed_mutex, shared_mutex, shared_timed_mutex, ... | ||
* User code can opt-in for any of those. Also, whether the actual | ||
* implementation will use shared-locks or exclusive-locks (for read-only | ||
* operations) is handled automagically by this class. | ||
* | ||
* Furthermore, user code can similarly opt-in for different key-value | ||
* implementation but whose interface is compatible with the one of | ||
* std::unordered_map. | ||
* */ | ||
template <typename Lock, | ||
template <typename...> class KeyValueImpl = std::unordered_map> | ||
class Key_value_store | ||
: public Key_value_store_logger<Key_value_store<Lock, KeyValueImpl>, | ||
DEBUG_BUILD> { | ||
/** Do not break encapsulation when using CRTP. */ | ||
friend struct Key_value_store_logger<Key_value_store<Lock, KeyValueImpl>, | ||
DEBUG_BUILD>; | ||
|
||
/** Help ADL to bring debugging/logging symbols into the scope. */ | ||
using Key_value_store_logger<Key_value_store<Lock, KeyValueImpl>, | ||
DEBUG_BUILD>::dbug_print; | ||
using Key_value_store_logger<Key_value_store<Lock, KeyValueImpl>, | ||
DEBUG_BUILD>::log; | ||
|
||
/** Check whether we can use shared locks (which enable multiple concurrent | ||
* readers) or must we rather fallback to exclusive locks. Shared-locks will | ||
* be used only during read-only operations. | ||
* */ | ||
using Exclusive_or_shared_lock = | ||
std::conditional_t<std::is_same<Lock, std::shared_timed_mutex>::value, | ||
std::shared_lock<Lock>, std::lock_guard<Lock>>; | ||
|
||
/** Alias for our key-value store implementation. */ | ||
using Key_value_store_impl = KeyValueImpl<std::string, Table>; | ||
|
||
/** Container holding (table-name, Table) tuples. */ | ||
Key_value_store_impl m_kv_store; | ||
|
||
/** Lock type. */ | ||
Lock m_lock; | ||
|
||
public: | ||
/** Inserts a new table into the container constructed in-place with the | ||
* given args if there is no table with the key in the container. | ||
* | ||
* [in] args Arguments to forward to the constructor of the table. | ||
* @return Returns a pair consisting of an iterator to the inserted table, | ||
* or the already-existing table if no insertion happened, and a bool | ||
* denoting whether the insertion took place (true if insertion happened, | ||
* false if it did not). | ||
* */ | ||
template <class... Args> | ||
std::pair<typename Key_value_store_impl::iterator, bool> emplace( | ||
Args &&... args) { | ||
std::lock_guard<Lock> lock(m_lock); | ||
dbug_print(); | ||
log(Key_value_store_stats::Event::EMPLACE); | ||
return m_kv_store.emplace(args...); | ||
} | ||
|
||
/** Searches for a table with given name (key). | ||
* | ||
* [in] key Name of a table to search for. | ||
* @return Pointer to table if found, nullptr otherwise. | ||
* */ | ||
Table *find(const std::string &key) { | ||
Exclusive_or_shared_lock lock(m_lock); | ||
auto iter = m_kv_store.find(key); | ||
if (iter != m_kv_store.end()) { | ||
return &iter->second; | ||
} else { | ||
return nullptr; | ||
} | ||
} | ||
|
||
/** Removes the table (if one exists) with the given name (key). | ||
* | ||
* [in] key Name of a table to remove.. | ||
* @return Number of elements removed. | ||
* */ | ||
typename Key_value_store_impl::size_type erase(const std::string &key) { | ||
std::lock_guard<Lock> lock(m_lock); | ||
dbug_print(); | ||
log(Key_value_store_stats::Event::ERASE); | ||
return m_kv_store.erase(key); | ||
} | ||
}; | ||
|
||
} // namespace temptable | ||
|
||
#endif /* TEMPTABLE_KV_STORE_H */ |
Oops, something went wrong.