Skip to content

Commit fe4d285

Browse files
committed
Bug#30323907 DISTRIBUTED GRANTS TESTS DO NOT DO FULL CLEANUP
Improve the implementation of NDB stored grants so that additional cleanup after DROP USER is not necessary. In wl#12637, both "DROP USER ndb_u@h" and "REVOKE NDB_STORED_USER ON *.* FROM ndb_u@h" statements are stored permanently in ndb_sql_metadata. After this patch, only REVOKE statements are stored. A DROP USER statement now causes the user record in ndb_sql_metadata to be deleted. When an ACL change is distributed as SOT_ACL_SNAPSHOT, participating servers consider any user that is present in the list of snapshot users, but not in ndb_sql_metadata, to have been dropped. At startup time, a server considers any user that exists locally with NDB_STORED_USER privilege, but is not in ndb_sql_metadata, to have been dropped while the server was not running. The tests ndb.distributed_grants and ndb.apply_stored_grants both include REVOKE statements, so use ndb_delete_all to delete these from ndb_sql_metadata during test cleanup. Change-Id: I9de735017345ee0014fda1a1aa012b09a225b913
1 parent 5f8fe25 commit fe4d285

File tree

3 files changed

+71
-19
lines changed

3 files changed

+71
-19
lines changed

mysql-test/suite/ndb/t/apply_stored_grants.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# WL#12637 Distribute ACL changes in MySQL Cluster.
22
--source include/have_ndb.inc
3+
--source suite/ndb/include/ndb_find_tools.inc
34

45
# The ACL statements here are similar to distributed_grants.test, but mysql
56
# server 2 is shut down at the start of this test. When restarted, it applies
@@ -200,3 +201,7 @@ DROP USER ndb_u6@a;
200201
DROP ROLE R3;
201202

202203
DROP DATABASE auth_test_db;
204+
205+
# Delete the "REVOKE" statements left in ndb_sql_metadata
206+
--disable_result_log
207+
--exec $NDB_DELETE_ALL -d mysql ndb_sql_metadata

mysql-test/suite/ndb/t/distributed_grants.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# WL#12637 Distribute ACL changes in MySQL Cluster
22

33
--source include/have_ndb.inc
4+
--source suite/ndb/include/ndb_find_tools.inc
45

56
connection default;
67
--echo Connected to server1 as root
@@ -190,3 +191,7 @@ DROP USER ndb_u6@a;
190191
DROP ROLE R3;
191192

192193
DROP DATABASE auth_test_db;
194+
195+
# Delete the "REVOKE" statements left in ndb_sql_metadata
196+
--disable_result_log
197+
--exec $NDB_DELETE_ALL -d mysql ndb_sql_metadata

storage/ndb/plugin/ndb_stored_grants.cc

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ class ThreadContext : public Ndb_local_connection {
8787
void deserialize_users(std::string &);
8888
bool cache_was_rebuilt() const { return m_rebuilt_cache; }
8989
void serialize_snapshot_user_list(std::string *out_str);
90+
void consider_all_local_users_for_drop();
91+
void handle_dropped_users();
9092

9193
/* NDB Transactions */
9294
bool read_snapshot();
@@ -136,6 +138,7 @@ class ThreadContext : public Ndb_local_connection {
136138
Mem_root_array<char *> m_read_keys;
137139
Mem_root_array<unsigned short> m_grant_count;
138140
Mem_root_array<char *> m_current_rows;
141+
Mem_root_array<char *> m_delete_users;
139142
Mem_root_array<std::string> m_statement_users;
140143
Mem_root_array<std::string> m_intersection;
141144
Mem_root_array<std::string> m_extra_grants;
@@ -193,6 +196,7 @@ ThreadContext::ThreadContext(THD *thd)
193196
m_read_keys(&mem_root),
194197
m_grant_count(&mem_root),
195198
m_current_rows(&mem_root),
199+
m_delete_users(&mem_root),
196200
m_statement_users(&mem_root),
197201
m_intersection(&mem_root),
198202
m_extra_grants(&mem_root),
@@ -248,10 +252,7 @@ void ThreadContext::serialize_snapshot_user_list(std::string *out_str) {
248252
Sets m_read_keys to a set of buffers that can be used in NdbScanFilter
249253
*/
250254
void ThreadContext::deserialize_users(std::string &str) {
251-
/* As an optimization, prefer a complete snapshot refresh to a partial
252-
refresh of n users if n is greater than half. */
253-
int max = local_granted_users.size() / 2;
254-
int nfound = 0;
255+
unsigned long nfound = 0;
255256

256257
for (size_t pos = 0; pos < str.length();) {
257258
/* Find the 4th quote mark in 'user'@'host' */
@@ -262,18 +263,21 @@ void ThreadContext::deserialize_users(std::string &str) {
262263
}
263264
size_t len = end + 1 - pos;
264265
std::string user = str.substr(pos, len);
265-
if (get_local_user(user) && (++nfound > max)) {
266-
ndb_log_verbose(9, "deserialize_users() choosing complete refresh");
267-
m_read_keys.clear();
268-
return;
269-
}
266+
if (get_local_user(user)) nfound++;
267+
m_users_in_snapshot.push_back(user);
270268
{
271269
char *buf = getBuffer(len + 4);
272270
metadata_table.packName(buf, user);
273271
m_read_keys.push_back(buf);
274272
}
275273
pos = end + 2;
276274
}
275+
/* As an optimization, prefer a complete snapshot refresh to a partial
276+
refresh of n users if n is greater than half. */
277+
if (nfound > local_granted_users.size() / 2) {
278+
ndb_log_verbose(9, "deserialize_users() choosing complete refresh");
279+
m_read_keys.clear();
280+
}
277281
}
278282

279283
/* returns false on success */
@@ -483,12 +487,17 @@ const NdbError *store_snapshot(NdbTransaction *tx, ThreadContext *ctx) {
483487
}
484488

485489
/* write_snapshot()
486-
m_current_rows holds a set of USER and GRANT records to be written.
490+
487491
m_read_keys holds a list of USER records to read.
488492
m_grant_count holds the number of grants that will be stored for each user.
489493
m_read_keys and m_grant_count are in one-to-one correspondence.
490494
Any extraneous old grants for a user above m_grant_count will be deleted.
491-
After execute(), m_current_rows, m_read_keys, and m_grant_count are cleared.
495+
496+
m_current_rows holds a set of USER and GRANT records to be written.
497+
m_delete_users holds a set of USER records to be deleted.
498+
499+
After execute(), m_current_rows, m_read_keys, m_grant_count, and
500+
m_delete_users are all cleared.
492501
*/
493502
const NdbError *ThreadContext::write_snapshot(NdbTransaction *tx) {
494503
Mem_root_array<char *> read_results(&mem_root);
@@ -522,11 +531,17 @@ const NdbError *ThreadContext::write_snapshot(NdbTransaction *tx) {
522531
Buffer::writeTuple(row, tx);
523532
}
524533

534+
/* Delete user records for DROP USER */
535+
for (char *key : m_delete_users) {
536+
Buffer::deleteTuple(key, tx);
537+
}
538+
525539
bool r = tx->execute(Commit);
526540

527541
m_current_rows.clear();
528542
m_read_keys.clear();
529543
m_grant_count.clear();
544+
m_delete_users.clear();
530545

531546
return r ? &tx->getNdbError() : nullptr;
532547
}
@@ -557,13 +572,13 @@ int ThreadContext::update_users(const Mem_root_array<std::string> &list) {
557572
}
558573

559574
void ThreadContext::drop_user(std::string user, bool is_revoke) {
560-
std::string drop("DROP USER IF EXISTS ");
561-
std::string revoke("REVOKE NDB_STORED_USER ON *.* FROM ");
562-
std::string *s = is_revoke ? &revoke : &drop;
563-
std::string statement(*s + user);
564575
unsigned int zero = 0;
565-
566-
m_current_rows.push_back(Row(TYPE_USER, user, 0, &zero, statement));
576+
if (is_revoke) {
577+
std::string statement("REVOKE NDB_STORED_USER ON *.* FROM " + user);
578+
m_current_rows.push_back(Row(TYPE_USER, user, 0, &zero, statement));
579+
} else {
580+
m_delete_users.push_back(Key(TYPE_USER, user, 0));
581+
}
567582
m_read_keys.push_back(Key(TYPE_USER, user, 0));
568583
m_grant_count.push_back(0);
569584
m_users_in_snapshot.push_back(user);
@@ -628,7 +643,8 @@ void ThreadContext::create_user(std::string &name, std::string &statement) {
628643
run_acl_statement(revoke_all + name);
629644
}
630645

631-
/* Apply the snapshot in m_current_rows
646+
/* Apply the snapshot in m_current_rows,
647+
removing each applied user from m_users_in_snapshot.
632648
*/
633649
void ThreadContext::apply_current_snapshot() {
634650
for (const char *row : m_current_rows) {
@@ -646,14 +662,15 @@ void ThreadContext::apply_current_snapshot() {
646662
switch (type) {
647663
case TYPE_USER:
648664
m_applied_users++;
665+
m_users_in_snapshot.erase_value(name);
649666
is_null = !metadata_table.getNote(row, &note);
650667
if (is_null) {
651668
ndb_log_error("Unexpected NULL in ndb_sql_metadata table");
652669
}
653670
if (note > 0) {
654671
create_user(name, statement);
655672
} else {
656-
/* The user has been dropped, or had NDB_STORED_USER revoked */
673+
/* REVOKE NDB_STORED_USER ON *.* FROM user, or 8.0.18 DROP USER */
657674
if (get_local_user(name)) {
658675
run_acl_statement(statement);
659676
}
@@ -674,6 +691,28 @@ void ThreadContext::apply_current_snapshot() {
674691
for (std::string grant : m_extra_grants) run_acl_statement(grant);
675692
}
676693

694+
/* After apply_current_snapshot() has iteratively removed users from
695+
m_users_in_snapshot, any user remaining there must be dropped.
696+
*/
697+
void ThreadContext::handle_dropped_users() {
698+
const std::string drop("DROP USER IF EXISTS ");
699+
700+
for (std::string user : m_users_in_snapshot) {
701+
ndb_log_info("Dropping user %s not present in stored snapshot",
702+
user.c_str());
703+
run_acl_statement(drop + user);
704+
}
705+
}
706+
707+
/* At server startup time, any local user with NDB_STORED_USER may have
708+
been dropped while the server was down, so m_users_in_snapshot is
709+
initialized with the whole list of local users.
710+
*/
711+
void ThreadContext::consider_all_local_users_for_drop() {
712+
for (std::string user : local_granted_users)
713+
m_users_in_snapshot.push_back(user);
714+
}
715+
677716
void ThreadContext::write_status_message_to_server_log() {
678717
ndb_log_info("From NDB stored grants, applied %zu grant%s for %zu user%s.",
679718
m_applied_grants, (m_applied_grants == 1 ? "" : "s"),
@@ -862,8 +901,10 @@ bool Ndb_stored_grants::apply_stored_grants(THD *thd) {
862901

863902
(void)context.build_cache_of_ndb_users();
864903

904+
context.consider_all_local_users_for_drop();
865905
context.apply_current_snapshot();
866906
context.write_status_message_to_server_log();
907+
context.handle_dropped_users();
867908
return true; // success
868909
}
869910

@@ -916,5 +957,6 @@ bool Ndb_stored_grants::update_users_from_snapshot(THD *thd,
916957

917958
(void)context.build_cache_of_ndb_users();
918959
context.apply_current_snapshot();
960+
context.handle_dropped_users();
919961
return true; // success
920962
}

0 commit comments

Comments
 (0)