Skip to content

Commit 2a277c0

Browse files
committed
Bug#106939 TRUNCATE performance_schema.accounts causes duplicated counts in global_status
Contribution by Tencent. Problem: ======== The statement TRUNCATE performance_schema.accounts; can cause statistics reported by: SHOW GLOBAL STATUS SELECT * FROM performance_schema.global_status; to be incorrect, with session status variables counted twice. This happens only when: - show_compatibility_56 is 0 (so that status variables are aggregated by accounts, users and hosts) - some hosts are not instrumented, for example with a low performance-schema-hosts-size. Root cause: =========== Session statistics are aggregated already from each THD (THD::status_var) to the global status variable (global_status_var) This is expected. The code path for TRUNCATE performance_schema.accounts, in function PFS_account::aggregate_status(), contains an extra aggregation to global_status_var, following the design pattern of other instruments. This aggregation is not needed in case of status variables, because of the THD -> global_status_var flow already implemented in the SQL layer. Fix: ==== Simplify PFS_account::aggregate_status(), never aggregate to global_status_var. Change-Id: Id1a83621bd6c0ff998f95041cd929dc478ab7362
1 parent 634790e commit 2a277c0

File tree

5 files changed

+241
-25
lines changed

5 files changed

+241
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
CREATE USER user1@localhost;
2+
CREATE USER user2@localhost;
3+
CREATE USER user3@localhost;
4+
grant ALL on *.* to user1@localhost;
5+
grant ALL on *.* to user2@localhost;
6+
grant ALL on *.* to user3@localhost;
7+
SET GLOBAL show_compatibility_56=0;
8+
TRUNCATE TABLE performance_schema.accounts;
9+
FLUSH PRIVILEGES;
10+
CREATE TABLE test.t_range(a int, b int, PRIMARY KEY(a));
11+
INSERT INTO test.t_range values (1, 1), (2,2), (3, 3), (4, 4), (5, 5);
12+
INSERT INTO test.t_range values (6, 6), (7,7), (8, 8), (9, 9), (10, 10);
13+
FLUSH STATUS;
14+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
15+
a b
16+
3 3
17+
4 4
18+
5 5
19+
SELECT * from performance_schema.session_status
20+
WHERE VARIABLE_NAME = 'Select_range';
21+
VARIABLE_NAME VARIABLE_VALUE
22+
Select_range 1
23+
VARIABLE_NAME DELTA
24+
Select_range 1
25+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
26+
a b
27+
3 3
28+
4 4
29+
5 5
30+
SELECT * from performance_schema.session_status
31+
WHERE VARIABLE_NAME = 'Select_range';
32+
VARIABLE_NAME VARIABLE_VALUE
33+
Select_range 1
34+
VARIABLE_NAME DELTA
35+
Select_range 2
36+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
37+
a b
38+
3 3
39+
4 4
40+
5 5
41+
SELECT * from test.t_range where (a >= 4) AND (a <= 6);
42+
a b
43+
4 4
44+
5 5
45+
6 6
46+
SELECT * from performance_schema.session_status
47+
WHERE VARIABLE_NAME = 'Select_range';
48+
VARIABLE_NAME VARIABLE_VALUE
49+
Select_range 2
50+
VARIABLE_NAME DELTA
51+
Select_range 4
52+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
53+
a b
54+
3 3
55+
4 4
56+
5 5
57+
SELECT * from test.t_range where (a >= 4) AND (a <= 6);
58+
a b
59+
4 4
60+
5 5
61+
6 6
62+
SELECT * from test.t_range where (a >= 5) AND (a <= 7);
63+
a b
64+
5 5
65+
6 6
66+
7 7
67+
SELECT * from performance_schema.session_status
68+
WHERE VARIABLE_NAME = 'Select_range';
69+
VARIABLE_NAME VARIABLE_VALUE
70+
Select_range 3
71+
VARIABLE_NAME DELTA
72+
Select_range 7
73+
VARIABLE_NAME DELTA
74+
Select_range 7
75+
SELECT `USER`, `HOST`, VARIABLE_NAME, VARIABLE_VALUE
76+
FROM performance_schema.status_by_account WHERE VARIABLE_NAME = 'Select_range'
77+
AND `USER` LIKE 'user%'
78+
ORDER BY `USER`;
79+
USER HOST VARIABLE_NAME VARIABLE_VALUE
80+
user1 localhost Select_range 1
81+
user2 localhost Select_range 2
82+
user3 localhost Select_range 3
83+
VARIABLE_NAME DELTA
84+
Select_range 7
85+
TRUNCATE TABLE performance_schema.accounts;
86+
VARIABLE_NAME DELTA
87+
Select_range 7
88+
VARIABLE_NAME DELTA
89+
Select_range 7
90+
TRUNCATE TABLE performance_schema.accounts;
91+
VARIABLE_NAME DELTA
92+
Select_range 7
93+
DROP TABLE test.t_range;
94+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
95+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user2@localhost;
96+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user3@localhost;
97+
DROP USER user1@localhost;
98+
DROP USER user2@localhost;
99+
DROP USER user3@localhost;
100+
SET GLOBAL show_compatibility_56=1;
101+
FLUSH PRIVILEGES;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--loose-performance_schema_hosts_size=0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Tests for PERFORMANCE_SCHEMA
2+
3+
--source include/not_embedded.inc
4+
--source include/have_perfschema.inc
5+
6+
CREATE USER user1@localhost;
7+
CREATE USER user2@localhost;
8+
CREATE USER user3@localhost;
9+
10+
grant ALL on *.* to user1@localhost;
11+
grant ALL on *.* to user2@localhost;
12+
grant ALL on *.* to user3@localhost;
13+
14+
# To aggregate to accounts
15+
SET GLOBAL show_compatibility_56=0;
16+
17+
TRUNCATE TABLE performance_schema.accounts;
18+
19+
FLUSH PRIVILEGES;
20+
21+
CREATE TABLE test.t_range(a int, b int, PRIMARY KEY(a));
22+
23+
INSERT INTO test.t_range values (1, 1), (2,2), (3, 3), (4, 4), (5, 5);
24+
INSERT INTO test.t_range values (6, 6), (7,7), (8, 8), (9, 9), (10, 10);
25+
26+
FLUSH STATUS;
27+
28+
let $initial= `SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range'`;
29+
30+
# Causes Select_range to increment (+1)
31+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
32+
33+
SELECT * from performance_schema.session_status
34+
WHERE VARIABLE_NAME = 'Select_range';
35+
36+
--disable_query_log
37+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
38+
--enable_query_log
39+
40+
connect(con1, localhost, user1,,);
41+
# Causes Select_range to increment (+1)
42+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
43+
44+
SELECT * from performance_schema.session_status
45+
WHERE VARIABLE_NAME = 'Select_range';
46+
47+
--disable_query_log
48+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
49+
--enable_query_log
50+
51+
connect(con2, localhost, user2,,);
52+
# Causes Select_range to increment (+2)
53+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
54+
SELECT * from test.t_range where (a >= 4) AND (a <= 6);
55+
56+
SELECT * from performance_schema.session_status
57+
WHERE VARIABLE_NAME = 'Select_range';
58+
59+
--disable_query_log
60+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
61+
--enable_query_log
62+
63+
connect(con3, localhost, user3,,);
64+
# Causes Select_range to increment (+3)
65+
SELECT * from test.t_range where (a >= 3) AND (a <= 5);
66+
SELECT * from test.t_range where (a >= 4) AND (a <= 6);
67+
SELECT * from test.t_range where (a >= 5) AND (a <= 7);
68+
69+
SELECT * from performance_schema.session_status
70+
WHERE VARIABLE_NAME = 'Select_range';
71+
72+
--disable_query_log
73+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
74+
--enable_query_log
75+
76+
--connection default
77+
78+
--disable_query_log
79+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
80+
--enable_query_log
81+
82+
SELECT `USER`, `HOST`, VARIABLE_NAME, VARIABLE_VALUE
83+
FROM performance_schema.status_by_account WHERE VARIABLE_NAME = 'Select_range'
84+
AND `USER` LIKE 'user%'
85+
ORDER BY `USER`;
86+
87+
--disconnect con1
88+
--disconnect con2
89+
90+
# Wait till all disconnects are completed
91+
let $count_sessions= 2;
92+
--source include/wait_until_count_sessions.inc
93+
94+
--disable_query_log
95+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
96+
--enable_query_log
97+
98+
TRUNCATE TABLE performance_schema.accounts;
99+
100+
--disable_query_log
101+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
102+
--enable_query_log
103+
104+
--disconnect con3
105+
106+
# Wait till all disconnects are completed
107+
let $count_sessions= 1;
108+
--source include/wait_until_count_sessions.inc
109+
110+
--disable_query_log
111+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
112+
--enable_query_log
113+
114+
# Make sure TRUNCATE on accounts does not add to global_status
115+
TRUNCATE TABLE performance_schema.accounts;
116+
117+
--disable_query_log
118+
eval SELECT VARIABLE_NAME, (VARIABLE_VALUE - $initial) AS DELTA from performance_schema.global_status WHERE VARIABLE_NAME = 'Select_range';
119+
--enable_query_log
120+
121+
DROP TABLE test.t_range;
122+
123+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
124+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user2@localhost;
125+
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user3@localhost;
126+
DROP USER user1@localhost;
127+
DROP USER user2@localhost;
128+
DROP USER user3@localhost;
129+
130+
SET GLOBAL show_compatibility_56=1;
131+
132+
FLUSH PRIVILEGES;
133+

storage/perfschema/pfs_account.cc

+5-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2021, Oracle and/or its affiliates.
1+
/* Copyright (c) 2010, 2022, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -527,30 +527,18 @@ void PFS_account::aggregate_memory(bool alive, PFS_user *safe_user, PFS_host *sa
527527

528528
void PFS_account::aggregate_status(PFS_user *safe_user, PFS_host *safe_host)
529529
{
530-
if (likely(safe_user != NULL && safe_host != NULL))
531-
{
532-
/*
533-
Aggregate STATUS_BY_ACCOUNT to:
534-
- STATUS_BY_USER
535-
- STATUS_BY_HOST
536-
*/
537-
safe_user->m_status_stats.aggregate(& m_status_stats);
538-
safe_host->m_status_stats.aggregate(& m_status_stats);
539-
m_status_stats.reset();
540-
return;
541-
}
530+
/*
531+
Never aggregate to global_status_var,
532+
because of the parallel THD -> global_status_var flow.
533+
*/
542534

543535
if (safe_user != NULL)
544536
{
545537
/*
546538
Aggregate STATUS_BY_ACCOUNT to:
547539
- STATUS_BY_USER
548-
- GLOBAL_STATUS
549540
*/
550541
safe_user->m_status_stats.aggregate(& m_status_stats);
551-
m_status_stats.aggregate_to(& global_status_var);
552-
m_status_stats.reset();
553-
return;
554542
}
555543

556544
if (safe_host != NULL)
@@ -560,15 +548,8 @@ void PFS_account::aggregate_status(PFS_user *safe_user, PFS_host *safe_host)
560548
- STATUS_BY_HOST
561549
*/
562550
safe_host->m_status_stats.aggregate(& m_status_stats);
563-
m_status_stats.reset();
564-
return;
565551
}
566552

567-
/*
568-
Aggregate STATUS_BY_ACCOUNT to:
569-
- GLOBAL_STATUS
570-
*/
571-
m_status_stats.aggregate_to(& global_status_var);
572553
m_status_stats.reset();
573554
return;
574555
}

storage/perfschema/table_status_by_thread.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ table_status_by_thread::create(void)
8888

8989
int table_status_by_thread::delete_all_rows(void)
9090
{
91-
/* Lock required to aggregate to global_status_vars. */
91+
/* Lock required to aggregate to global_status_var. */
9292
mysql_mutex_lock(&LOCK_status);
9393

9494
reset_status_by_thread();

0 commit comments

Comments
 (0)