~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/row/row0vers.c

  • Committer: Lee
  • Date: 2009-01-01 03:07:33 UTC
  • mto: (758.1.3 devel)
  • mto: This revision was merged to the branch mainline in revision 759.
  • Revision ID: lbieber@lbieber-desktop-20090101030733-fb411b55f07vij8q
more header file cleanup

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1997, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file row/row0vers.c
 
1
/******************************************************
21
2
Row versions
22
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
23
6
Created 2/6/1997 Heikki Tuuri
24
7
*******************************************************/
25
8
 
46
29
#include "read0read.h"
47
30
#include "lock0lock.h"
48
31
 
49
 
/*****************************************************************//**
 
32
/*********************************************************************
50
33
Finds out if an active transaction has inserted or modified a secondary
51
34
index record. NOTE: the kernel mutex is temporarily released in this
52
 
function!
53
 
@return NULL if committed, else the active transaction */
 
35
function! */
54
36
UNIV_INTERN
55
37
trx_t*
56
38
row_vers_impl_x_locked_off_kernel(
57
39
/*==============================*/
58
 
        const rec_t*    rec,    /*!< in: record in a secondary index */
59
 
        dict_index_t*   index,  /*!< in: the secondary index */
60
 
        const ulint*    offsets)/*!< in: rec_get_offsets(rec, index) */
 
40
                                /* out: NULL if committed, else the active
 
41
                                transaction; NOTE that the kernel mutex is
 
42
                                temporarily released! */
 
43
        const rec_t*    rec,    /* in: record in a secondary index */
 
44
        dict_index_t*   index,  /* in: the secondary index */
 
45
        const ulint*    offsets)/* in: rec_get_offsets(rec, index) */
61
46
{
62
47
        dict_index_t*   clust_index;
63
48
        rec_t*          clust_rec;
64
49
        ulint*          clust_offsets;
65
50
        rec_t*          version;
66
 
        trx_id_t        trx_id;
 
51
        rec_t*          prev_version;
 
52
        dulint          trx_id;
 
53
        dulint          prev_trx_id;
67
54
        mem_heap_t*     heap;
68
55
        mem_heap_t*     heap2;
69
56
        dtuple_t*       row;
70
57
        dtuple_t*       entry   = NULL; /* assignment to eliminate compiler
71
58
                                        warning */
72
59
        trx_t*          trx;
 
60
        ulint           vers_del= 0;
73
61
        ulint           rec_del;
74
 
#ifdef UNIV_DEBUG
75
62
        ulint           err;
76
 
#endif /* UNIV_DEBUG */
77
63
        mtr_t           mtr;
78
64
        ulint           comp;
79
65
 
86
72
 
87
73
        mtr_start(&mtr);
88
74
 
 
75
        prev_trx_id.high= 0;
 
76
        prev_trx_id.low= 0;
89
77
        /* Search for the clustered index record: this is a time-consuming
90
78
        operation: therefore we release the kernel mutex; also, the release
91
79
        is required by the latching order convention. The latch on the
155
143
        version = clust_rec;
156
144
 
157
145
        for (;;) {
158
 
                rec_t*          prev_version;
159
 
                ulint           vers_del;
160
 
                row_ext_t*      ext;
161
 
                trx_id_t        prev_trx_id;
162
 
 
163
146
                mutex_exit(&kernel_mutex);
164
147
 
165
148
                /* While we retrieve an earlier version of clust_rec, we
171
154
 
172
155
                heap2 = heap;
173
156
                heap = mem_heap_create(1024);
174
 
#ifdef UNIV_DEBUG
175
 
                err =
176
 
#endif /* UNIV_DEBUG */
177
 
                trx_undo_prev_version_build(clust_rec, &mtr, version,
178
 
                                            clust_index, clust_offsets,
179
 
                                            heap, &prev_version);
 
157
                err = trx_undo_prev_version_build(clust_rec, &mtr, version,
 
158
                                                  clust_index, clust_offsets,
 
159
                                                  heap, &prev_version);
180
160
                mem_heap_free(heap2); /* free version and clust_offsets */
181
161
 
182
 
                if (prev_version == NULL) {
183
 
                        mutex_enter(&kernel_mutex);
184
 
 
185
 
                        if (!trx_is_active(trx_id)) {
186
 
                                /* Transaction no longer active: no
187
 
                                implicit x-lock */
188
 
 
 
162
                if (prev_version) {
 
163
                        row_ext_t*      ext;
 
164
 
 
165
                        clust_offsets = rec_get_offsets(
 
166
                                prev_version, clust_index, NULL,
 
167
                                ULINT_UNDEFINED, &heap);
 
168
 
 
169
                        vers_del = rec_get_deleted_flag(prev_version,
 
170
                                                        comp);
 
171
                        prev_trx_id = row_get_rec_trx_id(prev_version,
 
172
                                                         clust_index,
 
173
                                                         clust_offsets);
 
174
 
 
175
                        /* If the trx_id and prev_trx_id are
 
176
                        different and if the prev_version is marked
 
177
                        deleted then the prev_trx_id must have
 
178
                        already committed for the trx_id to be able to
 
179
                        modify the row. Therefore, prev_trx_id cannot
 
180
                        hold any implicit lock. */
 
181
                        if (0 != ut_dulint_cmp(trx_id, prev_trx_id)
 
182
                            && vers_del) {
 
183
        
 
184
                                mutex_enter(&kernel_mutex);
189
185
                                break;
190
186
                        }
191
187
 
192
 
                        /* If the transaction is still active,
193
 
                        clust_rec must be a fresh insert, because no
194
 
                        previous version was found. */
195
 
                        ut_ad(err == DB_SUCCESS);
196
 
 
 
188
                        /* The stack of versions is locked by mtr.
 
189
                        Thus, it is safe to fetch the prefixes for
 
190
                        externally stored columns. */
 
191
                        row = row_build(ROW_COPY_POINTERS, clust_index,
 
192
                                        prev_version, clust_offsets,
 
193
                                        NULL, &ext, heap);
 
194
                        entry = row_build_index_entry(row, ext, index, heap);
 
195
                        /* entry may be NULL if a record was inserted
 
196
                        in place of a deleted record, and the BLOB
 
197
                        pointers of the new record were not
 
198
                        initialized yet.  But in that case,
 
199
                        prev_version should be NULL. */
 
200
                        ut_a(entry);
 
201
                }
 
202
 
 
203
                mutex_enter(&kernel_mutex);
 
204
 
 
205
                if (!trx_is_active(trx_id)) {
 
206
                        /* Transaction no longer active: no implicit x-lock */
 
207
 
 
208
                        break;
 
209
                }
 
210
 
 
211
                /* If the transaction is still active, the previous version
 
212
                of clust_rec must be accessible if not a fresh insert; we
 
213
                may assert the following: */
 
214
 
 
215
                ut_ad(err == DB_SUCCESS);
 
216
 
 
217
                if (prev_version == NULL) {
197
218
                        /* It was a freshly inserted version: there is an
198
219
                        implicit x-lock on rec */
199
220
 
202
223
                        break;
203
224
                }
204
225
 
205
 
                clust_offsets = rec_get_offsets(prev_version, clust_index,
206
 
                                                NULL, ULINT_UNDEFINED, &heap);
207
 
 
208
 
                vers_del = rec_get_deleted_flag(prev_version, comp);
209
 
                prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
210
 
                                                 clust_offsets);
211
 
 
212
 
                /* If the trx_id and prev_trx_id are different and if
213
 
                the prev_version is marked deleted then the
214
 
                prev_trx_id must have already committed for the trx_id
215
 
                to be able to modify the row. Therefore, prev_trx_id
216
 
                cannot hold any implicit lock. */
217
 
                if (vers_del && trx_id != prev_trx_id) {
218
 
 
219
 
                        mutex_enter(&kernel_mutex);
220
 
                        break;
221
 
                }
222
 
 
223
 
                /* The stack of versions is locked by mtr.  Thus, it
224
 
                is safe to fetch the prefixes for externally stored
225
 
                columns. */
226
 
                row = row_build(ROW_COPY_POINTERS, clust_index, prev_version,
227
 
                                clust_offsets, NULL, &ext, heap);
228
 
                entry = row_build_index_entry(row, ext, index, heap);
229
 
                /* entry may be NULL if a record was inserted in place
230
 
                of a deleted record, and the BLOB pointers of the new
231
 
                record were not initialized yet.  But in that case,
232
 
                prev_version should be NULL. */
233
 
                ut_a(entry);
234
 
 
235
 
                mutex_enter(&kernel_mutex);
236
 
 
237
 
                if (!trx_is_active(trx_id)) {
238
 
                        /* Transaction no longer active: no implicit x-lock */
239
 
 
240
 
                        break;
241
 
                }
242
 
 
243
226
                /* If we get here, we know that the trx_id transaction is
244
227
                still active and it has modified prev_version. Let us check
245
228
                if prev_version would require rec to be in a different
246
229
                state. */
247
230
 
248
 
                /* The previous version of clust_rec must be
249
 
                accessible, because the transaction is still active
250
 
                and clust_rec was not a fresh insert. */
251
 
                ut_ad(err == DB_SUCCESS);
252
 
 
253
231
                /* We check if entry and rec are identified in the alphabetical
254
232
                ordering */
255
233
                if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
285
263
                        break;
286
264
                }
287
265
 
288
 
                if (trx_id != prev_trx_id) {
 
266
                if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) {
289
267
                        /* The versions modified by the trx_id transaction end
290
268
                        to prev_version: no implicit x-lock */
291
269
 
302
280
        return(trx);
303
281
}
304
282
 
305
 
/*****************************************************************//**
 
283
/*********************************************************************
306
284
Finds out if we must preserve a delete marked earlier version of a clustered
307
 
index record, because it is >= the purge view.
308
 
@return TRUE if earlier version should be preserved */
 
285
index record, because it is >= the purge view. */
309
286
UNIV_INTERN
310
287
ibool
311
288
row_vers_must_preserve_del_marked(
312
289
/*==============================*/
313
 
        trx_id_t        trx_id, /*!< in: transaction id in the version */
314
 
        mtr_t*          mtr)    /*!< in: mtr holding the latch on the
315
 
                                clustered index record; it will also
316
 
                                hold the latch on purge_view */
 
290
                        /* out: TRUE if earlier version should be preserved */
 
291
        dulint  trx_id, /* in: transaction id in the version */
 
292
        mtr_t*  mtr)    /* in: mtr holding the latch on the clustered index
 
293
                        record; it will also hold the latch on purge_view */
317
294
{
318
295
#ifdef UNIV_SYNC_DEBUG
319
296
        ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
332
309
        return(FALSE);
333
310
}
334
311
 
335
 
/*****************************************************************//**
 
312
/*********************************************************************
336
313
Finds out if a version of the record, where the version >= the current
337
314
purge view, should have ientry as its secondary index entry. We check
338
315
if there is any not delete marked version of the record where the trx
339
316
id >= purge view, and the secondary index entry and ientry are identified in
340
 
the alphabetical ordering; exactly in this case we return TRUE.
341
 
@return TRUE if earlier version should have */
 
317
the alphabetical ordering; exactly in this case we return TRUE. */
342
318
UNIV_INTERN
343
319
ibool
344
320
row_vers_old_has_index_entry(
345
321
/*=========================*/
346
 
        ibool           also_curr,/*!< in: TRUE if also rec is included in the
 
322
                                /* out: TRUE if earlier version should have */
 
323
        ibool           also_curr,/* in: TRUE if also rec is included in the
347
324
                                versions to search; otherwise only versions
348
325
                                prior to it are searched */
349
 
        const rec_t*    rec,    /*!< in: record in the clustered index; the
 
326
        const rec_t*    rec,    /* in: record in the clustered index; the
350
327
                                caller must have a latch on the page */
351
 
        mtr_t*          mtr,    /*!< in: mtr holding the latch on rec; it will
 
328
        mtr_t*          mtr,    /* in: mtr holding the latch on rec; it will
352
329
                                also hold the latch on purge_view */
353
 
        dict_index_t*   index,  /*!< in: the secondary index */
354
 
        const dtuple_t* ientry) /*!< in: the secondary index entry */
 
330
        dict_index_t*   index,  /* in: the secondary index */
 
331
        const dtuple_t* ientry) /* in: the secondary index entry */
355
332
{
356
333
        const rec_t*    version;
357
334
        rec_t*          prev_version;
474
451
        }
475
452
}
476
453
 
477
 
/*****************************************************************//**
 
454
/*********************************************************************
478
455
Constructs the version of a clustered index record which a consistent
479
456
read should see. We assume that the trx id stored in rec is such that
480
 
the consistent read should not see rec in its present version.
481
 
@return DB_SUCCESS or DB_MISSING_HISTORY */
 
457
the consistent read should not see rec in its present version. */
482
458
UNIV_INTERN
483
459
ulint
484
460
row_vers_build_for_consistent_read(
485
461
/*===============================*/
486
 
        const rec_t*    rec,    /*!< in: record in a clustered index; the
 
462
                                /* out: DB_SUCCESS or DB_MISSING_HISTORY */
 
463
        const rec_t*    rec,    /* in: record in a clustered index; the
487
464
                                caller must have a latch on the page; this
488
465
                                latch locks the top of the stack of versions
489
466
                                of this records */
490
 
        mtr_t*          mtr,    /*!< in: mtr holding the latch on rec */
491
 
        dict_index_t*   index,  /*!< in: the clustered index */
492
 
        ulint**         offsets,/*!< in/out: offsets returned by
 
467
        mtr_t*          mtr,    /* in: mtr holding the latch on rec */
 
468
        dict_index_t*   index,  /* in: the clustered index */
 
469
        ulint**         offsets,/* in/out: offsets returned by
493
470
                                rec_get_offsets(rec, index) */
494
 
        read_view_t*    view,   /*!< in: the consistent read view */
495
 
        mem_heap_t**    offset_heap,/*!< in/out: memory heap from which
 
471
        read_view_t*    view,   /* in: the consistent read view */
 
472
        mem_heap_t**    offset_heap,/* in/out: memory heap from which
496
473
                                the offsets are allocated */
497
 
        mem_heap_t*     in_heap,/*!< in: memory heap from which the memory for
 
474
        mem_heap_t*     in_heap,/* in: memory heap from which the memory for
498
475
                                *old_vers is allocated; memory for possible
499
476
                                intermediate versions is allocated and freed
500
477
                                locally within the function */
501
 
        rec_t**         old_vers)/*!< out, own: old version, or NULL if the
 
478
        rec_t**         old_vers)/* out, own: old version, or NULL if the
502
479
                                record does not exist in the view, that is,
503
480
                                it was freshly inserted afterwards */
504
481
{
505
482
        const rec_t*    version;
506
483
        rec_t*          prev_version;
507
 
        trx_id_t        trx_id;
 
484
        dulint          trx_id;
508
485
        mem_heap_t*     heap            = NULL;
509
486
        byte*           buf;
510
487
        ulint           err;
528
505
        for (;;) {
529
506
                mem_heap_t*     heap2   = heap;
530
507
                trx_undo_rec_t* undo_rec;
531
 
                roll_ptr_t      roll_ptr;
532
 
                undo_no_t       undo_no;
 
508
                dulint          roll_ptr;
 
509
                dulint          undo_no;
533
510
                heap = mem_heap_create(1024);
534
511
 
535
512
                /* If we have high-granularity consistent read view and
538
515
                undo_no of the record is < undo_no in the view. */
539
516
 
540
517
                if (view->type == VIEW_HIGH_GRANULARITY
541
 
                    && view->creator_trx_id == trx_id) {
 
518
                    && ut_dulint_cmp(view->creator_trx_id, trx_id) == 0) {
542
519
 
543
520
                        roll_ptr = row_get_rec_roll_ptr(version, index,
544
521
                                                        *offsets);
546
523
                        undo_no = trx_undo_rec_get_undo_no(undo_rec);
547
524
                        mem_heap_empty(heap);
548
525
 
549
 
                        if (view->undo_no > undo_no) {
 
526
                        if (ut_dulint_cmp(view->undo_no, undo_no) > 0) {
550
527
                                /* The view already sees this version: we can
551
528
                                copy it to in_heap and return */
552
529
 
553
 
                                buf = static_cast<byte *>(mem_heap_alloc(in_heap,
554
 
                                                     rec_offs_size(*offsets)));
 
530
                                buf = mem_heap_alloc(in_heap,
 
531
                                                     rec_offs_size(*offsets));
555
532
                                *old_vers = rec_copy(buf, version, *offsets);
556
533
                                rec_offs_make_valid(*old_vers, index,
557
534
                                                    *offsets);
590
567
                        /* The view already sees this version: we can copy
591
568
                        it to in_heap and return */
592
569
 
593
 
                        buf = static_cast<byte *>(mem_heap_alloc(in_heap, rec_offs_size(*offsets)));
 
570
                        buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets));
594
571
                        *old_vers = rec_copy(buf, prev_version, *offsets);
595
572
                        rec_offs_make_valid(*old_vers, index, *offsets);
596
573
                        err = DB_SUCCESS;
607
584
        return(err);
608
585
}
609
586
 
610
 
/*****************************************************************//**
 
587
/*********************************************************************
611
588
Constructs the last committed version of a clustered index record,
612
 
which should be seen by a semi-consistent read.
613
 
@return DB_SUCCESS or DB_MISSING_HISTORY */
 
589
which should be seen by a semi-consistent read. */
614
590
UNIV_INTERN
615
591
ulint
616
592
row_vers_build_for_semi_consistent_read(
617
593
/*====================================*/
618
 
        const rec_t*    rec,    /*!< in: record in a clustered index; the
 
594
                                /* out: DB_SUCCESS or DB_MISSING_HISTORY */
 
595
        const rec_t*    rec,    /* in: record in a clustered index; the
619
596
                                caller must have a latch on the page; this
620
597
                                latch locks the top of the stack of versions
621
598
                                of this records */
622
 
        mtr_t*          mtr,    /*!< in: mtr holding the latch on rec */
623
 
        dict_index_t*   index,  /*!< in: the clustered index */
624
 
        ulint**         offsets,/*!< in/out: offsets returned by
 
599
        mtr_t*          mtr,    /* in: mtr holding the latch on rec */
 
600
        dict_index_t*   index,  /* in: the clustered index */
 
601
        ulint**         offsets,/* in/out: offsets returned by
625
602
                                rec_get_offsets(rec, index) */
626
 
        mem_heap_t**    offset_heap,/*!< in/out: memory heap from which
 
603
        mem_heap_t**    offset_heap,/* in/out: memory heap from which
627
604
                                the offsets are allocated */
628
 
        mem_heap_t*     in_heap,/*!< in: memory heap from which the memory for
 
605
        mem_heap_t*     in_heap,/* in: memory heap from which the memory for
629
606
                                *old_vers is allocated; memory for possible
630
607
                                intermediate versions is allocated and freed
631
608
                                locally within the function */
632
 
        const rec_t**   old_vers)/*!< out: rec, old version, or NULL if the
 
609
        const rec_t**   old_vers)/* out: rec, old version, or NULL if the
633
610
                                record does not exist in the view, that is,
634
611
                                it was freshly inserted afterwards */
635
612
{
637
614
        mem_heap_t*     heap            = NULL;
638
615
        byte*           buf;
639
616
        ulint           err;
640
 
        trx_id_t        rec_trx_id      = 0;
 
617
        dulint          rec_trx_id      = ut_dulint_zero;
641
618
 
642
619
        ut_ad(dict_index_is_clust(index));
643
620
        ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
660
637
                trx_t*          version_trx;
661
638
                mem_heap_t*     heap2;
662
639
                rec_t*          prev_version;
663
 
                trx_id_t        version_trx_id;
 
640
                dulint          version_trx_id;
664
641
 
665
642
                version_trx_id = row_get_rec_trx_id(version, index, *offsets);
666
643
                if (rec == version) {
689
666
                        rolled back and the transaction is removed from
690
667
                        the global list of transactions. */
691
668
 
692
 
                        if (rec_trx_id == version_trx_id) {
 
669
                        if (!ut_dulint_cmp(rec_trx_id, version_trx_id)) {
693
670
                                /* The transaction was committed while
694
671
                                we searched for earlier versions.
695
672
                                Return the current version as a
702
679
                                                           offset_heap);
703
680
                        }
704
681
 
705
 
                        buf = static_cast<byte *>(mem_heap_alloc(in_heap, rec_offs_size(*offsets)));
 
682
                        buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets));
706
683
                        *old_vers = rec_copy(buf, version, *offsets);
707
684
                        rec_offs_make_valid(*old_vers, index, *offsets);
708
685
                        err = DB_SUCCESS;