1
/*****************************************************************************
3
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************
22
Created 2/25/1997 Heikki Tuuri
23
*******************************************************/
28
#include "row0uins.ic"
31
#include "dict0dict.h"
32
#include "dict0boot.h"
33
#include "dict0crea.h"
37
#include "mach0data.h"
45
#include "ibuf0ibuf.h"
48
/*******************************************************************
49
Removes a clustered index record. The pcur in node was positioned on the
50
record, now it is detached. */
53
row_undo_ins_remove_clust_rec(
54
/*==========================*/
55
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
56
undo_node_t* node) /* in: undo node */
66
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
70
if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
71
ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
73
/* Drop the index tree associated with the row in
76
dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
82
success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
87
btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
89
success = btr_cur_optimistic_delete(btr_cur, &mtr);
91
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
94
trx_undo_rec_release(node->trx, node->undo_no);
99
/* If did not succeed, try pessimistic descent to tree */
102
success = btr_pcur_restore_position(BTR_MODIFY_TREE,
103
&(node->pcur), &mtr);
106
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
107
trx_is_recv(node->trx)
111
/* The delete operation may fail if we have little
112
file space left: TODO: easiest to crash the database
113
and restart with more file space */
115
if (err == DB_OUT_OF_FILE_SPACE
116
&& n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
118
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
122
os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
127
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
129
trx_undo_rec_release(node->trx, node->undo_no);
134
/*******************************************************************
135
Removes a secondary index entry if found. */
138
row_undo_ins_remove_sec_low(
139
/*========================*/
140
/* out: DB_SUCCESS, DB_FAIL, or
141
DB_OUT_OF_FILE_SPACE */
142
ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
143
depending on whether we wish optimistic or
144
pessimistic descent down the index tree */
145
dict_index_t* index, /* in: index */
146
dtuple_t* entry) /* in: index entry to remove */
158
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
160
btr_cur = btr_pcur_get_btr_cur(&pcur);
165
btr_pcur_close(&pcur);
171
if (mode == BTR_MODIFY_LEAF) {
172
success = btr_cur_optimistic_delete(btr_cur, &mtr);
180
ut_ad(mode == BTR_MODIFY_TREE);
182
/* No need to distinguish RB_RECOVERY here, because we
183
are deleting a secondary index record: the distinction
184
between RB_NORMAL and RB_RECOVERY only matters when
185
deleting a record that contains externally stored
187
ut_ad(!dict_index_is_clust(index));
188
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
192
btr_pcur_close(&pcur);
198
/*******************************************************************
199
Removes a secondary index entry from the index if found. Tries first
200
optimistic, then pessimistic descent down the tree. */
203
row_undo_ins_remove_sec(
204
/*====================*/
205
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
206
dict_index_t* index, /* in: index */
207
dtuple_t* entry) /* in: index entry to insert */
212
/* Try first optimistic descent to the B-tree */
214
err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
216
if (err == DB_SUCCESS) {
221
/* Try then pessimistic descent to the B-tree */
223
err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
225
/* The delete operation may fail if we have little
226
file space left: TODO: easiest to crash the database
227
and restart with more file space */
229
if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
233
os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
241
/***************************************************************
242
Parses the row reference and other info in a fresh insert undo record. */
245
row_undo_ins_parse_undo_rec(
246
/*========================*/
247
undo_node_t* node) /* in/out: row undo node */
249
dict_index_t* clust_index;
259
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
260
&dummy_extern, &undo_no, &table_id);
261
ut_ad(type == TRX_UNDO_INSERT_REC);
262
node->rec_type = type;
265
node->table = dict_table_get_on_id(table_id, node->trx);
267
/* Skip the UNDO if we can't find the table or the .ibd file. */
268
if (UNIV_UNLIKELY(node->table == NULL)) {
269
} else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
272
clust_index = dict_table_get_first_index(node->table);
274
if (clust_index != NULL) {
275
ptr = trx_undo_rec_get_row_ref(
276
ptr, clust_index, &node->ref, node->heap);
278
ut_print_timestamp(stderr);
279
fprintf(stderr, " InnoDB: table ");
280
ut_print_name(stderr, node->trx, TRUE,
282
fprintf(stderr, " has no indexes, "
283
"ignoring the table\n");
290
/***************************************************************
291
Undoes a fresh insert of a row to a table. A fresh insert means that
292
the same clustered index unique key did not have any record, even delete
293
marked, at the time of the insert. InnoDB is eager in a rollback:
294
if it figures out that an index record will be removed in the purge
295
anyway, it will remove it in the rollback. */
300
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
301
undo_node_t* node) /* in: row undo node */
304
ut_ad(node->state == UNDO_NODE_INSERT);
306
row_undo_ins_parse_undo_rec(node);
308
if (!node->table || !row_undo_search_clust_to_pcur(node)) {
309
trx_undo_rec_release(node->trx, node->undo_no);
314
/* Iterate over all the indexes and undo the insert.*/
316
/* Skip the clustered index (the first index) */
317
node->index = dict_table_get_next_index(
318
dict_table_get_first_index(node->table));
320
while (node->index != NULL) {
324
entry = row_build_index_entry(node->row, node->ext,
325
node->index, node->heap);
326
if (UNIV_UNLIKELY(!entry)) {
327
/* The database must have crashed after
328
inserting a clustered index record but before
329
writing all the externally stored columns of
330
that record. Because secondary index entries
331
are inserted after the clustered index record,
332
we may assume that the secondary index record
333
does not exist. However, this situation may
334
only occur during the rollback of incomplete
336
ut_a(trx_is_recv(node->trx));
338
err = row_undo_ins_remove_sec(node->index, entry);
340
if (err != DB_SUCCESS) {
346
node->index = dict_table_get_next_index(node->index);
349
return(row_undo_ins_remove_clust_rec(node));