~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-11-17 21:25:31 UTC
  • mto: (1939.1.1 quick)
  • mto: This revision was merged to the branch mainline in revision 1940.
  • Revision ID: brian@tangent.org-20101117212531-va13j4xh43zuma68
First pass though barriers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1997, 2009, 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
 
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.
 
218
Removes a secondary index entry if possible.
259
219
@return TRUE if success or if not found */
260
220
static
261
221
ibool
262
 
row_purge_remove_sec_if_poss_tree(
263
 
/*==============================*/
 
222
row_purge_remove_sec_if_poss_low(
 
223
/*=============================*/
264
224
        purge_node_t*   node,   /*!< in: row purge node */
265
225
        dict_index_t*   index,  /*!< in: index */
266
 
        const dtuple_t* entry)  /*!< in: index entry */
 
226
        const dtuple_t* entry,  /*!< in: index entry */
 
227
        ulint           mode)   /*!< in: latch mode BTR_MODIFY_LEAF or
 
228
                                BTR_MODIFY_TREE */
267
229
{
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;
 
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;
274
238
 
275
239
        log_free_check();
276
240
        mtr_start(&mtr);
277
241
 
278
 
        search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
279
 
                                               &pcur, &mtr);
 
242
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
280
243
 
281
 
        switch (search_result) {
282
 
        case ROW_NOT_FOUND:
 
244
        if (!found) {
283
245
                /* Not found.  This is a legitimate condition.  In a
284
246
                rollback, InnoDB will remove secondary recs that would
285
247
                be purged anyway.  Then the actual purge will not find
292
254
 
293
255
                /* fputs("PURGE:........sec entry not found\n", stderr); */
294
256
                /* dtuple_print(stderr, entry); */
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;
 
257
 
 
258
                btr_pcur_close(&pcur);
 
259
                mtr_commit(&mtr);
 
260
 
 
261
                return(TRUE);
304
262
        }
305
263
 
306
264
        btr_cur = btr_pcur_get_btr_cur(&pcur);
309
267
        which cannot be purged yet, requires its existence. If some requires,
310
268
        we should do nothing. */
311
269
 
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;
 
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);
329
293
                }
330
294
        }
331
295
 
332
 
func_exit:
333
296
        btr_pcur_close(&pcur);
334
297
        mtr_commit(&mtr);
335
298
 
336
299
        return(success);
337
300
}
338
301
 
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
 
 
408
302
/***********************************************************//**
409
303
Removes a secondary index entry if possible. */
410
304
UNIV_INLINE
420
314
 
421
315
        /*      fputs("Purge: Removing secondary record\n", stderr); */
422
316
 
423
 
        if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
 
317
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
 
318
                                                   BTR_MODIFY_LEAF);
 
319
        if (success) {
424
320
 
425
321
                return;
426
322
        }
427
323
retry:
428
 
        success = row_purge_remove_sec_if_poss_tree(node, index, entry);
 
324
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
 
325
                                                   BTR_MODIFY_TREE);
429
326
        /* The delete operation may fail if we have little
430
327
        file space left: TODO: easiest to crash the database
431
328
        and restart with more file space */