row0uins.c 6.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/******************************************************
Fresh insert undo

(c) 1996 Innobase Oy

Created 2/25/1997 Heikki Tuuri
*******************************************************/

#include "row0uins.h"

#ifdef UNIV_NONINL
#include "row0uins.ic"
#endif

#include "dict0dict.h"
#include "dict0boot.h"
#include "dict0crea.h"
#include "trx0undo.h"
#include "trx0roll.h"
#include "btr0btr.h"
#include "mach0data.h"
#include "row0undo.h"
#include "row0vers.h"
#include "trx0trx.h"
#include "trx0rec.h"
#include "row0row.h"
#include "row0upd.h"
#include "que0que.h"
#include "ibuf0ibuf.h"
#include "log0log.h"

/*******************************************************************
Removes a clustered index record. The pcur in node was positioned on the
record, now it is detached. */
static
ulint
row_undo_ins_remove_clust_rec(
/*==========================*/
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
40
	undo_node_t*	node)	/* in: undo node */
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
	btr_cur_t*	btr_cur;		
	ibool		success;
	ulint		err;
	ulint		n_tries		= 0;
	mtr_t		mtr;
	
	mtr_start(&mtr);
	
	success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur),
									&mtr);
	ut_a(success);

	if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {

		/* Drop the index tree associated with the row in
		SYS_INDEXES table: */
	
		dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);

		mtr_commit(&mtr);

		mtr_start(&mtr);

		success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
						&(node->pcur), &mtr);
		ut_a(success);
	}
		
	btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
	
	success = btr_cur_optimistic_delete(btr_cur, &mtr);

	btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);

	if (success) {
		trx_undo_rec_release(node->trx, node->undo_no);

		return(DB_SUCCESS);
	}
retry:
	/* If did not succeed, try pessimistic descent to tree */
	mtr_start(&mtr);
	
	success = btr_pcur_restore_position(BTR_MODIFY_TREE,
							&(node->pcur), &mtr);
	ut_a(success);

89
	btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

	/* The delete operation may fail if we have little
	file space left: TODO: easiest to crash the database
	and restart with more file space */

	if (err == DB_OUT_OF_FILE_SPACE
				&& n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {

		btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);

		n_tries++;

		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
			
		goto retry;
	}

	btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);

	trx_undo_rec_release(node->trx, node->undo_no);

	return(err);
}

/*******************************************************************
Removes a secondary index entry if found. */
static
ulint
row_undo_ins_remove_sec_low(
/*========================*/
				/* out: DB_SUCCESS, DB_FAIL, or
				DB_OUT_OF_FILE_SPACE */
	ulint		mode,	/* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
				depending on whether we wish optimistic or
				pessimistic descent down the index tree */
	dict_index_t*	index,	/* in: index */
126
	dtuple_t*	entry)	/* in: index entry to remove */
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
{
	btr_pcur_t	pcur;		
	btr_cur_t*	btr_cur;
	ibool		found;
	ibool		success;
	ulint		err;
	mtr_t		mtr;
	
	log_free_check();
	mtr_start(&mtr);

	found = row_search_index_entry(index, entry, mode, &pcur, &mtr);

	btr_cur = btr_pcur_get_btr_cur(&pcur);

	if (!found) {
		/* Not found */

		btr_pcur_close(&pcur);
		mtr_commit(&mtr);

		return(DB_SUCCESS);
	}

	if (mode == BTR_MODIFY_LEAF) {
		success = btr_cur_optimistic_delete(btr_cur, &mtr);

		if (success) {
			err = DB_SUCCESS;
		} else {
			err = DB_FAIL;
		}
	} else {
		ut_ad(mode == BTR_MODIFY_TREE);

162
		btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	}

	btr_pcur_close(&pcur);
	mtr_commit(&mtr);

	return(err);
}

/*******************************************************************
Removes a secondary index entry from the index if found. Tries first
optimistic, then pessimistic descent down the tree. */
static
ulint
row_undo_ins_remove_sec(
/*====================*/
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
	dict_index_t*	index,	/* in: index */
180
	dtuple_t*	entry)	/* in: index entry to insert */
181 182 183 184 185 186
{
	ulint	err;
	ulint	n_tries	= 0;
	
	/* Try first optimistic descent to the B-tree */

187
	err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
188 189 190 191 192 193 194 195
								
	if (err == DB_SUCCESS) {

		return(err);
	}

	/* Try then pessimistic descent to the B-tree */
retry:
196
	err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

	/* The delete operation may fail if we have little
	file space left: TODO: easiest to crash the database
	and restart with more file space */

	if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {

		n_tries++;

		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
			
		goto retry;
	}

	return(err);
}

/***************************************************************
Parses the row reference and other info in a fresh insert undo record. */
static
void
row_undo_ins_parse_undo_rec(
/*========================*/
220
	undo_node_t*	node)	/* in: row undo node */
221 222 223 224 225 226 227
{
	dict_index_t*	clust_index;
	byte*		ptr;
	dulint		undo_no;
	dulint		table_id;
	ulint		type;
	ulint		dummy;
228
	ibool		dummy_extern;
229

230
	ut_ad(node);
231
	
232 233
	ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
					&dummy_extern, &undo_no, &table_id);
234 235 236 237 238
	ut_ad(type == TRX_UNDO_INSERT_REC);
	node->rec_type = type;

	node->table = dict_table_get_on_id(table_id, node->trx);

239
	if (node->table == NULL) {
unknown's avatar
unknown committed
240 241

		return;
242 243
	}

unknown's avatar
unknown committed
244 245 246 247 248 249 250
	if (node->table->ibd_file_missing) {
		/* We skip undo operations to missing .ibd files */
		node->table = NULL;

		return;
	}

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	clust_index = dict_table_get_first_index(node->table);
	
	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
								node->heap);
}
	
/***************************************************************
Undoes a fresh insert of a row to a table. A fresh insert means that
the same clustered index unique key did not have any record, even delete
marked, at the time of the insert. */

ulint
row_undo_ins(
/*=========*/
				/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
266
	undo_node_t*	node)	/* in: row undo node */
267 268 269 270
{
	dtuple_t*	entry;
	ibool		found;
	ulint		err;
271 272

	ut_ad(node);
273
	ut_ad(node->state == UNDO_NODE_INSERT);
unknown's avatar
unknown committed
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);
unknown's avatar
unknown committed
285

286 287 288 289 290 291 292 293 294
		return(DB_SUCCESS);
	}

	node->index = dict_table_get_next_index(
				dict_table_get_first_index(node->table));

	while (node->index != NULL) {
		entry = row_build_index_entry(node->row, node->index,
								node->heap);
295
		err = row_undo_ins_remove_sec(node->index, entry);
296 297 298 299 300 301 302 303 304

		if (err != DB_SUCCESS) {

			return(err);
		}
		
		node->index = dict_table_get_next_index(node->index);
	}

305
	err = row_undo_ins_remove_clust_rec(node);
306 307 308
		
	return(err);
}