00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "trx0sys.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "trx0sys.ic"
00030 #endif
00031
00032 #ifndef UNIV_HOTBACKUP
00033 #include "fsp0fsp.h"
00034 #include "mtr0log.h"
00035 #include "mtr0log.h"
00036 #include "trx0trx.h"
00037 #include "trx0rseg.h"
00038 #include "trx0undo.h"
00039 #include "srv0srv.h"
00040 #include "trx0purge.h"
00041 #include "log0log.h"
00042 #include "log0recv.h"
00043 #include "os0file.h"
00044 #include "read0read.h"
00045
00047 struct file_format_struct {
00048 ulint id;
00049 const char* name;
00051 mutex_t mutex;
00053 };
00054
00055 #include <drizzled/errmsg_print.h>
00056
00058 typedef struct file_format_struct file_format_t;
00059
00061 UNIV_INTERN trx_sys_t* trx_sys = NULL;
00063 UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL;
00064
00067 UNIV_INTERN ibool trx_doublewrite_must_reset_space_ids = FALSE;
00069 UNIV_INTERN ibool trx_doublewrite_buf_is_being_created = FALSE;
00070
00074 UNIV_INTERN ibool trx_sys_multiple_tablespace_format = FALSE;
00075
00078
00080 UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
00084 UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1;
00085
00086
00090
00092 UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
00094 UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
00095
00096 UNIV_INTERN drizzled::atomic<uint64_t> trx_sys_commit_id;
00097
00098
00099 #endif
00100
00102 static const char* file_format_name_map[] = {
00103 "Antelope",
00104 "Barracuda",
00105 "Cheetah",
00106 "Dragon",
00107 "Elk",
00108 "Fox",
00109 "Gazelle",
00110 "Hornet",
00111 "Impala",
00112 "Jaguar",
00113 "Kangaroo",
00114 "Leopard",
00115 "Moose",
00116 "Nautilus",
00117 "Ocelot",
00118 "Porpoise",
00119 "Quail",
00120 "Rabbit",
00121 "Shark",
00122 "Tiger",
00123 "Urchin",
00124 "Viper",
00125 "Whale",
00126 "Xenops",
00127 "Yak",
00128 "Zebra"
00129 };
00130
00132 static const ulint FILE_FORMAT_NAME_N
00133 = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
00134
00135 #ifdef UNIV_PFS_MUTEX
00136
00137 UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key;
00138 UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key;
00139 #endif
00140
00141 #ifndef UNIV_HOTBACKUP
00142
00145 static file_format_t file_format_max;
00146
00147
00151 UNIV_INTERN
00152 ibool
00153 trx_doublewrite_page_inside(
00154
00155 ulint page_no)
00156 {
00157 if (trx_doublewrite == NULL) {
00158
00159 return(FALSE);
00160 }
00161
00162 if (page_no >= trx_doublewrite->block1
00163 && page_no < trx_doublewrite->block1
00164 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00165 return(TRUE);
00166 }
00167
00168 if (page_no >= trx_doublewrite->block2
00169 && page_no < trx_doublewrite->block2
00170 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00171 return(TRUE);
00172 }
00173
00174 return(FALSE);
00175 }
00176
00177
00179 static
00180 void
00181 trx_doublewrite_init(
00182
00183 byte* doublewrite)
00185 {
00186 trx_doublewrite = static_cast<trx_doublewrite_t *>(mem_alloc(sizeof(trx_doublewrite_t)));
00187
00188
00189
00190 #ifdef UNIV_DO_FLUSH
00191 os_do_not_call_flush_at_each_write = TRUE;
00192 #endif
00193
00194 mutex_create(trx_doublewrite_mutex_key,
00195 &trx_doublewrite->mutex, SYNC_DOUBLEWRITE);
00196
00197 trx_doublewrite->first_free = 0;
00198
00199 trx_doublewrite->block1 = mach_read_from_4(
00200 doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK1);
00201 trx_doublewrite->block2 = mach_read_from_4(
00202 doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2);
00203 trx_doublewrite->write_buf_unaligned = static_cast<byte *>(ut_malloc(
00204 (1 + 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) * UNIV_PAGE_SIZE));
00205
00206 trx_doublewrite->write_buf = static_cast<byte *>(ut_align(
00207 trx_doublewrite->write_buf_unaligned, UNIV_PAGE_SIZE));
00208 trx_doublewrite->buf_block_arr = static_cast<buf_page_t **>(mem_alloc(
00209 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * sizeof(void*)));
00210 }
00211
00212
00215 UNIV_INTERN
00216 void
00217 trx_sys_mark_upgraded_to_multiple_tablespaces(void)
00218
00219 {
00220 buf_block_t* block;
00221 byte* doublewrite;
00222 mtr_t mtr;
00223
00224
00225
00226
00227
00228 mtr_start(&mtr);
00229
00230 block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
00231 RW_X_LATCH, &mtr);
00232 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
00233
00234 doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
00235
00236 mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
00237 TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
00238 MLOG_4BYTES, &mtr);
00239 mtr_commit(&mtr);
00240
00241
00242 log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
00243
00244 trx_sys_multiple_tablespace_format = TRUE;
00245 }
00246
00247
00250 UNIV_INTERN
00251 void
00252 trx_sys_create_doublewrite_buf(void)
00253
00254 {
00255 buf_block_t* block;
00256 buf_block_t* block2;
00257 #ifdef UNIV_SYNC_DEBUG
00258 buf_block_t* new_block;
00259 #endif
00260 byte* doublewrite;
00261 byte* fseg_header;
00262 ulint page_no;
00263 ulint prev_page_no;
00264 ulint i;
00265 mtr_t mtr;
00266
00267 if (trx_doublewrite) {
00268
00269
00270 return;
00271 }
00272
00273 start_again:
00274 mtr_start(&mtr);
00275 trx_doublewrite_buf_is_being_created = TRUE;
00276
00277 block = buf_page_get(TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO,
00278 RW_X_LATCH, &mtr);
00279 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
00280
00281 doublewrite = buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE;
00282
00283 if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
00284 == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
00285
00286
00287
00288 trx_doublewrite_init(doublewrite);
00289
00290 mtr_commit(&mtr);
00291 trx_doublewrite_buf_is_being_created = FALSE;
00292 } else {
00293 fprintf(stderr,
00294 "InnoDB: Doublewrite buffer not found:"
00295 " creating new\n");
00296
00297 if (buf_pool_get_curr_size()
00298 < ((2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
00299 + FSP_EXTENT_SIZE / 2 + 100)
00300 * UNIV_PAGE_SIZE)) {
00301 fprintf(stderr,
00302 "InnoDB: Cannot create doublewrite buffer:"
00303 " you must\n"
00304 "InnoDB: increase your buffer pool size.\n"
00305 "InnoDB: Cannot continue operation.\n");
00306
00307 exit(1);
00308 }
00309
00310 block2 = fseg_create(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
00311 TRX_SYS_DOUBLEWRITE
00312 + TRX_SYS_DOUBLEWRITE_FSEG, &mtr);
00313
00314
00315
00316
00317 buf_block_dbg_add_level(block2, SYNC_NO_ORDER_CHECK);
00318
00319 if (block2 == NULL) {
00320 fprintf(stderr,
00321 "InnoDB: Cannot create doublewrite buffer:"
00322 " you must\n"
00323 "InnoDB: increase your tablespace size.\n"
00324 "InnoDB: Cannot continue operation.\n");
00325
00326
00327
00328
00329 exit(1);
00330 }
00331
00332 fseg_header = buf_block_get_frame(block)
00333 + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG;
00334 prev_page_no = 0;
00335
00336 for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
00337 + FSP_EXTENT_SIZE / 2; i++) {
00338 page_no = fseg_alloc_free_page(fseg_header,
00339 prev_page_no + 1,
00340 FSP_UP, &mtr);
00341 if (page_no == FIL_NULL) {
00342 fprintf(stderr,
00343 "InnoDB: Cannot create doublewrite"
00344 " buffer: you must\n"
00345 "InnoDB: increase your"
00346 " tablespace size.\n"
00347 "InnoDB: Cannot continue operation.\n"
00348 );
00349
00350 exit(1);
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 #ifdef UNIV_SYNC_DEBUG
00363 new_block =
00364 #endif
00365 buf_page_get(TRX_SYS_SPACE, 0, page_no,
00366 RW_X_LATCH, &mtr);
00367 buf_block_dbg_add_level(new_block,
00368 SYNC_NO_ORDER_CHECK);
00369
00370 if (i == FSP_EXTENT_SIZE / 2) {
00371 ut_a(page_no == FSP_EXTENT_SIZE);
00372 mlog_write_ulint(doublewrite
00373 + TRX_SYS_DOUBLEWRITE_BLOCK1,
00374 page_no, MLOG_4BYTES, &mtr);
00375 mlog_write_ulint(doublewrite
00376 + TRX_SYS_DOUBLEWRITE_REPEAT
00377 + TRX_SYS_DOUBLEWRITE_BLOCK1,
00378 page_no, MLOG_4BYTES, &mtr);
00379 } else if (i == FSP_EXTENT_SIZE / 2
00380 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00381 ut_a(page_no == 2 * FSP_EXTENT_SIZE);
00382 mlog_write_ulint(doublewrite
00383 + TRX_SYS_DOUBLEWRITE_BLOCK2,
00384 page_no, MLOG_4BYTES, &mtr);
00385 mlog_write_ulint(doublewrite
00386 + TRX_SYS_DOUBLEWRITE_REPEAT
00387 + TRX_SYS_DOUBLEWRITE_BLOCK2,
00388 page_no, MLOG_4BYTES, &mtr);
00389 } else if (i > FSP_EXTENT_SIZE / 2) {
00390 ut_a(page_no == prev_page_no + 1);
00391 }
00392
00393 prev_page_no = page_no;
00394 }
00395
00396 mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC,
00397 TRX_SYS_DOUBLEWRITE_MAGIC_N,
00398 MLOG_4BYTES, &mtr);
00399 mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC
00400 + TRX_SYS_DOUBLEWRITE_REPEAT,
00401 TRX_SYS_DOUBLEWRITE_MAGIC_N,
00402 MLOG_4BYTES, &mtr);
00403
00404 mlog_write_ulint(doublewrite
00405 + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
00406 TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
00407 MLOG_4BYTES, &mtr);
00408 mtr_commit(&mtr);
00409
00410
00411 log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
00412
00413 fprintf(stderr, "InnoDB: Doublewrite buffer created\n");
00414
00415 trx_sys_multiple_tablespace_format = TRUE;
00416
00417 goto start_again;
00418 }
00419 }
00420
00421
00428 UNIV_INTERN
00429 void
00430 trx_sys_doublewrite_init_or_restore_pages(
00431
00432 ibool restore_corrupt_pages)
00433 {
00434 byte* buf;
00435 byte* read_buf;
00436 byte* unaligned_read_buf;
00437 ulint block1;
00438 ulint block2;
00439 ulint source_page_no;
00440 byte* page;
00441 byte* doublewrite;
00442 ulint space_id;
00443 ulint page_no;
00444 ulint i;
00445
00446
00447
00448 unaligned_read_buf = static_cast<byte *>(ut_malloc(2 * UNIV_PAGE_SIZE));
00449 read_buf = static_cast<byte *>(ut_align(unaligned_read_buf, UNIV_PAGE_SIZE));
00450
00451
00452
00453
00454 fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
00455 UNIV_PAGE_SIZE, read_buf, NULL);
00456 doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
00457
00458 if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
00459 == TRX_SYS_DOUBLEWRITE_MAGIC_N) {
00460
00461
00462 trx_doublewrite_init(doublewrite);
00463
00464 block1 = trx_doublewrite->block1;
00465 block2 = trx_doublewrite->block2;
00466
00467 buf = trx_doublewrite->write_buf;
00468 } else {
00469 goto leave_func;
00470 }
00471
00472 if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED)
00473 != TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) {
00474
00475
00476
00477
00478
00479
00480
00481 trx_doublewrite_must_reset_space_ids = TRUE;
00482
00483 fprintf(stderr,
00484 "InnoDB: Resetting space id's in the"
00485 " doublewrite buffer\n");
00486 } else {
00487 trx_sys_multiple_tablespace_format = TRUE;
00488 }
00489
00490
00491
00492 fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block1, 0,
00493 TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00494 buf, NULL);
00495 fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block2, 0,
00496 TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00497 buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
00498 NULL);
00499
00500
00501
00502 page = buf;
00503
00504 for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
00505
00506 page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
00507
00508 if (trx_doublewrite_must_reset_space_ids) {
00509
00510 space_id = 0;
00511 mach_write_to_4(page
00512 + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
00513
00514
00515
00516
00517 if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
00518 source_page_no = block1 + i;
00519 } else {
00520 source_page_no = block2
00521 + i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
00522 }
00523
00524 fil_io(OS_FILE_WRITE, TRUE, 0, 0, source_page_no, 0,
00525 UNIV_PAGE_SIZE, page, NULL);
00526
00527
00528 } else {
00529 space_id = mach_read_from_4(
00530 page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
00531 }
00532
00533 if (!restore_corrupt_pages) {
00534
00535
00536
00537 } else if (!fil_tablespace_exists_in_mem(space_id)) {
00538
00539
00540
00541 } else if (!fil_check_adress_in_tablespace(space_id,
00542 page_no)) {
00543 fprintf(stderr,
00544 "InnoDB: Warning: a page in the"
00545 " doublewrite buffer is not within space\n"
00546 "InnoDB: bounds; space id %lu"
00547 " page number %lu, page %lu in"
00548 " doublewrite buf.\n",
00549 (ulong) space_id, (ulong) page_no, (ulong) i);
00550
00551 } else if (space_id == TRX_SYS_SPACE
00552 && ((page_no >= block1
00553 && page_no
00554 < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
00555 || (page_no >= block2
00556 && page_no
00557 < (block2
00558 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) {
00559
00560
00561
00562 } else {
00563 ulint zip_size = fil_space_get_zip_size(space_id);
00564
00565
00566 fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
00567 page_no, 0,
00568 zip_size ? zip_size : UNIV_PAGE_SIZE,
00569 read_buf, NULL);
00570
00571
00572
00573 if (UNIV_UNLIKELY
00574 (buf_page_is_corrupted(read_buf, zip_size))) {
00575
00576 fprintf(stderr,
00577 "InnoDB: Warning: database page"
00578 " corruption or a failed\n"
00579 "InnoDB: file read of"
00580 " space %lu page %lu.\n"
00581 "InnoDB: Trying to recover it from"
00582 " the doublewrite buffer.\n",
00583 (ulong) space_id, (ulong) page_no);
00584
00585 if (buf_page_is_corrupted(page, zip_size)) {
00586 fprintf(stderr,
00587 "InnoDB: Dump of the page:\n");
00588 buf_page_print(read_buf, zip_size);
00589 fprintf(stderr,
00590 "InnoDB: Dump of"
00591 " corresponding page"
00592 " in doublewrite buffer:\n");
00593 buf_page_print(page, zip_size);
00594
00595 fprintf(stderr,
00596 "InnoDB: Also the page in the"
00597 " doublewrite buffer"
00598 " is corrupt.\n"
00599 "InnoDB: Cannot continue"
00600 " operation.\n"
00601 "InnoDB: You can try to"
00602 " recover the database"
00603 " with the my.cnf\n"
00604 "InnoDB: option:\n"
00605 "InnoDB:"
00606 " innodb_force_recovery=6\n");
00607 exit(1);
00608 }
00609
00610
00611
00612
00613
00614 fil_io(OS_FILE_WRITE, TRUE, space_id,
00615 zip_size, page_no, 0,
00616 zip_size ? zip_size : UNIV_PAGE_SIZE,
00617 page, NULL);
00618 fprintf(stderr,
00619 "InnoDB: Recovered the page from"
00620 " the doublewrite buffer.\n");
00621 }
00622 }
00623
00624 page += UNIV_PAGE_SIZE;
00625 }
00626
00627 fil_flush_file_spaces(FIL_TABLESPACE);
00628
00629 leave_func:
00630 ut_free(unaligned_read_buf);
00631 }
00632
00633
00636 UNIV_INTERN
00637 ibool
00638 trx_in_trx_list(
00639
00640 trx_t* in_trx)
00641 {
00642 trx_t* trx;
00643
00644 ut_ad(mutex_own(&(kernel_mutex)));
00645
00646 trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
00647
00648 while (trx != NULL) {
00649
00650 if (trx == in_trx) {
00651
00652 return(TRUE);
00653 }
00654
00655 trx = UT_LIST_GET_NEXT(trx_list, trx);
00656 }
00657
00658 return(FALSE);
00659 }
00660
00661
00663 UNIV_INTERN
00664 void
00665 trx_sys_flush_max_trx_id(void)
00666
00667 {
00668 trx_sysf_t* sys_header;
00669 mtr_t mtr;
00670
00671 ut_ad(mutex_own(&kernel_mutex));
00672
00673 mtr_start(&mtr);
00674
00675 sys_header = trx_sysf_get(&mtr);
00676
00677 mlog_write_ull(sys_header + TRX_SYS_TRX_ID_STORE,
00678 trx_sys->max_trx_id, &mtr);
00679 mtr_commit(&mtr);
00680 }
00681
00682 UNIV_INTERN
00683 void
00684 trx_sys_flush_commit_id(uint64_t commit_id, ulint field, mtr_t* mtr)
00685 {
00686 trx_sysf_t* sys_header;
00687
00688 sys_header = trx_sysf_get(mtr);
00689
00690 mlog_write_ull(sys_header + field + TRX_SYS_DRIZZLE_MAX_COMMIT_ID,
00691 commit_id, mtr);
00692 }
00693
00694
00695 UNIV_INTERN
00696 void
00697 trx_sys_read_commit_id(void)
00698
00699 {
00700 trx_sysf_t* sys_header;
00701 mtr_t mtr;
00702
00703 mtr_start(&mtr);
00704
00705 sys_header = trx_sysf_get(&mtr);
00706
00707 trx_sys_commit_id = mach_read_from_8(sys_header + TRX_SYS_DRIZZLE_LOG_INFO
00708 + TRX_SYS_DRIZZLE_MAX_COMMIT_ID);
00709
00710 mtr_commit(&mtr);
00711 }
00712
00713
00716 UNIV_INTERN
00717 ulint
00718 trx_sysf_rseg_find_free(
00719
00720 mtr_t* mtr)
00721 {
00722 trx_sysf_t* sys_header;
00723 ulint page_no;
00724 ulint i;
00725
00726 ut_ad(mutex_own(&(kernel_mutex)));
00727
00728 sys_header = trx_sysf_get(mtr);
00729
00730 for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
00731
00732 page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
00733
00734 if (page_no == FIL_NULL) {
00735
00736 return(i);
00737 }
00738 }
00739
00740 return(ULINT_UNDEFINED);
00741 }
00742
00743
00746 static
00747 void
00748 trx_sysf_create(
00749
00750 mtr_t* mtr)
00751 {
00752 trx_sysf_t* sys_header;
00753 ulint slot_no;
00754 buf_block_t* block;
00755 page_t* page;
00756 ulint page_no;
00757 byte* ptr;
00758 ulint len;
00759
00760 ut_ad(mtr);
00761
00762
00763
00764
00765
00766 mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
00767 mutex_enter(&kernel_mutex);
00768
00769
00770 block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
00771 mtr);
00772 buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
00773
00774 ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
00775
00776 page = buf_block_get_frame(block);
00777
00778 mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_TRX_SYS,
00779 MLOG_2BYTES, mtr);
00780
00781
00782
00783
00784
00785 mlog_write_ulint(page + TRX_SYS_DOUBLEWRITE
00786 + TRX_SYS_DOUBLEWRITE_MAGIC, 0, MLOG_4BYTES, mtr);
00787
00788 sys_header = trx_sysf_get(mtr);
00789
00790
00791 mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1);
00792
00793
00794
00795
00796 ptr = TRX_SYS_RSEGS + sys_header;
00797 len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS)
00798 * TRX_SYS_RSEG_SLOT_SIZE;
00799 memset(ptr, 0xff, len);
00800 ptr += len;
00801 ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END));
00802
00803
00804 memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr);
00805
00806 mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
00807 + page - sys_header, mtr);
00808
00809
00810 slot_no = trx_sysf_rseg_find_free(mtr);
00811 page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no,
00812 mtr);
00813 ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
00814 ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
00815
00816 mutex_exit(&kernel_mutex);
00817 }
00818
00819
00822 UNIV_INTERN
00823 void
00824 trx_sys_init_at_db_start(void)
00825
00826 {
00827 trx_sysf_t* sys_header;
00828 ib_uint64_t rows_to_undo = 0;
00829 const char* unit = "";
00830 trx_t* trx;
00831 mtr_t mtr;
00832
00833 mtr_start(&mtr);
00834
00835 ut_ad(trx_sys == NULL);
00836
00837 mutex_enter(&kernel_mutex);
00838
00839 trx_sys = static_cast<trx_sys_t *>(mem_alloc(sizeof(trx_sys_t)));
00840
00841 sys_header = trx_sysf_get(&mtr);
00842
00843 trx_rseg_list_and_array_init(sys_header, &mtr);
00844
00845 trx_sys->latest_rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
00846
00847
00848
00849
00850
00851
00852
00853
00854 trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
00855 + ut_uint64_align_up(mach_read_from_8(sys_header
00856 + TRX_SYS_TRX_ID_STORE),
00857 TRX_SYS_TRX_ID_WRITE_MARGIN);
00858
00859 UT_LIST_INIT(trx_sys->mysql_trx_list);
00860 trx_dummy_sess = sess_open();
00861 trx_lists_init_at_db_start();
00862
00863 if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
00864 trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
00865
00866 for (;;) {
00867
00868 if (trx->conc_state != TRX_PREPARED) {
00869 rows_to_undo += trx->undo_no;
00870 }
00871
00872 trx = UT_LIST_GET_NEXT(trx_list, trx);
00873
00874 if (!trx) {
00875 break;
00876 }
00877 }
00878
00879 if (rows_to_undo > 1000000000) {
00880 unit = "M";
00881 rows_to_undo = rows_to_undo / 1000000;
00882 }
00883
00884 fprintf(stderr,
00885 "InnoDB: %lu transaction(s) which must be"
00886 " rolled back or cleaned up\n"
00887 "InnoDB: in total %lu%s row operations to undo\n",
00888 (ulong) UT_LIST_GET_LEN(trx_sys->trx_list),
00889 (ulong) rows_to_undo, unit);
00890
00891 fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
00892 trx_sys->max_trx_id);
00893 }
00894
00895 UT_LIST_INIT(trx_sys->view_list);
00896
00897 trx_purge_sys_create();
00898
00899 mutex_exit(&kernel_mutex);
00900
00901 mtr_commit(&mtr);
00902 }
00903
00904
00906 UNIV_INTERN
00907 void
00908 trx_sys_create(void)
00909
00910 {
00911 mtr_t mtr;
00912
00913 mtr_start(&mtr);
00914
00915 trx_sysf_create(&mtr);
00916
00917 mtr_commit(&mtr);
00918
00919 trx_sys_init_at_db_start();
00920 }
00921
00922
00925 static
00926 ibool
00927 trx_sys_file_format_max_write(
00928
00929 ulint format_id,
00930 const char** name)
00932 {
00933 mtr_t mtr;
00934 byte* ptr;
00935 buf_block_t* block;
00936 ib_uint64_t tag_value;
00937
00938 mtr_start(&mtr);
00939
00940 block = buf_page_get(
00941 TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
00942
00943 file_format_max.id = format_id;
00944 file_format_max.name = trx_sys_file_format_id_to_name(format_id);
00945
00946 ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
00947 tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
00948
00949 if (name) {
00950 *name = file_format_max.name;
00951 }
00952
00953 mlog_write_ull(ptr, tag_value, &mtr);
00954
00955 mtr_commit(&mtr);
00956
00957 return(TRUE);
00958 }
00959
00960
00963 static
00964 ulint
00965 trx_sys_file_format_max_read(void)
00966
00967 {
00968 mtr_t mtr;
00969 const byte* ptr;
00970 const buf_block_t* block;
00971 ib_id_t file_format_id;
00972
00973
00974
00975 mtr_start(&mtr);
00976
00977 block = buf_page_get(
00978 TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
00979
00980 ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
00981 file_format_id = mach_read_from_8(ptr);
00982
00983 mtr_commit(&mtr);
00984
00985 file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
00986
00987 if (file_format_id >= FILE_FORMAT_NAME_N) {
00988
00989
00990 return(ULINT_UNDEFINED);
00991 }
00992
00993 return((ulint) file_format_id);
00994 }
00995
00996
00999 UNIV_INTERN
01000 const char*
01001 trx_sys_file_format_id_to_name(
01002
01003 const ulint id)
01004 {
01005 ut_a(id < FILE_FORMAT_NAME_N);
01006
01007 return(file_format_name_map[id]);
01008 }
01009
01010
01014 UNIV_INTERN
01015 ulint
01016 trx_sys_file_format_max_check(
01017
01018 ulint max_format_id)
01019 {
01020 ulint format_id;
01021
01022
01023
01024
01025 format_id = trx_sys_file_format_max_read();
01026 if (format_id == ULINT_UNDEFINED) {
01027
01028
01029 format_id = DICT_TF_FORMAT_MIN;
01030 }
01031
01032 drizzled::errmsg_printf(drizzled::error::INFO, "InnoDB: highest supported file format is %s",
01033 trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
01034
01035 if (format_id > DICT_TF_FORMAT_MAX) {
01036
01037 ut_a(format_id < FILE_FORMAT_NAME_N);
01038
01039 drizzled::errmsg_printf(drizzled::error::ERROR,
01040 "InnoDB: %s: the system tablespace is in a file "
01041 "format that this version doesn't support - %s",
01042 ((max_format_id <= DICT_TF_FORMAT_MAX)
01043 ? "Error" : "Warning"),
01044 trx_sys_file_format_id_to_name(format_id));
01045
01046 if (max_format_id <= DICT_TF_FORMAT_MAX) {
01047 return(DB_ERROR);
01048 }
01049 }
01050
01051 format_id = (format_id > max_format_id) ? format_id : max_format_id;
01052
01053
01054
01055 file_format_max.id = format_id;
01056 file_format_max.name = trx_sys_file_format_id_to_name(format_id);
01057
01058 return(DB_SUCCESS);
01059 }
01060
01061
01065 UNIV_INTERN
01066 ibool
01067 trx_sys_file_format_max_set(
01068
01069 ulint format_id,
01070 const char** name)
01072 {
01073 ibool ret = FALSE;
01074
01075 ut_a(format_id <= DICT_TF_FORMAT_MAX);
01076
01077 mutex_enter(&file_format_max.mutex);
01078
01079
01080 if (format_id != file_format_max.id) {
01081
01082 ret = trx_sys_file_format_max_write(format_id, name);
01083 }
01084
01085 mutex_exit(&file_format_max.mutex);
01086
01087 return(ret);
01088 }
01089
01090
01095 UNIV_INTERN
01096 void
01097 trx_sys_file_format_tag_init(void)
01098
01099 {
01100 ulint format_id;
01101
01102 format_id = trx_sys_file_format_max_read();
01103
01104
01105 if (format_id == ULINT_UNDEFINED) {
01106 trx_sys_file_format_max_set(DICT_TF_FORMAT_MIN, NULL);
01107 }
01108 }
01109
01110
01114 UNIV_INTERN
01115 ibool
01116 trx_sys_file_format_max_upgrade(
01117
01118 const char** name,
01119 ulint format_id)
01120 {
01121 ibool ret = FALSE;
01122
01123 ut_a(name);
01124 ut_a(file_format_max.name != NULL);
01125 ut_a(format_id <= DICT_TF_FORMAT_MAX);
01126
01127 mutex_enter(&file_format_max.mutex);
01128
01129 if (format_id > file_format_max.id) {
01130
01131 ret = trx_sys_file_format_max_write(format_id, name);
01132 }
01133
01134 mutex_exit(&file_format_max.mutex);
01135
01136 return(ret);
01137 }
01138
01139
01142 UNIV_INTERN
01143 const char*
01144 trx_sys_file_format_max_get(void)
01145
01146 {
01147 return(file_format_max.name);
01148 }
01149
01150
01152 UNIV_INTERN
01153 void
01154 trx_sys_file_format_init(void)
01155
01156 {
01157 mutex_create(file_format_max_mutex_key,
01158 &file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
01159
01160
01161
01162 file_format_max.id = DICT_TF_FORMAT_MIN;
01163
01164 file_format_max.name = trx_sys_file_format_id_to_name(
01165 file_format_max.id);
01166 }
01167
01168
01170 UNIV_INTERN
01171 void
01172 trx_sys_file_format_close(void)
01173
01174 {
01175
01176 }
01177
01178
01179
01180 UNIV_INTERN
01181 void
01182 trx_sys_create_rsegs(
01183
01184 ulint n_rsegs)
01185 {
01186 ulint new_rsegs = 0;
01187
01188
01189
01190
01191 if (!srv_force_recovery && !recv_needed_recovery) {
01192 ulint i;
01193
01194 for (i = 0; i < n_rsegs; ++i) {
01195
01196 if (trx_rseg_create() != NULL) {
01197 ++new_rsegs;
01198 } else {
01199 break;
01200 }
01201 }
01202 }
01203
01204 if (new_rsegs > 0) {
01205 fprintf(stderr,
01206 "InnoDB: %lu rollback segment(s) active.\n",
01207 new_rsegs);
01208 }
01209 }
01210
01211 #else
01212
01213
01214
01215
01216
01217 #define TRX_SYS_SPACE 0
01218
01219 #define TRX_SYS_FILE_FORMAT_TAG (UNIV_PAGE_SIZE - 16)
01220
01221
01222
01223 #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW 3645922177UL
01224 #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH 2745987765UL
01225
01226
01227
01228
01229
01235 UNIV_INTERN
01236 ibool
01237 trx_sys_read_file_format_id(
01238
01239 const char *pathname,
01241 ulint *format_id)
01243 {
01244 os_file_t file;
01245 ibool success;
01246 byte buf[UNIV_PAGE_SIZE * 2];
01247 page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
01248 const byte* ptr;
01249 ib_id_t file_format_id;
01250
01251 *format_id = ULINT_UNDEFINED;
01252
01253 file = os_file_create_simple_no_error_handling(
01254 innodb_file_data_key,
01255 pathname,
01256 OS_FILE_OPEN,
01257 OS_FILE_READ_ONLY,
01258 &success
01259 );
01260 if (!success) {
01261
01262 os_file_get_last_error(TRUE);
01263
01264 ut_print_timestamp(stderr);
01265
01266 fprintf(stderr,
01267 " ibbackup: Error: trying to read system tablespace file format,\n"
01268 " ibbackup: but could not open the tablespace file %s!\n",
01269 pathname
01270 );
01271 return(FALSE);
01272 }
01273
01274
01275
01276 success = os_file_read_no_error_handling(
01277 file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, 0, UNIV_PAGE_SIZE
01278 );
01279 if (!success) {
01280
01281 os_file_get_last_error(TRUE);
01282
01283 ut_print_timestamp(stderr);
01284
01285 fprintf(stderr,
01286 " ibbackup: Error: trying to read system table space file format,\n"
01287 " ibbackup: but failed to read the tablespace file %s!\n",
01288 pathname
01289 );
01290 os_file_close(file);
01291 return(FALSE);
01292 }
01293 os_file_close(file);
01294
01295
01296 ptr = page + TRX_SYS_FILE_FORMAT_TAG;
01297 file_format_id = mach_read_from_8(ptr);
01298 file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
01299
01300 if (file_format_id >= FILE_FORMAT_NAME_N) {
01301
01302
01303 return(TRUE);
01304 }
01305
01306 *format_id = (ulint) file_format_id;
01307
01308 return(TRUE);
01309 }
01310
01311
01312
01315 UNIV_INTERN
01316 ibool
01317 trx_sys_read_pertable_file_format_id(
01318
01319 const char *pathname,
01321 ulint *format_id)
01323 {
01324 os_file_t file;
01325 ibool success;
01326 byte buf[UNIV_PAGE_SIZE * 2];
01327 page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
01328 const byte* ptr;
01329 ib_uint32_t flags;
01330
01331 *format_id = ULINT_UNDEFINED;
01332
01333 file = os_file_create_simple_no_error_handling(
01334 innodb_file_data_key,
01335 pathname,
01336 OS_FILE_OPEN,
01337 OS_FILE_READ_ONLY,
01338 &success
01339 );
01340 if (!success) {
01341
01342 os_file_get_last_error(TRUE);
01343
01344 ut_print_timestamp(stderr);
01345
01346 fprintf(stderr,
01347 " ibbackup: Error: trying to read per-table tablespace format,\n"
01348 " ibbackup: but could not open the tablespace file %s!\n",
01349 pathname
01350 );
01351 return(FALSE);
01352 }
01353
01354
01355
01356 success = os_file_read_no_error_handling(
01357 file, page, 0, 0, UNIV_PAGE_SIZE
01358 );
01359 if (!success) {
01360
01361 os_file_get_last_error(TRUE);
01362
01363 ut_print_timestamp(stderr);
01364
01365 fprintf(stderr,
01366 " ibbackup: Error: trying to per-table data file format,\n"
01367 " ibbackup: but failed to read the tablespace file %s!\n",
01368 pathname
01369 );
01370 os_file_close(file);
01371 return(FALSE);
01372 }
01373 os_file_close(file);
01374
01375
01376 ptr = page + 54;
01377 flags = mach_read_from_4(ptr);
01378 if (flags == 0) {
01379
01380 *format_id = 0;
01381 return (TRUE);
01382 } else if (flags & 1) {
01383
01384 *format_id = (flags / 32) % 128;
01385 return (TRUE);
01386 } else {
01387
01388 return(FALSE);
01389 }
01390 }
01391
01392
01393
01396 UNIV_INTERN
01397 const char*
01398 trx_sys_file_format_id_to_name(
01399
01400 const ulint id)
01401 {
01402 if (!(id < FILE_FORMAT_NAME_N)) {
01403
01404 return ("Unknown");
01405 }
01406
01407 return(file_format_name_map[id]);
01408 }
01409
01410 #endif
01411
01412 #ifndef UNIV_HOTBACKUP
01413
01414
01415 UNIV_INTERN
01416 void
01417 trx_sys_close(void)
01418
01419 {
01420 trx_rseg_t* rseg;
01421 read_view_t* view;
01422
01423 ut_ad(trx_sys != NULL);
01424
01425
01426
01427
01428 if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
01429 fprintf(stderr,
01430 "InnoDB: Error: all read views were not closed"
01431 " before shutdown:\n"
01432 "InnoDB: %lu read views open \n",
01433 static_cast<ulint>(UT_LIST_GET_LEN(trx_sys->view_list)) - 1);
01434 }
01435
01436 sess_close(trx_dummy_sess);
01437 trx_dummy_sess = NULL;
01438
01439 trx_purge_sys_close();
01440
01441 mutex_enter(&kernel_mutex);
01442
01443
01444 ut_a(trx_doublewrite != NULL);
01445 ut_free(trx_doublewrite->write_buf_unaligned);
01446 trx_doublewrite->write_buf_unaligned = NULL;
01447
01448 mem_free(trx_doublewrite->buf_block_arr);
01449 trx_doublewrite->buf_block_arr = NULL;
01450
01451 mutex_free(&trx_doublewrite->mutex);
01452 mem_free(trx_doublewrite);
01453 trx_doublewrite = NULL;
01454
01455
01456 rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
01457
01458 while (rseg != NULL) {
01459 trx_rseg_t* prev_rseg = rseg;
01460
01461 rseg = UT_LIST_GET_NEXT(rseg_list, prev_rseg);
01462 UT_LIST_REMOVE(rseg_list, trx_sys->rseg_list, prev_rseg);
01463
01464 trx_rseg_mem_free(prev_rseg);
01465 }
01466
01467 view = UT_LIST_GET_FIRST(trx_sys->view_list);
01468
01469 while (view != NULL) {
01470 read_view_t* prev_view = view;
01471
01472 view = UT_LIST_GET_NEXT(view_list, prev_view);
01473
01474
01475
01476 UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
01477 }
01478
01479 ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == 0);
01480 ut_a(UT_LIST_GET_LEN(trx_sys->rseg_list) == 0);
01481 ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
01482 ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
01483
01484 mem_free(trx_sys);
01485
01486 trx_sys = NULL;
01487 mutex_exit(&kernel_mutex);
01488 }
01489 #endif