Skip to content

Commit 60a65b3

Browse files
Merge pull request #5452 from kamil-holubicki/PS-9382-8.0
PS-9453: percona_telemetry causes a long wait on COND_thd_list due to the absence of the root user
2 parents 73ddb41 + 22edfb4 commit 60a65b3

20 files changed

+226
-40
lines changed

components/percona_telemetry/data_provider.cc

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
namespace {
2424
inline const char *b2s(bool val) { return val ? "1" : "0"; }
2525

26+
/*
27+
mysql.session user is mostly enough, but it lacks the following privileges:
28+
29+
1. REPLICATION SLAVE
30+
2. REPLICATION CLIENT
31+
3. SELECT on mysql.component
32+
4. SELECT on performance_schema.replication_group_members
33+
34+
These privileges are added at server startup in setup_percona_telemetry()
35+
if Percona telemetry is enabled.
36+
*/
37+
constexpr const char default_command_user_name[] = "mysql.session";
38+
constexpr const char default_command_host_name[] = "localhost";
39+
2640
namespace JSONKey {
2741
const char *pillar_version = "pillar_version";
2842
const char *db_instance_id = "db_instance_id";
@@ -120,25 +134,29 @@ bool DataProvider::do_query(const std::string &query, QueryResult *result,
120134
}
121135
result->clear();
122136

137+
/* command_factory_service_.init() allocates memory for mysql_h
138+
We need to call close() always.
139+
Even if init() fails, becaues it doesn't allocate anything, calling close()
140+
is safe, because internally it checks if provided pointer is valid
141+
*/
142+
std::shared_ptr<MYSQL_H> mysql_h_close_guard(
143+
&mysql_h, [&srv = command_factory_service_](MYSQL_H *ptr) {
144+
srv.close(*ptr);
145+
});
146+
123147
mysql_service_status_t sstatus = command_factory_service_.init(&mysql_h);
148+
124149
if (!sstatus)
125150
sstatus |=
126151
command_options_service_.set(mysql_h, MYSQL_COMMAND_PROTOCOL, nullptr);
127152
if (!sstatus)
128-
sstatus |=
129-
command_options_service_.set(mysql_h, MYSQL_COMMAND_USER_NAME, "root");
153+
sstatus |= command_options_service_.set(mysql_h, MYSQL_COMMAND_USER_NAME,
154+
default_command_user_name);
130155
if (!sstatus)
131-
sstatus |=
132-
command_options_service_.set(mysql_h, MYSQL_COMMAND_HOST_NAME, nullptr);
156+
sstatus |= command_options_service_.set(mysql_h, MYSQL_COMMAND_HOST_NAME,
157+
default_command_host_name);
133158
if (!sstatus) sstatus |= command_factory_service_.connect(mysql_h);
134159

135-
// starting from this point, if the above succeeded we need to close mysql_h.
136-
std::shared_ptr<void> mysql_h_close_guard(
137-
mysql_h,
138-
[&srv = command_factory_service_, do_close = !sstatus](void *ptr) {
139-
if (do_close && ptr) srv.close(static_cast<MYSQL_H>(ptr));
140-
});
141-
142160
// if any of the above failed, just exit
143161
if (sstatus) {
144162
goto err;
@@ -212,7 +230,7 @@ bool DataProvider::collect_db_instance_id_info(rapidjson::Document *document) {
212230
so the SQL query failed. It will recover next time.
213231
2. Some other reason that caused selecting server_id to fail. */
214232
if (id.length() == 0) {
215-
logger_.warning(
233+
logger_.info(
216234
"Collecting db_instance_id failed. It may be caused by server still "
217235
"initializing.");
218236
return true;
@@ -346,7 +364,7 @@ bool DataProvider::collect_se_usage_info(rapidjson::Document *document) {
346364
QueryResult result;
347365
if (do_query("SELECT DISTINCT ENGINE FROM information_schema.tables WHERE "
348366
"table_schema NOT IN('mysql', 'information_schema', "
349-
"'performance_schema', 'sys');",
367+
"'performance_schema', 'sys')",
350368
&result)) {
351369
return true;
352370
}

mysql-test/r/grant.result

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,9 @@ show grants for mysqltest_8;
831831
Grants for mysqltest_8@%
832832
GRANT USAGE ON *.* TO `mysqltest_8`@`%`
833833
GRANT UPDATE ON `test`.`t1` TO `mysqltest_8`@`%`
834-
select * from information_schema.table_privileges where table_schema NOT IN ('sys','mysql');
834+
select * from information_schema.table_privileges where table_schema NOT IN ('sys','mysql')
835+
and not (grantee = "'mysql.session'@'localhost'"
836+
and table_name in ('component', 'replication_group_members'));
835837
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
836838
'mysqltest_8'@'%' def test t1 UPDATE NO
837839
'mysqltest_8'@'' def test t1 UPDATE NO
@@ -845,7 +847,9 @@ GRANT USAGE ON *.* TO `mysqltest_8`@``
845847
show grants for mysqltest_8;
846848
Grants for mysqltest_8@%
847849
GRANT USAGE ON *.* TO `mysqltest_8`@`%`
848-
select * from information_schema.table_privileges where table_schema NOT IN ('sys','mysql');
850+
select * from information_schema.table_privileges where table_schema NOT IN ('sys','mysql')
851+
and not (grantee = "'mysql.session'@'localhost'"
852+
and table_name in ('component', 'replication_group_members'));
849853
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
850854
flush privileges;
851855
show grants for mysqltest_8@'';

mysql-test/r/information_schema_ci.result

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,9 @@ grant select (a) on test.t1 to joe@localhost with grant option;
544544
select * from INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE table_schema != 'sys';
545545
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
546546
'joe'@'localhost' def test t1 a SELECT YES
547-
select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE table_schema NOT IN ('sys','mysql');
547+
select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE table_schema NOT IN ('sys','mysql')
548+
and not (grantee = "'mysql.session'@'localhost'"
549+
and table_name in ('component', 'replication_group_members'));
548550
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
549551
drop view v1, v2, v3;
550552
drop table t1;

mysql-test/r/information_schema_cs.result

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,9 @@ grant select (a) on test.t1 to joe@localhost with grant option;
544544
select * from INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE table_schema != 'sys';
545545
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE
546546
'joe'@'localhost' def test t1 a SELECT YES
547-
select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE table_schema NOT IN ('sys','mysql');
547+
select * from INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE table_schema NOT IN ('sys','mysql')
548+
and not (grantee = "'mysql.session'@'localhost'"
549+
and table_name in ('component', 'replication_group_members'));
548550
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
549551
drop view v1, v2, v3;
550552
drop table t1;

mysql-test/r/transactional_acl_tables.result

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,9 @@ SELECT host, db, user, table_name, column_name, column_priv FROM mysql.columns_p
13421342
host db user table_name column_name column_priv
13431343
h test u1 t1 a Select,Insert,Update,References
13441344
h test u1 t2 a Insert
1345-
SELECT host, db, user, table_name, grantor, table_priv, column_priv FROM mysql.tables_priv;
1345+
SELECT host, db, user, table_name, grantor, table_priv, column_priv FROM mysql.tables_priv
1346+
WHERE NOT (user = 'mysql.session'
1347+
AND table_name IN ('component', 'replication_group_members'));
13461348
host db user table_name grantor table_priv column_priv
13471349
h test u1 t1 root@localhost Select,Insert,Update,References
13481350
h test u1 t2 root@localhost Insert
@@ -1354,7 +1356,9 @@ COMMIT;
13541356
REVOKE ALL PRIVILEGES, GRANT OPTION FROM u1@h;
13551357
SELECT host, db, user, table_name, column_name, column_priv FROM mysql.columns_priv;
13561358
host db user table_name column_name column_priv
1357-
SELECT host, db, user, table_name, grantor, table_priv, column_priv FROM mysql.tables_priv;
1359+
SELECT host, db, user, table_name, grantor, table_priv, column_priv FROM mysql.tables_priv
1360+
WHERE NOT (user = 'mysql.session'
1361+
AND table_name IN ('component', 'replication_group_members'));
13581362
host db user table_name grantor table_priv column_priv
13591363
localhost mysql mysql.session user root@localhost Select
13601364
localhost sys mysql.sys sys_config root@localhost Select
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
SELECT * FROM information_schema.table_privileges WHERE grantee = "'mysql.session'@'localhost'" ORDER BY table_schema, table_name;
2+
GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE
3+
'mysql.session'@'localhost' def mysql component SELECT NO
4+
'mysql.session'@'localhost' def mysql user SELECT NO
5+
'mysql.session'@'localhost' def performance_schema replication_group_members SELECT NO
6+
SHOW GRANTS FOR 'mysql.session'@'localhost';
7+
Grants for mysql.session@localhost
8+
GRANT SHUTDOWN, SUPER, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO `mysql.session`@`localhost`
9+
GRANT AUDIT_ABORT_EXEMPT,AUTHENTICATION_POLICY_ADMIN,BACKUP_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,FIREWALL_EXEMPT,PERSIST_RO_VARIABLES_ADMIN,SESSION_VARIABLES_ADMIN,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN ON *.* TO `mysql.session`@`localhost`
10+
GRANT SELECT ON `performance_schema`.* TO `mysql.session`@`localhost`
11+
GRANT SELECT ON `mysql`.`component` TO `mysql.session`@`localhost`
12+
GRANT SELECT ON `mysql`.`user` TO `mysql.session`@`localhost`
13+
GRANT SELECT ON `performance_schema`.`replication_group_members` TO `mysql.session`@`localhost`
14+
# restart:--percona_telemetry.grace_interval=30 --percona_telemetry.scrape_interval=30 --percona_telemetry.telemetry_root_dir=<telemetry_root_dir>
15+
RENAME USER 'root'@'localhost' to 'root.tmp'@'localhost';
16+
Warnings:
17+
Warning 4005 User 'root'@'localhost' is referenced as a definer account in a stored routine.
18+
Warning 4005 User 'root'@'localhost' is referenced as a definer account in a trigger.
19+
'root' user used by component's 1st verison does not exist. Telemetry dir should contain 1 file.
20+
1
21+
RENAME USER 'root.tmp'@'localhost' to 'root'@'localhost';
22+
Warnings:
23+
Warning 4005 User 'root'@'localhost' is referenced as a definer account in a stored routine.
24+
Warning 4005 User 'root'@'localhost' is referenced as a definer account in a trigger.
25+
# restart:--percona_telemetry.grace_interval=30 --percona_telemetry.scrape_interval=30 --percona_telemetry.telemetry_root_dir=<telemetry_root_dir>
26+
RENAME USER 'mysql.session'@'localhost' to 'mysql.session.tmp'@'localhost';
27+
include/assert.inc [No orphaned sessions expected in processlist]
28+
'mysql.session' user used by component does not exist. Telemetry dir should still contain 1 file.
29+
1
30+
RENAME USER 'mysql.session.tmp'@'localhost' to 'mysql.session'@'localhost';
31+
# restart:--percona_telemetry.grace_interval=30 --percona_telemetry.scrape_interval=30 --percona_telemetry.telemetry_root_dir=<telemetry_root_dir>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Test that lack of the user used by Percona Telemetry Component
2+
# doesn't cause hangs during server restart and no orphaned sessions are created.
3+
4+
--source include/have_percona_telemetry.inc
5+
6+
--let $telemetry_root_dir = $MYSQL_TMP_DIR/telemetry_dir
7+
--let $grace_interval = 30
8+
--let $scrape_interval = 30
9+
10+
--mkdir $telemetry_root_dir
11+
12+
# Record mysql.session user privileges
13+
SELECT * FROM information_schema.table_privileges WHERE grantee = "'mysql.session'@'localhost'" ORDER BY table_schema, table_name;
14+
SHOW GRANTS FOR 'mysql.session'@'localhost';
15+
16+
# restart the server with custom telemetry file path and timeouts
17+
--let $restart_parameters = "restart:--percona_telemetry.grace_interval=$grace_interval --percona_telemetry.scrape_interval=$scrape_interval --percona_telemetry.telemetry_root_dir=$telemetry_root_dir"
18+
--replace_regex /telemetry_root_dir=.*telemetry_dir/telemetry_root_dir=<telemetry_root_dir>/
19+
--source include/restart_mysqld.inc
20+
21+
# Rename 'root' user (1st version of Percona Telemetry Component used 'root' user)
22+
# 1st version will not collect any data and will not create telemetry file and the restart will hang.
23+
# Fixed version will work properly as it doesn't use 'root' user.
24+
RENAME USER 'root'@'localhost' to 'root.tmp'@'localhost';
25+
26+
# sleep more than grace_interval and check that telemetry file was created
27+
--let $timeout = `select $grace_interval + 10`
28+
--sleep $timeout
29+
30+
--echo 'root' user used by component's 1st verison does not exist. Telemetry dir should contain 1 file.
31+
--exec ls -1 $telemetry_root_dir | wc -l
32+
33+
#
34+
# It should be possible to restart the server.
35+
#
36+
RENAME USER 'root.tmp'@'localhost' to 'root'@'localhost';
37+
--let $restart_parameters = "restart:--percona_telemetry.grace_interval=$grace_interval --percona_telemetry.scrape_interval=$scrape_interval --percona_telemetry.telemetry_root_dir=$telemetry_root_dir"
38+
--replace_regex /telemetry_root_dir=.*telemetry_dir/telemetry_root_dir=<telemetry_root_dir>/
39+
--source include/restart_mysqld.inc
40+
41+
42+
#
43+
# Now rename the user used by component
44+
#
45+
RENAME USER 'mysql.session'@'localhost' to 'mysql.session.tmp'@'localhost';
46+
47+
# Wait a few cycles and ensure that SHOW PROCESSLIST does not contain rows related to orphaned sessions.
48+
--let $timeout = `select $grace_interval + 3 * $scrape_interval`
49+
--sleep $timeout
50+
51+
--let $assert_text = No orphaned sessions expected in processlist
52+
--let $assert_cond = [SELECT COUNT(*) as Result FROM performance_schema.processlist WHERE user = "mysql.session";, Result, 1] = 0
53+
--source include/assert.inc
54+
55+
# Check that no new telemetry file was created
56+
--echo 'mysql.session' user used by component does not exist. Telemetry dir should still contain 1 file.
57+
--exec ls -1 $telemetry_root_dir | wc -l
58+
59+
60+
#
61+
# It should be still possible to restart the server.
62+
#
63+
RENAME USER 'mysql.session.tmp'@'localhost' to 'mysql.session'@'localhost';
64+
--let $restart_parameters = "restart:--percona_telemetry.grace_interval=$grace_interval --percona_telemetry.scrape_interval=$scrape_interval --percona_telemetry.telemetry_root_dir=$telemetry_root_dir"
65+
--replace_regex /telemetry_root_dir=.*telemetry_dir/telemetry_root_dir=<telemetry_root_dir>/
66+
--source include/restart_mysqld.inc
67+
68+
# cleanup
69+
--force-rmdir $telemetry_root_dir
70+

mysql-test/suite/funcs_1/r/is_table_privileges.result

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ TABLE_NAME varchar(64) NO
5353
PRIVILEGE_TYPE varchar(64) NO
5454
IS_GRANTABLE varchar(3) NO
5555
SELECT table_catalog, table_schema, table_name, privilege_type
56-
FROM information_schema.table_privileges WHERE table_catalog IS NOT NULL;
56+
FROM information_schema.table_privileges WHERE table_catalog IS NOT NULL
57+
AND NOT (grantee = "'mysql.session'@'localhost'"
58+
AND table_name IN ('component', 'replication_group_members'));
5759
table_catalog table_schema table_name privilege_type
5860
def mysql user SELECT
5961
def sys sys_config SELECT

mysql-test/suite/funcs_1/t/is_table_privileges.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ eval SHOW COLUMNS FROM information_schema.$is_table;
6464
# Show that TABLE_CATALOG is always NULL.
6565
--sorted_result
6666
SELECT table_catalog, table_schema, table_name, privilege_type
67-
FROM information_schema.table_privileges WHERE table_catalog IS NOT NULL;
67+
FROM information_schema.table_privileges WHERE table_catalog IS NOT NULL
68+
AND NOT (grantee = "'mysql.session'@'localhost'"
69+
AND table_name IN ('component', 'replication_group_members'));
6870

6971
--echo ######################################################################
7072
--echo # Testcase 3.2.11.2+3.2.11.3+3.2.11.4:

mysql-test/suite/innodb/r/log_first_rec_group.result

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@ include/assert.inc [All must happen within the single log block (this was requir
1717
# value of 5 in first pass, 4 in second).
1818
SELECT * FROM t;
1919
a b
20-
98 1
21-
99 2
22-
100 3
23-
101 4
24-
102 5
25-
103 6
20+
97 1
21+
98 2
22+
99 3
23+
100 4
24+
101 5
25+
102 6
26+
103 7
2627
SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't';
2728
AUTO_INCREMENT
28-
7
29+
8
2930
Pass: 1
3031
# Initialization - create table, resets autoincrement value.
3132
# 0. Move to the next log block.
@@ -42,14 +43,15 @@ include/assert.inc [All must happen within the single log block (this was requir
4243
# value of 5 in first pass, 4 in second).
4344
SELECT * FROM t;
4445
a b
45-
98 1
46-
99 2
47-
100 3
48-
101 4
49-
103 5
46+
97 1
47+
98 2
48+
99 3
49+
100 4
50+
101 5
51+
103 6
5052
SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't';
5153
AUTO_INCREMENT
52-
6
54+
7
5355
#
5456
# Scenario 2. Restart after writing full log block with record ending at boundary,
5557
# recovery should start in middle of the last written block (pass 0, 2)

0 commit comments

Comments
 (0)