]>
Commit | Line | Data |
---|---|---|
b4e1fa2c AM |
1 | # name : innodb_pass_corrupt_table.patch |
2 | # introduced : 11 or before | |
3 | # maintainer : Yasufumi | |
4 | # | |
5 | #!!! notice !!! | |
6 | # Any small change to this file in the main branch | |
7 | # should be done or reviewed by the maintainer! | |
db82db79 AM |
8 | --- a/storage/innobase/btr/btr0btr.c |
9 | +++ b/storage/innobase/btr/btr0btr.c | |
734d6226 | 10 | @@ -692,6 +692,12 @@ |
b4e1fa2c | 11 | |
734d6226 AM |
12 | block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, |
13 | index, mtr); | |
b4e1fa2c AM |
14 | + |
15 | + if (srv_pass_corrupt_table && !block) { | |
16 | + return(0); | |
17 | + } | |
18 | + ut_a(block); | |
19 | + | |
20 | ut_a((ibool)!!page_is_comp(buf_block_get_frame(block)) | |
21 | == dict_table_is_comp(index->table)); | |
22 | #ifdef UNIV_BTR_DEBUG | |
734d6226 | 23 | @@ -978,6 +984,12 @@ |
b4e1fa2c AM |
24 | |
25 | root = btr_root_get(index, &mtr); | |
26 | ||
27 | + if (srv_pass_corrupt_table && !root) { | |
28 | + mtr_commit(&mtr); | |
29 | + return(0); | |
30 | + } | |
31 | + ut_a(root); | |
32 | + | |
33 | if (flag == BTR_N_LEAF_PAGES) { | |
34 | seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; | |
35 | ||
734d6226 | 36 | @@ -1437,6 +1449,13 @@ |
b4e1fa2c | 37 | |
734d6226 AM |
38 | root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, |
39 | NULL, &mtr); | |
b4e1fa2c AM |
40 | + |
41 | + if (srv_pass_corrupt_table && !root) { | |
42 | + mtr_commit(&mtr); | |
43 | + return; | |
44 | + } | |
45 | + ut_a(root); | |
734d6226 | 46 | + |
b4e1fa2c AM |
47 | #ifdef UNIV_BTR_DEBUG |
48 | ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF | |
49 | + root, space)); | |
734d6226 | 50 | @@ -1460,6 +1479,12 @@ |
b4e1fa2c | 51 | |
734d6226 AM |
52 | root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, |
53 | NULL, &mtr); | |
b4e1fa2c AM |
54 | + |
55 | + if (srv_pass_corrupt_table && !root) { | |
56 | + mtr_commit(&mtr); | |
57 | + return; | |
58 | + } | |
59 | + ut_a(root); | |
60 | #ifdef UNIV_BTR_DEBUG | |
61 | ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP | |
62 | + root, space)); | |
734d6226 AM |
63 | @@ -1493,6 +1518,11 @@ |
64 | block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, | |
65 | NULL, mtr); | |
b4e1fa2c AM |
66 | |
67 | + if (srv_pass_corrupt_table && !block) { | |
68 | + return; | |
69 | + } | |
70 | + ut_a(block); | |
71 | + | |
72 | btr_search_drop_page_hash_index(block); | |
73 | ||
74 | header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP; | |
db82db79 AM |
75 | --- a/storage/innobase/btr/btr0cur.c |
76 | +++ b/storage/innobase/btr/btr0cur.c | |
734d6226 | 77 | @@ -251,6 +251,11 @@ |
b4e1fa2c | 78 | mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH; |
734d6226 AM |
79 | get_block = btr_block_get( |
80 | space, zip_size, page_no, mode, cursor->index, mtr); | |
b4e1fa2c AM |
81 | + |
82 | + if (srv_pass_corrupt_table && !get_block) { | |
83 | + return; | |
84 | + } | |
85 | + ut_a(get_block); | |
86 | #ifdef UNIV_BTR_DEBUG | |
87 | ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); | |
88 | #endif /* UNIV_BTR_DEBUG */ | |
734d6226 AM |
89 | @@ -264,6 +269,11 @@ |
90 | get_block = btr_block_get( | |
91 | space, zip_size, left_page_no, | |
92 | RW_X_LATCH, cursor->index, mtr); | |
b4e1fa2c AM |
93 | + |
94 | + if (srv_pass_corrupt_table && !get_block) { | |
95 | + return; | |
96 | + } | |
97 | + ut_a(get_block); | |
98 | #ifdef UNIV_BTR_DEBUG | |
99 | ut_a(page_is_comp(get_block->frame) | |
100 | == page_is_comp(page)); | |
734d6226 AM |
101 | @@ -276,6 +286,11 @@ |
102 | get_block = btr_block_get( | |
103 | space, zip_size, page_no, | |
104 | RW_X_LATCH, cursor->index, mtr); | |
b4e1fa2c AM |
105 | + |
106 | + if (srv_pass_corrupt_table && !get_block) { | |
107 | + return; | |
108 | + } | |
109 | + ut_a(get_block); | |
110 | #ifdef UNIV_BTR_DEBUG | |
111 | ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); | |
112 | #endif /* UNIV_BTR_DEBUG */ | |
734d6226 AM |
113 | @@ -287,6 +302,11 @@ |
114 | get_block = btr_block_get( | |
115 | space, zip_size, right_page_no, | |
116 | RW_X_LATCH, cursor->index, mtr); | |
b4e1fa2c AM |
117 | + |
118 | + if (srv_pass_corrupt_table && !get_block) { | |
119 | + return; | |
120 | + } | |
121 | + ut_a(get_block); | |
122 | #ifdef UNIV_BTR_DEBUG | |
123 | ut_a(page_is_comp(get_block->frame) | |
124 | == page_is_comp(page)); | |
734d6226 AM |
125 | @@ -309,6 +329,11 @@ |
126 | space, zip_size, | |
127 | left_page_no, mode, cursor->index, mtr); | |
b4e1fa2c AM |
128 | cursor->left_block = get_block; |
129 | + | |
130 | + if (srv_pass_corrupt_table && !get_block) { | |
131 | + return; | |
132 | + } | |
133 | + ut_a(get_block); | |
134 | #ifdef UNIV_BTR_DEBUG | |
135 | ut_a(page_is_comp(get_block->frame) | |
136 | == page_is_comp(page)); | |
734d6226 | 137 | @@ -320,6 +345,11 @@ |
b4e1fa2c | 138 | |
734d6226 AM |
139 | get_block = btr_block_get( |
140 | space, zip_size, page_no, mode, cursor->index, mtr); | |
b4e1fa2c AM |
141 | + |
142 | + if (srv_pass_corrupt_table && !get_block) { | |
143 | + return; | |
144 | + } | |
145 | + ut_a(get_block); | |
146 | #ifdef UNIV_BTR_DEBUG | |
147 | ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); | |
148 | #endif /* UNIV_BTR_DEBUG */ | |
734d6226 | 149 | @@ -592,6 +622,19 @@ |
b4e1fa2c AM |
150 | file, line, mtr); |
151 | ||
152 | if (block == NULL) { | |
153 | + if (srv_pass_corrupt_table | |
154 | + && buf_mode != BUF_GET_IF_IN_POOL | |
155 | + && buf_mode != BUF_GET_IF_IN_POOL_OR_WATCH) { | |
156 | + page_cursor->block = 0; | |
157 | + page_cursor->rec = 0; | |
158 | + if (estimate) { | |
159 | + cursor->path_arr->nth_rec = ULINT_UNDEFINED; | |
160 | + } | |
161 | + goto func_exit; | |
162 | + } | |
163 | + ut_a(buf_mode == BUF_GET_IF_IN_POOL | |
164 | + || buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH); | |
165 | + | |
166 | /* This must be a search to perform an insert/delete | |
167 | mark/ delete; try using the insert/delete buffer */ | |
168 | ||
734d6226 | 169 | @@ -666,6 +709,16 @@ |
b4e1fa2c AM |
170 | block->check_index_page_at_flush = TRUE; |
171 | page = buf_block_get_frame(block); | |
172 | ||
173 | + if (srv_pass_corrupt_table && !page) { | |
174 | + page_cursor->block = 0; | |
175 | + page_cursor->rec = 0; | |
176 | + if (estimate) { | |
177 | + cursor->path_arr->nth_rec = ULINT_UNDEFINED; | |
178 | + } | |
179 | + goto func_exit; | |
180 | + } | |
181 | + ut_a(page); | |
182 | + | |
183 | if (rw_latch != RW_NO_LATCH) { | |
184 | #ifdef UNIV_ZIP_DEBUG | |
185 | const page_zip_des_t* page_zip | |
734d6226 | 186 | @@ -872,6 +925,17 @@ |
b4e1fa2c AM |
187 | RW_NO_LATCH, NULL, BUF_GET, |
188 | file, line, mtr); | |
189 | page = buf_block_get_frame(block); | |
190 | + | |
191 | + if (srv_pass_corrupt_table && !page) { | |
192 | + page_cursor->block = 0; | |
193 | + page_cursor->rec = 0; | |
194 | + if (estimate) { | |
195 | + cursor->path_arr->nth_rec = ULINT_UNDEFINED; | |
196 | + } | |
197 | + break; | |
198 | + } | |
199 | + ut_a(page); | |
200 | + | |
201 | ut_ad(index->id == btr_page_get_index_id(page)); | |
202 | ||
203 | block->check_index_page_at_flush = TRUE; | |
734d6226 | 204 | @@ -992,6 +1056,14 @@ |
b4e1fa2c AM |
205 | RW_NO_LATCH, NULL, BUF_GET, |
206 | file, line, mtr); | |
207 | page = buf_block_get_frame(block); | |
208 | + | |
209 | + if (srv_pass_corrupt_table && !page) { | |
210 | + page_cursor->block = 0; | |
211 | + page_cursor->rec = 0; | |
212 | + break; | |
213 | + } | |
214 | + ut_a(page); | |
215 | + | |
216 | ut_ad(index->id == btr_page_get_index_id(page)); | |
217 | ||
218 | if (height == ULINT_UNDEFINED) { | |
734d6226 | 219 | @@ -1205,6 +1277,12 @@ |
b4e1fa2c AM |
220 | *big_rec = NULL; |
221 | ||
222 | block = btr_cur_get_block(cursor); | |
223 | + | |
224 | + if (srv_pass_corrupt_table && !block) { | |
225 | + return(DB_CORRUPTION); | |
226 | + } | |
227 | + ut_a(block); | |
228 | + | |
229 | page = buf_block_get_frame(block); | |
230 | index = cursor->index; | |
231 | zip_size = buf_block_get_zip_size(block); | |
734d6226 | 232 | @@ -2937,6 +3015,11 @@ |
b4e1fa2c AM |
233 | |
234 | block = btr_cur_get_block(cursor); | |
235 | ||
236 | + if (srv_pass_corrupt_table && !block) { | |
237 | + return(DB_CORRUPTION); | |
238 | + } | |
239 | + ut_a(block); | |
240 | + | |
241 | ut_ad(page_is_leaf(buf_block_get_frame(block))); | |
242 | ||
243 | rec = btr_cur_get_rec(cursor); | |
734d6226 | 244 | @@ -3650,6 +3733,11 @@ |
b4e1fa2c AM |
245 | |
246 | page = btr_cur_get_page(&cursor); | |
247 | ||
248 | + if (srv_pass_corrupt_table && !page) { | |
249 | + break; | |
250 | + } | |
251 | + ut_a(page); | |
252 | + | |
df1b5770 AM |
253 | rec = page_rec_get_next(page_get_infimum_rec(page)); |
254 | ||
255 | if (!page_rec_is_supremum(rec)) { | |
db82db79 AM |
256 | --- a/storage/innobase/btr/btr0pcur.c |
257 | +++ b/storage/innobase/btr/btr0pcur.c | |
b4e1fa2c AM |
258 | @@ -32,7 +32,7 @@ |
259 | #include "ut0byte.h" | |
260 | #include "rem0cmp.h" | |
261 | #include "trx0trx.h" | |
262 | - | |
263 | +#include "srv0srv.h" | |
264 | /**************************************************************//** | |
265 | Allocates memory for a persistent cursor object and initializes the cursor. | |
266 | @return own: persistent cursor */ | |
267 | @@ -102,6 +102,12 @@ | |
268 | ut_ad(cursor->latch_mode != BTR_NO_LATCHES); | |
269 | ||
270 | block = btr_pcur_get_block(cursor); | |
271 | + | |
272 | + if (srv_pass_corrupt_table && !block) { | |
273 | + return; | |
274 | + } | |
275 | + ut_a(block); | |
276 | + | |
277 | index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor)); | |
278 | ||
279 | page_cursor = btr_pcur_get_page_cur(cursor); | |
734d6226 AM |
280 | @@ -395,6 +401,15 @@ |
281 | cursor->latch_mode, | |
282 | btr_pcur_get_btr_cur(cursor)->index, mtr); | |
b4e1fa2c AM |
283 | next_page = buf_block_get_frame(next_block); |
284 | + | |
285 | + if (srv_pass_corrupt_table && !next_page) { | |
286 | + btr_leaf_page_release(btr_pcur_get_block(cursor), | |
287 | + cursor->latch_mode, mtr); | |
288 | + btr_pcur_get_page_cur(cursor)->block = 0; | |
289 | + btr_pcur_get_page_cur(cursor)->rec = 0; | |
290 | + return; | |
291 | + } | |
292 | + ut_a(next_page); | |
293 | #ifdef UNIV_BTR_DEBUG | |
294 | ut_a(page_is_comp(next_page) == page_is_comp(page)); | |
295 | ut_a(btr_page_get_prev(next_page, mtr) | |
db82db79 AM |
296 | --- a/storage/innobase/btr/btr0sea.c |
297 | +++ b/storage/innobase/btr/btr0sea.c | |
b4e1fa2c AM |
298 | @@ -42,7 +42,7 @@ |
299 | #include "btr0pcur.h" | |
300 | #include "btr0btr.h" | |
301 | #include "ha0ha.h" | |
302 | - | |
303 | +#include "srv0srv.h" | |
304 | /** Flag: has the search system been enabled? | |
305 | Protected by btr_search_latch and btr_search_enabled_mutex. */ | |
306 | UNIV_INTERN char btr_search_enabled = TRUE; | |
307 | @@ -607,6 +607,11 @@ | |
308 | ||
309 | block = btr_cur_get_block(cursor); | |
310 | ||
311 | + if (srv_pass_corrupt_table && !block) { | |
312 | + return; | |
313 | + } | |
314 | + ut_a(block); | |
315 | + | |
316 | /* NOTE that the following two function calls do NOT protect | |
317 | info or block->n_fields etc. with any semaphore, to save CPU time! | |
318 | We cannot assume the fields are consistent when we return from | |
db82db79 AM |
319 | --- a/storage/innobase/buf/buf0buf.c |
320 | +++ b/storage/innobase/buf/buf0buf.c | |
b4e1fa2c AM |
321 | @@ -52,6 +52,7 @@ |
322 | #include "log0recv.h" | |
323 | #include "page0zip.h" | |
324 | #include "trx0trx.h" | |
325 | +#include "srv0start.h" | |
326 | ||
327 | /* prototypes for new functions added to ha_innodb.cc */ | |
328 | trx_t* innobase_get_trx(); | |
734d6226 | 329 | @@ -1136,6 +1137,11 @@ |
b4e1fa2c AM |
330 | ready = buf_flush_ready_for_replace(&block->page); |
331 | mutex_exit(&block->mutex); | |
332 | ||
333 | + if (block->page.is_corrupt) { | |
334 | + /* corrupt page may remain, it can be skipped */ | |
335 | + break; | |
336 | + } | |
337 | + | |
338 | if (!ready) { | |
339 | ||
340 | return(block); | |
734d6226 | 341 | @@ -2007,6 +2013,13 @@ |
b4e1fa2c AM |
342 | return(NULL); |
343 | } | |
344 | ||
adf0fb13 | 345 | + if (srv_pass_corrupt_table <= 1) { |
b4e1fa2c AM |
346 | + if (bpage->is_corrupt) { |
347 | + rw_lock_s_unlock(&buf_pool->page_hash_latch); | |
348 | + return(NULL); | |
349 | + } | |
350 | + } | |
b4e1fa2c AM |
351 | + |
352 | block_mutex = buf_page_get_mutex_enter(bpage); | |
353 | ||
354 | rw_lock_s_unlock(&buf_pool->page_hash_latch); | |
734d6226 | 355 | @@ -2587,6 +2600,13 @@ |
b4e1fa2c AM |
356 | return(NULL); |
357 | } | |
358 | ||
adf0fb13 | 359 | + if (srv_pass_corrupt_table <= 1) { |
b4e1fa2c AM |
360 | + if (block->page.is_corrupt) { |
361 | + mutex_exit(block_mutex); | |
362 | + return(NULL); | |
363 | + } | |
364 | + } | |
b4e1fa2c AM |
365 | + |
366 | switch (buf_block_get_state(block)) { | |
367 | buf_page_t* bpage; | |
368 | ibool success; | |
734d6226 | 369 | @@ -3261,6 +3281,7 @@ |
b4e1fa2c AM |
370 | bpage->newest_modification = 0; |
371 | bpage->oldest_modification = 0; | |
372 | HASH_INVALIDATE(bpage, hash); | |
373 | + bpage->is_corrupt = FALSE; | |
df1b5770 | 374 | #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG |
b4e1fa2c | 375 | bpage->file_page_was_freed = FALSE; |
df1b5770 | 376 | #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ |
734d6226 | 377 | @@ -3899,6 +3920,7 @@ |
b4e1fa2c AM |
378 | (ulong) bpage->offset); |
379 | } | |
380 | ||
381 | + if (!srv_pass_corrupt_table || !bpage->is_corrupt) { | |
382 | /* From version 3.23.38 up we store the page checksum | |
383 | to the 4 first bytes of the page end lsn field */ | |
384 | ||
734d6226 | 385 | @@ -3940,6 +3962,23 @@ |
d8778560 | 386 | REFMAN "forcing-innodb-recovery.html\n" |
b4e1fa2c AM |
387 | "InnoDB: about forcing recovery.\n", stderr); |
388 | ||
389 | + if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space) | |
390 | + && bpage->space < SRV_LOG_SPACE_FIRST_ID) { | |
adf0fb13 AM |
391 | + trx_t* trx; |
392 | + | |
b4e1fa2c AM |
393 | + fprintf(stderr, |
394 | + "InnoDB: space %u will be treated as corrupt.\n", | |
395 | + bpage->space); | |
396 | + fil_space_set_corrupt(bpage->space); | |
adf0fb13 AM |
397 | + |
398 | + trx = innobase_get_trx(); | |
399 | + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) { | |
b4e1fa2c | 400 | + dict_table_set_corrupt_by_space(bpage->space, FALSE); |
adf0fb13 AM |
401 | + } else { |
402 | + dict_table_set_corrupt_by_space(bpage->space, TRUE); | |
b4e1fa2c AM |
403 | + } |
404 | + bpage->is_corrupt = TRUE; | |
405 | + } else | |
406 | if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { | |
734d6226 AM |
407 | /* If page space id is larger than TRX_SYS_SPACE |
408 | (0), we will attempt to mark the corresponding | |
409 | @@ -3956,6 +3995,7 @@ | |
410 | } | |
b4e1fa2c AM |
411 | } |
412 | } | |
413 | + } /**/ | |
414 | ||
415 | if (recv_recovery_is_on()) { | |
416 | /* Pages must be uncompressed for crash recovery. */ | |
734d6226 | 417 | @@ -3965,8 +4005,11 @@ |
b4e1fa2c AM |
418 | |
419 | if (uncompressed && !recv_no_ibuf_operations) { | |
420 | ibuf_merge_or_delete_for_page( | |
421 | + /* Delete possible entries, if bpage is_corrupt */ | |
422 | + (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL : | |
423 | (buf_block_t*) bpage, bpage->space, | |
424 | bpage->offset, buf_page_get_zip_size(bpage), | |
425 | + (srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE : | |
426 | TRUE); | |
427 | } | |
428 | } | |
db82db79 AM |
429 | --- a/storage/innobase/buf/buf0rea.c |
430 | +++ b/storage/innobase/buf/buf0rea.c | |
734d6226 | 431 | @@ -195,7 +195,14 @@ |
b4e1fa2c AM |
432 | ((buf_block_t*) bpage)->frame, bpage, trx); |
433 | } | |
434 | thd_wait_end(NULL); | |
435 | + | |
436 | + if (srv_pass_corrupt_table) { | |
437 | + if (*err != DB_SUCCESS) { | |
438 | + bpage->is_corrupt = TRUE; | |
439 | + } | |
440 | + } else { | |
441 | ut_a(*err == DB_SUCCESS); | |
442 | + } | |
443 | ||
444 | if (sync) { | |
445 | /* The i/o is already completed when we arrive from | |
db82db79 AM |
446 | --- a/storage/innobase/dict/dict0dict.c |
447 | +++ b/storage/innobase/dict/dict0dict.c | |
734d6226 | 448 | @@ -55,6 +55,7 @@ |
b4e1fa2c | 449 | #include "m_ctype.h" /* my_isspace() */ |
d8778560 | 450 | #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/ |
734d6226 | 451 | #include "row0upd.h" |
b4e1fa2c AM |
452 | +#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */ |
453 | ||
454 | #include <ctype.h> | |
455 | ||
adf0fb13 | 456 | @@ -750,7 +751,7 @@ |
b4e1fa2c AM |
457 | |
458 | mutex_exit(&(dict_sys->mutex)); | |
459 | ||
460 | - if (table != NULL) { | |
461 | + if (table != NULL && !table->is_corrupt) { | |
462 | /* If table->ibd_file_missing == TRUE, this will | |
463 | print an error message and return without doing | |
464 | anything. */ | |
adf0fb13 | 465 | @@ -1293,7 +1294,7 @@ |
b4e1fa2c AM |
466 | + dict_sys->size) > srv_dict_size_limit ) { |
467 | prev_table = UT_LIST_GET_PREV(table_LRU, table); | |
468 | ||
469 | - if (table == self || table->n_mysql_handles_opened) | |
470 | + if (table == self || table->n_mysql_handles_opened || table->is_corrupt) | |
471 | goto next_loop; | |
472 | ||
473 | cached_foreign_tables = 0; | |
734d6226 | 474 | @@ -4367,6 +4368,12 @@ |
b4e1fa2c AM |
475 | heap = mem_heap_create(1000); |
476 | ||
477 | while (index) { | |
478 | + if (table->is_corrupt) { | |
479 | + ut_a(srv_pass_corrupt_table); | |
480 | + mem_heap_free(heap); | |
481 | + return(FALSE); | |
482 | + } | |
483 | + | |
484 | size = btr_get_size(index, BTR_TOTAL_SIZE); | |
485 | ||
486 | index->stat_index_size = size; | |
734d6226 | 487 | @@ -4514,6 +4521,12 @@ |
b4e1fa2c AM |
488 | heap = mem_heap_create(1000); |
489 | ||
490 | while (index) { | |
491 | + if (table->is_corrupt) { | |
492 | + ut_a(srv_pass_corrupt_table); | |
493 | + mem_heap_free(heap); | |
494 | + return; | |
495 | + } | |
496 | + | |
497 | /*===========================================*/ | |
498 | { | |
499 | dict_table_t* sys_stats; | |
734d6226 | 500 | @@ -4706,6 +4719,13 @@ |
b4e1fa2c AM |
501 | || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO |
502 | && dict_index_is_clust(index)))) { | |
503 | ulint size; | |
504 | + | |
505 | + if (table->is_corrupt) { | |
506 | + ut_a(srv_pass_corrupt_table); | |
adf0fb13 | 507 | + dict_table_stats_unlock(table, RW_X_LATCH); |
b4e1fa2c AM |
508 | + return; |
509 | + } | |
510 | + | |
511 | size = btr_get_size(index, BTR_TOTAL_SIZE); | |
512 | ||
513 | index->stat_index_size = size; | |
734d6226 AM |
514 | @@ -5685,4 +5705,42 @@ |
515 | ||
516 | index->type |= DICT_CORRUPT; | |
b4e1fa2c AM |
517 | } |
518 | + | |
519 | +/************************************************************************* | |
520 | +set is_corrupt flag by space_id*/ | |
521 | + | |
522 | +void | |
523 | +dict_table_set_corrupt_by_space( | |
524 | +/*============================*/ | |
525 | + ulint space_id, | |
526 | + ibool need_mutex) | |
527 | +{ | |
528 | + dict_table_t* table; | |
529 | + ibool found = FALSE; | |
530 | + | |
531 | + ut_a(!trx_sys_sys_space(space_id) && space_id < SRV_LOG_SPACE_FIRST_ID); | |
532 | + | |
533 | + if (need_mutex) | |
534 | + mutex_enter(&(dict_sys->mutex)); | |
535 | + | |
536 | + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); | |
537 | + | |
538 | + while (table) { | |
539 | + if (table->space == space_id) { | |
540 | + table->is_corrupt = TRUE; | |
541 | + found = TRUE; | |
542 | + } | |
543 | + | |
544 | + table = UT_LIST_GET_NEXT(table_LRU, table); | |
545 | + } | |
546 | + | |
547 | + if (need_mutex) | |
548 | + mutex_exit(&(dict_sys->mutex)); | |
549 | + | |
550 | + if (!found) { | |
551 | + fprintf(stderr, "InnoDB: space to be marked as " | |
552 | + "crashed was not found for id %lu.\n", | |
553 | + (ulong) space_id); | |
554 | + } | |
555 | +} | |
556 | #endif /* !UNIV_HOTBACKUP */ | |
db82db79 AM |
557 | --- a/storage/innobase/dict/dict0mem.c |
558 | +++ b/storage/innobase/dict/dict0mem.c | |
adf0fb13 | 559 | @@ -96,6 +96,8 @@ |
b4e1fa2c AM |
560 | /* The number of transactions that are either waiting on the |
561 | AUTOINC lock or have been granted the lock. */ | |
562 | table->n_waiting_or_granted_auto_inc_locks = 0; | |
563 | + | |
564 | + table->is_corrupt = FALSE; | |
565 | #endif /* !UNIV_HOTBACKUP */ | |
566 | ||
567 | ut_d(table->magic_n = DICT_TABLE_MAGIC_N); | |
db82db79 AM |
568 | --- a/storage/innobase/fil/fil0fil.c |
569 | +++ b/storage/innobase/fil/fil0fil.c | |
adf0fb13 | 570 | @@ -235,6 +235,7 @@ |
b4e1fa2c AM |
571 | file we have written to */ |
572 | ibool is_in_unflushed_spaces; /*!< TRUE if this space is | |
573 | currently in unflushed_spaces */ | |
574 | + ibool is_corrupt; | |
575 | UT_LIST_NODE_T(fil_space_t) space_list; | |
576 | /*!< list of all spaces */ | |
577 | ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ | |
db82db79 | 578 | @@ -1294,6 +1295,8 @@ |
b4e1fa2c AM |
579 | ut_fold_string(name), space); |
580 | space->is_in_unflushed_spaces = FALSE; | |
581 | ||
582 | + space->is_corrupt = FALSE; | |
583 | + | |
584 | UT_LIST_ADD_LAST(space_list, fil_system->space_list, space); | |
585 | ||
586 | mutex_exit(&fil_system->mutex); | |
db82db79 | 587 | @@ -5268,6 +5271,34 @@ |
b4e1fa2c AM |
588 | ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); |
589 | ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); | |
590 | ||
adf0fb13 | 591 | + if (srv_pass_corrupt_table == 1 && space->is_corrupt) { |
b4e1fa2c AM |
592 | + /* should ignore i/o for the crashed space */ |
593 | + mutex_enter(&fil_system->mutex); | |
594 | + fil_node_complete_io(node, fil_system, type); | |
595 | + mutex_exit(&fil_system->mutex); | |
596 | + if (mode == OS_AIO_NORMAL) { | |
597 | + ut_a(space->purpose == FIL_TABLESPACE); | |
adf0fb13 | 598 | + buf_page_io_complete(message); |
b4e1fa2c AM |
599 | + } |
600 | + if (type == OS_FILE_READ) { | |
601 | + return(DB_TABLESPACE_DELETED); | |
602 | + } else { | |
603 | + return(DB_SUCCESS); | |
604 | + } | |
605 | + } else { | |
adf0fb13 AM |
606 | + if (srv_pass_corrupt_table > 1 && space->is_corrupt) { |
607 | + /* should ignore write i/o for the crashed space */ | |
608 | + if (type == OS_FILE_WRITE) { | |
609 | + mutex_enter(&fil_system->mutex); | |
610 | + fil_node_complete_io(node, fil_system, type); | |
611 | + mutex_exit(&fil_system->mutex); | |
612 | + if (mode == OS_AIO_NORMAL) { | |
613 | + ut_a(space->purpose == FIL_TABLESPACE); | |
614 | + buf_page_io_complete(message); | |
615 | + } | |
616 | + return(DB_SUCCESS); | |
617 | + } | |
618 | + } | |
b4e1fa2c AM |
619 | #ifdef UNIV_HOTBACKUP |
620 | /* In ibbackup do normal i/o, not aio */ | |
621 | if (type == OS_FILE_READ) { | |
db82db79 | 622 | @@ -5282,6 +5313,8 @@ |
b4e1fa2c AM |
623 | ret = os_aio(type, mode | wake_later, node->name, node->handle, buf, |
624 | offset_low, offset_high, len, node, message, trx); | |
625 | #endif | |
626 | + } /**/ | |
627 | + | |
628 | ut_a(ret); | |
629 | ||
630 | if (mode == OS_AIO_SYNC) { | |
db82db79 | 631 | @@ -5782,3 +5815,46 @@ |
b4e1fa2c AM |
632 | return 0; |
633 | } | |
634 | } | |
635 | + | |
636 | +/************************************************************************* | |
637 | +functions to access is_corrupt flag of fil_space_t*/ | |
638 | + | |
639 | +ibool | |
640 | +fil_space_is_corrupt( | |
641 | +/*=================*/ | |
642 | + ulint space_id) | |
643 | +{ | |
644 | + fil_space_t* space; | |
645 | + ibool ret = FALSE; | |
646 | + | |
647 | + mutex_enter(&fil_system->mutex); | |
648 | + | |
649 | + space = fil_space_get_by_id(space_id); | |
650 | + | |
651 | + if (space && space->is_corrupt) { | |
652 | + ret = TRUE; | |
653 | + } | |
654 | + | |
655 | + mutex_exit(&fil_system->mutex); | |
656 | + | |
657 | + return(ret); | |
658 | +} | |
659 | + | |
660 | +void | |
661 | +fil_space_set_corrupt( | |
662 | +/*==================*/ | |
663 | + ulint space_id) | |
664 | +{ | |
665 | + fil_space_t* space; | |
666 | + | |
667 | + mutex_enter(&fil_system->mutex); | |
668 | + | |
669 | + space = fil_space_get_by_id(space_id); | |
670 | + | |
671 | + if (space) { | |
672 | + space->is_corrupt = TRUE; | |
673 | + } | |
674 | + | |
675 | + mutex_exit(&fil_system->mutex); | |
676 | +} | |
677 | + | |
db82db79 AM |
678 | --- a/storage/innobase/fsp/fsp0fsp.c |
679 | +++ b/storage/innobase/fsp/fsp0fsp.c | |
b4e1fa2c AM |
680 | @@ -369,6 +369,12 @@ |
681 | ut_ad(id || !zip_size); | |
682 | ||
683 | block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr); | |
684 | + | |
685 | + if (srv_pass_corrupt_table && !block) { | |
686 | + return(0); | |
687 | + } | |
688 | + ut_a(block); | |
689 | + | |
690 | header = FSP_HEADER_OFFSET + buf_block_get_frame(block); | |
691 | buf_block_dbg_add_level(block, SYNC_FSP_PAGE); | |
692 | ||
693 | @@ -787,6 +793,12 @@ | |
694 | fsp_header_t* sp_header; | |
695 | ||
696 | block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr); | |
697 | + | |
698 | + if (srv_pass_corrupt_table && !block) { | |
699 | + return(0); | |
700 | + } | |
701 | + ut_a(block); | |
702 | + | |
703 | buf_block_dbg_add_level(block, SYNC_FSP_PAGE); | |
704 | ||
705 | sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block); | |
706 | @@ -1866,6 +1878,11 @@ | |
707 | { | |
708 | fseg_inode_t* inode; | |
709 | ||
710 | + if (srv_pass_corrupt_table && !page) { | |
711 | + return(ULINT_UNDEFINED); | |
712 | + } | |
713 | + ut_a(page); | |
714 | + | |
715 | for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) { | |
716 | ||
717 | inode = fsp_seg_inode_page_get_nth_inode( | |
718 | @@ -1979,6 +1996,11 @@ | |
719 | ||
720 | page = buf_block_get_frame(block); | |
721 | ||
722 | + if (srv_pass_corrupt_table && !page) { | |
723 | + return(0); | |
724 | + } | |
725 | + ut_a(page); | |
726 | + | |
727 | n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr); | |
728 | ||
729 | ut_a(n != ULINT_UNDEFINED); | |
730 | @@ -2072,6 +2094,11 @@ | |
731 | ||
732 | inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr); | |
733 | ||
734 | + if (srv_pass_corrupt_table && !inode) { | |
735 | + return(0); | |
736 | + } | |
737 | + ut_a(inode); | |
738 | + | |
739 | if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) { | |
740 | ||
741 | inode = NULL; | |
742 | @@ -2098,7 +2125,7 @@ | |
743 | { | |
744 | fseg_inode_t* inode | |
745 | = fseg_inode_try_get(header, space, zip_size, mtr); | |
746 | - ut_a(inode); | |
747 | + ut_a(srv_pass_corrupt_table || inode); | |
748 | return(inode); | |
749 | } | |
750 | ||
751 | @@ -3304,6 +3331,11 @@ | |
752 | ||
753 | descr = xdes_get_descriptor(space, zip_size, page, mtr); | |
754 | ||
755 | + if (srv_pass_corrupt_table && !descr) { | |
756 | + /* The page may be corrupt. pass it. */ | |
757 | + return; | |
758 | + } | |
759 | + | |
760 | ut_a(descr); | |
761 | if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) { | |
762 | fputs("InnoDB: Dump of the tablespace extent descriptor: ", | |
763 | @@ -3551,6 +3583,11 @@ | |
764 | ||
765 | descr = xdes_get_descriptor(space, zip_size, header_page, mtr); | |
766 | ||
767 | + if (srv_pass_corrupt_table && !descr) { | |
768 | + /* The page may be corrupt. pass it. */ | |
769 | + return(TRUE); | |
770 | + } | |
771 | + | |
772 | /* Check that the header resides on a page which has not been | |
773 | freed yet */ | |
774 | ||
775 | @@ -3635,6 +3672,12 @@ | |
776 | ||
777 | inode = fseg_inode_get(header, space, zip_size, mtr); | |
778 | ||
779 | + if (srv_pass_corrupt_table && !inode) { | |
780 | + /* ignore the corruption */ | |
781 | + return(TRUE); | |
782 | + } | |
783 | + ut_a(inode); | |
784 | + | |
785 | descr = fseg_get_first_extent(inode, space, zip_size, mtr); | |
786 | ||
787 | if (descr != NULL) { | |
db82db79 AM |
788 | --- a/storage/innobase/handler/ha_innodb.cc |
789 | +++ b/storage/innobase/handler/ha_innodb.cc | |
734d6226 | 790 | @@ -4012,6 +4012,12 @@ |
b4e1fa2c AM |
791 | DBUG_RETURN(1); |
792 | } | |
793 | ||
adf0fb13 | 794 | + if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
795 | + free_share(share); |
796 | + | |
797 | + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); | |
798 | + } | |
799 | + | |
800 | /* Create buffers for packing the fields of a record. Why | |
801 | table->reclength did not work here? Obviously, because char | |
802 | fields when packed actually became 1 byte longer, when we also | |
734d6226 | 803 | @@ -4039,6 +4045,19 @@ |
b4e1fa2c AM |
804 | /* Get pointer to a table object in InnoDB dictionary cache */ |
805 | ib_table = dict_table_get(norm_name, TRUE); | |
806 | ||
adf0fb13 | 807 | + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) { |
b4e1fa2c AM |
808 | + free_share(share); |
809 | + my_free(upd_buff); | |
810 | + | |
811 | + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); | |
812 | + } | |
813 | + | |
734d6226 AM |
814 | + share->ib_table = ib_table; |
815 | + | |
816 | + | |
817 | + | |
818 | + | |
b4e1fa2c AM |
819 | + |
820 | if (NULL == ib_table) { | |
821 | if (is_part && retries < 10) { | |
822 | ++retries; | |
734d6226 | 823 | @@ -5188,6 +5207,10 @@ |
b4e1fa2c AM |
824 | |
825 | ha_statistic_increment(&SSV::ha_write_count); | |
826 | ||
827 | + if (share->ib_table->is_corrupt) { | |
828 | + DBUG_RETURN(HA_ERR_CRASHED); | |
829 | + } | |
830 | + | |
831 | if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) | |
832 | table->timestamp_field->set_time(); | |
833 | ||
734d6226 | 834 | @@ -5405,6 +5428,10 @@ |
b4e1fa2c AM |
835 | func_exit: |
836 | innobase_active_small(); | |
837 | ||
838 | + if (share->ib_table->is_corrupt) { | |
839 | + DBUG_RETURN(HA_ERR_CRASHED); | |
840 | + } | |
841 | + | |
842 | DBUG_RETURN(error_result); | |
843 | } | |
844 | ||
734d6226 | 845 | @@ -5581,6 +5608,10 @@ |
b4e1fa2c AM |
846 | |
847 | ha_statistic_increment(&SSV::ha_update_count); | |
848 | ||
849 | + if (share->ib_table->is_corrupt) { | |
850 | + DBUG_RETURN(HA_ERR_CRASHED); | |
851 | + } | |
852 | + | |
853 | if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) | |
854 | table->timestamp_field->set_time(); | |
855 | ||
734d6226 | 856 | @@ -5670,6 +5701,10 @@ |
b4e1fa2c AM |
857 | |
858 | innobase_active_small(); | |
859 | ||
860 | + if (share->ib_table->is_corrupt) { | |
861 | + DBUG_RETURN(HA_ERR_CRASHED); | |
862 | + } | |
863 | + | |
864 | DBUG_RETURN(error); | |
865 | } | |
866 | ||
734d6226 | 867 | @@ -5691,6 +5726,10 @@ |
b4e1fa2c AM |
868 | |
869 | ha_statistic_increment(&SSV::ha_delete_count); | |
870 | ||
871 | + if (share->ib_table->is_corrupt) { | |
872 | + DBUG_RETURN(HA_ERR_CRASHED); | |
873 | + } | |
874 | + | |
875 | if (!prebuilt->upd_node) { | |
876 | row_get_prebuilt_update_vector(prebuilt); | |
877 | } | |
734d6226 | 878 | @@ -5717,6 +5756,10 @@ |
b4e1fa2c AM |
879 | |
880 | innobase_active_small(); | |
881 | ||
882 | + if (share->ib_table->is_corrupt) { | |
883 | + DBUG_RETURN(HA_ERR_CRASHED); | |
884 | + } | |
885 | + | |
886 | DBUG_RETURN(error); | |
887 | } | |
888 | ||
734d6226 | 889 | @@ -5956,6 +5999,10 @@ |
b4e1fa2c AM |
890 | |
891 | ha_statistic_increment(&SSV::ha_read_key_count); | |
892 | ||
adf0fb13 | 893 | + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
894 | + DBUG_RETURN(HA_ERR_CRASHED); |
895 | + } | |
896 | + | |
897 | index = prebuilt->index; | |
898 | ||
734d6226 AM |
899 | if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) { |
900 | @@ -6023,6 +6070,10 @@ | |
b4e1fa2c AM |
901 | ret = DB_UNSUPPORTED; |
902 | } | |
903 | ||
adf0fb13 | 904 | + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
905 | + DBUG_RETURN(HA_ERR_CRASHED); |
906 | + } | |
907 | + | |
908 | switch (ret) { | |
909 | case DB_SUCCESS: | |
910 | error = 0; | |
734d6226 | 911 | @@ -6138,6 +6189,10 @@ |
b4e1fa2c AM |
912 | { |
913 | DBUG_ENTER("change_active_index"); | |
914 | ||
adf0fb13 | 915 | + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
916 | + DBUG_RETURN(HA_ERR_CRASHED); |
917 | + } | |
918 | + | |
919 | ut_ad(user_thd == ha_thd()); | |
920 | ut_a(prebuilt->trx == thd_to_trx(user_thd)); | |
921 | ||
734d6226 | 922 | @@ -6251,6 +6306,10 @@ |
b4e1fa2c AM |
923 | |
924 | DBUG_ENTER("general_fetch"); | |
925 | ||
adf0fb13 | 926 | + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
927 | + DBUG_RETURN(HA_ERR_CRASHED); |
928 | + } | |
929 | + | |
930 | ut_a(prebuilt->trx == thd_to_trx(user_thd)); | |
931 | ||
932 | innodb_srv_conc_enter_innodb(prebuilt->trx); | |
734d6226 | 933 | @@ -6260,6 +6319,10 @@ |
b4e1fa2c AM |
934 | |
935 | innodb_srv_conc_exit_innodb(prebuilt->trx); | |
936 | ||
adf0fb13 | 937 | + if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) { |
b4e1fa2c AM |
938 | + DBUG_RETURN(HA_ERR_CRASHED); |
939 | + } | |
940 | + | |
941 | switch (ret) { | |
942 | case DB_SUCCESS: | |
943 | error = 0; | |
734d6226 | 944 | @@ -7526,10 +7589,18 @@ |
b4e1fa2c AM |
945 | |
946 | update_thd(ha_thd()); | |
947 | ||
948 | + if (share->ib_table->is_corrupt) { | |
949 | + DBUG_RETURN(HA_ERR_CRASHED); | |
950 | + } | |
951 | + | |
952 | /* Truncate the table in InnoDB */ | |
953 | ||
954 | error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx); | |
955 | ||
956 | + if (share->ib_table->is_corrupt) { | |
957 | + DBUG_RETURN(HA_ERR_CRASHED); | |
958 | + } | |
959 | + | |
960 | error = convert_error_code_to_mysql(error, prebuilt->table->flags, | |
961 | NULL); | |
962 | ||
734d6226 | 963 | @@ -8034,6 +8105,16 @@ |
b4e1fa2c AM |
964 | return(ranges + (double) rows / (double) total_rows * time_for_scan); |
965 | } | |
966 | ||
967 | +UNIV_INTERN | |
968 | +bool | |
969 | +ha_innobase::is_corrupt() const | |
970 | +{ | |
971 | + if (share->ib_table) | |
972 | + return ((bool)share->ib_table->is_corrupt); | |
973 | + else | |
974 | + return (FALSE); | |
975 | +} | |
976 | + | |
977 | /*********************************************************************//** | |
978 | Calculates the key number used inside MySQL for an Innobase index. We will | |
979 | first check the "index translation table" for a match of the index to get | |
734d6226 | 980 | @@ -8211,7 +8292,7 @@ |
b4e1fa2c AM |
981 | ib_table = prebuilt->table; |
982 | ||
983 | if (flag & HA_STATUS_TIME) { | |
984 | - if (called_from_analyze || innobase_stats_on_metadata) { | |
985 | + if ((called_from_analyze || innobase_stats_on_metadata) && !share->ib_table->is_corrupt) { | |
986 | /* In sql_show we call with this flag: update | |
987 | then statistics so that they are up-to-date */ | |
988 | ||
734d6226 | 989 | @@ -8511,10 +8592,18 @@ |
b4e1fa2c AM |
990 | THD* thd, /*!< in: connection thread handle */ |
991 | HA_CHECK_OPT* check_opt) /*!< in: currently ignored */ | |
992 | { | |
993 | + if (share->ib_table->is_corrupt) { | |
994 | + return(HA_ADMIN_CORRUPT); | |
995 | + } | |
996 | + | |
997 | /* Simply call ::info() with all the flags */ | |
998 | info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE, | |
999 | true /* called from analyze */); | |
1000 | ||
1001 | + if (share->ib_table->is_corrupt) { | |
1002 | + return(HA_ADMIN_CORRUPT); | |
1003 | + } | |
1004 | + | |
1005 | return(0); | |
1006 | } | |
1007 | ||
734d6226 | 1008 | @@ -8747,6 +8836,10 @@ |
b4e1fa2c AM |
1009 | my_error(ER_QUERY_INTERRUPTED, MYF(0)); |
1010 | } | |
1011 | ||
1012 | + if (share->ib_table->is_corrupt) { | |
1013 | + return(HA_ADMIN_CORRUPT); | |
1014 | + } | |
1015 | + | |
1016 | DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT); | |
1017 | } | |
1018 | ||
734d6226 | 1019 | @@ -9517,6 +9610,10 @@ |
b4e1fa2c AM |
1020 | |
1021 | update_thd(thd); | |
1022 | ||
1023 | + if (share->ib_table->is_corrupt) { | |
1024 | + DBUG_RETURN(HA_ERR_CRASHED); | |
1025 | + } | |
1026 | + | |
1027 | if (prebuilt->table->ibd_file_missing && !thd_tablespace_op(thd)) { | |
1028 | ut_print_timestamp(stderr); | |
1029 | fprintf(stderr, | |
734d6226 AM |
1030 | @@ -11941,6 +12038,26 @@ |
1031 | "dump file (if present). Disabled by default.", | |
1032 | NULL, NULL, FALSE); | |
b4e1fa2c | 1033 | |
a9ee80b9 ER |
1034 | +const char *corrupt_table_action_names[]= |
1035 | +{ | |
1036 | + "assert", /* 0 */ | |
1037 | + "warn", /* 1 */ | |
adf0fb13 | 1038 | + "salvage", /* 2 */ |
a9ee80b9 ER |
1039 | + NullS |
1040 | +}; | |
1041 | +TYPELIB corrupt_table_action_typelib= | |
1042 | +{ | |
1043 | + array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib", | |
1044 | + corrupt_table_action_names, NULL | |
1045 | +}; | |
1046 | +static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table, | |
b4e1fa2c | 1047 | + PLUGIN_VAR_RQCMDARG, |
a9ee80b9 | 1048 | + "Warn corruptions of user tables as 'corrupt table' instead of not crashing itself, " |
b4e1fa2c AM |
1049 | + "when used with file_per_table. " |
1050 | + "All file io for the datafile after detected as corrupt are disabled, " | |
1051 | + "except for the deletion.", | |
a9ee80b9 | 1052 | + NULL, NULL, 0, &corrupt_table_action_typelib); |
b4e1fa2c AM |
1053 | + |
1054 | static struct st_mysql_sys_var* innobase_system_variables[]= { | |
1055 | MYSQL_SYSVAR(additional_mem_pool_size), | |
1056 | MYSQL_SYSVAR(autoextend_increment), | |
734d6226 | 1057 | @@ -12031,6 +12148,7 @@ |
b4e1fa2c AM |
1058 | MYSQL_SYSVAR(purge_threads), |
1059 | MYSQL_SYSVAR(purge_batch_size), | |
11822e22 | 1060 | MYSQL_SYSVAR(rollback_segments), |
a9ee80b9 | 1061 | + MYSQL_SYSVAR(corrupt_table_action), |
b4e1fa2c AM |
1062 | NULL |
1063 | }; | |
1064 | ||
db82db79 AM |
1065 | --- a/storage/innobase/handler/ha_innodb.h |
1066 | +++ b/storage/innobase/handler/ha_innodb.h | |
b4e1fa2c AM |
1067 | @@ -52,6 +52,7 @@ |
1068 | innodb_idx_translate_t idx_trans_tbl; /*!< index translation | |
1069 | table between MySQL and | |
1070 | Innodb */ | |
1071 | + dict_table_t* ib_table; | |
1072 | } INNOBASE_SHARE; | |
1073 | ||
1074 | ||
1075 | @@ -135,6 +136,7 @@ | |
1076 | int close(void); | |
1077 | double scan_time(); | |
1078 | double read_time(uint index, uint ranges, ha_rows rows); | |
1079 | + bool is_corrupt() const; | |
1080 | ||
1081 | int write_row(uchar * buf); | |
1082 | int update_row(const uchar * old_data, uchar * new_data); | |
db82db79 AM |
1083 | --- a/storage/innobase/include/btr0btr.ic |
1084 | +++ b/storage/innobase/include/btr0btr.ic | |
b4e1fa2c AM |
1085 | @@ -28,7 +28,7 @@ |
1086 | #include "mtr0mtr.h" | |
1087 | #include "mtr0log.h" | |
1088 | #include "page0zip.h" | |
1089 | - | |
1090 | +#include "srv0srv.h" | |
1091 | #define BTR_MAX_NODE_LEVEL 50 /*!< Maximum B-tree page level | |
1092 | (not really a hard limit). | |
1093 | Used in debug assertions | |
734d6226 | 1094 | @@ -59,7 +59,9 @@ |
b4e1fa2c AM |
1095 | block = buf_page_get_gen(space, zip_size, page_no, mode, |
1096 | NULL, BUF_GET, file, line, mtr); | |
1097 | ||
1098 | - if (mode != RW_NO_LATCH) { | |
1099 | + ut_a(srv_pass_corrupt_table || block); | |
1100 | + | |
1101 | + if (block && mode != RW_NO_LATCH) { | |
1102 | ||
734d6226 AM |
1103 | buf_block_dbg_add_level( |
1104 | block, index != NULL && dict_index_is_ibuf(index) | |
db82db79 AM |
1105 | --- a/storage/innobase/include/buf0buf.h |
1106 | +++ b/storage/innobase/include/buf0buf.h | |
734d6226 | 1107 | @@ -1016,7 +1016,7 @@ |
b4e1fa2c AM |
1108 | const buf_block_t* block) /*!< in: pointer to the control block */ |
1109 | __attribute__((pure)); | |
1110 | #else /* UNIV_DEBUG */ | |
1111 | -# define buf_block_get_frame(block) (block)->frame | |
1112 | +# define buf_block_get_frame(block) (block ? (block)->frame : 0) | |
1113 | #endif /* UNIV_DEBUG */ | |
1114 | /*********************************************************************//** | |
1115 | Gets the space id of a block. | |
734d6226 | 1116 | @@ -1463,6 +1463,7 @@ |
b4e1fa2c AM |
1117 | 0 if the block was never accessed |
1118 | in the buffer pool */ | |
1119 | /* @} */ | |
1120 | + ibool is_corrupt; | |
df1b5770 | 1121 | # if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG |
b4e1fa2c AM |
1122 | ibool file_page_was_freed; |
1123 | /*!< this is set to TRUE when fsp | |
db82db79 AM |
1124 | --- a/storage/innobase/include/buf0buf.ic |
1125 | +++ b/storage/innobase/include/buf0buf.ic | |
b4e1fa2c AM |
1126 | @@ -34,7 +34,7 @@ |
1127 | #include "buf0flu.h" | |
1128 | #include "buf0lru.h" | |
1129 | #include "buf0rea.h" | |
1130 | - | |
1131 | +#include "srv0srv.h" | |
1132 | /*********************************************************************//** | |
1133 | Gets the current size of buffer buf_pool in bytes. | |
1134 | @return size in bytes */ | |
734d6226 | 1135 | @@ -637,6 +637,12 @@ |
b4e1fa2c AM |
1136 | /*================*/ |
1137 | const buf_block_t* block) /*!< in: pointer to the control block */ | |
1138 | { | |
1139 | + ut_a(srv_pass_corrupt_table || block); | |
1140 | + | |
1141 | + if (srv_pass_corrupt_table && !block) { | |
1142 | + return(0); | |
1143 | + } | |
1144 | + | |
1145 | ut_ad(block); | |
1146 | ||
1147 | switch (buf_block_get_state(block)) { | |
db82db79 AM |
1148 | --- a/storage/innobase/include/dict0dict.h |
1149 | +++ b/storage/innobase/include/dict0dict.h | |
734d6226 AM |
1150 | @@ -1326,6 +1326,15 @@ |
1151 | /*========================*/ | |
1152 | ulint space_id); /*!< in: space ID */ | |
b4e1fa2c AM |
1153 | |
1154 | +/************************************************************************* | |
1155 | +set is_corrupt flag by space_id*/ | |
1156 | + | |
1157 | +void | |
1158 | +dict_table_set_corrupt_by_space( | |
1159 | +/*============================*/ | |
1160 | + ulint space_id, | |
1161 | + ibool need_mutex); | |
1162 | + | |
1163 | #ifndef UNIV_NONINL | |
1164 | #include "dict0dict.ic" | |
1165 | #endif | |
db82db79 AM |
1166 | --- a/storage/innobase/include/dict0mem.h |
1167 | +++ b/storage/innobase/include/dict0mem.h | |
734d6226 | 1168 | @@ -670,6 +670,7 @@ |
b4e1fa2c AM |
1169 | the AUTOINC lock on this table. */ |
1170 | /* @} */ | |
1171 | /*----------------------*/ | |
1172 | + ibool is_corrupt; | |
1173 | #endif /* !UNIV_HOTBACKUP */ | |
1174 | ||
1175 | #ifdef UNIV_DEBUG | |
db82db79 AM |
1176 | --- a/storage/innobase/include/fil0fil.h |
1177 | +++ b/storage/innobase/include/fil0fil.h | |
413cadc7 | 1178 | @@ -750,6 +750,19 @@ |
b4e1fa2c AM |
1179 | fil_system_hash_nodes(void); |
1180 | /*========================*/ | |
1181 | ||
1182 | +/************************************************************************* | |
1183 | +functions to access is_corrupt flag of fil_space_t*/ | |
1184 | + | |
1185 | +ibool | |
1186 | +fil_space_is_corrupt( | |
1187 | +/*=================*/ | |
1188 | + ulint space_id); | |
1189 | + | |
1190 | +void | |
1191 | +fil_space_set_corrupt( | |
1192 | +/*==================*/ | |
1193 | + ulint space_id); | |
1194 | + | |
1195 | typedef struct fil_space_struct fil_space_t; | |
1196 | ||
1197 | #endif | |
db82db79 AM |
1198 | --- a/storage/innobase/include/fut0fut.ic |
1199 | +++ b/storage/innobase/include/fut0fut.ic | |
b4e1fa2c AM |
1200 | @@ -23,6 +23,7 @@ |
1201 | Created 12/13/1995 Heikki Tuuri | |
1202 | ***********************************************************************/ | |
1203 | ||
1204 | +#include "srv0srv.h" | |
1205 | #include "sync0rw.h" | |
1206 | #include "buf0buf.h" | |
1207 | ||
1208 | @@ -48,6 +49,12 @@ | |
1209 | ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); | |
1210 | ||
1211 | block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr); | |
1212 | + | |
1213 | + if (srv_pass_corrupt_table && !block) { | |
1214 | + return(0); | |
1215 | + } | |
1216 | + ut_a(block); | |
1217 | + | |
1218 | ptr = buf_block_get_frame(block) + addr.boffset; | |
1219 | ||
1220 | buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); | |
db82db79 AM |
1221 | --- a/storage/innobase/include/page0page.h |
1222 | +++ b/storage/innobase/include/page0page.h | |
734d6226 | 1223 | @@ -497,7 +497,7 @@ |
b4e1fa2c AM |
1224 | page_is_leaf( |
1225 | /*=========*/ | |
1226 | const page_t* page) /*!< in: page */ | |
1227 | - __attribute__((nonnull, pure)); | |
1228 | + __attribute__((pure)); | |
1229 | /************************************************************//** | |
1230 | Gets the pointer to the next record on the page. | |
1231 | @return pointer to next record */ | |
db82db79 AM |
1232 | --- a/storage/innobase/include/page0page.ic |
1233 | +++ b/storage/innobase/include/page0page.ic | |
b4e1fa2c AM |
1234 | @@ -274,6 +274,9 @@ |
1235 | /*=========*/ | |
1236 | const page_t* page) /*!< in: page */ | |
1237 | { | |
1238 | + if (!page) { | |
1239 | + return(FALSE); | |
1240 | + } | |
1241 | return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL))); | |
1242 | } | |
1243 | ||
db82db79 AM |
1244 | --- a/storage/innobase/include/page0zip.h |
1245 | +++ b/storage/innobase/include/page0zip.h | |
b4e1fa2c AM |
1246 | @@ -114,7 +114,7 @@ |
1247 | const page_t* page, /*!< in: uncompressed page */ | |
1248 | dict_index_t* index, /*!< in: index of the B-tree node */ | |
1249 | mtr_t* mtr) /*!< in: mini-transaction, or NULL */ | |
1250 | - __attribute__((nonnull(1,2,3))); | |
1251 | + __attribute__((nonnull(1,3))); | |
1252 | ||
1253 | /**********************************************************************//** | |
1254 | Decompress a page. This function should tolerate errors on the compressed | |
db82db79 AM |
1255 | --- a/storage/innobase/include/srv0srv.h |
1256 | +++ b/storage/innobase/include/srv0srv.h | |
734d6226 | 1257 | @@ -245,6 +245,7 @@ |
b4e1fa2c AM |
1258 | extern ulint srv_adaptive_flushing_method; |
1259 | ||
1260 | extern ulint srv_expand_import; | |
1261 | +extern ulint srv_pass_corrupt_table; | |
1262 | ||
b4e1fa2c | 1263 | extern ulint srv_dict_size_limit; |
11822e22 | 1264 | /*-------------------------------------------*/ |
db82db79 AM |
1265 | --- a/storage/innobase/page/page0zip.c |
1266 | +++ b/storage/innobase/page/page0zip.c | |
1267 | @@ -1195,6 +1195,10 @@ | |
b4e1fa2c AM |
1268 | FILE* logfile = NULL; |
1269 | #endif | |
1270 | ||
1271 | + if (!page) { | |
1272 | + return(FALSE); | |
1273 | + } | |
1274 | + | |
1275 | ut_a(page_is_comp(page)); | |
1276 | ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX); | |
1277 | ut_ad(page_simple_validate_new((page_t*) page)); | |
db82db79 AM |
1278 | --- a/storage/innobase/row/row0ins.c |
1279 | +++ b/storage/innobase/row/row0ins.c | |
734d6226 | 1280 | @@ -1338,6 +1338,12 @@ |
b4e1fa2c AM |
1281 | const rec_t* rec = btr_pcur_get_rec(&pcur); |
1282 | const buf_block_t* block = btr_pcur_get_block(&pcur); | |
1283 | ||
1284 | + if (srv_pass_corrupt_table && !block) { | |
1285 | + err = DB_CORRUPTION; | |
1286 | + break; | |
1287 | + } | |
1288 | + ut_a(block); | |
1289 | + | |
1290 | if (page_rec_is_infimum(rec)) { | |
1291 | ||
1292 | continue; | |
db82db79 AM |
1293 | --- a/storage/innobase/row/row0merge.c |
1294 | +++ b/storage/innobase/row/row0merge.c | |
b4e1fa2c AM |
1295 | @@ -1245,6 +1245,13 @@ |
1296 | ||
1297 | if (UNIV_LIKELY(has_next)) { | |
1298 | rec = btr_pcur_get_rec(&pcur); | |
1299 | + | |
1300 | + if (srv_pass_corrupt_table && !rec) { | |
1301 | + err = DB_CORRUPTION; | |
1302 | + goto err_exit; | |
1303 | + } | |
1304 | + ut_a(rec); | |
1305 | + | |
1306 | offsets = rec_get_offsets(rec, clust_index, NULL, | |
1307 | ULINT_UNDEFINED, &row_heap); | |
1308 | ||
db82db79 AM |
1309 | --- a/storage/innobase/row/row0sel.c |
1310 | +++ b/storage/innobase/row/row0sel.c | |
734d6226 | 1311 | @@ -3912,6 +3912,13 @@ |
b4e1fa2c AM |
1312 | /* PHASE 4: Look for matching records in a loop */ |
1313 | ||
1314 | rec = btr_pcur_get_rec(pcur); | |
1315 | + | |
1316 | + if (srv_pass_corrupt_table && !rec) { | |
1317 | + err = DB_CORRUPTION; | |
1318 | + goto lock_wait_or_error; | |
1319 | + } | |
1320 | + ut_a(rec); | |
1321 | + | |
1322 | ut_ad(!!page_rec_is_comp(rec) == comp); | |
1323 | #ifdef UNIV_SEARCH_DEBUG | |
1324 | /* | |
734d6226 | 1325 | @@ -3989,7 +3996,13 @@ |
adf0fb13 AM |
1326 | if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) { |
1327 | ||
1328 | wrong_offs: | |
1329 | - if (srv_force_recovery == 0 || moves_up == FALSE) { | |
1330 | + if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) { | |
1331 | + index->table->is_corrupt = TRUE; | |
1332 | + fil_space_set_corrupt(index->table->space); | |
1333 | + } | |
1334 | + | |
1335 | + if ((srv_force_recovery == 0 || moves_up == FALSE) | |
1336 | + && srv_pass_corrupt_table <= 1) { | |
1337 | ut_print_timestamp(stderr); | |
1338 | buf_page_print(page_align(rec), 0); | |
1339 | fprintf(stderr, | |
734d6226 | 1340 | @@ -4040,7 +4053,8 @@ |
adf0fb13 AM |
1341 | |
1342 | offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); | |
1343 | ||
1344 | - if (UNIV_UNLIKELY(srv_force_recovery > 0)) { | |
1345 | + if (UNIV_UNLIKELY(srv_force_recovery > 0) | |
1346 | + || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) { | |
1347 | if (!rec_validate(rec, offsets) | |
1348 | || !btr_index_rec_validate(rec, index, FALSE)) { | |
1349 | fprintf(stderr, | |
db82db79 AM |
1350 | --- a/storage/innobase/srv/srv0srv.c |
1351 | +++ b/storage/innobase/srv/srv0srv.c | |
734d6226 | 1352 | @@ -435,6 +435,7 @@ |
b4e1fa2c AM |
1353 | UNIV_INTERN ulint srv_adaptive_flushing_method = 0; /* 0: native 1: estimate 2: keep_average */ |
1354 | ||
1355 | UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */ | |
1356 | +UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */ | |
1357 | ||
b4e1fa2c | 1358 | UNIV_INTERN ulint srv_dict_size_limit = 0; |
11822e22 | 1359 | /*-------------------------------------------*/ |
db82db79 AM |
1360 | --- a/storage/innobase/srv/srv0start.c |
1361 | +++ b/storage/innobase/srv/srv0start.c | |
734d6226 | 1362 | @@ -2155,6 +2155,13 @@ |
b4e1fa2c AM |
1363 | |
1364 | os_fast_mutex_free(&srv_os_test_mutex); | |
1365 | ||
1366 | + if (!srv_file_per_table_original_value | |
1367 | + && srv_pass_corrupt_table) { | |
1368 | + fprintf(stderr, "InnoDB: Warning:" | |
d8778560 AM |
1369 | + " The option innodb_file_per_table is disabled," |
1370 | + " so using the option innodb_pass_corrupt_table doesn't make sense.\n"); | |
b4e1fa2c AM |
1371 | + } |
1372 | + | |
1373 | if (srv_print_verbose_log) { | |
1374 | ut_print_timestamp(stderr); | |
1375 | fprintf(stderr, |