~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/******************************************************
2
Fresh insert undo
3
4
(c) 1996 Innobase Oy
5
6
Created 2/25/1997 Heikki Tuuri
7
*******************************************************/
8
9
#include "row0uins.h"
10
11
#ifdef UNIV_NONINL
12
#include "row0uins.ic"
13
#endif
14
15
#include "dict0dict.h"
16
#include "dict0boot.h"
17
#include "dict0crea.h"
18
#include "trx0undo.h"
19
#include "trx0roll.h"
20
#include "btr0btr.h"
21
#include "mach0data.h"
22
#include "row0undo.h"
23
#include "row0vers.h"
24
#include "trx0trx.h"
25
#include "trx0rec.h"
26
#include "row0row.h"
27
#include "row0upd.h"
28
#include "que0que.h"
29
#include "ibuf0ibuf.h"
30
#include "log0log.h"
31
32
/*******************************************************************
33
Removes a clustered index record. The pcur in node was positioned on the
34
record, now it is detached. */
35
static
36
ulint
37
row_undo_ins_remove_clust_rec(
38
/*==========================*/
39
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
40
	undo_node_t*	node)	/* in: undo node */
41
{
42
	btr_cur_t*	btr_cur;
43
	ibool		success;
44
	ulint		err;
45
	ulint		n_tries		= 0;
46
	mtr_t		mtr;
47
48
	mtr_start(&mtr);
49
50
	success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
51
					    &mtr);
52
	ut_a(success);
53
54
	if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
55
56
		/* Drop the index tree associated with the row in
57
		SYS_INDEXES table: */
58
59
		dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
60
61
		mtr_commit(&mtr);
62
63
		mtr_start(&mtr);
64
65
		success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
66
						    &(node->pcur), &mtr);
67
		ut_a(success);
68
	}
69
70
	btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
71
72
	success = btr_cur_optimistic_delete(btr_cur, &mtr);
73
74
	btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
75
76
	if (success) {
77
		trx_undo_rec_release(node->trx, node->undo_no);
78
79
		return(DB_SUCCESS);
80
	}
81
retry:
82
	/* If did not succeed, try pessimistic descent to tree */
83
	mtr_start(&mtr);
84
85
	success = btr_pcur_restore_position(BTR_MODIFY_TREE,
86
					    &(node->pcur), &mtr);
87
	ut_a(success);
88
89
	btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
90
91
	/* The delete operation may fail if we have little
92
	file space left: TODO: easiest to crash the database
93
	and restart with more file space */
94
95
	if (err == DB_OUT_OF_FILE_SPACE
96
	    && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
97
98
		btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
99
100
		n_tries++;
101
102
		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
103
104
		goto retry;
105
	}
106
107
	btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
108
109
	trx_undo_rec_release(node->trx, node->undo_no);
110
111
	return(err);
112
}
113
114
/*******************************************************************
115
Removes a secondary index entry if found. */
116
static
117
ulint
118
row_undo_ins_remove_sec_low(
119
/*========================*/
120
				/* out: DB_SUCCESS, DB_FAIL, or
121
				DB_OUT_OF_FILE_SPACE */
122
	ulint		mode,	/* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
123
				depending on whether we wish optimistic or
124
				pessimistic descent down the index tree */
125
	dict_index_t*	index,	/* in: index */
126
	dtuple_t*	entry)	/* in: index entry to remove */
127
{
128
	btr_pcur_t	pcur;
129
	btr_cur_t*	btr_cur;
130
	ibool		found;
131
	ibool		success;
132
	ulint		err;
133
	mtr_t		mtr;
134
135
	log_free_check();
136
	mtr_start(&mtr);
137
138
	found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
139
140
	btr_cur = btr_pcur_get_btr_cur(&pcur);
141
142
	if (!found) {
143
		/* Not found */
144
145
		btr_pcur_close(&pcur);
146
		mtr_commit(&mtr);
147
148
		return(DB_SUCCESS);
149
	}
150
151
	if (mode == BTR_MODIFY_LEAF) {
152
		success = btr_cur_optimistic_delete(btr_cur, &mtr);
153
154
		if (success) {
155
			err = DB_SUCCESS;
156
		} else {
157
			err = DB_FAIL;
158
		}
159
	} else {
160
		ut_ad(mode == BTR_MODIFY_TREE);
161
162
		btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
163
	}
164
165
	btr_pcur_close(&pcur);
166
	mtr_commit(&mtr);
167
168
	return(err);
169
}
170
171
/*******************************************************************
172
Removes a secondary index entry from the index if found. Tries first
173
optimistic, then pessimistic descent down the tree. */
174
static
175
ulint
176
row_undo_ins_remove_sec(
177
/*====================*/
178
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
179
	dict_index_t*	index,	/* in: index */
180
	dtuple_t*	entry)	/* in: index entry to insert */
181
{
182
	ulint	err;
183
	ulint	n_tries	= 0;
184
185
	/* Try first optimistic descent to the B-tree */
186
187
	err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
188
189
	if (err == DB_SUCCESS) {
190
191
		return(err);
192
	}
193
194
	/* Try then pessimistic descent to the B-tree */
195
retry:
196
	err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
197
198
	/* The delete operation may fail if we have little
199
	file space left: TODO: easiest to crash the database
200
	and restart with more file space */
201
202
	if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
203
204
		n_tries++;
205
206
		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
207
208
		goto retry;
209
	}
210
211
	return(err);
212
}
213
214
/***************************************************************
215
Parses the row reference and other info in a fresh insert undo record. */
216
static
217
void
218
row_undo_ins_parse_undo_rec(
219
/*========================*/
220
	undo_node_t*	node)	/* in: row undo node */
221
{
222
	dict_index_t*	clust_index;
223
	byte*		ptr;
224
	dulint		undo_no;
225
	dulint		table_id;
226
	ulint		type;
227
	ulint		dummy;
228
	ibool		dummy_extern;
229
230
	ut_ad(node);
231
232
	ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
233
				    &dummy_extern, &undo_no, &table_id);
234
	ut_ad(type == TRX_UNDO_INSERT_REC);
235
	node->rec_type = type;
236
237
	node->table = dict_table_get_on_id(table_id, node->trx);
238
239
	if (node->table == NULL) {
240
241
		return;
242
	}
243
244
	if (node->table->ibd_file_missing) {
245
		/* We skip undo operations to missing .ibd files */
246
		node->table = NULL;
247
248
		return;
249
	}
250
251
	clust_index = dict_table_get_first_index(node->table);
252
253
	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
254
				       node->heap);
255
}
256
257
/***************************************************************
258
Undoes a fresh insert of a row to a table. A fresh insert means that
259
the same clustered index unique key did not have any record, even delete
260
marked, at the time of the insert. */
261
262
ulint
263
row_undo_ins(
264
/*=========*/
265
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
266
	undo_node_t*	node)	/* in: row undo node */
267
{
268
	dtuple_t*	entry;
269
	ibool		found;
270
	ulint		err;
271
272
	ut_ad(node);
273
	ut_ad(node->state == UNDO_NODE_INSERT);
274
275
	row_undo_ins_parse_undo_rec(node);
276
277
	if (node->table == NULL) {
278
		found = FALSE;
279
	} else {
280
		found = row_undo_search_clust_to_pcur(node);
281
	}
282
283
	if (!found) {
284
		trx_undo_rec_release(node->trx, node->undo_no);
285
286
		return(DB_SUCCESS);
287
	}
288
289
	node->index = dict_table_get_next_index(
290
		dict_table_get_first_index(node->table));
291
292
	while (node->index != NULL) {
293
		entry = row_build_index_entry(node->row, node->index,
294
					      node->heap);
295
		err = row_undo_ins_remove_sec(node->index, entry);
296
297
		if (err != DB_SUCCESS) {
298
299
			return(err);
300
		}
301
302
		node->index = dict_table_get_next_index(node->index);
303
	}
304
305
	err = row_undo_ins_remove_clust_rec(node);
306
307
	return(err);
308
}