1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
--source include/have_binlog_format_mixed.inc
SET GLOBAL binlog_gtid_index= 0;
SET GLOBAL binlog_gtid_index= 1;
--let $file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $pos1= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid1= @@gtid_binlog_pos;
CREATE TABLE t1 (a INT PRIMARY KEY);
--let $pos2= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid2= @@gtid_binlog_pos;
INSERT INTO t1 VALUES (1);
--let $pos3= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid3= @@gtid_binlog_pos;
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (3);
INSERT INTO t1 VALUES (4);
--let $pos4= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid4= @@gtid_binlog_pos;
INSERT INTO t1 VALUES (5);
--let $pos5= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid5= @@gtid_binlog_pos;
--disable_query_log
--let $i=0
while ($i < 100) {
eval INSERT INTO t1 VALUES (6 + $i);
inc $i;
}
--enable_query_log
--let $pos6= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid6= @@gtid_binlog_pos;
INSERT INTO t1 VALUES (106);
INSERT INTO t1 VALUES (107);
# Test first the hot and then the cold index.
--let $i= 0
while ($i < 2) {
--disable_query_log
eval SELECT BINLOG_GTID_POS('$file', $pos1) = @gtid1 AS Ok;
eval SELECT BINLOG_GTID_POS('$file', $pos2) = @gtid2 AS Ok;
eval SELECT BINLOG_GTID_POS('$file', $pos3) = @gtid3 AS Ok;
eval SELECT BINLOG_GTID_POS('$file', $pos4) = @gtid4 AS Ok;
eval SELECT BINLOG_GTID_POS('$file', $pos5) = @gtid5 AS Ok;
eval SELECT BINLOG_GTID_POS('$file', $pos6) = @gtid6 AS Ok;
--enable_query_log
inc $i;
if ($i == 1) {
FLUSH BINARY LOGS;
}
}
--echo *** Test that purge deletes the gtid index files. ***
FLUSH BINARY LOGS;
INSERT INTO t1 VALUES (200);
--let $file2= query_get_value(SHOW MASTER STATUS, File, 1)
FLUSH BINARY LOGS;
INSERT INTO t1 VALUES (201);
--let $file3= query_get_value(SHOW MASTER STATUS, File, 1)
FLUSH BINARY LOGS;
INSERT INTO t1 VALUES (202);
--let $file4= query_get_value(SHOW MASTER STATUS, File, 1)
--replace_result $file3 FILE
eval PURGE BINARY LOGS TO '$file3';
--let $MYSQLD_DATADIR= `select @@datadir`
--error 1
--file_exists $MYSQLD_DATADIR/$file.idx
--error 1
--file_exists $MYSQLD_DATADIR/$file2.idx
--file_exists $MYSQLD_DATADIR/$file3.idx
--file_exists $MYSQLD_DATADIR/$file4.idx
--echo *** Test missed index lookup due to missing or corrupt index file.
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
--let $file= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (301);
INSERT INTO t1 VALUES (302);
INSERT INTO t1 VALUES (303);
--let $pos= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid_pos= @@GLOBAL.gtid_binlog_pos;
INSERT INTO t1 VALUES (304);
INSERT INTO t1 VALUES (305);
# BINLOG_GTID_POS() has a side effect: it increments binlog_gtid_index_hit
--disable_ps2_protocol
FLUSH NO_WRITE_TO_BINLOG STATUS;
--echo +++ Initial status:
SHOW STATUS LIKE 'binlog_gtid_index_%';
--echo +++ GTID Lookup in good index.
--disable_query_log
eval SELECT BINLOG_GTID_POS('$file', $pos) = @gtid_pos AS Gtid_Lookup_Ok;
--enable_query_log
SHOW STATUS LIKE 'binlog_gtid_index_%';
--remove_file $MYSQLD_DATADIR/$file.idx
--echo +++ GTID Lookup, index file is missing.
--disable_query_log
eval SELECT BINLOG_GTID_POS('$file', $pos) = @gtid_pos AS Gtid_Lookup_Ok;
--enable_query_log
SHOW STATUS LIKE 'binlog_gtid_index_%';
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
--let $file= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (306);
--let $pos= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid_pos= @@GLOBAL.gtid_binlog_pos;
INSERT INTO t1 VALUES (307);
INSERT INTO t1 VALUES (308);
# Rotate again so we hit an on-disk index file, not the "hot" index.
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
# Corrupt the flag byte of the first page with an unused bit.
--let FILE_TO_CORRUPT= $MYSQLD_DATADIR/$file.idx
--perl
use strict;
use warnings;
use Fcntl qw(:DEFAULT :seek);
sysopen F, $ENV{FILE_TO_CORRUPT}, O_RDWR
or die "Cannot open file $ENV{FILE_TO_CORRUPT}: $!\n";
# Corrupt the flag byte with an unused flag.
sysseek(F, 16, SEEK_SET)
or die "Cannot seek file: $!\n";
my $buf;
sysread(F, $buf, 1)
or die "Cannot read file: $!\n";
$buf= chr(ord($buf) | 0x80);
sysseek(F, 16, SEEK_SET)
or die "Cannot seek file: $!\n";
syswrite(F, $buf, 1) == 1
or die "Cannot write file: $!\n";
close F;
EOF
--echo +++ GTID Lookup, first page of index is corrupt.
--disable_query_log
eval SELECT BINLOG_GTID_POS('$file', $pos) = @gtid_pos AS Gtid_Lookup_Ok;
--enable_query_log
SHOW STATUS LIKE 'binlog_gtid_index_%';
# Corrupt the last byte of the root page.
# Set a small page-size so we test corruption in something not the header page.
SET @old_page_size= @@GLOBAL.binlog_gtid_index_page_size;
SET @old_span_min= @@GLOBAL.binlog_gtid_index_span_min;
SET GLOBAL binlog_gtid_index_page_size= 64;
SET GLOBAL binlog_gtid_index_span_min= 1;
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
--let $file= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (310);
INSERT INTO t1 VALUES (311);
INSERT INTO t1 VALUES (312);
--let $pos= query_get_value(SHOW MASTER STATUS, Position, 1)
SET @gtid_pos= @@GLOBAL.gtid_binlog_pos;
INSERT INTO t1 VALUES (313);
INSERT INTO t1 VALUES (314);
INSERT INTO t1 VALUES (315);
INSERT INTO t1 VALUES (316);
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
SET GLOBAL binlog_gtid_index_page_size= @old_page_size;
SET GLOBAL binlog_gtid_index_span_min= @old_span_min;
--let FILE_TO_CORRUPT= $MYSQLD_DATADIR/$file.idx
--perl
use strict;
use warnings;
use Fcntl qw(:DEFAULT :seek);
sysopen F, $ENV{FILE_TO_CORRUPT}, O_RDWR
or die "Cannot open file $ENV{FILE_TO_CORRUPT}: $!\n";
# Tricky: The index is written asynchroneously, it may still be incomplete.
# So wait for the file to be written completely with a root node at the end.
my $count= 0;
for (;;) {
my $end= sysseek(F, 0, SEEK_END);
if ($end > 0 && ($end % 64) == 0) {
# The index file is non-empty with a full page at the end, test if the
# root page has been fully written. This is seen as bit 2 (PAGE_FLAG_LAST)
# and bit 3 (PAGE_FLAG_ROOT) being set (0xc).
my $flag;
if (sysseek(F, -64, SEEK_CUR) &&
sysread(F, $flag, 1) &&
(ord($flag) & 0xc) == 0xc) {
last;
}
}
die "Timeout waiting for GTID index to be non-empty\n"
if ++$count >= 500;
# Simple way to do sub-second sleep.
select(undef, undef, undef, 0.050);
}
# Corrupt the flag byte with an unused flag.
sysseek(F, -2, SEEK_END)
or die "Cannot seek file: $!\n";
my $buf;
sysread(F, $buf, 1)
or die "Cannot read file: $!\n";
$buf= chr(ord($buf) ^ 0x4);
sysseek(F, -2, SEEK_END)
or die "Cannot seek file: $!\n";
syswrite(F, $buf, 1) == 1
or die "Cannot write file: $!\n";
close F;
EOF
--echo +++ GTID Lookup, root page of index is corrupt.
--disable_query_log
eval SELECT BINLOG_GTID_POS('$file', $pos) = @gtid_pos AS Gtid_Lookup_Ok;
--enable_query_log
SHOW STATUS LIKE 'binlog_gtid_index_%';
--echo *** Test BINLOG_GTID_POS() with too-large offset.
# New binlog to skip the now corrupted one.
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
--let $file= query_get_value(SHOW MASTER STATUS, File, 1)
INSERT INTO t1 VALUES (401);
INSERT INTO t1 VALUES (402);
--echo +++ Test the hot index.
--replace_result $file FILE
eval SELECT BINLOG_GTID_POS('$file', 100000000);
SHOW STATUS LIKE 'binlog_gtid_index_%';
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
--echo +++ Test the cold index.
--replace_result $file FILE
eval SELECT BINLOG_GTID_POS('$file', 100000000);
SHOW STATUS LIKE 'binlog_gtid_index_%';
--enable_ps2_protocol
DROP TABLE t1;
|