217
217
/***********************************************************//**
218
Removes a secondary index entry if possible.
218
Determines if it is possible to remove a secondary index entry.
219
Removal is possible if the secondary index entry does not refer to any
220
not delete marked version of a clustered index record where DB_TRX_ID
221
is newer than the purge view.
223
NOTE: This function should only be called by the purge thread, only
224
while holding a latch on the leaf page of the secondary index entry
225
(or keeping the buffer pool watch on the page). It is possible that
226
this function first returns TRUE and then FALSE, if a user transaction
227
inserts a record that the secondary index entry would refer to.
228
However, in that case, the user transaction would also re-insert the
229
secondary index entry after purge has removed it and released the leaf
231
@return TRUE if the secondary index record can be purged */
236
purge_node_t* node, /*!< in/out: row purge node */
237
dict_index_t* index, /*!< in: secondary index */
238
const dtuple_t* entry) /*!< in: secondary index entry */
243
ut_ad(!dict_index_is_clust(index));
246
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
247
|| !row_vers_old_has_index_entry(TRUE,
248
btr_pcur_get_rec(&node->pcur),
251
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
256
/***************************************************************
257
Removes a secondary index entry if possible, by modifying the
258
index tree. Does not try to buffer the delete.
219
259
@return TRUE if success or if not found */
222
row_purge_remove_sec_if_poss_low(
223
/*=============================*/
262
row_purge_remove_sec_if_poss_tree(
263
/*==============================*/
224
264
purge_node_t* node, /*!< in: row purge node */
225
265
dict_index_t* index, /*!< in: index */
226
const dtuple_t* entry, /*!< in: index entry */
227
ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or
266
const dtuple_t* entry) /*!< in: index entry */
233
ibool old_has = 0; /* remove warning */
270
ibool success = TRUE;
273
enum row_search_result search_result;
239
275
log_free_check();
242
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
278
search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
281
switch (search_result) {
245
283
/* Not found. This is a legitimate condition. In a
246
284
rollback, InnoDB will remove secondary recs that would
247
285
be purged anyway. Then the actual purge will not find
267
309
which cannot be purged yet, requires its existence. If some requires,
268
310
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);
312
if (row_purge_poss_sec(node, index, entry)) {
313
/* Remove the index record, which should have been
314
marked for deletion. */
315
ut_ad(REC_INFO_DELETED_FLAG
316
& rec_get_info_bits(btr_cur_get_rec(btr_cur),
317
dict_table_is_comp(index->table)));
319
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
321
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
324
case DB_OUT_OF_FILE_SPACE:
296
333
btr_pcur_close(&pcur);
297
334
mtr_commit(&mtr);
339
/***************************************************************
340
Removes a secondary index entry without modifying the index tree,
342
@return TRUE if success or if not found */
345
row_purge_remove_sec_if_poss_leaf(
346
/*==============================*/
347
purge_node_t* node, /*!< in: row purge node */
348
dict_index_t* index, /*!< in: index */
349
const dtuple_t* entry) /*!< in: index entry */
353
enum row_search_result search_result;
359
/* Set the purge node for the call to row_purge_poss_sec(). */
360
pcur.btr_cur.purge_node = node;
361
/* Set the query thread, so that ibuf_insert_low() will be
362
able to invoke thd_get_trx(). */
363
pcur.btr_cur.thr = que_node_get_parent(node);
365
search_result = row_search_index_entry(
366
index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
368
switch (search_result) {
371
/* Before attempting to purge a record, check
372
if it is safe to do so. */
373
if (row_purge_poss_sec(node, index, entry)) {
374
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
376
/* Only delete-marked records should be purged. */
377
ut_ad(REC_INFO_DELETED_FLAG
379
btr_cur_get_rec(btr_cur),
380
dict_table_is_comp(index->table)));
382
if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
384
/* The index entry could not be deleted. */
389
/* fall through (the index entry is still needed,
390
or the deletion succeeded) */
391
case ROW_NOT_DELETED_REF:
392
/* The index entry is still needed. */
394
/* The deletion was buffered. */
396
/* The index entry does not exist, nothing to do. */
399
btr_pcur_close(&pcur);
302
408
/***********************************************************//**
303
409
Removes a secondary index entry if possible. */
315
421
/* fputs("Purge: Removing secondary record\n", stderr); */
317
success = row_purge_remove_sec_if_poss_low(node, index, entry,
423
if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
324
success = row_purge_remove_sec_if_poss_low(node, index, entry,
428
success = row_purge_remove_sec_if_poss_tree(node, index, entry);
326
429
/* The delete operation may fail if we have little
327
430
file space left: TODO: easiest to crash the database
328
431
and restart with more file space */