Skip to content

Commit 75a9217

Browse files
PS-10595 [8.4]: combined lazy latch init + rw_lock_list bulk registration
https://perconadev.atlassian.net/browse/PS-10595 Combines two buffer-pool initialization speedups: 1. Reduce rw_lock_list contention during buffer pool initialization by registering block rw-locks in bulk via an O(1) list splice under rw_lock_list_mutex instead of taking it once per block. 2. Lazy per-block latch initialization - defer creation of each block's mutex and rw-locks until the block is first used. The second optimization is deferring the cost (paid later in runtime). Therefore it is disabled by default and a new sysvar has to be used to enable it: innodb_buffer_pool_lazy_latch_init. While it is disabled, the first optimization helps a little bit. These changes are based on a contribution we got from: Alexey Bychko <abychko@gmail.com>
1 parent 8405b40 commit 75a9217

19 files changed

Lines changed: 621 additions & 97 deletions

mysql-test/r/all_persisted_variables.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ include/assert.inc [Expect 500+ variables in the table. Due to open Bugs, we are
4747

4848
# Test SET PERSIST
4949

50-
include/assert.inc [Expect 491 persisted variables in the table.]
50+
include/assert.inc [Expect 492 persisted variables in the table.]
5151

5252
************************************************************
5353
* 3. Restart server, it must preserve the persisted variable
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
2+
@@global.innodb_buffer_pool_lazy_latch_init
3+
1
4+
# Scan I_S.INNODB_BUFFER_PAGE while the pool is mostly unused.
5+
# Without the lazy-init guard this enters an unconstructed mutex.
6+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page
7+
WHERE page_state = 'NOT_USED' AND page_type = 'UNKNOWN';
8+
ok
9+
1
10+
# Fault index/data pages into the pool.
11+
CREATE TABLE t1 (id INT PRIMARY KEY, val INT) ENGINE=InnoDB;
12+
# Some INDEX pages are now cached.
13+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page
14+
WHERE page_type = 'INDEX';
15+
ok
16+
1
17+
# Create compressed pages, evict their uncompressed frames, then scan
18+
# I_S.INNODB_BUFFER_PAGE_LRU for standalone compressed descriptors.
19+
CREATE TABLE t_zip (
20+
id INT PRIMARY KEY,
21+
val BLOB,
22+
KEY(val(10))
23+
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
24+
SELECT COUNT(*) FROM t_zip;
25+
COUNT(*)
26+
100
27+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page_lru;
28+
ok
29+
1
30+
# Expand the buffer pool (new lazy chunks), then re-scan.
31+
SET GLOBAL innodb_buffer_pool_size = 25165824;
32+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
33+
ok
34+
1
35+
# Shrink the buffer pool (chunks freed), then re-scan.
36+
SET GLOBAL innodb_buffer_pool_size = 8388608;
37+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
38+
ok
39+
1
40+
# Restart: the pool comes back up in lazy mode (opt reapplied).
41+
# restart
42+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
43+
@@global.innodb_buffer_pool_lazy_latch_init
44+
1
45+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
46+
ok
47+
1
48+
SELECT COUNT(*) FROM t1;
49+
COUNT(*)
50+
2000
51+
DROP TABLE t1, t_zip;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb-buffer-pool-lazy-latch-init=ON --innodb-buffer-pool-size=16M --innodb-buffer-pool-chunk-size=2M
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#
2+
# PS-10595: exercise innodb_buffer_pool_lazy_latch_init=ON end to end.
3+
#
4+
# With lazy latch init, a never-used buffer block has no constructed latches.
5+
# This test drives the paths that touch every chunk block regardless of state:
6+
# - INFORMATION_SCHEMA.INNODB_BUFFER_PAGE scans all blocks (including unused
7+
# ones) - it must report unused blocks as free without entering their
8+
# (unconstructed) mutex,
9+
# - online buffer pool resize creates fresh lazy chunks and later frees them,
10+
# - a restart brings the pool back up in lazy mode.
11+
# On a debug build this also activates all the block->latches_initialized
12+
# assertions added by this feature.
13+
#
14+
15+
--source include/have_innodb_max_16k.inc
16+
17+
# The feature is opt-in and read only; confirm the server started with it ON.
18+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
19+
20+
let $wait_timeout = 180;
21+
let $wait_condition =
22+
SELECT SUBSTR(variable_value, 1, 34) = 'Completed resizing buffer pool at '
23+
FROM performance_schema.global_status
24+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_resize_status';
25+
26+
--echo # Scan I_S.INNODB_BUFFER_PAGE while the pool is mostly unused.
27+
--echo # Without the lazy-init guard this enters an unconstructed mutex.
28+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page
29+
WHERE page_state = 'NOT_USED' AND page_type = 'UNKNOWN';
30+
31+
--echo # Fault index/data pages into the pool.
32+
CREATE TABLE t1 (id INT PRIMARY KEY, val INT) ENGINE=InnoDB;
33+
--disable_query_log
34+
BEGIN;
35+
let $i = 2000;
36+
while ($i) {
37+
eval INSERT INTO t1 VALUES ($i, $i);
38+
dec $i;
39+
}
40+
COMMIT;
41+
--enable_query_log
42+
43+
--echo # Some INDEX pages are now cached.
44+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page
45+
WHERE page_type = 'INDEX';
46+
47+
--echo # Create compressed pages, evict their uncompressed frames, then scan
48+
--echo # I_S.INNODB_BUFFER_PAGE_LRU for standalone compressed descriptors.
49+
CREATE TABLE t_zip (
50+
id INT PRIMARY KEY,
51+
val BLOB,
52+
KEY(val(10))
53+
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
54+
--disable_query_log
55+
BEGIN;
56+
let $i = 100;
57+
while ($i) {
58+
eval INSERT INTO t_zip VALUES ($i, REPEAT('a', 2000));
59+
dec $i;
60+
}
61+
COMMIT;
62+
--enable_query_log
63+
SELECT COUNT(*) FROM t_zip;
64+
65+
let $have_debug = `SELECT VERSION() LIKE '%debug%'`;
66+
if ($have_debug) {
67+
--disable_query_log
68+
SET GLOBAL innodb_buffer_pool_evict = 'uncompressed';
69+
--enable_query_log
70+
71+
let $compressed_only_pages = `SELECT COUNT(*)
72+
FROM information_schema.innodb_buffer_page_lru
73+
WHERE table_name LIKE '%t_zip%' AND compressed = 'YES'`;
74+
if (!$compressed_only_pages) {
75+
--die Expected standalone compressed descriptors for t_zip
76+
}
77+
}
78+
79+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page_lru;
80+
81+
--echo # Expand the buffer pool (new lazy chunks), then re-scan.
82+
SET GLOBAL innodb_buffer_pool_size = 25165824;
83+
--source include/wait_condition.inc
84+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
85+
86+
--echo # Shrink the buffer pool (chunks freed), then re-scan.
87+
SET GLOBAL innodb_buffer_pool_size = 8388608;
88+
--source include/wait_condition.inc
89+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
90+
91+
--echo # Restart: the pool comes back up in lazy mode (opt reapplied).
92+
--source include/restart_mysqld.inc
93+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
94+
SELECT COUNT(*) > 0 AS ok FROM information_schema.innodb_buffer_page;
95+
SELECT COUNT(*) FROM t1;
96+
97+
DROP TABLE t1, t_zip;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
2+
@@global.innodb_buffer_pool_lazy_latch_init
3+
0
4+
SET @@global.innodb_buffer_pool_lazy_latch_init = ON;
5+
ERROR HY000: Variable 'innodb_buffer_pool_lazy_latch_init' is a read only variable
6+
SET @@global.innodb_buffer_pool_lazy_latch_init = OFF;
7+
ERROR HY000: Variable 'innodb_buffer_pool_lazy_latch_init' is a read only variable
8+
SELECT @@session.innodb_buffer_pool_lazy_latch_init;
9+
ERROR HY000: Variable 'innodb_buffer_pool_lazy_latch_init' is a GLOBAL variable
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Basic test for innodb_buffer_pool_lazy_latch_init
3+
#
4+
# It is a read-only, global-only boolean that defaults to OFF.
5+
#
6+
7+
# Check the default value.
8+
SELECT @@global.innodb_buffer_pool_lazy_latch_init;
9+
10+
# It is read only: it cannot be changed at runtime.
11+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
12+
SET @@global.innodb_buffer_pool_lazy_latch_init = ON;
13+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
14+
SET @@global.innodb_buffer_pool_lazy_latch_init = OFF;
15+
16+
# It has only a global scope.
17+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
18+
SELECT @@session.innodb_buffer_pool_lazy_latch_init;

0 commit comments

Comments
 (0)