Skip to content

Commit b8c9939

Browse files
committed
Bug#29812659 DROPPED SHARE LIST KEY CONFLICT
The list of dropped shares can currently only hold one dropped NDB_SHARE instance for each key. This prevents NDB_SHARE instances with same key to be dropped several times while handlers are holding references to those NDB_SHARE instances. The intention with the list of dropped shares is to keep track of the memory allocated and be able to release it if MySQL Server shutdown without all handlers having released their references to the shares. Fix by changing the dropped share list to use a list type which allows more than one NDB_SHARE with same key to exists. Also rename the list variable to a shorter more descriptive name. Change-Id: Ie50f57b2274a2eff2ccdea94a0b09ca58f83f8d4
1 parent 6b56bc5 commit b8c9939

File tree

2 files changed

+52
-65
lines changed

2 files changed

+52
-65
lines changed

sql/ndb_share.cc

+52-64
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <iostream>
2828
#include <sstream>
29+
#include <unordered_set>
2930

3031
#include "m_string.h"
3132
#include "sql/ndb_conflict.h"
@@ -42,9 +43,13 @@
4243
extern Ndb* g_ndb;
4344
extern mysql_mutex_t ndbcluster_mutex;
4445

45-
/// Table lock handling
46+
// List of NDB_SHARE's which correspond to an open table.
4647
std::unique_ptr<collation_unordered_map<std::string, NDB_SHARE *>>
47-
ndbcluster_open_tables, ndbcluster_dropped_tables;
48+
ndbcluster_open_tables;
49+
50+
// List of NDB_SHARE's which have been dropped, they are kept in this list
51+
// until all references to them have been released.
52+
static std::unordered_set<NDB_SHARE*> dropped_shares;
4853

4954
NDB_SHARE*
5055
NDB_SHARE::create(const char* key)
@@ -674,58 +679,46 @@ NDB_SHARE::initialize(CHARSET_INFO* charset)
674679
ndbcluster_open_tables.reset
675680
(new collation_unordered_map<std::string, NDB_SHARE *>
676681
(charset, PSI_INSTRUMENT_ME));
677-
ndbcluster_dropped_tables.reset
678-
(new collation_unordered_map<std::string, NDB_SHARE *>
679-
(charset, PSI_INSTRUMENT_ME));
680682
}
681683

682684

683685
void
684686
NDB_SHARE::deinitialize(void)
685687
{
686-
{
687-
mysql_mutex_lock(&ndbcluster_mutex);
688-
auto save = ndbcluster_open_tables->size();
689-
(void)save;
690-
while (!ndbcluster_open_tables->empty())
691-
{
692-
NDB_SHARE *share= ndbcluster_open_tables->begin()->second;
693-
#ifndef DBUG_OFF
694-
fprintf(stderr,
695-
"NDB: table share %s with use_count %d state: %s(%u) still open\n",
696-
share->key_string(), share->use_count(),
697-
share->share_state_string(),
698-
(uint)share->state);
699-
#endif
688+
mysql_mutex_lock(&ndbcluster_mutex);
700689

701-
// If last ref, share is destructed, else moved to dropped_tables (see below)
702-
NDB_SHARE::mark_share_dropped(&share);
703-
}
704-
mysql_mutex_unlock(&ndbcluster_mutex);
705-
DBUG_ASSERT(save == 0);
690+
// There should not be any NDB_SHARE's left -> crash after logging in debug
691+
const class Debug_require {
692+
const bool m_required_val;
693+
694+
public:
695+
Debug_require(bool val) : m_required_val(val) {}
696+
~Debug_require() { DBUG_ASSERT(m_required_val); }
697+
} shares_remaining(ndbcluster_open_tables->empty() && dropped_shares.empty());
698+
699+
// Drop remaining open shares, drop one NDB_SHARE after the other
700+
// until open tables list is empty
701+
while (!ndbcluster_open_tables->empty()) {
702+
NDB_SHARE *share = ndbcluster_open_tables->begin()->second;
703+
ndb_log_error("Still open NDB_SHARE '%s', use_count: %d, state: %s",
704+
share->key_string(), share->use_count(),
705+
share->share_state_string());
706+
// If last ref, share is destroyed immediately, else moved to list of
707+
// dropped shares
708+
NDB_SHARE::mark_share_dropped(&share);
706709
}
707-
ndbcluster_open_tables->clear();
708710

709-
{
710-
mysql_mutex_lock(&ndbcluster_mutex);
711-
auto save = ndbcluster_dropped_tables->size();
712-
(void)save;
713-
while (!ndbcluster_dropped_tables->empty())
714-
{
715-
NDB_SHARE *share= ndbcluster_dropped_tables->begin()->second;
716-
#ifndef DBUG_OFF
717-
fprintf(stderr,
718-
"NDB: table share %s with use_count %d state: %s(%u) not freed\n",
719-
share->key_string(), share->use_count(),
720-
share->share_state_string(),
721-
(uint)share->state);
722-
#endif
723-
NDB_SHARE::real_free_share(&share);
724-
}
725-
mysql_mutex_unlock(&ndbcluster_mutex);
726-
DBUG_ASSERT(save == 0);
711+
// Release remaining dropped shares, release one NDB_SHARE after the other
712+
// until dropped list is empty
713+
while (!dropped_shares.empty()) {
714+
NDB_SHARE *share = *dropped_shares.begin();
715+
ndb_log_error("Not freed NDB_SHARE '%s', use_count: %d, state: %s",
716+
share->key_string(), share->use_count(),
717+
share->share_state_string());
718+
NDB_SHARE::real_free_share(&share);
727719
}
728-
ndbcluster_dropped_tables.reset();
720+
721+
mysql_mutex_unlock(&ndbcluster_mutex);
729722
}
730723

731724

@@ -756,14 +749,13 @@ void NDB_SHARE::real_free_share(NDB_SHARE **share_ptr) {
756749
ndbcluster::ndbrequire(share->state == NSS_DROPPED);
757750

758751
// Share must be in dropped list
759-
ndbcluster::ndbrequire(
760-
find_or_nullptr(*ndbcluster_dropped_tables, share->key_string()));
752+
ndbcluster::ndbrequire(dropped_shares.find(share) != dropped_shares.end());
761753

762754
// Remove share from dropped list
763-
ndbcluster::ndbrequire(ndbcluster_dropped_tables->erase(share->key_string()));
755+
ndbcluster::ndbrequire(dropped_shares.erase(share));
764756

765-
// Remove shares reference from 'ndbcluster_dropped_tables'
766-
share->refs_erase("ndbcluster_dropped_tables");
757+
// Remove shares reference from 'dropped_shares'
758+
share->refs_erase("dropped_shares");
767759

768760
NDB_SHARE::destroy(share);
769761
}
@@ -808,14 +800,16 @@ void NDB_SHARE::mark_share_dropped(NDB_SHARE **share_ptr) {
808800

809801
// Someone is still using the NDB_SHARE, insert it into the list of dropped
810802
// to keep track of it until all references has been released
811-
ndbcluster_dropped_tables->emplace(share->key_string(), share);
803+
dropped_shares.emplace(share);
812804

805+
#ifndef DBUG_OFF
813806
std::string s;
814807
share->debug_print(s, "\n");
815808
std::cerr << "dropped_share: " << s << std::endl;
809+
#endif
816810

817-
// Share is referenced by 'ndbcluster_dropped_tables'
818-
share->refs_insert("ndbcluster_dropped_tables");
811+
// Share is referenced by 'dropped_shares'
812+
share->refs_insert("dropped_shares");
819813
// NOTE! The refcount has not been incremented
820814
}
821815

@@ -836,14 +830,10 @@ NDB_SHARE::dbg_check_shares_update()
836830
}
837831

838832
ndb_log_info("dbug_check_shares dropped:");
839-
for (const auto &key_and_value : *ndbcluster_dropped_tables)
840-
{
841-
const NDB_SHARE *share= key_and_value.second;
842-
ndb_log_info(" %s.%s: state: %s(%u) use_count: %u",
843-
share->db, share->table_name,
844-
share->share_state_string(),
845-
(unsigned)share->state,
846-
share->use_count());
833+
for (const NDB_SHARE * share: dropped_shares) {
834+
ndb_log_info(" %s.%s: state: %s(%u) use_count: %u", share->db,
835+
share->table_name, share->share_state_string(),
836+
(unsigned)share->state, share->use_count());
847837
assert(share->state == NSS_DROPPED);
848838
}
849839

@@ -857,11 +847,9 @@ NDB_SHARE::dbg_check_shares_update()
857847
}
858848

859849
/**
860-
* Only shares in mysql database may be open...
850+
* Only shares in mysql database may be in dropped list...
861851
*/
862-
for (const auto &key_and_value : *ndbcluster_dropped_tables)
863-
{
864-
const NDB_SHARE *share= key_and_value.second;
852+
for (const NDB_SHARE *share : dropped_shares) {
865853
assert(strcmp(share->db, "mysql") == 0);
866854
}
867855
}

sql/ndb_share.h

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#ifndef NDB_SHARE_H
2626
#define NDB_SHARE_H
2727

28-
#include <stdio.h> // FILE, stderr
2928
#include <string>
3029
#ifndef DBUG_OFF
3130
#include <unordered_set>

0 commit comments

Comments
 (0)