diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 4926797721c8f8b2005bf55b3696ba1db09f7d50..fda09feca6fc7a36638dc640cc80a33b6ad27eca 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -729,14 +729,17 @@ dict_drop_index_tree( /*********************************************************************** Truncates the index tree associated with a row in SYS_INDEXES table. */ -void +ulint dict_truncate_index_tree( /*=====================*/ + /* out: new root page number, or + FIL_NULL on failure */ dict_table_t* table, /* in: the table the index belongs to */ rec_t* rec, /* in: record in the clustered index of SYS_INDEXES table */ mtr_t* mtr) /* in: mtr having the latch - on the record page */ + on the record page. The mtr may be + committed and restarted in this call. */ { ulint root_page_no; ulint space; @@ -761,7 +764,10 @@ dict_truncate_index_tree( if (root_page_no == FIL_NULL) { /* The tree has been freed. */ - return; + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Trying to TRUNCATE" + " a missing index of table %s!\n", table->name); + return(FIL_NULL); } ptr = rec_get_nth_field_old(rec, @@ -775,7 +781,10 @@ dict_truncate_index_tree( /* It is a single table tablespace and the .ibd file is missing: do nothing */ - return; + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Trying to TRUNCATE" + " a missing .ibd file of table %s!\n", table->name); + return(FIL_NULL); } ptr = rec_get_nth_field_old(rec, @@ -801,6 +810,20 @@ dict_truncate_index_tree( space, root_page_no, RW_X_LATCH, mtr)); btr_free_root(space, root_page_no, mtr); + /* We will temporarily write FIL_NULL to the PAGE_NO field + in SYS_INDEXES, so that the database will not get into an + inconsistent state in case it crashes between the mtr_commit() + below and the following mtr_commit() call. */ + page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, + FIL_NULL, mtr); + + /* We will need to commit the mini-transaction in order to avoid + deadlocks in the btr_create() call, because otherwise we would + be freeing and allocating pages in the same mini-transaction. */ + mtr_commit(mtr); + /* mtr_commit() will invalidate rec. */ + rec = NULL; + mtr_start(mtr); /* Find the index corresponding to this SYS_INDEXES record. */ for (index = UT_LIST_GET_FIRST(table->indexes); @@ -814,11 +837,17 @@ dict_truncate_index_tree( root_page_no = btr_create(type, space, index_id, comp, mtr); if (index) { index->tree->page = root_page_no; + } else { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Index %lu %lu of table %s is missing\n" + "InnoDB: from the data dictionary during TRUNCATE!\n", + ut_dulint_get_high(index_id), + ut_dulint_get_low(index_id), + table->name); } - page_rec_write_index_page_no(rec, - DICT_SYS_INDEXES_PAGE_NO_FIELD, - root_page_no, mtr); + return(root_page_no); } /************************************************************************* diff --git a/innobase/include/dict0crea.h b/innobase/include/dict0crea.h index 7164e53bceb634a1f3eb382b31479f16cc9f10c5..5dd571be59ca9fe7603a086b7f798be081dec7ae 100644 --- a/innobase/include/dict0crea.h +++ b/innobase/include/dict0crea.h @@ -56,14 +56,17 @@ dict_create_index_step( /*********************************************************************** Truncates the index tree associated with a row in SYS_INDEXES table. */ -void +ulint dict_truncate_index_tree( /*=====================*/ + /* out: new root page number, or + FIL_NULL on failure */ dict_table_t* table, /* in: the table the index belongs to */ rec_t* rec, /* in: record in the clustered index of SYS_INDEXES table */ mtr_t* mtr); /* in: mtr having the latch - on the record page */ + on the record page. The mtr may be + committed and restarted in this call. */ /*********************************************************************** Drops the index tree associated with a row in SYS_INDEXES table. */ diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic index e3e93e9f7567628bd4c6e8fc433c05fbd88e83ea..ac6b0263a7dcb91a3b2240979c22a4ccd5f3f20b 100644 --- a/innobase/include/page0page.ic +++ b/innobase/include/page0page.ic @@ -788,12 +788,15 @@ page_mem_free( page_rec_set_next(rec, free); page_header_set_ptr(page, PAGE_FREE, rec); +#if 0 /* It's better not to destroy the user's data. */ + /* Clear the data bytes of the deleted record in order to improve the compression ratio of the page and to make it easier to read page dumps in corruption reports. The extra bytes of the record cannot be cleared, because page_mem_alloc() needs them in order to determine the size of the deleted record. */ memset(rec, 0, rec_offs_data_size(offsets)); +#endif garbage = page_header_get_field(page, PAGE_GARBAGE); diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index e1869a171b52f55e219a23377771807103df6ab5..ac230f6461bb39943fba3d70ecd0a9245c2ad333 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -1435,7 +1435,6 @@ recv_apply_hashed_log_recs( mutex_exit(&(recv_sys->mutex)); } -#ifdef UNIV_HOTBACKUP /* This page is allocated from the buffer pool and used in the function below */ static page_t* recv_backup_application_page = NULL; @@ -1560,7 +1559,6 @@ recv_apply_log_recs_for_backup(void) recv_sys_empty_hash(); } -#endif /* UNIV_HOTBACKUP */ #ifdef notdefined /*********************************************************************** diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 39c4b76f8144a15f0f86af677c3f55bcdf0be7b6..4c014d39f7af25423bd384d368fb979d07570f7b 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2615,6 +2615,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ rec_t* rec; const byte* field; ulint len; + ulint root_page_no; if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { /* The end of SYS_INDEXES has been reached. */ @@ -2633,11 +2634,33 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ if (rec_get_deleted_flag(rec, FALSE)) { /* The index has been dropped. */ - continue; + goto next_rec; } - dict_truncate_index_tree(table, rec, &mtr); + btr_pcur_store_position(&pcur, &mtr); + /* This call may commit and restart mtr. */ + root_page_no = dict_truncate_index_tree(table, rec, &mtr); + + btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr); + rec = btr_pcur_get_rec(&pcur); + + if (root_page_no != FIL_NULL) { + page_rec_write_index_page_no(rec, + DICT_SYS_INDEXES_PAGE_NO_FIELD, + root_page_no, &mtr); + /* We will need to commit and restart the + mini-transaction in order to avoid deadlocks. + The dict_truncate_index_tree() call has allocated + a page in this mini-transaction, and the rest of + this loop could latch another index page. */ + mtr_commit(&mtr); + mtr_start(&mtr); + btr_pcur_restore_position(BTR_MODIFY_LEAF, + &pcur, &mtr); + } + + next_rec: btr_pcur_move_to_next_user_rec(&pcur, &mtr); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index f68ad99ac44114249ea54718e0fcafbacd4f9326..c23b316f180a0afe74f4d7aea9fc847ee0df7a5b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4250,6 +4250,8 @@ ha_innobase::delete_all_rows(void) /* Truncate the table in InnoDB */ + trx->active_trans = 1; + error = row_truncate_table_for_mysql(prebuilt->table, trx); if (error == DB_ERROR) { /* Cannot truncate; resort to ha_innobase::delete_row() */