Skip to content

Commit a24dffd

Browse files
committed
Fixed RocksDB to follow THD ha_data protocol
Use thd_get_ha_data()/thd_set_ha_data() which protect against plugin removal until it has THD ha_data. Do not reset THD ha_data in rocksdb_close_connection(), cleaner approach is to let ha_close_connection() do it. Removed transaction objects cleanup from rocksdb_done_func(). As we lock plugin properly, there must be no transaction objects during RocksDB shutdown.
1 parent 8a880d6 commit a24dffd

File tree

4 files changed

+30
-67
lines changed

4 files changed

+30
-67
lines changed

storage/rocksdb/ha_rocksdb.cc

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3290,9 +3290,9 @@ void Rdb_snapshot_notifier::SnapshotCreated(
32903290
std::multiset<Rdb_transaction *> Rdb_transaction::s_tx_list;
32913291
mysql_mutex_t Rdb_transaction::s_tx_list_mutex;
32923292

3293-
static Rdb_transaction *&get_tx_from_thd(THD *const thd) {
3294-
return *reinterpret_cast<Rdb_transaction **>(
3295-
my_core::thd_ha_data(thd, rocksdb_hton));
3293+
static Rdb_transaction *get_tx_from_thd(THD *const thd) {
3294+
return reinterpret_cast<Rdb_transaction *>(
3295+
my_core::thd_get_ha_data(thd, rocksdb_hton));
32963296
}
32973297

32983298
namespace {
@@ -3339,7 +3339,7 @@ class Rdb_perf_context_guard {
33393339
*/
33403340

33413341
static Rdb_transaction *get_or_create_tx(THD *const thd) {
3342-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3342+
Rdb_transaction *tx = get_tx_from_thd(thd);
33433343
// TODO: this is called too many times.. O(#rows)
33443344
if (tx == nullptr) {
33453345
bool rpl_skip_tx_api= false; // MARIAROCKS_NOT_YET.
@@ -3354,6 +3354,7 @@ static Rdb_transaction *get_or_create_tx(THD *const thd) {
33543354
}
33553355
tx->set_params(THDVAR(thd, lock_wait_timeout), THDVAR(thd, max_row_locks));
33563356
tx->start_tx();
3357+
my_core::thd_set_ha_data(thd, rocksdb_hton, tx);
33573358
} else {
33583359
tx->set_params(THDVAR(thd, lock_wait_timeout), THDVAR(thd, max_row_locks));
33593360
if (!tx->is_tx_started()) {
@@ -3365,7 +3366,7 @@ static Rdb_transaction *get_or_create_tx(THD *const thd) {
33653366
}
33663367

33673368
static int rocksdb_close_connection(handlerton *const hton, THD *const thd) {
3368-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3369+
Rdb_transaction *tx = get_tx_from_thd(thd);
33693370
if (tx != nullptr) {
33703371
int rc = tx->finish_bulk_load(false);
33713372
if (rc != 0) {
@@ -3376,7 +3377,6 @@ static int rocksdb_close_connection(handlerton *const hton, THD *const thd) {
33763377
}
33773378

33783379
delete tx;
3379-
tx = nullptr;
33803380
}
33813381
return HA_EXIT_SUCCESS;
33823382
}
@@ -3444,7 +3444,7 @@ static int rocksdb_prepare(handlerton* hton, THD* thd, bool prepare_tx)
34443444
{
34453445
bool async=false; // This is "ASYNC_COMMIT" feature which is only present in webscalesql
34463446

3447-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3447+
Rdb_transaction *tx = get_tx_from_thd(thd);
34483448
if (!tx->can_prepare()) {
34493449
return HA_EXIT_FAILURE;
34503450
}
@@ -3695,7 +3695,7 @@ static void rocksdb_commit_ordered(handlerton *hton, THD* thd, bool all)
36953695
// Same assert as InnoDB has
36963696
DBUG_ASSERT(all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT |
36973697
OPTION_BEGIN)));
3698-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3698+
Rdb_transaction *tx = get_tx_from_thd(thd);
36993699
if (!tx->is_two_phase()) {
37003700
/*
37013701
ordered_commit is supposedly slower as it is done sequentially
@@ -3727,7 +3727,7 @@ static int rocksdb_commit(handlerton* hton, THD* thd, bool commit_tx)
37273727
rocksdb::StopWatchNano timer(rocksdb::Env::Default(), true);
37283728

37293729
/* note: h->external_lock(F_UNLCK) is called after this function is called) */
3730-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3730+
Rdb_transaction *tx = get_tx_from_thd(thd);
37313731

37323732
/* this will trigger saving of perf_context information */
37333733
Rdb_perf_context_guard guard(tx, rocksdb_perf_context_level(thd));
@@ -3800,7 +3800,7 @@ static int rocksdb_commit(handlerton* hton, THD* thd, bool commit_tx)
38003800

38013801
static int rocksdb_rollback(handlerton *const hton, THD *const thd,
38023802
bool rollback_tx) {
3803-
Rdb_transaction *&tx = get_tx_from_thd(thd);
3803+
Rdb_transaction *tx = get_tx_from_thd(thd);
38043804
Rdb_perf_context_guard guard(tx, rocksdb_perf_context_level(thd));
38053805

38063806
if (tx != nullptr) {
@@ -4607,7 +4607,7 @@ static int rocksdb_savepoint(handlerton *const hton, THD *const thd,
46074607

46084608
static int rocksdb_rollback_to_savepoint(handlerton *const hton, THD *const thd,
46094609
void *const savepoint) {
4610-
Rdb_transaction *&tx = get_tx_from_thd(thd);
4610+
Rdb_transaction *tx = get_tx_from_thd(thd);
46114611
return tx->rollback_to_savepoint(savepoint);
46124612
}
46134613

@@ -5346,49 +5346,6 @@ static int rocksdb_done_func(void *const p) {
53465346
error = 1;
53475347
}
53485348

5349-
/*
5350-
MariaDB: When the plugin is unloaded with UNINSTALL SONAME command, some
5351-
connections may still have Rdb_transaction objects.
5352-
5353-
These objects are not genuine transactions (as SQL layer makes sure that
5354-
a plugin that is being unloaded has no open tables), they are empty
5355-
Rdb_transaction objects that were left there to save on object
5356-
creation/deletion.
5357-
5358-
Go through the list and delete them.
5359-
*/
5360-
{
5361-
class Rdb_trx_deleter: public Rdb_tx_list_walker {
5362-
public:
5363-
std::set<Rdb_transaction*> rdb_trxs;
5364-
5365-
void process_tran(const Rdb_transaction *const tx) override {
5366-
/*
5367-
Check if the transaction is really empty. We only check
5368-
non-WriteBatch-based transactions, because there is no easy way to
5369-
check WriteBatch-based transactions.
5370-
*/
5371-
if (!tx->is_writebatch_trx()) {
5372-
const auto tx_impl = static_cast<const Rdb_transaction_impl *>(tx);
5373-
DBUG_ASSERT(tx_impl);
5374-
if (tx_impl->get_rdb_trx())
5375-
DBUG_ASSERT(0);
5376-
}
5377-
rdb_trxs.insert((Rdb_transaction*)tx);
5378-
};
5379-
} deleter;
5380-
5381-
Rdb_transaction::walk_tx_list(&deleter);
5382-
5383-
for (std::set<Rdb_transaction*>::iterator it= deleter.rdb_trxs.begin();
5384-
it != deleter.rdb_trxs.end();
5385-
++it)
5386-
{
5387-
// When a transaction is deleted, it removes itself from s_tx_list.
5388-
delete *it;
5389-
}
5390-
}
5391-
53925349
/*
53935350
destructors for static objects can be called at _exit(),
53945351
but we want to free the memory at dlclose()
@@ -13831,7 +13788,7 @@ int rocksdb_check_bulk_load(
1383113788
return 1;
1383213789
}
1383313790

13834-
Rdb_transaction *&tx = get_tx_from_thd(thd);
13791+
Rdb_transaction *tx = get_tx_from_thd(thd);
1383513792
if (tx != nullptr) {
1383613793
const int rc = tx->finish_bulk_load();
1383713794
if (rc != 0) {

storage/rocksdb/mysql-test/rocksdb/r/mariadb_plugin.result

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
# MDEV-14843: Assertion `s_tx_list.size() == 0' failed in myrocks::Rdb_transaction::term_mutex
33
#
44
INSTALL SONAME 'ha_rocksdb';
5+
connect con1,localhost,root,,test;
56
CREATE TABLE t1 (i INT) ENGINE=RocksDB;
67
insert into t1 values (1);
7-
connect con1,localhost,root,,;
8-
connection con1;
9-
insert into test.t1 values (1);
10-
connection default;
118
DROP TABLE t1;
9+
connection default;
1210
UNINSTALL SONAME 'ha_rocksdb';
11+
Warnings:
12+
Warning 1620 Plugin is busy and will be uninstalled on shutdown
13+
SELECT ENGINE, SUPPORT FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='ROCKSDB';
14+
ENGINE SUPPORT
15+
ROCKSDB NO
16+
disconnect con1;
1317
#
1418
# MDEV-15686: Loading MyRocks plugin back after it has been unloaded causes a crash
1519
#

storage/rocksdb/mysql-test/rocksdb/t/mariadb_plugin.test

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@
1414
INSTALL SONAME 'ha_rocksdb';
1515
--enable_warnings
1616

17+
connect (con1,localhost,root,,test);
1718
CREATE TABLE t1 (i INT) ENGINE=RocksDB;
1819
insert into t1 values (1);
19-
20-
connect (con1,localhost,root,,);
21-
connection con1;
22-
insert into test.t1 values (1);
20+
DROP TABLE t1;
2321

2422
connection default;
25-
2623
# Cleanup
27-
DROP TABLE t1;
2824
UNINSTALL SONAME 'ha_rocksdb';
25+
SELECT ENGINE, SUPPORT FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE='ROCKSDB';
26+
disconnect con1;
27+
# Unfortunately this is the only more or less reliable way to wait until
28+
# connection done ha_close_connections().
29+
let $wait_condition= SELECT VARIABLE_VALUE=1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='Threads_cached';
30+
--source include/wait_condition.inc
2931

3032
--echo #
3133
--echo # MDEV-15686: Loading MyRocks plugin back after it has been unloaded causes a crash

storage/rocksdb/rdb_utils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ namespace myrocks {
5252
Since we cannot or don't want to change the API in any way, we can use this
5353
mechanism to define readability tokens that look like C++ namespaces, but are
5454
not enforced in any way by the compiler, since the pre-compiler strips them
55-
out. However, on the calling side, code looks like my_core::thd_ha_data()
56-
rather than plain a thd_ha_data() call. This technique adds an immediate
55+
out. However, on the calling side, code looks like my_core::thd_get_ha_data()
56+
rather than plain a thd_get_ha_data() call. This technique adds an immediate
5757
visible cue on what type of API we are calling into.
5858
*/
5959

0 commit comments

Comments
 (0)