Commit 9b9db434 authored by unknown's avatar unknown

After review fixes. Fix bugs in TRUNCATE.


innobase/dict/dict0crea.c:
  dict_truncate_index_tree(): Commit the mtr after deleting the
  index tree. Add diagnostics for error cases. Let the caller update
  SYS_INDEXES.PAGE_NO to the new root page number. Return the new
  root page number, or FIL_NULL on error.
innobase/include/dict0crea.h:
  dict_truncate_index_tree(): Commit the mtr after deleting the
  index tree. Add diagnostics for error cases. Let the caller update
  SYS_INDEXES.PAGE_NO to the new root page number. Return the new
  root page number, or FIL_NULL on error.
innobase/include/page0page.ic:
  page_mem_free(): Disable the memset() call, to make it possible to
  recover some data if someone accidentally deletes a large number
  of records from a table.
innobase/log/log0recv.c:
  Do not disable InnoDB Hot Backup specific code in MySQL builds.
innobase/row/row0mysql.c:
  row_truncate_table_for_mysql(): Remove an infinite loop in case
  a SYS_INDEXES record has been deleted. Avoid deadlocks by committing
  and restarting the mini-transaction.
sql/ha_innodb.cc:
  ha_innobase::delete_all_rows(): set trx->active_trans = 1
parent 6fc758a3
......@@ -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);
}
/*************************************************************************
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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
/***********************************************************************
......
......@@ -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);
}
......
......@@ -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() */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment