summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <marko@hundin.mysql.fi>2005-03-01 19:42:59 +0200
committerunknown <marko@hundin.mysql.fi>2005-03-01 19:42:59 +0200
commit39cf45fd54247ca02554a2ecfedcbfbd996b9060 (patch)
tree87a9487085f2946b718777b52b8cfc500bea903b
parent91fa4862c07354a7ac65055758ca21cf21296245 (diff)
downloadmariadb-git-39cf45fd54247ca02554a2ecfedcbfbd996b9060.tar.gz
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
-rw-r--r--innobase/dict/dict0crea.c43
-rw-r--r--innobase/include/dict0crea.h7
-rw-r--r--innobase/include/page0page.ic3
-rw-r--r--innobase/log/log0recv.c2
-rw-r--r--innobase/row/row0mysql.c27
-rw-r--r--sql/ha_innodb.cc2
6 files changed, 71 insertions, 13 deletions
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 4926797721c..fda09feca6f 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 7164e53bceb..5dd571be59c 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 e3e93e9f756..ac6b0263a7d 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 e1869a171b5..ac230f6461b 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -1435,7 +1435,6 @@ loop:
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 @@ skip_this_recv_addr:
recv_sys_empty_hash();
}
-#endif /* UNIV_HOTBACKUP */
#ifdef notdefined
/***********************************************************************
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 39c4b76f814..4c014d39f7a 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 f68ad99ac44..c23b316f180 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() */