MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
row0vers.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "row0vers.h"
27 
28 #ifdef UNIV_NONINL
29 #include "row0vers.ic"
30 #endif
31 
32 #include "dict0dict.h"
33 #include "dict0boot.h"
34 #include "btr0btr.h"
35 #include "mach0data.h"
36 #include "trx0rseg.h"
37 #include "trx0trx.h"
38 #include "trx0roll.h"
39 #include "trx0undo.h"
40 #include "trx0purge.h"
41 #include "trx0rec.h"
42 #include "que0que.h"
43 #include "row0row.h"
44 #include "row0upd.h"
45 #include "rem0cmp.h"
46 #include "read0read.h"
47 #include "lock0lock.h"
48 
49 /*****************************************************************/
56 UNIV_INLINE
59 /*=======================*/
60  const rec_t* clust_rec,
61  dict_index_t* clust_index,
62  const rec_t* rec,
64  const ulint* offsets,
65  mtr_t* mtr)
66 {
67  trx_id_t trx_id;
68  ibool corrupt;
69  ulint comp;
70  ulint rec_del;
71  const rec_t* version;
72  rec_t* prev_version = NULL;
73  ulint* clust_offsets;
75 
76  ut_ad(rec_offs_validate(rec, index, offsets));
77 
78  heap = mem_heap_create(1024);
79 
80  clust_offsets = rec_get_offsets(
81  clust_rec, clust_index, NULL, ULINT_UNDEFINED, &heap);
82 
83  trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
84  corrupt = FALSE;
85 
86  if (!trx_rw_is_active(trx_id, &corrupt)) {
87  /* The transaction that modified or inserted clust_rec is no
88  longer active, or it is corrupt: no implicit lock on rec */
89  if (corrupt) {
91  trx_id, clust_rec, clust_index, clust_offsets,
93  }
94  mem_heap_free(heap);
95  return(0);
96  }
97 
98  comp = page_rec_is_comp(rec);
99  ut_ad(index->table == clust_index->table);
100  ut_ad(!!comp == dict_table_is_comp(index->table));
101  ut_ad(!comp == !page_rec_is_comp(clust_rec));
102 
103  rec_del = rec_get_deleted_flag(rec, comp);
104 
105  /* We look up if some earlier version, which was modified by
106  the trx_id transaction, of the clustered index record would
107  require rec to be in a different state (delete marked or
108  unmarked, or have different field values, or not existing). If
109  there is such a version, then rec was modified by the trx_id
110  transaction, and it has an implicit x-lock on rec. Note that
111  if clust_rec itself would require rec to be in a different
112  state, then the trx_id transaction has not yet had time to
113  modify rec, and does not necessarily have an implicit x-lock
114  on rec. */
115 
116  for (version = clust_rec;; version = prev_version) {
117  row_ext_t* ext;
118  const dtuple_t* row;
119  dtuple_t* entry;
120  ulint vers_del;
121  trx_id_t prev_trx_id;
122  mem_heap_t* old_heap = heap;
123 
124  /* We keep the semaphore in mtr on the clust_rec page, so
125  that no other transaction can update it and get an
126  implicit x-lock on rec until mtr_commit(mtr). */
127 
128  heap = mem_heap_create(1024);
129 
131  clust_rec, mtr, version, clust_index, clust_offsets,
132  heap, &prev_version);
133 
134  /* Free version and clust_offsets. */
135 
136  mem_heap_free(old_heap);
137 
138  if (prev_version == NULL) {
139 
140  /* clust_rec should be a fresh insert, because
141  no previous version was found or the transaction
142  has committed. The caller has to recheck as the
143  synopsis of this function states, whether trx_id
144  is active or not. */
145 
146  break;
147  }
148 
149  clust_offsets = rec_get_offsets(
150  prev_version, clust_index, NULL, ULINT_UNDEFINED,
151  &heap);
152 
153  vers_del = rec_get_deleted_flag(prev_version, comp);
154 
155  prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
156  clust_offsets);
157 
158  /* The stack of versions is locked by mtr. Thus, it
159  is safe to fetch the prefixes for externally stored
160  columns. */
161 
162  row = row_build(ROW_COPY_POINTERS, clust_index, prev_version,
163  clust_offsets,
164  NULL, NULL, NULL, &ext, heap);
165 
166  entry = row_build_index_entry(row, ext, index, heap);
167 
168  /* entry may be NULL if a record was inserted in place
169  of a deleted record, and the BLOB pointers of the new
170  record were not initialized yet. But in that case,
171  prev_version should be NULL. */
172 
173  ut_a(entry != NULL);
174 
175  /* If we get here, we know that the trx_id transaction
176  modified prev_version. Let us check if prev_version
177  would require rec to be in a different state. */
178 
179  /* The previous version of clust_rec must be
180  accessible, because clust_rec was not a fresh insert.
181  There is no guarantee that the transaction is still
182  active. */
183 
184  /* We check if entry and rec are identified in the alphabetical
185  ordering */
186 
187  if (!trx_rw_is_active(trx_id, &corrupt)) {
188  /* Transaction no longer active: no implicit
189  x-lock. This situation should only be possible
190  because we are not holding lock_sys->mutex. */
191  ut_ad(!lock_mutex_own());
192  if (corrupt) {
194  trx_id,
195  prev_version, clust_index,
196  clust_offsets,
198  }
199  trx_id = 0;
200  break;
201  } else if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
202  /* The delete marks of rec and prev_version should be
203  equal for rec to be in the state required by
204  prev_version */
205 
206  if (rec_del != vers_del) {
207 
208  break;
209  }
210 
211  /* It is possible that the row was updated so that the
212  secondary index record remained the same in
213  alphabetical ordering, but the field values changed
214  still. For example, 'abc' -> 'ABC'. Check also that. */
215 
217  entry, dtuple_get_n_fields(entry));
218 
219  if (0 != cmp_dtuple_rec(entry, rec, offsets)) {
220 
221  break;
222  }
223 
224  } else if (!rec_del) {
225  /* The delete mark should be set in rec for it to be
226  in the state required by prev_version */
227 
228  break;
229  }
230 
231  if (trx_id != prev_trx_id) {
232  /* prev_version was the first version modified by
233  the trx_id transaction: no implicit x-lock */
234 
235  trx_id = 0;
236  break;
237  }
238  }
239 
240  mem_heap_free(heap);
241  return(trx_id);
242 }
243 
244 /*****************************************************************/
251 UNIV_INTERN
252 trx_id_t
254 /*===================*/
255  const rec_t* rec,
257  const ulint* offsets)
258 {
259  dict_index_t* clust_index;
260  const rec_t* clust_rec;
261  trx_id_t trx_id;
262  mtr_t mtr;
263 
264  ut_ad(!lock_mutex_own());
265  ut_ad(!mutex_own(&trx_sys->mutex));
266 
267  mtr_start(&mtr);
268 
269  /* Search for the clustered index record. The latch on the
270  page of clust_rec locks the top of the stack of versions. The
271  bottom of the version stack is not locked; oldest versions may
272  disappear by the fact that transactions may be committed and
273  collected by the purge. This is not a problem, because we are
274  only interested in active transactions. */
275 
276  clust_rec = row_get_clust_rec(
277  BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr);
278 
279  if (UNIV_UNLIKELY(!clust_rec)) {
280  /* In a rare case it is possible that no clust rec is found
281  for a secondary index record: if in row0umod.cc
282  row_undo_mod_remove_clust_low() we have already removed the
283  clust rec, while purge is still cleaning and removing
284  secondary index records associated with earlier versions of
285  the clustered index record. In that case there cannot be
286  any implicit lock on the secondary index record, because
287  an active transaction which has modified the secondary index
288  record has also modified the clustered index record. And in
289  a rollback we always undo the modifications to secondary index
290  records before the clustered index record. */
291 
292  trx_id = 0;
293  } else {
295  clust_rec, clust_index, rec, index, offsets, &mtr);
296  }
297 
298  mtr_commit(&mtr);
299 
300  return(trx_id);
301 }
302 
303 /*****************************************************************/
307 UNIV_INTERN
308 ibool
310 /*==============================*/
311  trx_id_t trx_id,
312  mtr_t* mtr)
315 {
316 #ifdef UNIV_SYNC_DEBUG
317  ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
318 #endif /* UNIV_SYNC_DEBUG */
319 
320  mtr_s_lock(&(purge_sys->latch), mtr);
321 
322  return(!read_view_sees_trx_id(purge_sys->view, trx_id));
323 }
324 
325 /*****************************************************************/
332 UNIV_INTERN
333 ibool
335 /*=========================*/
336  ibool also_curr,
339  const rec_t* rec,
341  mtr_t* mtr,
344  const dtuple_t* ientry)
345 {
346  const rec_t* version;
347  rec_t* prev_version;
348  dict_index_t* clust_index;
349  ulint* clust_offsets;
350  mem_heap_t* heap;
351  mem_heap_t* heap2;
352  const dtuple_t* row;
353  const dtuple_t* entry;
354  ulint comp;
355 
356  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
357  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
358 #ifdef UNIV_SYNC_DEBUG
359  ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
360 #endif /* UNIV_SYNC_DEBUG */
361 
362  clust_index = dict_table_get_first_index(index->table);
363 
364  comp = page_rec_is_comp(rec);
365  ut_ad(!dict_table_is_comp(index->table) == !comp);
366  heap = mem_heap_create(1024);
367  clust_offsets = rec_get_offsets(rec, clust_index, NULL,
368  ULINT_UNDEFINED, &heap);
369 
370  if (also_curr && !rec_get_deleted_flag(rec, comp)) {
371  row_ext_t* ext;
372 
373  /* The top of the stack of versions is locked by the
374  mtr holding a latch on the page containing the
375  clustered index record. The bottom of the stack is
376  locked by the fact that the purge_sys->view must
377  'overtake' any read view of an active transaction.
378  Thus, it is safe to fetch the prefixes for
379  externally stored columns. */
380  row = row_build(ROW_COPY_POINTERS, clust_index,
381  rec, clust_offsets,
382  NULL, NULL, NULL, &ext, heap);
383  entry = row_build_index_entry(row, ext, index, heap);
384 
385  /* If entry == NULL, the record contains unset BLOB
386  pointers. This must be a freshly inserted record. If
387  this is called from
388  row_purge_remove_sec_if_poss_low(), the thread will
389  hold latches on the clustered index and the secondary
390  index. Because the insert works in three steps:
391 
392  (1) insert the record to clustered index
393  (2) store the BLOBs and update BLOB pointers
394  (3) insert records to secondary indexes
395 
396  the purge thread can safely ignore freshly inserted
397  records and delete the secondary index record. The
398  thread that inserted the new record will be inserting
399  the secondary index records. */
400 
401  /* NOTE that we cannot do the comparison as binary
402  fields because the row is maybe being modified so that
403  the clustered index record has already been updated to
404  a different binary value in a char field, but the
405  collation identifies the old and new value anyway! */
406  if (entry && !dtuple_coll_cmp(ientry, entry)) {
407 
408  mem_heap_free(heap);
409 
410  return(TRUE);
411  }
412  }
413 
414  version = rec;
415 
416  for (;;) {
417  heap2 = heap;
418  heap = mem_heap_create(1024);
419  trx_undo_prev_version_build(rec, mtr, version,
420  clust_index, clust_offsets,
421  heap, &prev_version);
422  mem_heap_free(heap2); /* free version and clust_offsets */
423 
424  if (!prev_version) {
425  /* Versions end here */
426 
427  mem_heap_free(heap);
428 
429  return(FALSE);
430  }
431 
432  clust_offsets = rec_get_offsets(prev_version, clust_index,
433  NULL, ULINT_UNDEFINED, &heap);
434 
435  if (!rec_get_deleted_flag(prev_version, comp)) {
436  row_ext_t* ext;
437 
438  /* The stack of versions is locked by mtr.
439  Thus, it is safe to fetch the prefixes for
440  externally stored columns. */
441  row = row_build(ROW_COPY_POINTERS, clust_index,
442  prev_version, clust_offsets,
443  NULL, NULL, NULL, &ext, heap);
444  entry = row_build_index_entry(row, ext, index, heap);
445 
446  /* If entry == NULL, the record contains unset
447  BLOB pointers. This must be a freshly
448  inserted record that we can safely ignore.
449  For the justification, see the comments after
450  the previous row_build_index_entry() call. */
451 
452  /* NOTE that we cannot do the comparison as binary
453  fields because maybe the secondary index record has
454  already been updated to a different binary value in
455  a char field, but the collation identifies the old
456  and new value anyway! */
457 
458  if (entry && !dtuple_coll_cmp(ientry, entry)) {
459 
460  mem_heap_free(heap);
461 
462  return(TRUE);
463  }
464  }
465 
466  version = prev_version;
467  }
468 }
469 
470 /*****************************************************************/
475 UNIV_INTERN
476 dberr_t
478 /*===============================*/
479  const rec_t* rec,
483  mtr_t* mtr,
485  ulint** offsets,
487  read_view_t* view,
490  mem_heap_t* in_heap,
494  rec_t** old_vers)
498 {
499  const rec_t* version;
500  rec_t* prev_version;
501  trx_id_t trx_id;
502  mem_heap_t* heap = NULL;
503  byte* buf;
504  dberr_t err;
505 
506  ut_ad(dict_index_is_clust(index));
507  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
508  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
509 #ifdef UNIV_SYNC_DEBUG
510  ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
511 #endif /* UNIV_SYNC_DEBUG */
512 
513  ut_ad(rec_offs_validate(rec, index, *offsets));
514 
515  trx_id = row_get_rec_trx_id(rec, index, *offsets);
516 
517  ut_ad(!read_view_sees_trx_id(view, trx_id));
518 
519  version = rec;
520 
521  for (;;) {
522  mem_heap_t* heap2 = heap;
523  trx_undo_rec_t* undo_rec;
524  roll_ptr_t roll_ptr;
525  undo_no_t undo_no;
526  heap = mem_heap_create(1024);
527 
528  /* If we have high-granularity consistent read view and
529  creating transaction of the view is the same as trx_id in
530  the record we see this record only in the case when
531  undo_no of the record is < undo_no in the view. */
532 
533  if (view->type == VIEW_HIGH_GRANULARITY
534  && view->creator_trx_id == trx_id) {
535 
536  roll_ptr = row_get_rec_roll_ptr(version, index,
537  *offsets);
538  undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap);
539  undo_no = trx_undo_rec_get_undo_no(undo_rec);
540  mem_heap_empty(heap);
541 
542  if (view->undo_no > undo_no) {
543  /* The view already sees this version: we can
544  copy it to in_heap and return */
545 
546 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
548  version, *offsets));
549 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
550 
551  buf = static_cast<byte*>(mem_heap_alloc(
552  in_heap, rec_offs_size(*offsets)));
553 
554  *old_vers = rec_copy(buf, version, *offsets);
555  rec_offs_make_valid(*old_vers, index,
556  *offsets);
557  err = DB_SUCCESS;
558  break;
559  }
560  }
561 
562  err = trx_undo_prev_version_build(rec, mtr, version, index,
563  *offsets, heap,
564  &prev_version)
565  ? DB_SUCCESS : DB_MISSING_HISTORY;
566  if (heap2) {
567  mem_heap_free(heap2); /* free version */
568  }
569 
570  if (prev_version == NULL) {
571  /* It was a freshly inserted version */
572  *old_vers = NULL;
573  break;
574  }
575 
576  *offsets = rec_get_offsets(prev_version, index, *offsets,
577  ULINT_UNDEFINED, offset_heap);
578 
579 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
580  ut_a(!rec_offs_any_null_extern(prev_version, *offsets));
581 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
582 
583  trx_id = row_get_rec_trx_id(prev_version, index, *offsets);
584 
585  if (read_view_sees_trx_id(view, trx_id)) {
586 
587  /* The view already sees this version: we can copy
588  it to in_heap and return */
589 
590  buf = static_cast<byte*>(
592  in_heap, rec_offs_size(*offsets)));
593 
594  *old_vers = rec_copy(buf, prev_version, *offsets);
595  rec_offs_make_valid(*old_vers, index, *offsets);
596  break;
597  }
598 
599  version = prev_version;
600  }/* for (;;) */
601 
602  mem_heap_free(heap);
603 
604  return(err);
605 }
606 
607 /*****************************************************************/
610 UNIV_INTERN
611 void
613 /*====================================*/
614  const rec_t* rec,
618  mtr_t* mtr,
620  ulint** offsets,
624  mem_heap_t* in_heap,
628  const rec_t** old_vers)
631 {
632  const rec_t* version;
633  mem_heap_t* heap = NULL;
634  byte* buf;
635  trx_id_t rec_trx_id = 0;
636 
637  ut_ad(dict_index_is_clust(index));
638  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
639  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
640 #ifdef UNIV_SYNC_DEBUG
641  ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
642 #endif /* UNIV_SYNC_DEBUG */
643 
644  ut_ad(rec_offs_validate(rec, index, *offsets));
645 
646  version = rec;
647 
648  for (;;) {
649  const trx_t* version_trx;
650  mem_heap_t* heap2;
651  rec_t* prev_version;
652  trx_id_t version_trx_id;
653 
654  version_trx_id = row_get_rec_trx_id(version, index, *offsets);
655  if (rec == version) {
656  rec_trx_id = version_trx_id;
657  }
658 
659  mutex_enter(&trx_sys->mutex);
660  version_trx = trx_get_rw_trx_by_id(version_trx_id);
661  /* Because version_trx is a read-write transaction,
662  its state cannot change from or to NOT_STARTED while
663  we are holding the trx_sys->mutex. It may change from
664  ACTIVE to PREPARED or COMMITTED. */
665  if (version_trx
666  && trx_state_eq(version_trx,
667  TRX_STATE_COMMITTED_IN_MEMORY)) {
668  version_trx = NULL;
669  }
670  mutex_exit(&trx_sys->mutex);
671 
672  if (!version_trx) {
673 committed_version_trx:
674  /* We found a version that belongs to a
675  committed transaction: return it. */
676 
677 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
678  ut_a(!rec_offs_any_null_extern(version, *offsets));
679 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
680 
681  if (rec == version) {
682  *old_vers = rec;
683  break;
684  }
685 
686  /* We assume that a rolled-back transaction stays in
687  TRX_STATE_ACTIVE state until all the changes have been
688  rolled back and the transaction is removed from
689  the global list of transactions. */
690 
691  if (rec_trx_id == version_trx_id) {
692  /* The transaction was committed while
693  we searched for earlier versions.
694  Return the current version as a
695  semi-consistent read. */
696 
697  version = rec;
698  *offsets = rec_get_offsets(version,
699  index, *offsets,
700  ULINT_UNDEFINED,
701  offset_heap);
702  }
703 
704  buf = static_cast<byte*>(
706  in_heap, rec_offs_size(*offsets)));
707 
708  *old_vers = rec_copy(buf, version, *offsets);
709  rec_offs_make_valid(*old_vers, index, *offsets);
710  break;
711  }
712 
713  DEBUG_SYNC_C("after_row_vers_check_trx_active");
714 
715  heap2 = heap;
716  heap = mem_heap_create(1024);
717 
718  if (!trx_undo_prev_version_build(rec, mtr, version, index,
719  *offsets, heap,
720  &prev_version)) {
721  mem_heap_free(heap);
722  heap = heap2;
723  heap2 = NULL;
724  goto committed_version_trx;
725  }
726 
727  if (heap2) {
728  mem_heap_free(heap2); /* free version */
729  }
730 
731  if (prev_version == NULL) {
732  /* It was a freshly inserted version */
733  *old_vers = NULL;
734  break;
735  }
736 
737  version = prev_version;
738  *offsets = rec_get_offsets(version, index, *offsets,
739  ULINT_UNDEFINED, offset_heap);
740 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
741  ut_a(!rec_offs_any_null_extern(version, *offsets));
742 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
743  }/* for (;;) */
744 
745  if (heap) {
746  mem_heap_free(heap);
747  }
748 }