~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/row/row0purge.c

  • Committer: Monty Taylor
  • Date: 2010-11-26 22:50:54 UTC
  • mfrom: (1953.1.6 build)
  • Revision ID: mordred@inaugust.com-20101126225054-sg90svw8579t5p3i
Stewart - InnoDB 1.1.1
Monty - Fixed some autoconf tests which were returning false positives.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
215
215
}
216
216
 
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.
 
222
 
 
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
 
230
page latch.
 
231
@return TRUE if the secondary index record can be purged */
 
232
UNIV_INTERN
 
233
ibool
 
234
row_purge_poss_sec(
 
235
/*===============*/
 
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 */
 
239
{
 
240
        ibool   can_delete;
 
241
        mtr_t   mtr;
 
242
 
 
243
        ut_ad(!dict_index_is_clust(index));
 
244
        mtr_start(&mtr);
 
245
 
 
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),
 
249
                                                 &mtr, index, entry);
 
250
 
 
251
        btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
 
252
 
 
253
        return(can_delete);
 
254
}
 
255
 
 
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 */
220
260
static
221
261
ibool
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
228
 
                                BTR_MODIFY_TREE */
 
266
        const dtuple_t* entry)  /*!< in: index entry */
229
267
{
230
 
        btr_pcur_t      pcur;
231
 
        btr_cur_t*      btr_cur;
232
 
        ibool           success;
233
 
        ibool           old_has = 0; /* remove warning */
234
 
        ibool           found;
235
 
        ulint           err;
236
 
        mtr_t           mtr;
237
 
        mtr_t           mtr_vers;
 
268
        btr_pcur_t              pcur;
 
269
        btr_cur_t*              btr_cur;
 
270
        ibool                   success = TRUE;
 
271
        ulint                   err;
 
272
        mtr_t                   mtr;
 
273
        enum row_search_result  search_result;
238
274
 
239
275
        log_free_check();
240
276
        mtr_start(&mtr);
241
277
 
242
 
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
278
        search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
 
279
                                               &pcur, &mtr);
243
280
 
244
 
        if (!found) {
 
281
        switch (search_result) {
 
282
        case ROW_NOT_FOUND:
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
254
292
 
255
293
                /* fputs("PURGE:........sec entry not found\n", stderr); */
256
294
                /* dtuple_print(stderr, entry); */
257
 
 
258
 
                btr_pcur_close(&pcur);
259
 
                mtr_commit(&mtr);
260
 
 
261
 
                return(TRUE);
 
295
                goto func_exit;
 
296
        case ROW_FOUND:
 
297
                break;
 
298
        case ROW_BUFFERED:
 
299
        case ROW_NOT_DELETED_REF:
 
300
                /* These are invalid outcomes, because the mode passed
 
301
                to row_search_index_entry() did not include any of the
 
302
                flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
 
303
                ut_error;
262
304
        }
263
305
 
264
306
        btr_cur = btr_pcur_get_btr_cur(&pcur);
267
309
        which cannot be purged yet, requires its existence. If some requires,
268
310
        we should do nothing. */
269
311
 
270
 
        mtr_start(&mtr_vers);
271
 
 
272
 
        success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr_vers);
273
 
 
274
 
        if (success) {
275
 
                old_has = row_vers_old_has_index_entry(
276
 
                        TRUE, btr_pcur_get_rec(&(node->pcur)),
277
 
                        &mtr_vers, index, entry);
278
 
        }
279
 
 
280
 
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
281
 
 
282
 
        if (!success || !old_has) {
283
 
                /* Remove the index record */
284
 
 
285
 
                if (mode == BTR_MODIFY_LEAF) {
286
 
                        success = btr_cur_optimistic_delete(btr_cur, &mtr);
287
 
                } else {
288
 
                        ut_ad(mode == BTR_MODIFY_TREE);
289
 
                        btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
290
 
                                                   RB_NONE, &mtr);
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)));
 
318
 
 
319
                btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
 
320
                                           RB_NONE, &mtr);
 
321
                switch (UNIV_EXPECT(err, DB_SUCCESS)) {
 
322
                case DB_SUCCESS:
 
323
                        break;
 
324
                case DB_OUT_OF_FILE_SPACE:
 
325
                        success = FALSE;
 
326
                        break;
 
327
                default:
 
328
                        ut_error;
293
329
                }
294
330
        }
295
331
 
 
332
func_exit:
296
333
        btr_pcur_close(&pcur);
297
334
        mtr_commit(&mtr);
298
335
 
299
336
        return(success);
300
337
}
301
338
 
 
339
/***************************************************************
 
340
Removes a secondary index entry without modifying the index tree,
 
341
if possible.
 
342
@return TRUE if success or if not found */
 
343
static
 
344
ibool
 
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 */
 
350
{
 
351
        mtr_t                   mtr;
 
352
        btr_pcur_t              pcur;
 
353
        enum row_search_result  search_result;
 
354
 
 
355
        log_free_check();
 
356
 
 
357
        mtr_start(&mtr);
 
358
 
 
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);
 
364
 
 
365
        search_result = row_search_index_entry(
 
366
                index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
 
367
 
 
368
        switch (search_result) {
 
369
                ibool   success;
 
370
        case ROW_FOUND:
 
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);
 
375
 
 
376
                        /* Only delete-marked records should be purged. */
 
377
                        ut_ad(REC_INFO_DELETED_FLAG
 
378
                              & rec_get_info_bits(
 
379
                                      btr_cur_get_rec(btr_cur),
 
380
                                      dict_table_is_comp(index->table)));
 
381
 
 
382
                        if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
 
383
 
 
384
                                /* The index entry could not be deleted. */
 
385
                                success = FALSE;
 
386
                                goto func_exit;
 
387
                        }
 
388
                }
 
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. */
 
393
        case ROW_BUFFERED:
 
394
                /* The deletion was buffered. */
 
395
        case ROW_NOT_FOUND:
 
396
                /* The index entry does not exist, nothing to do. */
 
397
                success = TRUE;
 
398
        func_exit:
 
399
                btr_pcur_close(&pcur);
 
400
                mtr_commit(&mtr);
 
401
                return(success);
 
402
        }
 
403
 
 
404
        ut_error;
 
405
        return(FALSE);
 
406
}
 
407
 
302
408
/***********************************************************//**
303
409
Removes a secondary index entry if possible. */
304
410
UNIV_INLINE
314
420
 
315
421
        /*      fputs("Purge: Removing secondary record\n", stderr); */
316
422
 
317
 
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
318
 
                                                   BTR_MODIFY_LEAF);
319
 
        if (success) {
 
423
        if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
320
424
 
321
425
                return;
322
426
        }
323
427
retry:
324
 
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
325
 
                                                   BTR_MODIFY_TREE);
 
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 */