MXS-2794: Log changes in loaded users

By checking whether the users have changed whenever they are reloaded, we
improve the visibility of the user reloading process. Using a checksum
allows us to easily compress the information with acceptable loss of
accuracy. Using a CAS loop prevents duplicate messages without losing any
updates even if multiple user reloads result in different outcomes.
This commit is contained in:
Markus Mäkelä 2019-12-10 08:40:07 +02:00
parent e36c7efa25
commit cb4e43b05a
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
3 changed files with 40 additions and 6 deletions

View File

@ -1143,6 +1143,42 @@ bool query_and_process_users(const char* query, MYSQL* con, SERVICE* service, in
return rval;
}
void log_loaded_users(MYSQL_AUTH* instance, SERVICE* service, Listener* port, SERVER* srv,
const std::vector<User>& userlist, const std::vector<std::string>& dblist)
{
uint64_t c = crc32(0, 0, 0);
for (const auto& user : userlist)
{
c = crc32(c, (uint8_t*)user.user.c_str(), user.user.length());
c = crc32(c, (uint8_t*)user.host.c_str(), user.host.length());
c = crc32(c, (uint8_t*)user.db.c_str(), user.db.length());
uint8_t anydb = user.anydb;
c = crc32(c, &anydb, sizeof(anydb));
c = crc32(c, (uint8_t*)user.pw.c_str(), user.pw.length());
}
for (const auto& db : dblist)
{
c = crc32(c, (uint8_t*)db.c_str(), db.length());
}
uint64_t old_c = instance->checksum;
while (old_c != c)
{
if (mxb::atomic::compare_exchange(&instance->checksum, &old_c, c,
mxb::atomic::RELAXED, mxb::atomic::RELAXED))
{
MXS_NOTICE("[%s] Loaded %lu MySQL users for listener '%s' from server '%s' with checksum 0x%0lx.",
service->name(), userlist.size(), port->name(), srv->name(), c);
break;
}
old_c = instance->checksum;
}
}
int get_users_from_server(MYSQL* con, SERVER* server, SERVICE* service, Listener* listener)
{
auto server_version = server->version();
@ -1216,6 +1252,8 @@ int get_users_from_server(MYSQL* con, SERVER* server, SERVICE* service, Listener
if (rv)
{
log_loaded_users(instance, service, listener, server, userlist, dblist);
auto func = [instance, userlist, dblist]() {
sqlite3* handle = get_handle(instance);

View File

@ -192,6 +192,7 @@ static void* mysql_auth_init(char** options)
instance->skip_auth = false;
instance->check_permissions = true;
instance->lower_case_table_names = false;
instance->checksum = 0;
for (int i = 0; options[i]; i++)
{
@ -820,12 +821,6 @@ static int mysql_auth_load_users(Listener* port)
" will probably fail as a result.",
service->name());
}
else if (loaded > 0 && first_load)
{
mxb_assert(srv);
MXS_NOTICE("[%s] Loaded %d MySQL users for listener %s from server %s.",
service->name(), loaded, port->name(), srv->name());
}
return rc;
}

View File

@ -112,6 +112,7 @@ typedef struct mysql_auth
bool skip_auth; /**< Authentication will always be successful */
bool check_permissions;
bool lower_case_table_names; /**< Disable database case-sensitivity */
uint64_t checksum;
} MYSQL_AUTH;
/**