Skip to content

Commit 59dd046

Browse files
committed
MDEV-11455 shutdown or abort during innodb buffer pool load (from file) causing incomplete save
Merge pull request #622
2 parents 907b236 + 9b8d0d9 commit 59dd046

File tree

9 files changed

+310
-12
lines changed

9 files changed

+310
-12
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
2+
# innodb_buffer_pool_load_incomplete defaults 0
3+
SELECT variable_name, variable_value
4+
FROM information_schema.global_status
5+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_load_incomplete';
6+
variable_name variable_value
7+
INNODB_BUFFER_POOL_LOAD_INCOMPLETE OFF
8+
9+
# populate with data
10+
CREATE TABLE t1 (
11+
c01 blob, c02 blob, c03 blob, c04 blob, c05 blob,
12+
c06 blob, c07 blob, c08 blob, c09 blob, c10 blob,
13+
c11 blob, c12 blob, c13 blob, c14 blob, c15 blob,
14+
c16 blob, c17 blob, c18 blob, c19 blob, c20 blob,
15+
c21 blob, c22 blob, c23 blob, c24 blob, c25 blob,
16+
c26 blob, c27 blob, c28 blob, c29 blob, c30 blob,
17+
c31 blob, c32 blob, c33 blob, c34 blob, c35 blob,
18+
c36 blob, c37 blob, c38 blob, c39 blob, c40 blob,
19+
c41 blob, c42 blob, c43 blob, c44 blob, c45 blob,
20+
c46 blob, c47 blob, c48 blob, c49 blob, c50 blob,
21+
c51 blob, c52 blob, c53 blob, c54 blob, c55 blob,
22+
c56 blob, c57 blob, c58 blob, c59 blob, c60 blob,
23+
c61 blob, c62 blob, c63 blob, c64 blob
24+
) ROW_FORMAT=dynamic;
25+
SET @a = repeat('a', 16 * 1024);
26+
INSERT INTO t1 VALUES (@a,@a,@a,@a,@a,
27+
@a,@a,@a,@a,@a,
28+
@a,@a,@a,@a,@a,
29+
@a,@a,@a,@a,@a,
30+
@a,@a,@a,@a,@a,
31+
@a,@a,@a,@a,@a,
32+
@a,@a,@a,@a,@a,
33+
@a,@a,@a,@a,@a,
34+
@a,@a,@a,@a,@a,
35+
@a,@a,@a,@a,@a,
36+
@a,@a,@a,@a,@a,
37+
@a,@a,@a,@a,@a,
38+
@a,@a,@a,@a
39+
);
40+
SET GLOBAL innodb_buffer_pool_dump_now=1;
41+
42+
# Restart server
43+
44+
# Abort after 16 pages
45+
SET GLOBAL innodb_buffer_pool_load_pages_abort=16,
46+
GLOBAL innodb_buffer_pool_load_now=1,
47+
GLOBAL innodb_buffer_pool_dump_at_shutdown=1;
48+
SELECT variable_name, SUBSTR(variable_value, 1, 38) as VALUE
49+
FROM information_schema.global_status
50+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete','innodb_buffer_pool_load_status')
51+
ORDER BY variable_name;
52+
variable_name VALUE
53+
INNODB_BUFFER_POOL_LOAD_INCOMPLETE ON
54+
INNODB_BUFFER_POOL_LOAD_STATUS Buffer pool(s) load aborted on request
55+
56+
# Restart server
57+
58+
# Load buffer pool
59+
SET GLOBAL innodb_buffer_pool_load_now=1;
60+
61+
# Should be more than previous as we didn't overwrite our save file
62+
select count(*) > Previous_loaded as Loaded_more from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE;;
63+
Loaded_more
64+
1
65+
66+
# Successful, so innodb_buffer_pool_load_incomplete should be FALSE
67+
SELECT variable_name, SUBSTR(variable_value, 1, 33) as VALUE
68+
FROM information_schema.global_status
69+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete','innodb_buffer_pool_load_status')
70+
ORDER BY variable_name;
71+
variable_name VALUE
72+
INNODB_BUFFER_POOL_LOAD_INCOMPLETE OFF
73+
INNODB_BUFFER_POOL_LOAD_STATUS Buffer pool(s) load completed at
74+
75+
# innodb_buffer_pool_dump_now=1 should reset the innodb_buffer_pool_load_incomplete status
76+
SET GLOBAL innodb_buffer_pool_dump_now=1;
77+
SELECT variable_name, SUBSTR(variable_value, 1, 33) as VALUE
78+
FROM information_schema.global_status
79+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete', 'innodb_buffer_pool_dump_status');
80+
variable_name VALUE
81+
INNODB_BUFFER_POOL_DUMP_STATUS Buffer pool(s) dump completed at
82+
INNODB_BUFFER_POOL_LOAD_INCOMPLETE OFF
83+
84+
# Restart server
85+
86+
# Load buffer pool
87+
SET GLOBAL innodb_buffer_pool_load_now=1;
88+
89+
# Should be same amount
90+
select abs(Previously_dumped - count(*)) <= 2 as Loaded_about_same_size from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE;;
91+
Loaded_about_same_size
92+
1
93+
94+
# Clean up
95+
DROP TABLE t1;

mysql-test/suite/sys_vars/r/sysvars_innodb.result

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ variable_name not in (
44
'innodb_disallow_writes', # only available WITH_WSREP
55
'innodb_numa_interleave', # only available WITH_NUMA
66
'innodb_sched_priority_cleaner', # linux only
7-
'innodb_use_native_aio') # default value depends on OS
7+
'innodb_use_native_aio', # default value depends on OS
8+
'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing
89
order by variable_name;
910
VARIABLE_NAME INNODB_ADAPTIVE_FLUSHING
1011
SESSION_VALUE NULL
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
--loose-default-storage-engine=innodb
2+
--loose-innodb_buffer_pool_load_at_startup=0
3+
--loose-innodb_buffer_pool_dump_at_shutdown=0
4+
--loose-innodb-buffer-pool-size=8M
5+
--loose-innodb-page-size=16k
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#
2+
# MDEV-11455 - add status variable innodb_buffer_pool_load_abort
3+
#
4+
--source include/have_innodb.inc
5+
--source include/have_debug.inc
6+
7+
--echo
8+
--echo # innodb_buffer_pool_load_incomplete defaults 0
9+
SELECT variable_name, variable_value
10+
FROM information_schema.global_status
11+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_load_incomplete';
12+
13+
--echo
14+
--echo # populate with data
15+
16+
CREATE TABLE t1 (
17+
c01 blob, c02 blob, c03 blob, c04 blob, c05 blob,
18+
c06 blob, c07 blob, c08 blob, c09 blob, c10 blob,
19+
c11 blob, c12 blob, c13 blob, c14 blob, c15 blob,
20+
c16 blob, c17 blob, c18 blob, c19 blob, c20 blob,
21+
c21 blob, c22 blob, c23 blob, c24 blob, c25 blob,
22+
c26 blob, c27 blob, c28 blob, c29 blob, c30 blob,
23+
c31 blob, c32 blob, c33 blob, c34 blob, c35 blob,
24+
c36 blob, c37 blob, c38 blob, c39 blob, c40 blob,
25+
c41 blob, c42 blob, c43 blob, c44 blob, c45 blob,
26+
c46 blob, c47 blob, c48 blob, c49 blob, c50 blob,
27+
c51 blob, c52 blob, c53 blob, c54 blob, c55 blob,
28+
c56 blob, c57 blob, c58 blob, c59 blob, c60 blob,
29+
c61 blob, c62 blob, c63 blob, c64 blob
30+
) ROW_FORMAT=dynamic;
31+
32+
SET @a = repeat('a', 16 * 1024);
33+
INSERT INTO t1 VALUES (@a,@a,@a,@a,@a,
34+
@a,@a,@a,@a,@a,
35+
@a,@a,@a,@a,@a,
36+
@a,@a,@a,@a,@a,
37+
@a,@a,@a,@a,@a,
38+
@a,@a,@a,@a,@a,
39+
@a,@a,@a,@a,@a,
40+
@a,@a,@a,@a,@a,
41+
@a,@a,@a,@a,@a,
42+
@a,@a,@a,@a,@a,
43+
@a,@a,@a,@a,@a,
44+
@a,@a,@a,@a,@a,
45+
@a,@a,@a,@a
46+
);
47+
48+
SET GLOBAL innodb_buffer_pool_dump_now=1;
49+
# Wait for for the dump to complete
50+
let $wait_condition =
51+
SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at '
52+
FROM information_schema.global_status
53+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status';
54+
-- source include/wait_condition.inc
55+
56+
--echo
57+
--echo # Restart server
58+
--source include/restart_mysqld.inc
59+
60+
--echo
61+
--echo # Abort after 16 pages
62+
SET GLOBAL innodb_buffer_pool_load_pages_abort=16,
63+
GLOBAL innodb_buffer_pool_load_now=1,
64+
GLOBAL innodb_buffer_pool_dump_at_shutdown=1;
65+
66+
let $wait_condition =
67+
SELECT SUBSTR(variable_value, 1, 19) = 'Buffer pool(s) load'
68+
FROM information_schema.global_status
69+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_load_status';
70+
-- source include/wait_condition.inc
71+
72+
SELECT variable_name, SUBSTR(variable_value, 1, 38) as VALUE
73+
FROM information_schema.global_status
74+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete','innodb_buffer_pool_load_status')
75+
ORDER BY variable_name;
76+
77+
--let $incomplete=`select count(*) as BLOB_PAGES from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE`
78+
79+
# Shouldn't dump at shutdown due to innodb_buffer_pool_load_incomplete
80+
81+
--echo
82+
--echo # Restart server
83+
--source include/restart_mysqld.inc
84+
85+
--echo
86+
--echo # Load buffer pool
87+
SET GLOBAL innodb_buffer_pool_load_now=1;
88+
89+
# Wait for for the load to complete
90+
let $wait_condition =
91+
SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) load completed at '
92+
FROM information_schema.global_status
93+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_load_status';
94+
-- source include/wait_condition.inc
95+
96+
--echo
97+
--echo # Should be more than previous as we didn't overwrite our save file
98+
--replace_result $incomplete Previous_loaded
99+
--eval select count(*) > $incomplete as Loaded_more from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE;
100+
101+
--echo
102+
--echo # Successful, so innodb_buffer_pool_load_incomplete should be FALSE
103+
SELECT variable_name, SUBSTR(variable_value, 1, 33) as VALUE
104+
FROM information_schema.global_status
105+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete','innodb_buffer_pool_load_status')
106+
ORDER BY variable_name;
107+
108+
--echo
109+
--echo # innodb_buffer_pool_dump_now=1 should reset the innodb_buffer_pool_load_incomplete status
110+
111+
SET GLOBAL innodb_buffer_pool_dump_now=1;
112+
# Wait for for the dump to complete
113+
let $wait_condition =
114+
SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) dump completed at '
115+
FROM information_schema.global_status
116+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_dump_status';
117+
-- source include/wait_condition.inc
118+
119+
SELECT variable_name, SUBSTR(variable_value, 1, 33) as VALUE
120+
FROM information_schema.global_status
121+
WHERE LOWER(variable_name) IN ('innodb_buffer_pool_load_incomplete', 'innodb_buffer_pool_dump_status');
122+
123+
--let $fulldump=`select count(*) as BLOB_PAGES from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE`
124+
125+
--echo
126+
--echo # Restart server
127+
--source include/restart_mysqld.inc
128+
129+
--echo
130+
--echo # Load buffer pool
131+
SET GLOBAL innodb_buffer_pool_load_now=1;
132+
133+
# Wait for for the load to complete
134+
let $wait_condition =
135+
SELECT SUBSTR(variable_value, 1, 33) = 'Buffer pool(s) load completed at '
136+
FROM information_schema.global_status
137+
WHERE LOWER(variable_name) = 'innodb_buffer_pool_load_status';
138+
-- source include/wait_condition.inc
139+
140+
--echo
141+
--echo # Should be same amount
142+
--replace_result $fulldump Previously_dumped
143+
--eval select abs($fulldump - count(*)) <= 2 as Loaded_about_same_size from information_schema.INNODB_BUFFER_PAGE WHERE PAGE_TYPE='BLOB' group by PAGE_TYPE;
144+
145+
--echo
146+
--echo # Clean up
147+
148+
--remove_file $MYSQLTEST_VARDIR/mysqld.1/data/ib_buffer_pool
149+
DROP TABLE t1;

mysql-test/suite/sys_vars/t/sysvars_innodb.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ select * from information_schema.system_variables
1616
'innodb_disallow_writes', # only available WITH_WSREP
1717
'innodb_numa_interleave', # only available WITH_NUMA
1818
'innodb_sched_priority_cleaner', # linux only
19-
'innodb_use_native_aio') # default value depends on OS
19+
'innodb_use_native_aio', # default value depends on OS
20+
'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing
2021
order by variable_name;

storage/innobase/buf/buf0dump.cc

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,11 @@ buf_dump(
413413

414414
buf_dump_status(STATUS_INFO,
415415
"Buffer pool(s) dump completed at %s", now);
416+
417+
/* Though dumping doesn't related to an incomplete load,
418+
we reset this to 0 here to indicate that a shutdown can also perform
419+
a dump */
420+
export_vars.innodb_buffer_pool_load_incomplete = 0;
416421
}
417422

418423
/*****************************************************************//**
@@ -576,6 +581,8 @@ buf_load()
576581

577582
rewind(f);
578583

584+
export_vars.innodb_buffer_pool_load_incomplete = 1;
585+
579586
for (i = 0; i < dump_n && !SHUTTING_DOWN(); i++) {
580587
fscanf_ret = fscanf(f, ULINTPF "," ULINTPF,
581588
&space_id, &page_no);
@@ -624,7 +631,7 @@ buf_load()
624631
ut_sprintf_timestamp(now);
625632
buf_load_status(STATUS_INFO,
626633
"Buffer pool(s) load completed at %s"
627-
" (%s was empty)", now, full_filename);
634+
" (%s was empty or had errors)", now, full_filename);
628635
return;
629636
}
630637

@@ -713,6 +720,12 @@ buf_load()
713720

714721
buf_load_throttle_if_needed(
715722
&last_check_time, &last_activity_cnt, i);
723+
724+
#ifdef UNIV_DEBUG
725+
if ((i+1) >= srv_buf_pool_load_pages_abort) {
726+
buf_load_abort_flag = 1;
727+
}
728+
#endif
716729
}
717730

718731
if (space != NULL) {
@@ -723,8 +736,23 @@ buf_load()
723736

724737
ut_sprintf_timestamp(now);
725738

726-
buf_load_status(STATUS_INFO,
739+
if (i == dump_n) {
740+
buf_load_status(STATUS_INFO,
727741
"Buffer pool(s) load completed at %s", now);
742+
export_vars.innodb_buffer_pool_load_incomplete = 0;
743+
} else if (!buf_load_abort_flag) {
744+
buf_load_status(STATUS_INFO,
745+
"Buffer pool(s) load aborted due to user instigated abort at %s",
746+
now);
747+
/* intentionally don't reset innodb_buffer_pool_load_incomplete
748+
as we don't want a shutdown to save the buffer pool */
749+
} else {
750+
buf_load_status(STATUS_INFO,
751+
"Buffer pool(s) load aborted due to shutdown at %s",
752+
now);
753+
/* intentionally don't reset innodb_buffer_pool_load_incomplete
754+
as we want to abort without saving the buffer pool */
755+
}
728756

729757
/* Make sure that estimated = completed when we end. */
730758
/* mysql_stage_set_work_completed(pfs_stage_progress, dump_n); */
@@ -793,15 +821,16 @@ DECLARE_THREAD(buf_dump_thread)(void*)
793821
}
794822

795823
if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) {
824+
if (export_vars.innodb_buffer_pool_load_incomplete) {
825+
buf_dump_status(STATUS_INFO,
826+
"Dumping of buffer pool not started"
827+
" as load was incomplete");
796828
#ifdef WITH_WSREP
797-
if (!wsrep_recovery) {
829+
} else if (wsrep_recovery) {
798830
#endif /* WITH_WSREP */
799-
800-
buf_dump(FALSE /* ignore shutdown down flag,
801-
keep going even if we are in a shutdown state */);
802-
#ifdef WITH_WSREP
831+
} else {
832+
buf_dump(FALSE/* do complete dump at shutdown */);
803833
}
804-
#endif /* WITH_WSREP */
805834
}
806835

807836
srv_buf_dump_thread_active = false;

storage/innobase/handler/ha_innodb.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,8 @@ static SHOW_VAR innodb_status_variables[]= {
930930
(char*) &export_vars.innodb_buffer_pool_load_status, SHOW_CHAR},
931931
{"buffer_pool_resize_status",
932932
(char*) &export_vars.innodb_buffer_pool_resize_status, SHOW_CHAR},
933+
{"buffer_pool_load_incomplete",
934+
&export_vars.innodb_buffer_pool_load_incomplete, SHOW_BOOL},
933935
{"buffer_pool_pages_data",
934936
(char*) &export_vars.innodb_buffer_pool_pages_data, SHOW_LONG},
935937
{"buffer_pool_bytes_data",
@@ -20157,6 +20159,12 @@ static MYSQL_SYSVAR_ULONG(buffer_pool_dump_pct, srv_buf_pool_dump_pct,
2015720159
NULL, NULL, 25, 1, 100, 0);
2015820160

2015920161
#ifdef UNIV_DEBUG
20162+
/* Added to test the innodb_buffer_pool_load_incomplete status variable. */
20163+
static MYSQL_SYSVAR_ULONG(buffer_pool_load_pages_abort, srv_buf_pool_load_pages_abort,
20164+
PLUGIN_VAR_RQCMDARG,
20165+
"Number of pages during a buffer pool load to process before signaling innodb_buffer_pool_load_abort=1",
20166+
NULL, NULL, LONG_MAX, 1, LONG_MAX, 0);
20167+
2016020168
static MYSQL_SYSVAR_STR(buffer_pool_evict, srv_buffer_pool_evict,
2016120169
PLUGIN_VAR_RQCMDARG,
2016220170
"Evict pages from the buffer pool",
@@ -20901,6 +20909,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
2090120909
#endif /* UNIV_DEBUG */
2090220910
MYSQL_SYSVAR(buffer_pool_load_now),
2090320911
MYSQL_SYSVAR(buffer_pool_load_abort),
20912+
#ifdef UNIV_DEBUG
20913+
MYSQL_SYSVAR(buffer_pool_load_pages_abort),
20914+
#endif /* UNIV_DEBUG */
2090420915
MYSQL_SYSVAR(buffer_pool_load_at_startup),
2090520916
MYSQL_SYSVAR(defragment),
2090620917
MYSQL_SYSVAR(defragment_n_pages),

0 commit comments

Comments
 (0)