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