~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2011-02-13 17:26:39 UTC
  • mfrom: (2157.2.2 give-in-to-pkg-config)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110213172639-nhy7i72sfhoq13ms
Merged in pkg-config fixes.

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
44
44
#include "row0mysql.h"
45
45
#include "log0log.h"
46
46
 
 
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
 
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
 
 
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
 
47
67
/********************************************************************//**
48
68
Creates a purge node to a query graph.
49
69
@return own: purge node */
58
78
 
59
79
        ut_ad(parent && heap);
60
80
 
61
 
        node = mem_heap_alloc(heap, sizeof(purge_node_t));
 
81
        node = static_cast<purge_node_t *>(mem_heap_alloc(heap, sizeof(purge_node_t)));
62
82
 
63
83
        node->common.type = QUE_NODE_PURGE;
64
84
        node->common.parent = parent;
126
146
        pcur = &(node->pcur);
127
147
        btr_cur = btr_pcur_get_btr_cur(pcur);
128
148
 
 
149
        log_free_check();
129
150
        mtr_start(&mtr);
130
151
 
131
152
        success = row_purge_reposition_pcur(mode, node, &mtr);
140
161
 
141
162
        rec = btr_pcur_get_rec(pcur);
142
163
 
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);
149
169
                }
215
235
}
216
236
 
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.
 
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.
219
279
@return TRUE if success or if not found */
220
280
static
221
281
ibool
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
228
 
                                BTR_MODIFY_TREE */
 
286
        const dtuple_t* entry)  /*!< in: index entry */
229
287
{
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;
 
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;
238
294
 
239
295
        log_free_check();
240
296
        mtr_start(&mtr);
241
297
 
242
 
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
298
        search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
 
299
                                               &pcur, &mtr);
243
300
 
244
 
        if (!found) {
 
301
        switch (search_result) {
 
302
        case ROW_NOT_FOUND:
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
254
312
 
255
313
                /* fputs("PURGE:........sec entry not found\n", stderr); */
256
314
                /* dtuple_print(stderr, entry); */
257
 
 
258
 
                btr_pcur_close(&pcur);
259
 
                mtr_commit(&mtr);
260
 
 
261
 
                return(TRUE);
 
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;
262
324
        }
263
325
 
264
326
        btr_cur = btr_pcur_get_btr_cur(&pcur);
267
329
        which cannot be purged yet, requires its existence. If some requires,
268
330
        we should do nothing. */
269
331
 
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);
 
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;
293
349
                }
294
350
        }
295
351
 
 
352
func_exit:
296
353
        btr_pcur_close(&pcur);
297
354
        mtr_commit(&mtr);
298
355
 
299
356
        return(success);
300
357
}
301
358
 
 
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(). */
 
383
        pcur.btr_cur.thr = static_cast<que_thr_t *>(que_node_get_parent(node));
 
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
 
302
428
/***********************************************************//**
303
429
Removes a secondary index entry if possible. */
304
430
UNIV_INLINE
314
440
 
315
441
        /*      fputs("Purge: Removing secondary record\n", stderr); */
316
442
 
317
 
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
318
 
                                                   BTR_MODIFY_LEAF);
319
 
        if (success) {
 
443
        if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
320
444
 
321
445
                return;
322
446
        }
323
447
retry:
324
 
        success = row_purge_remove_sec_if_poss_low(node, index, entry,
325
 
                                                   BTR_MODIFY_TREE);
 
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 */
503
626
        byte*           ptr;
504
627
        trx_t*          trx;
505
628
        undo_no_t       undo_no;
506
 
        dulint          table_id;
 
629
        table_id_t      table_id;
507
630
        trx_id_t        trx_id;
508
631
        roll_ptr_t      roll_ptr;
509
632
        ulint           info_bits;
673
796
        que_thr_t*      thr)    /*!< in: query thread */
674
797
{
675
798
        purge_node_t*   node;
 
799
#ifdef UNIV_DEBUG
676
800
        ulint           err;
 
801
#endif /* UNIV_DEBUG */
677
802
 
678
803
        ut_ad(thr);
679
804
 
680
 
        node = thr->run_node;
 
805
        node = static_cast<purge_node_t *>(thr->run_node);
681
806
 
682
807
        ut_ad(que_node_get_type(node) == QUE_NODE_PURGE);
683
808
 
684
 
        err = row_purge(node, thr);
 
809
#ifdef UNIV_DEBUG
 
810
        err =
 
811
#endif /* UNIV_DEBUG */
 
812
        row_purge(node, thr);
685
813
 
686
 
        ut_ad(err == DB_SUCCESS);
 
814
#ifdef UNIV_DEBUG
 
815
        ut_a(err == DB_SUCCESS);
 
816
#endif /* UNIV_DEBUG */
687
817
 
688
818
        return(thr);
689
819
}