~drizzle-trunk/drizzle/development

641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1
/*****************************************************************************
2
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
3
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
4
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.
8
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.
12
13
You should have received a copy of the GNU General Public License along with
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
16
17
*****************************************************************************/
18
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
19
/**************************************************//**
20
@file row/row0purge.c
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
21
Purge obsolete records
22
23
Created 3/14/1997 Heikki Tuuri
24
*******************************************************/
25
26
#include "row0purge.h"
27
28
#ifdef UNIV_NONINL
29
#include "row0purge.ic"
30
#endif
31
32
#include "fsp0fsp.h"
33
#include "mach0data.h"
34
#include "trx0rseg.h"
35
#include "trx0trx.h"
36
#include "trx0roll.h"
37
#include "trx0undo.h"
38
#include "trx0purge.h"
39
#include "trx0rec.h"
40
#include "que0que.h"
41
#include "row0row.h"
42
#include "row0upd.h"
43
#include "row0vers.h"
44
#include "row0mysql.h"
45
#include "log0log.h"
46
1819.9.13 by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100610135811-1jxs81q050wpabyc from MySQL InnoDB
47
/*************************************************************************
1819.9.12 by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100608181408-c5xsjlom5olr4mxt from MySQL InnoDB
48
IMPORTANT NOTE: Any operation that generates redo MUST check that there
49
is enough space in the redo log before for that operation. This is
50
done by calling log_free_check(). The reason for checking the
51
availability of the redo log space before the start of the operation is
52
that we MUST not hold any synchonization objects when performing the
53
check.
54
If you make a change in this module make sure that no codepath is
55
introduced where a call to log_free_check() is bypassed. */
56
1819.9.25 by Inaam Rana, Stewart Smith
Merge Revision revid:inaam.rana@oracle.com-20100621155209-1pu7nwq05x7tbfoo from MySQL InnoDB
57
/*************************************************************************
58
IMPORTANT NOTE: Any operation that generates redo MUST check that there
59
is enough space in the redo log before for that operation. This is
60
done by calling log_free_check(). The reason for checking the
61
availability of the redo log space before the start of the operation is
62
that we MUST not hold any synchonization objects when performing the
63
check.
64
If you make a change in this module make sure that no codepath is
65
introduced where a call to log_free_check() is bypassed. */
66
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
67
/********************************************************************//**
68
Creates a purge node to a query graph.
69
@return	own: purge node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
70
UNIV_INTERN
71
purge_node_t*
72
row_purge_node_create(
73
/*==================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
74
	que_thr_t*	parent,	/*!< in: parent node, i.e., a thr node */
75
	mem_heap_t*	heap)	/*!< in: memory heap where created */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
76
{
77
	purge_node_t*	node;
78
79
	ut_ad(parent && heap);
80
2023.3.14 by Monty Taylor
More casting.
81
	node = static_cast<purge_node_t *>(mem_heap_alloc(heap, sizeof(purge_node_t)));
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
82
83
	node->common.type = QUE_NODE_PURGE;
84
	node->common.parent = parent;
85
86
	node->heap = mem_heap_create(256);
87
88
	return(node);
89
}
90
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
91
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
92
Repositions the pcur in the purge node on the clustered index record,
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
93
if found.
94
@return	TRUE if the record was found */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
95
static
96
ibool
97
row_purge_reposition_pcur(
98
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
99
	ulint		mode,	/*!< in: latching mode */
100
	purge_node_t*	node,	/*!< in: row purge node */
101
	mtr_t*		mtr)	/*!< in: mtr */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
102
{
103
	ibool	found;
104
105
	if (node->found_clust) {
106
		found = btr_pcur_restore_position(mode, &(node->pcur), mtr);
107
108
		return(found);
109
	}
110
111
	found = row_search_on_row_ref(&(node->pcur), mode, node->table,
112
				      node->ref, mtr);
113
	node->found_clust = found;
114
115
	if (found) {
116
		btr_pcur_store_position(&(node->pcur), mtr);
117
	}
118
119
	return(found);
120
}
121
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
122
/***********************************************************//**
123
Removes a delete marked clustered index record if possible.
124
@return TRUE if success, or if not found, or if modified after the
125
delete marking */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
126
static
127
ibool
128
row_purge_remove_clust_if_poss_low(
129
/*===============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
130
	purge_node_t*	node,	/*!< in: row purge node */
131
	ulint		mode)	/*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
132
{
133
	dict_index_t*	index;
134
	btr_pcur_t*	pcur;
135
	btr_cur_t*	btr_cur;
136
	ibool		success;
137
	ulint		err;
138
	mtr_t		mtr;
139
	rec_t*		rec;
140
	mem_heap_t*	heap		= NULL;
141
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
142
	rec_offs_init(offsets_);
143
144
	index = dict_table_get_first_index(node->table);
145
146
	pcur = &(node->pcur);
147
	btr_cur = btr_pcur_get_btr_cur(pcur);
148
1819.9.12 by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100608181408-c5xsjlom5olr4mxt from MySQL InnoDB
149
	log_free_check();
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
150
	mtr_start(&mtr);
151
152
	success = row_purge_reposition_pcur(mode, node, &mtr);
153
154
	if (!success) {
155
		/* The record is already removed */
156
157
		btr_pcur_commit_specify_mtr(pcur, &mtr);
158
159
		return(TRUE);
160
	}
161
162
	rec = btr_pcur_get_rec(pcur);
163
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
164
	if (node->roll_ptr != row_get_rec_roll_ptr(
165
		    rec, index, rec_get_offsets(rec, index, offsets_,
166
						ULINT_UNDEFINED, &heap))) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
167
		if (UNIV_LIKELY_NULL(heap)) {
168
			mem_heap_free(heap);
169
		}
170
		/* Someone else has modified the record later: do not remove */
171
		btr_pcur_commit_specify_mtr(pcur, &mtr);
172
173
		return(TRUE);
174
	}
175
176
	if (UNIV_LIKELY_NULL(heap)) {
177
		mem_heap_free(heap);
178
	}
179
180
	if (mode == BTR_MODIFY_LEAF) {
181
		success = btr_cur_optimistic_delete(btr_cur, &mtr);
182
	} else {
183
		ut_ad(mode == BTR_MODIFY_TREE);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
184
		btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
185
					   RB_NONE, &mtr);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
186
187
		if (err == DB_SUCCESS) {
188
			success = TRUE;
189
		} else if (err == DB_OUT_OF_FILE_SPACE) {
190
			success = FALSE;
191
		} else {
192
			ut_error;
193
		}
194
	}
195
196
	btr_pcur_commit_specify_mtr(pcur, &mtr);
197
198
	return(success);
199
}
200
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
201
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
202
Removes a clustered index record if it has not been modified after the delete
203
marking. */
204
static
205
void
206
row_purge_remove_clust_if_poss(
207
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
208
	purge_node_t*	node)	/*!< in: row purge node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
209
{
210
	ibool	success;
211
	ulint	n_tries	= 0;
212
213
	/*	fputs("Purge: Removing clustered record\n", stderr); */
214
215
	success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF);
216
	if (success) {
217
218
		return;
219
	}
220
retry:
221
	success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE);
222
	/* The delete operation may fail if we have little
223
	file space left: TODO: easiest to crash the database
224
	and restart with more file space */
225
226
	if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
227
		n_tries++;
228
229
		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
230
231
		goto retry;
232
	}
233
234
	ut_a(success);
235
}
236
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
237
/***********************************************************//**
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
238
Determines if it is possible to remove a secondary index entry.
239
Removal is possible if the secondary index entry does not refer to any
240
not delete marked version of a clustered index record where DB_TRX_ID
241
is newer than the purge view.
242
243
NOTE: This function should only be called by the purge thread, only
244
while holding a latch on the leaf page of the secondary index entry
245
(or keeping the buffer pool watch on the page).  It is possible that
246
this function first returns TRUE and then FALSE, if a user transaction
247
inserts a record that the secondary index entry would refer to.
248
However, in that case, the user transaction would also re-insert the
249
secondary index entry after purge has removed it and released the leaf
250
page latch.
251
@return	TRUE if the secondary index record can be purged */
252
UNIV_INTERN
253
ibool
254
row_purge_poss_sec(
255
/*===============*/
256
	purge_node_t*	node,	/*!< in/out: row purge node */
257
	dict_index_t*	index,	/*!< in: secondary index */
258
	const dtuple_t*	entry)	/*!< in: secondary index entry */
259
{
260
	ibool	can_delete;
261
	mtr_t	mtr;
262
263
	ut_ad(!dict_index_is_clust(index));
264
	mtr_start(&mtr);
265
266
	can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
267
		|| !row_vers_old_has_index_entry(TRUE,
268
						 btr_pcur_get_rec(&node->pcur),
269
						 &mtr, index, entry);
270
271
	btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
272
273
	return(can_delete);
274
}
275
276
/***************************************************************
277
Removes a secondary index entry if possible, by modifying the
278
index tree.  Does not try to buffer the delete.
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
279
@return	TRUE if success or if not found */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
280
static
281
ibool
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
282
row_purge_remove_sec_if_poss_tree(
283
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
284
	purge_node_t*	node,	/*!< in: row purge node */
285
	dict_index_t*	index,	/*!< in: index */
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
286
	const dtuple_t*	entry)	/*!< in: index entry */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
287
{
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
288
	btr_pcur_t		pcur;
289
	btr_cur_t*		btr_cur;
290
	ibool			success	= TRUE;
291
	ulint			err;
292
	mtr_t			mtr;
293
	enum row_search_result	search_result;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
294
295
	log_free_check();
296
	mtr_start(&mtr);
297
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
298
	search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
299
					       &pcur, &mtr);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
300
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
301
	switch (search_result) {
302
	case ROW_NOT_FOUND:
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
303
		/* Not found.  This is a legitimate condition.  In a
304
		rollback, InnoDB will remove secondary recs that would
305
		be purged anyway.  Then the actual purge will not find
306
		the secondary index record.  Also, the purge itself is
307
		eager: if it comes to consider a secondary index
308
		record, and notices it does not need to exist in the
309
		index, it will remove it.  Then if/when the purge
310
		comes to consider the secondary index record a second
311
		time, it will not exist any more in the index. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
312
313
		/* fputs("PURGE:........sec entry not found\n", stderr); */
314
		/* dtuple_print(stderr, entry); */
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
315
		goto func_exit;
316
	case ROW_FOUND:
317
		break;
318
	case ROW_BUFFERED:
319
	case ROW_NOT_DELETED_REF:
320
		/* These are invalid outcomes, because the mode passed
321
		to row_search_index_entry() did not include any of the
322
		flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
323
		ut_error;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
324
	}
325
326
	btr_cur = btr_pcur_get_btr_cur(&pcur);
327
328
	/* We should remove the index record if no later version of the row,
329
	which cannot be purged yet, requires its existence. If some requires,
330
	we should do nothing. */
331
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
332
	if (row_purge_poss_sec(node, index, entry)) {
333
		/* Remove the index record, which should have been
334
		marked for deletion. */
335
		ut_ad(REC_INFO_DELETED_FLAG
336
		      & rec_get_info_bits(btr_cur_get_rec(btr_cur),
337
					  dict_table_is_comp(index->table)));
338
339
		btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
340
					   RB_NONE, &mtr);
341
		switch (UNIV_EXPECT(err, DB_SUCCESS)) {
342
		case DB_SUCCESS:
343
			break;
344
		case DB_OUT_OF_FILE_SPACE:
345
			success = FALSE;
346
			break;
347
		default:
348
			ut_error;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
349
		}
350
	}
351
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
352
func_exit:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
353
	btr_pcur_close(&pcur);
354
	mtr_commit(&mtr);
355
356
	return(success);
357
}
358
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
359
/***************************************************************
360
Removes a secondary index entry without modifying the index tree,
361
if possible.
362
@return	TRUE if success or if not found */
363
static
364
ibool
365
row_purge_remove_sec_if_poss_leaf(
366
/*==============================*/
367
	purge_node_t*	node,	/*!< in: row purge node */
368
	dict_index_t*	index,	/*!< in: index */
369
	const dtuple_t*	entry)	/*!< in: index entry */
370
{
371
	mtr_t			mtr;
372
	btr_pcur_t		pcur;
373
	enum row_search_result	search_result;
374
375
	log_free_check();
376
377
	mtr_start(&mtr);
378
379
	/* Set the purge node for the call to row_purge_poss_sec(). */
380
	pcur.btr_cur.purge_node = node;
381
	/* Set the query thread, so that ibuf_insert_low() will be
382
	able to invoke thd_get_trx(). */
2023.3.14 by Monty Taylor
More casting.
383
	pcur.btr_cur.thr = static_cast<que_thr_t *>(que_node_get_parent(node));
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
384
385
	search_result = row_search_index_entry(
386
		index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
387
388
	switch (search_result) {
389
		ibool	success;
390
	case ROW_FOUND:
391
		/* Before attempting to purge a record, check
392
		if it is safe to do so. */
393
		if (row_purge_poss_sec(node, index, entry)) {
394
			btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
395
396
			/* Only delete-marked records should be purged. */
397
			ut_ad(REC_INFO_DELETED_FLAG
398
			      & rec_get_info_bits(
399
				      btr_cur_get_rec(btr_cur),
400
				      dict_table_is_comp(index->table)));
401
402
			if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
403
404
				/* The index entry could not be deleted. */
405
				success = FALSE;
406
				goto func_exit;
407
			}
408
		}
409
		/* fall through (the index entry is still needed,
410
		or the deletion succeeded) */
411
	case ROW_NOT_DELETED_REF:
412
		/* The index entry is still needed. */
413
	case ROW_BUFFERED:
414
		/* The deletion was buffered. */
415
	case ROW_NOT_FOUND:
416
		/* The index entry does not exist, nothing to do. */
417
		success = TRUE;
418
	func_exit:
419
		btr_pcur_close(&pcur);
420
		mtr_commit(&mtr);
421
		return(success);
422
	}
423
424
	ut_error;
425
	return(FALSE);
426
}
427
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
428
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
429
Removes a secondary index entry if possible. */
430
UNIV_INLINE
431
void
432
row_purge_remove_sec_if_poss(
433
/*=========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
434
	purge_node_t*	node,	/*!< in: row purge node */
435
	dict_index_t*	index,	/*!< in: index */
436
	dtuple_t*	entry)	/*!< in: index entry */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
437
{
438
	ibool	success;
439
	ulint	n_tries		= 0;
440
441
	/*	fputs("Purge: Removing secondary record\n", stderr); */
442
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
443
	if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
444
445
		return;
446
	}
447
retry:
1819.7.68 by Stewart Smith
Merge initial InnoDB+ import.
448
	success = row_purge_remove_sec_if_poss_tree(node, index, entry);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
449
	/* The delete operation may fail if we have little
450
	file space left: TODO: easiest to crash the database
451
	and restart with more file space */
452
453
	if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
454
455
		n_tries++;
456
457
		os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
458
459
		goto retry;
460
	}
461
462
	ut_a(success);
463
}
464
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
465
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
466
Purges a delete marking of a record. */
467
static
468
void
469
row_purge_del_mark(
470
/*===============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
471
	purge_node_t*	node)	/*!< in: row purge node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
472
{
473
	mem_heap_t*	heap;
474
	dtuple_t*	entry;
475
	dict_index_t*	index;
476
477
	ut_ad(node);
478
479
	heap = mem_heap_create(1024);
480
481
	while (node->index != NULL) {
482
		index = node->index;
483
484
		/* Build the index entry */
485
		entry = row_build_index_entry(node->row, NULL, index, heap);
486
		ut_a(entry);
487
		row_purge_remove_sec_if_poss(node, index, entry);
488
489
		node->index = dict_table_get_next_index(node->index);
490
	}
491
492
	mem_heap_free(heap);
493
494
	row_purge_remove_clust_if_poss(node);
495
}
496
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
497
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
498
Purges an update of an existing record. Also purges an update of a delete
499
marked record if that record contained an externally stored field. */
500
static
501
void
502
row_purge_upd_exist_or_extern(
503
/*==========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
504
	purge_node_t*	node)	/*!< in: row purge node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
505
{
506
	mem_heap_t*	heap;
507
	dtuple_t*	entry;
508
	dict_index_t*	index;
509
	ibool		is_insert;
510
	ulint		rseg_id;
511
	ulint		page_no;
512
	ulint		offset;
513
	ulint		i;
514
	mtr_t		mtr;
515
516
	ut_ad(node);
517
518
	if (node->rec_type == TRX_UNDO_UPD_DEL_REC) {
519
520
		goto skip_secondaries;
521
	}
522
523
	heap = mem_heap_create(1024);
524
525
	while (node->index != NULL) {
526
		index = node->index;
527
528
		if (row_upd_changes_ord_field_binary(NULL, node->index,
529
						     node->update)) {
530
			/* Build the older version of the index entry */
531
			entry = row_build_index_entry(node->row, NULL,
532
						      index, heap);
533
			ut_a(entry);
534
			row_purge_remove_sec_if_poss(node, index, entry);
535
		}
536
537
		node->index = dict_table_get_next_index(node->index);
538
	}
539
540
	mem_heap_free(heap);
541
542
skip_secondaries:
543
	/* Free possible externally stored fields */
544
	for (i = 0; i < upd_get_n_fields(node->update); i++) {
545
546
		const upd_field_t*	ufield
547
			= upd_get_nth_field(node->update, i);
548
549
		if (dfield_is_ext(&ufield->new_val)) {
550
			buf_block_t*	block;
551
			ulint		internal_offset;
552
			byte*		data_field;
553
554
			/* We use the fact that new_val points to
555
			node->undo_rec and get thus the offset of
556
			dfield data inside the undo record. Then we
557
			can calculate from node->roll_ptr the file
558
			address of the new_val data */
559
560
			internal_offset
561
				= ((const byte*)
562
				   dfield_get_data(&ufield->new_val))
563
				- node->undo_rec;
564
565
			ut_a(internal_offset < UNIV_PAGE_SIZE);
566
567
			trx_undo_decode_roll_ptr(node->roll_ptr,
568
						 &is_insert, &rseg_id,
569
						 &page_no, &offset);
570
			mtr_start(&mtr);
571
572
			/* We have to acquire an X-latch to the clustered
573
			index tree */
574
575
			index = dict_table_get_first_index(node->table);
576
577
			mtr_x_lock(dict_index_get_lock(index), &mtr);
578
579
			/* NOTE: we must also acquire an X-latch to the
580
			root page of the tree. We will need it when we
581
			free pages from the tree. If the tree is of height 1,
582
			the tree X-latch does NOT protect the root page,
583
			because it is also a leaf page. Since we will have a
584
			latch on an undo log page, we would break the
585
			latching order if we would only later latch the
586
			root page of such a tree! */
587
588
			btr_root_get(index, &mtr);
589
590
			/* We assume in purge of externally stored fields
591
			that the space id of the undo log record is 0! */
592
593
			block = buf_page_get(0, 0, page_no, RW_X_LATCH, &mtr);
594
			buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
595
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
596
			data_field = buf_block_get_frame(block)
597
				+ offset + internal_offset;
598
599
			ut_a(dfield_get_len(&ufield->new_val)
600
			     >= BTR_EXTERN_FIELD_REF_SIZE);
601
			btr_free_externally_stored_field(
602
				index,
603
				data_field + dfield_get_len(&ufield->new_val)
604
				- BTR_EXTERN_FIELD_REF_SIZE,
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
605
				NULL, NULL, NULL, 0, RB_NONE, &mtr);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
606
			mtr_commit(&mtr);
607
		}
608
	}
609
}
610
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
611
/***********************************************************//**
612
Parses the row reference and other info in a modify undo log record.
613
@return TRUE if purge operation required: NOTE that then the CALLER
614
must unfreeze data dictionary! */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
615
static
616
ibool
617
row_purge_parse_undo_rec(
618
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
619
	purge_node_t*	node,	/*!< in: row undo node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
620
	ibool*		updated_extern,
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
621
				/*!< out: TRUE if an externally stored field
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
622
				was updated */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
623
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
624
{
625
	dict_index_t*	clust_index;
626
	byte*		ptr;
627
	trx_t*		trx;
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
628
	undo_no_t	undo_no;
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
629
	table_id_t	table_id;
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
630
	trx_id_t	trx_id;
631
	roll_ptr_t	roll_ptr;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
632
	ulint		info_bits;
633
	ulint		type;
634
	ulint		cmpl_info;
635
636
	ut_ad(node && thr);
637
638
	trx = thr_get_trx(thr);
639
640
	ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
641
				    updated_extern, &undo_no, &table_id);
642
	node->rec_type = type;
643
644
	if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) {
645
646
		return(FALSE);
647
	}
648
649
	ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
650
					       &info_bits);
651
	node->table = NULL;
652
653
	if (type == TRX_UNDO_UPD_EXIST_REC
654
	    && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) {
655
656
		/* Purge requires no changes to indexes: we may return */
657
658
		return(FALSE);
659
	}
660
661
	/* Prevent DROP TABLE etc. from running when we are doing the purge
662
	for this row */
663
664
	row_mysql_freeze_data_dictionary(trx);
665
666
	mutex_enter(&(dict_sys->mutex));
667
668
	node->table = dict_table_get_on_id_low(table_id);
669
670
	mutex_exit(&(dict_sys->mutex));
671
672
	if (node->table == NULL) {
673
		/* The table has been dropped: no need to do purge */
674
err_exit:
675
		row_mysql_unfreeze_data_dictionary(trx);
676
		return(FALSE);
677
	}
678
679
	if (node->table->ibd_file_missing) {
680
		/* We skip purge of missing .ibd files */
681
682
		node->table = NULL;
683
684
		goto err_exit;
685
	}
686
687
	clust_index = dict_table_get_first_index(node->table);
688
689
	if (clust_index == NULL) {
690
		/* The table was corrupt in the data dictionary */
691
692
		goto err_exit;
693
	}
694
695
	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
696
				       node->heap);
697
698
	ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
699
					     roll_ptr, info_bits, trx,
700
					     node->heap, &(node->update));
701
702
	/* Read to the partial row the fields that occur in indexes */
703
704
	if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
705
		ptr = trx_undo_rec_get_partial_row(
706
			ptr, clust_index, &node->row,
707
			type == TRX_UNDO_UPD_DEL_REC,
708
			node->heap);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
709
	}
710
711
	return(TRUE);
712
}
713
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
714
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
715
Fetches an undo log record and does the purge for the recorded operation.
716
If none left, or the current purge completed, returns the control to the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
717
parent node, which is always a query thread node.
718
@return	DB_SUCCESS if operation successfully completed, else error code */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
719
static
720
ulint
721
row_purge(
722
/*======*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
723
	purge_node_t*	node,	/*!< in: row purge node */
724
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
725
{
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
726
	roll_ptr_t	roll_ptr;
727
	ibool		purge_needed;
728
	ibool		updated_extern;
729
	trx_t*		trx;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
730
731
	ut_ad(node && thr);
732
733
	trx = thr_get_trx(thr);
734
735
	node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
736
						  &(node->reservation),
737
						  node->heap);
738
	if (!node->undo_rec) {
739
		/* Purge completed for this query thread */
740
741
		thr->run_node = que_node_get_parent(node);
742
743
		return(DB_SUCCESS);
744
	}
745
746
	node->roll_ptr = roll_ptr;
747
748
	if (node->undo_rec == &trx_purge_dummy_rec) {
749
		purge_needed = FALSE;
750
	} else {
751
		purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
752
							thr);
753
		/* If purge_needed == TRUE, we must also remember to unfreeze
754
		data dictionary! */
755
	}
756
757
	if (purge_needed) {
758
		node->found_clust = FALSE;
759
760
		node->index = dict_table_get_next_index(
761
			dict_table_get_first_index(node->table));
762
763
		if (node->rec_type == TRX_UNDO_DEL_MARK_REC) {
764
			row_purge_del_mark(node);
765
766
		} else if (updated_extern
767
			   || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
768
769
			row_purge_upd_exist_or_extern(node);
770
		}
771
772
		if (node->found_clust) {
773
			btr_pcur_close(&(node->pcur));
774
		}
775
776
		row_mysql_unfreeze_data_dictionary(trx);
777
	}
778
779
	/* Do some cleanup */
780
	trx_purge_rec_release(node->reservation);
781
	mem_heap_empty(node->heap);
782
783
	thr->run_node = node;
784
785
	return(DB_SUCCESS);
786
}
787
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
788
/***********************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
789
Does the purge operation for a single undo log record. This is a high-level
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
790
function used in an SQL execution graph.
791
@return	query thread to run next or NULL */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
792
UNIV_INTERN
793
que_thr_t*
794
row_purge_step(
795
/*===========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
796
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
797
{
798
	purge_node_t*	node;
1819.9.141 by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB
799
#ifdef UNIV_DEBUG
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
800
	ulint		err;
1819.9.141 by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB
801
#endif /* UNIV_DEBUG */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
802
803
	ut_ad(thr);
804
2023.3.14 by Monty Taylor
More casting.
805
	node = static_cast<purge_node_t *>(thr->run_node);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
806
807
	ut_ad(que_node_get_type(node) == QUE_NODE_PURGE);
808
1819.9.141 by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB
809
#ifdef UNIV_DEBUG
810
	err =
811
#endif /* UNIV_DEBUG */
812
	row_purge(node, thr);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
813
1819.9.142 by Stewart Smith
fix build problem in moving some error checking to debug only in row0purge.c
814
#ifdef UNIV_DEBUG
1819.9.104 by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100914105629-mh9i2j3y953qwt8h from MySQL InnoDB
815
	ut_a(err == DB_SUCCESS);
1819.9.142 by Stewart Smith
fix build problem in moving some error checking to debug only in row0purge.c
816
#endif /* UNIV_DEBUG */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
817
818
	return(thr);
819
}