44
44
#include "row0mysql.h"
45
45
#include "log0log.h"
47
/*************************************************************************
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
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. */
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
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. */
47
67
/********************************************************************//**
48
68
Creates a purge node to a query graph.
49
69
@return own: purge node */
141
162
rec = btr_pcur_get_rec(pcur);
143
if (0 != ut_dulint_cmp(node->roll_ptr, row_get_rec_roll_ptr(
144
rec, index, rec_get_offsets(
145
rec, index, offsets_,
146
ULINT_UNDEFINED, &heap)))) {
164
if (node->roll_ptr != row_get_rec_roll_ptr(
165
rec, index, rec_get_offsets(rec, index, offsets_,
166
ULINT_UNDEFINED, &heap))) {
147
167
if (UNIV_LIKELY_NULL(heap)) {
148
168
mem_heap_free(heap);
217
237
/***********************************************************//**
218
Removes a secondary index entry if possible.
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.
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
251
@return TRUE if the secondary index record can be purged */
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 */
263
ut_ad(!dict_index_is_clust(index));
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),
271
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
276
/***************************************************************
277
Removes a secondary index entry if possible, by modifying the
278
index tree. Does not try to buffer the delete.
219
279
@return TRUE if success or if not found */
222
row_purge_remove_sec_if_poss_low(
223
/*=============================*/
282
row_purge_remove_sec_if_poss_tree(
283
/*==============================*/
224
284
purge_node_t* node, /*!< in: row purge node */
225
285
dict_index_t* index, /*!< in: index */
226
const dtuple_t* entry, /*!< in: index entry */
227
ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or
286
const dtuple_t* entry) /*!< in: index entry */
233
ibool old_has = 0; /* remove warning */
290
ibool success = TRUE;
293
enum row_search_result search_result;
239
295
log_free_check();
242
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
298
search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
301
switch (search_result) {
245
303
/* Not found. This is a legitimate condition. In a
246
304
rollback, InnoDB will remove secondary recs that would
247
305
be purged anyway. Then the actual purge will not find
267
329
which cannot be purged yet, requires its existence. If some requires,
268
330
we should do nothing. */
270
mtr_start(&mtr_vers);
272
success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr_vers);
275
old_has = row_vers_old_has_index_entry(
276
TRUE, btr_pcur_get_rec(&(node->pcur)),
277
&mtr_vers, index, entry);
280
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
282
if (!success || !old_has) {
283
/* Remove the index record */
285
if (mode == BTR_MODIFY_LEAF) {
286
success = btr_cur_optimistic_delete(btr_cur, &mtr);
288
ut_ad(mode == BTR_MODIFY_TREE);
289
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
291
success = err == DB_SUCCESS;
292
ut_a(success || err == DB_OUT_OF_FILE_SPACE);
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)));
339
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
341
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
344
case DB_OUT_OF_FILE_SPACE:
296
353
btr_pcur_close(&pcur);
297
354
mtr_commit(&mtr);
359
/***************************************************************
360
Removes a secondary index entry without modifying the index tree,
362
@return TRUE if success or if not found */
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 */
373
enum row_search_result search_result;
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(). */
383
pcur.btr_cur.thr = static_cast<que_thr_t *>(que_node_get_parent(node));
385
search_result = row_search_index_entry(
386
index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
388
switch (search_result) {
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);
396
/* Only delete-marked records should be purged. */
397
ut_ad(REC_INFO_DELETED_FLAG
399
btr_cur_get_rec(btr_cur),
400
dict_table_is_comp(index->table)));
402
if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
404
/* The index entry could not be deleted. */
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. */
414
/* The deletion was buffered. */
416
/* The index entry does not exist, nothing to do. */
419
btr_pcur_close(&pcur);
302
428
/***********************************************************//**
303
429
Removes a secondary index entry if possible. */
315
441
/* fputs("Purge: Removing secondary record\n", stderr); */
317
success = row_purge_remove_sec_if_poss_low(node, index, entry,
443
if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
324
success = row_purge_remove_sec_if_poss_low(node, index, entry,
448
success = row_purge_remove_sec_if_poss_tree(node, index, entry);
326
449
/* The delete operation may fail if we have little
327
450
file space left: TODO: easiest to crash the database
328
451
and restart with more file space */