Skip to content

Commit 54d003b

Browse files
blauddendahlerlend
authored andcommitted
Merge from mysql-trunk of:
BUG#35949017 Schema dist setup lockup Bug#35948153 Problem setting up events due to stale NdbApi dictionary cache [#2] Bug#35948153 Problem setting up events due to stale NdbApi dictionary cache [#1] Bug#32550019 Missing check for ndb_schema_result leads to schema dist timeout Change-Id: I4a32197992bf8b6899892f21587580788f828f34
1 parent 78c835a commit 54d003b

19 files changed

+148
-128
lines changed

mysql-test/suite/ndb_ddl/check_util_table_drop.inc

+9-11
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,15 @@ RESET BINARY LOGS AND GTIDS;
2626
--echo # Drop mysql.$util_table_name from NDB
2727
--exec $NDB_DROP_TABLE -d mysql $util_table_name
2828

29-
--connection mysqld1
30-
--echo # mysqld1: Wait until ready again...
31-
--source include/ndb_not_readonly.inc
32-
33-
--connection mysqld3
34-
--echo # mysqld3: Wait until ready again...
35-
--source include/ndb_not_readonly.inc
36-
37-
--connection mysqld5
38-
--echo # mysqld5: Wait until ready again...
39-
--source include/ndb_not_readonly.inc
29+
# Wait for all servers connected again
30+
let $i = 1;
31+
while($i <= $NUM_MYSQLDS)
32+
{
33+
--connection mysqld$i
34+
--echo # mysqld$i: Wait until ready again...
35+
--source include/ndb_not_readonly.inc
36+
inc $i;
37+
}
4038

4139
--connection mysqld5
4240
# NOTE! Neither drop of ndb_schema or ndb_schema_result should have a LOST_EVENT

mysql-test/suite/ndb_ddl/util_tables_drop.result

+9
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ Dropping table ndb_schema...OK
1414
NDBT_ProgramExit: 0 - OK
1515

1616
# mysqld1: Wait until ready again...
17+
# mysqld2: Wait until ready again...
1718
# mysqld3: Wait until ready again...
19+
# mysqld4: Wait until ready again...
1820
# mysqld5: Wait until ready again...
21+
# mysqld6: Wait until ready again...
1922
# Check if a LOST_EVENTS event was written to the binlog
2023
include/show_binlog_events.inc
2124
Log_name Pos Event_type Server_id End_log_pos Info
@@ -44,8 +47,11 @@ Dropping table ndb_apply_status...OK
4447
NDBT_ProgramExit: 0 - OK
4548

4649
# mysqld1: Wait until ready again...
50+
# mysqld2: Wait until ready again...
4751
# mysqld3: Wait until ready again...
52+
# mysqld4: Wait until ready again...
4853
# mysqld5: Wait until ready again...
54+
# mysqld6: Wait until ready again...
4955
# Check if a LOST_EVENTS event was written to the binlog
5056
include/show_binlog_events.inc
5157
Log_name Pos Event_type Server_id End_log_pos Info
@@ -76,8 +82,11 @@ Dropping table ndb_schema_result...OK
7682
NDBT_ProgramExit: 0 - OK
7783

7884
# mysqld1: Wait until ready again...
85+
# mysqld2: Wait until ready again...
7986
# mysqld3: Wait until ready again...
87+
# mysqld4: Wait until ready again...
8088
# mysqld5: Wait until ready again...
89+
# mysqld6: Wait until ready again...
8190
# Check if a LOST_EVENTS event was written to the binlog
8291
include/show_binlog_events.inc
8392
Log_name Pos Event_type Server_id End_log_pos Info

mysql-test/suite/ndbcluster/stale_schema_event.cnf

-12
This file was deleted.

mysql-test/suite/ndbcluster/stale_schema_event.result

-10
This file was deleted.

mysql-test/suite/ndbcluster/stale_schema_event.test

-59
This file was deleted.

storage/ndb/include/ndbapi/Ndb.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,9 @@ class Ndb {
22152215

22162216
static const char *externalizeTableName(const char *internalTableName,
22172217
bool fullyQualifiedNames);
2218+
static BaseString internalize_table_name(const char *db_name,
2219+
const char *schema,
2220+
const char *table_name);
22182221
const BaseString internalize_table_name(const char *external_name) const;
22192222

22202223
static const char *externalizeIndexName(const char *internalIndexName,

storage/ndb/include/ndbapi/NdbDictionary.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -2917,6 +2917,9 @@ class NdbDictionary {
29172917
int removeIndexGlobal(const Index &ndbidx, int invalidate) const;
29182918
int removeTableGlobal(const Table &ndbtab, int invalidate) const;
29192919
void invalidateDbGlobal(const char *dbname);
2920+
// Invalidate table by name if it exist in the cache
2921+
void invalidateTableGlobal(const char *dbName, const char *schemaName,
2922+
const char *tableName);
29202923
#endif
29212924

29222925
/*

storage/ndb/plugin/ha_ndbcluster_binlog.cc

+16-23
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,8 @@ bool Ndb_schema_dist_client::log_schema_op_impl(
11591159
}
11601160

11611161
// Check if schema distribution is still ready.
1162-
if (m_share->have_event_operation() == false) {
1162+
if (m_share->have_event_operation() == false ||
1163+
m_result_share->have_event_operation() == false) {
11631164
// This case is unlikely, but there is small race between
11641165
// clients first check for schema distribution ready and schema op
11651166
// registered in the coordinator(since the message is passed
@@ -1221,19 +1222,9 @@ static void ndbcluster_binlog_event_operation_teardown(THD *thd, Ndb *is_ndb,
12211222
Ndb_event_data::get_event_data(pOp->getCustomData());
12221223
NDB_SHARE *const share = event_data->share;
12231224

1224-
// Invalidate any cached NdbApi table if object version is lower
1225-
// than what was used when setting up the NdbEventOperation
1226-
// NOTE! This functionality need to be explained further
1227-
{
1228-
Thd_ndb *thd_ndb = get_thd_ndb(thd);
1229-
Ndb *ndb = thd_ndb->ndb;
1230-
Ndb_table_guard ndbtab_g(ndb, share->db, share->table_name);
1231-
const NDBTAB *ev_tab = pOp->getTable();
1232-
const NDBTAB *cache_tab = ndbtab_g.get_table();
1233-
if (cache_tab && cache_tab->getObjectId() == ev_tab->getObjectId() &&
1234-
cache_tab->getObjectVersion() <= ev_tab->getObjectVersion())
1235-
ndbtab_g.invalidate();
1236-
}
1225+
// Since table has been dropped or cluster connection lost the NdbApi table
1226+
// should be invalidated in the global dictionary cache
1227+
Ndb_table_guard::invalidate_table(is_ndb, share->db, share->table_name);
12371228

12381229
// Close the table in MySQL Server
12391230
ndb_tdc_close_cached_table(thd, share->db, share->table_name);
@@ -2270,9 +2261,8 @@ class Ndb_schema_event_handler {
22702261
void ndbapi_invalidate_table(const std::string &db_name,
22712262
const std::string &table_name) const {
22722263
DBUG_TRACE;
2273-
Ndb_table_guard ndbtab_g(m_thd_ndb->ndb, db_name.c_str(),
2274-
table_name.c_str());
2275-
ndbtab_g.invalidate();
2264+
Ndb_table_guard::invalidate_table(m_thd_ndb->ndb, db_name.c_str(),
2265+
table_name.c_str());
22762266
}
22772267

22782268
NDB_SHARE *acquire_reference(const std::string &db, const std::string &name,
@@ -3163,6 +3153,8 @@ class Ndb_schema_event_handler {
31633153
if (schema->node_id == own_nodeid()) return;
31643154

31653155
write_schema_op_to_binlog(m_thd, schema);
3156+
ndbapi_invalidate_table(schema->db, schema->name);
3157+
ndb_tdc_close_cached_table(m_thd, schema->db.c_str(), schema->name.c_str());
31663158

31673159
if (!create_table_from_engine(schema->db.c_str(), schema->name.c_str(),
31683160
true, /* force_overwrite */
@@ -4221,14 +4213,9 @@ class Ndb_schema_event_handler {
42214213
// take the GSL properly
42224214
assert(!m_thd_ndb->check_option(Thd_ndb::IS_SCHEMA_DIST_PARTICIPANT));
42234215

4224-
// Sleep here will make other mysql server in same cluster setup to create
4225-
// the schema result table in NDB before this mysql server. This also makes
4226-
// the create table in the connection thread to acquire GSL before the
4227-
// Binlog thread
4228-
DBUG_EXECUTE_IF("ndb_bi_sleep_before_gsl", sleep(1););
42294216
// Protect the setup with GSL(Global Schema Lock)
42304217
Ndb_global_schema_lock_guard global_schema_lock_guard(m_thd);
4231-
if (global_schema_lock_guard.lock()) {
4218+
if (!global_schema_lock_guard.try_lock()) {
42324219
ndb_log_info(" - failed to lock GSL");
42334220
return true;
42344221
}
@@ -5003,6 +4990,12 @@ static int ndbcluster_setup_binlog_for_share(THD *thd, Ndb *ndb,
50034990
return -1;
50044991
}
50054992
}
4993+
// The function that check if event exist will silently mark the NDB table
4994+
// definition as 'Invalid' when the event's table version does not match the
4995+
// cached NDB table definitions version. This indicates that the caller have
4996+
// used a stale version of the NDB table definition and is a problem which
4997+
// has to be fixed by the caller of this function.
4998+
assert(ndbtab->getObjectStatus() != NdbDictionary::Object::Invalid);
50064999

50075000
if (share->have_event_operation()) {
50085001
DBUG_PRINT("info", ("binlogging already setup"));

storage/ndb/plugin/ndb_dd_sync.cc

+3
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,9 @@ bool Ndb_dd_sync::synchronize_table(const char *schema_name,
11871187
const char *table_name) const {
11881188
ndb_log_verbose(1, "Synchronizing table '%s.%s'", schema_name, table_name);
11891189

1190+
// Invalidate potentially stale cached table
1191+
Ndb_table_guard::invalidate_table(m_thd_ndb->ndb, schema_name, table_name);
1192+
11901193
Ndb_table_guard ndbtab_g(m_thd_ndb->ndb, schema_name, table_name);
11911194
const NdbDictionary::Table *ndbtab = ndbtab_g.get_table();
11921195
if (!ndbtab) {

storage/ndb/plugin/ndb_metadata_sync.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,8 @@ bool Ndb_metadata_sync::sync_table(THD *thd, const std::string &schema_name,
913913
table_name.c_str());
914914

915915
// Invalidate the table in NdbApi
916-
Ndb_table_guard ndbtab_guard(ndb, schema_name.c_str(), table_name.c_str());
917-
ndbtab_guard.invalidate();
916+
Ndb_table_guard::invalidate_table(ndb, schema_name.c_str(),
917+
table_name.c_str());
918918
return true;
919919
}
920920

storage/ndb/plugin/ndb_schema_dist.cc

+19-2
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ bool Ndb_schema_dist_client::prepare(const char *db, const char *tabname) {
139139
return false;
140140
}
141141

142+
// Acquire reference also on mysql.ndb_schema_result
143+
m_result_share = NDB_SHARE::acquire_reference(
144+
Ndb_schema_result_table::DB_NAME.c_str(),
145+
Ndb_schema_result_table::TABLE_NAME.c_str(), m_share_reference.c_str());
146+
if (m_result_share == nullptr ||
147+
m_result_share->have_event_operation() == false) {
148+
// The mysql.ndb_schema_result hasn't been created or not setup yet ->
149+
// schema distribution is not ready
150+
push_warning(m_thd, Sql_condition::SL_WARNING, ER_GET_ERRMSG,
151+
"Schema distribution is not ready (ndb_schema_result)");
152+
return false;
153+
}
154+
142155
if (unlikely(m_ddl_blocked)) {
143156
// If a data node gets upgraded after this MySQL Server is upgraded, this
144157
// MySQL Server will not be aware of the upgrade due to Bug#30930132.
@@ -287,6 +300,10 @@ Ndb_schema_dist_client::~Ndb_schema_dist_client() {
287300
// Release the reference to mysql.ndb_schema table
288301
NDB_SHARE::release_reference(m_share, m_share_reference.c_str());
289302
}
303+
if (m_result_share) {
304+
// Release the reference to mysql.ndb_schema_result table
305+
NDB_SHARE::release_reference(m_result_share, m_share_reference.c_str());
306+
}
290307

291308
if (m_thd_ndb) {
292309
// Inform Applier that one schema distribution has completed
@@ -374,9 +391,9 @@ bool Ndb_schema_dist_client::log_schema_op(const char *query,
374391
return false;
375392
}
376393

377-
// Require that m_share has been initialized to reference the
378-
// schema distribution table
394+
// Require that references to schema distribution tables has been initialized
379395
ndbcluster::ndbrequire(m_share);
396+
ndbcluster::ndbrequire(m_result_share);
380397

381398
// Check that prepared keys match
382399
if (!m_prepared_keys.check_key(db, table_name)) {

storage/ndb/plugin/ndb_schema_dist.h

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class Ndb_schema_dist_client {
130130
class THD *const m_thd;
131131
class Thd_ndb *const m_thd_ndb;
132132
struct NDB_SHARE *m_share{nullptr};
133+
struct NDB_SHARE *m_result_share{nullptr};
133134
const std::string m_share_reference;
134135
class Prepared_keys {
135136
using Key = std::pair<std::string, std::string>;

storage/ndb/plugin/ndb_table_guard.h

+12
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ class Ndb_table_guard {
186186
}
187187

188188
const NdbError &getNdbError() const { return m_ndberror; }
189+
190+
/**
191+
@brief Invalidate table in the global dictionary cache (if it exists)
192+
without fetching table from NDB on cache miss, this saves one roundtrip.
193+
194+
This function is to be used to invalidate table when it's not already being
195+
held open.
196+
*/
197+
static void invalidate_table(Ndb *ndb, const char *dbname,
198+
const char *tabname) {
199+
ndb->getDictionary()->invalidateTableGlobal(dbname, "def", tabname);
200+
}
189201
};
190202

191203
#endif

storage/ndb/src/ndbapi/DictCache.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,35 @@ void GlobalDictCache::invalidateDb(const char *name, size_t len) {
360360
DBUG_VOID_RETURN;
361361
}
362362

363+
void GlobalDictCache::invalidateTable(const BaseString &internal_name) {
364+
DBUG_TRACE;
365+
DBUG_PRINT("enter", ("internal_name: '%s'", internal_name.c_str()));
366+
Vector<TableVersion> *vers =
367+
m_tableHash.getData(internal_name.c_str(), internal_name.length());
368+
if (vers == nullptr) {
369+
DBUG_PRINT("exit", ("nothing cached"));
370+
return;
371+
}
372+
373+
if (vers->size() == 0) {
374+
DBUG_PRINT("exit", ("no cached versions"));
375+
return;
376+
}
377+
378+
TableVersion *const ver = &vers->back();
379+
if (ver->m_status == RETREIVING) {
380+
DBUG_PRINT("exit", ("fresh version on the way"));
381+
return;
382+
}
383+
384+
ver->m_impl->m_status = NdbDictionary::Object::Invalid;
385+
ver->m_status = DROPPED;
386+
if (ver->m_refCount == 0) {
387+
delete ver->m_impl;
388+
vers->erase(vers->size() - 1);
389+
}
390+
}
391+
363392
void GlobalDictCache::release(const NdbTableImpl *tab, int invalidate) {
364393
DBUG_ENTER("GlobalDictCache::release");
365394
DBUG_PRINT("enter",

storage/ndb/src/ndbapi/DictCache.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class GlobalDictCache : public NdbLockable {
9494
}
9595

9696
void invalidateDb(const char *name, size_t len);
97+
void invalidateTable(const BaseString &name);
9798

9899
public:
99100
enum Status { OK = 0, DROPPED = 1, RETREIVING = 2 };

0 commit comments

Comments
 (0)