Drizzled Public API Documentation

trx0rec.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1996, 2010, 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 /**************************************************/
26 #include "trx0rec.h"
27 
28 #ifdef UNIV_NONINL
29 #include "trx0rec.ic"
30 #endif
31 
32 #include "fsp0fsp.h"
33 #include "mach0data.h"
34 #include "trx0undo.h"
35 #include "mtr0log.h"
36 #ifndef UNIV_HOTBACKUP
37 #include "dict0dict.h"
38 #include "ut0mem.h"
39 #include "row0ext.h"
40 #include "row0upd.h"
41 #include "que0que.h"
42 #include "trx0purge.h"
43 #include "trx0rseg.h"
44 #include "row0row.h"
45 
46 /*=========== UNDO LOG RECORD CREATION AND DECODING ====================*/
47 
48 /**********************************************************************/
51 UNIV_INLINE
52 void
53 trx_undof_page_add_undo_rec_log(
54 /*============================*/
55  page_t* undo_page,
56  ulint old_free,
57  ulint new_free,
58  mtr_t* mtr)
59 {
60  byte* log_ptr;
61  const byte* log_end;
62  ulint len;
63 
64  log_ptr = mlog_open(mtr, 11 + 13 + MLOG_BUF_MARGIN);
65 
66  if (log_ptr == NULL) {
67 
68  return;
69  }
70 
71  log_end = &log_ptr[11 + 13 + MLOG_BUF_MARGIN];
73  undo_page, MLOG_UNDO_INSERT, log_ptr, mtr);
74  len = new_free - old_free - 4;
75 
76  mach_write_to_2(log_ptr, len);
77  log_ptr += 2;
78 
79  if (log_ptr + len <= log_end) {
80  memcpy(log_ptr, undo_page + old_free + 2, len);
81  mlog_close(mtr, log_ptr + len);
82  } else {
83  mlog_close(mtr, log_ptr);
84  mlog_catenate_string(mtr, undo_page + old_free + 2, len);
85  }
86 }
87 #endif /* !UNIV_HOTBACKUP */
88 
89 /***********************************************************/
92 UNIV_INTERN
93 byte*
95 /*========================*/
96  byte* ptr,
97  byte* end_ptr,
98  page_t* page)
99 {
100  ulint len;
101  byte* rec;
102  ulint first_free;
103 
104  if (end_ptr < ptr + 2) {
105 
106  return(NULL);
107  }
108 
109  len = mach_read_from_2(ptr);
110  ptr += 2;
111 
112  if (end_ptr < ptr + len) {
113 
114  return(NULL);
115  }
116 
117  if (page == NULL) {
118 
119  return(ptr + len);
120  }
121 
122  first_free = mach_read_from_2(page + TRX_UNDO_PAGE_HDR
124  rec = page + first_free;
125 
126  mach_write_to_2(rec, first_free + 4 + len);
127  mach_write_to_2(rec + 2 + len, first_free);
128 
130  first_free + 4 + len);
131  ut_memcpy(rec + 2, ptr, len);
132 
133  return(ptr + len);
134 }
135 
136 #ifndef UNIV_HOTBACKUP
137 /**********************************************************************/
140 UNIV_INLINE
141 ulint
142 trx_undo_left(
143 /*==========*/
144  const page_t* page,
145  const byte* ptr)
146 {
147  /* The '- 10' is a safety margin, in case we have some small
148  calculation error below */
149 
150  return(UNIV_PAGE_SIZE - (ptr - page) - 10 - FIL_PAGE_DATA_END);
151 }
152 
153 /**********************************************************************/
158 static
159 ulint
160 trx_undo_page_set_next_prev_and_add(
161 /*================================*/
162  page_t* undo_page,
163  byte* ptr,
165  mtr_t* mtr)
166 {
167  ulint first_free;
168  ulint end_of_rec;
169  byte* ptr_to_first_free;
170  /* pointer within undo_page
171  that points to the next free
172  offset value within undo_page.*/
173 
174  ut_ad(ptr > undo_page);
175  ut_ad(ptr < undo_page + UNIV_PAGE_SIZE);
176 
177  if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < 2)) {
178 
179  return(0);
180  }
181 
182  ptr_to_first_free = undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE;
183 
184  first_free = mach_read_from_2(ptr_to_first_free);
185 
186  /* Write offset of the previous undo log record */
187  mach_write_to_2(ptr, first_free);
188  ptr += 2;
189 
190  end_of_rec = ptr - undo_page;
191 
192  /* Write offset of the next undo log record */
193  mach_write_to_2(undo_page + first_free, end_of_rec);
194 
195  /* Update the offset to first free undo record */
196  mach_write_to_2(ptr_to_first_free, end_of_rec);
197 
198  /* Write this log entry to the UNDO log */
199  trx_undof_page_add_undo_rec_log(undo_page, first_free,
200  end_of_rec, mtr);
201 
202  return(first_free);
203 }
204 
205 /**********************************************************************/
208 static
209 ulint
210 trx_undo_page_report_insert(
211 /*========================*/
212  page_t* undo_page,
213  trx_t* trx,
214  dict_index_t* index,
215  const dtuple_t* clust_entry,
217  mtr_t* mtr)
218 {
219  ulint first_free;
220  byte* ptr;
221  ulint i;
222 
223  ut_ad(dict_index_is_clust(index));
225  + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
226 
227  first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
228  + TRX_UNDO_PAGE_FREE);
229  ptr = undo_page + first_free;
230 
231  ut_ad(first_free <= UNIV_PAGE_SIZE);
232 
233  if (trx_undo_left(undo_page, ptr) < 2 + 1 + 11 + 11) {
234 
235  /* Not enough space for writing the general parameters */
236 
237  return(0);
238  }
239 
240  /* Reserve 2 bytes for the pointer to the next undo log record */
241  ptr += 2;
242 
243  /* Store first some general parameters to the undo log */
244  *ptr++ = TRX_UNDO_INSERT_REC;
245  ptr += mach_ull_write_much_compressed(ptr, trx->undo_no);
246  ptr += mach_ull_write_much_compressed(ptr, index->table->id);
247  /*----------------------------------------*/
248  /* Store then the fields required to uniquely determine the record
249  to be inserted in the clustered index */
250 
251  for (i = 0; i < dict_index_get_n_unique(index); i++) {
252 
253  const dfield_t* field = dtuple_get_nth_field(clust_entry, i);
254  ulint flen = dfield_get_len(field);
255 
256  if (trx_undo_left(undo_page, ptr) < 5) {
257 
258  return(0);
259  }
260 
261  ptr += mach_write_compressed(ptr, flen);
262 
263  if (flen != UNIV_SQL_NULL) {
264  if (trx_undo_left(undo_page, ptr) < flen) {
265 
266  return(0);
267  }
268 
269  ut_memcpy(ptr, dfield_get_data(field), flen);
270  ptr += flen;
271  }
272  }
273 
274  return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
275 }
276 
277 /**********************************************************************/
280 UNIV_INTERN
281 byte*
283 /*==================*/
284  trx_undo_rec_t* undo_rec,
285  ulint* type,
287  ulint* cmpl_info,
289  ibool* updated_extern,
291  undo_no_t* undo_no,
292  table_id_t* table_id)
293 {
294  byte* ptr;
295  ulint type_cmpl;
296 
297  ptr = undo_rec + 2;
298 
299  type_cmpl = mach_read_from_1(ptr);
300  ptr++;
301 
302  if (type_cmpl & TRX_UNDO_UPD_EXTERN) {
303  *updated_extern = TRUE;
304  type_cmpl -= TRX_UNDO_UPD_EXTERN;
305  } else {
306  *updated_extern = FALSE;
307  }
308 
309  *type = type_cmpl & (TRX_UNDO_CMPL_INFO_MULT - 1);
310  *cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
311 
312  *undo_no = mach_ull_read_much_compressed(ptr);
313  ptr += mach_ull_get_much_compressed_size(*undo_no);
314 
315  *table_id = mach_ull_read_much_compressed(ptr);
316  ptr += mach_ull_get_much_compressed_size(*table_id);
317 
318  return(ptr);
319 }
320 
321 /**********************************************************************/
324 static
325 byte*
326 trx_undo_rec_get_col_val(
327 /*=====================*/
328  byte* ptr,
329  byte** field,
330  ulint* len,
331  ulint* orig_len)
333 {
334  *len = mach_read_compressed(ptr);
335  ptr += mach_get_compressed_size(*len);
336 
337  *orig_len = 0;
338 
339  switch (*len) {
340  case UNIV_SQL_NULL:
341  *field = NULL;
342  break;
343  case UNIV_EXTERN_STORAGE_FIELD:
344  *orig_len = mach_read_compressed(ptr);
345  ptr += mach_get_compressed_size(*orig_len);
346  *len = mach_read_compressed(ptr);
347  ptr += mach_get_compressed_size(*len);
348  *field = ptr;
349  ptr += *len;
350 
351  ut_ad(*orig_len >= BTR_EXTERN_FIELD_REF_SIZE);
352  ut_ad(*len > *orig_len);
353  /* @see dtuple_convert_big_rec() */
354  ut_ad(*len >= BTR_EXTERN_FIELD_REF_SIZE * 2);
355  /* we do not have access to index->table here
356  ut_ad(dict_table_get_format(index->table) >= DICT_TF_FORMAT_ZIP
357  || *len >= REC_MAX_INDEX_COL_LEN
358  + BTR_EXTERN_FIELD_REF_SIZE);
359  */
360 
361  *len += UNIV_EXTERN_STORAGE_FIELD;
362  break;
363  default:
364  *field = ptr;
365  if (*len >= UNIV_EXTERN_STORAGE_FIELD) {
366  ptr += *len - UNIV_EXTERN_STORAGE_FIELD;
367  } else {
368  ptr += *len;
369  }
370  }
371 
372  return(ptr);
373 }
374 
375 /*******************************************************************/
378 UNIV_INTERN
379 byte*
381 /*=====================*/
382  byte* ptr,
388  dict_index_t* index,
389  dtuple_t** ref,
390  mem_heap_t* heap)
392 {
393  ulint ref_len;
394  ulint i;
395 
396  ut_ad(index && ptr && ref && heap);
397  ut_a(dict_index_is_clust(index));
398 
399  ref_len = dict_index_get_n_unique(index);
400 
401  *ref = dtuple_create(heap, ref_len);
402 
403  dict_index_copy_types(*ref, index, ref_len);
404 
405  for (i = 0; i < ref_len; i++) {
406  dfield_t* dfield;
407  byte* field;
408  ulint len;
409  ulint orig_len;
410 
411  dfield = dtuple_get_nth_field(*ref, i);
412 
413  ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
414 
415  dfield_set_data(dfield, field, len);
416  }
417 
418  return(ptr);
419 }
420 
421 /*******************************************************************/
424 UNIV_INTERN
425 byte*
427 /*======================*/
428  byte* ptr,
430  dict_index_t* index)
431 {
432  ulint ref_len;
433  ulint i;
434 
435  ut_ad(index && ptr);
436  ut_a(dict_index_is_clust(index));
437 
438  ref_len = dict_index_get_n_unique(index);
439 
440  for (i = 0; i < ref_len; i++) {
441  byte* field;
442  ulint len;
443  ulint orig_len;
444 
445  ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
446  }
447 
448  return(ptr);
449 }
450 
451 /**********************************************************************/
455 static
456 byte*
457 trx_undo_page_fetch_ext(
458 /*====================*/
459  byte* ext_buf,
462  ulint zip_size,
464  const byte* field,
465  ulint* len)
467 {
468  /* Fetch the BLOB. */
470  ext_buf, REC_MAX_INDEX_COL_LEN, zip_size, field, *len);
471  /* BLOBs should always be nonempty. */
472  ut_a(ext_len);
473  /* Append the BLOB pointer to the prefix. */
474  memcpy(ext_buf + ext_len,
475  field + *len - BTR_EXTERN_FIELD_REF_SIZE,
477  *len = ext_len + BTR_EXTERN_FIELD_REF_SIZE;
478  return(ext_buf);
479 }
480 
481 /**********************************************************************/
484 static
485 byte*
486 trx_undo_page_report_modify_ext(
487 /*============================*/
488  byte* ptr,
490  byte* ext_buf,
495  ulint zip_size,
497  const byte** field,
499  ulint* len)
500 {
501  if (ext_buf) {
502  /* If an ordering column is externally stored, we will
503  have to store a longer prefix of the field. In this
504  case, write to the log a marker followed by the
505  original length and the real length of the field. */
506  ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD);
507 
508  ptr += mach_write_compressed(ptr, *len);
509 
510  *field = trx_undo_page_fetch_ext(ext_buf, zip_size,
511  *field, len);
512 
513  ptr += mach_write_compressed(ptr, *len);
514  } else {
515  ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD
516  + *len);
517  }
518 
519  return(ptr);
520 }
521 
522 /**********************************************************************/
527 static
528 ulint
529 trx_undo_page_report_modify(
530 /*========================*/
531  page_t* undo_page,
532  trx_t* trx,
533  dict_index_t* index,
535  const rec_t* rec,
537  const ulint* offsets,
538  const upd_t* update,
541  ulint cmpl_info,
543  mtr_t* mtr)
544 {
545  dict_table_t* table;
546  ulint first_free;
547  byte* ptr;
548  const byte* field;
549  ulint flen;
550  ulint col_no;
551  ulint type_cmpl;
552  byte* type_cmpl_ptr;
553  ulint i;
554  trx_id_t trx_id;
555  ibool ignore_prefix = FALSE;
556  byte ext_buf[REC_MAX_INDEX_COL_LEN
558 
559  ut_a(dict_index_is_clust(index));
560  ut_ad(rec_offs_validate(rec, index, offsets));
562  + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE);
563  table = index->table;
564 
565  first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
566  + TRX_UNDO_PAGE_FREE);
567  ptr = undo_page + first_free;
568 
569  ut_ad(first_free <= UNIV_PAGE_SIZE);
570 
571  if (trx_undo_left(undo_page, ptr) < 50) {
572 
573  /* NOTE: the value 50 must be big enough so that the general
574  fields written below fit on the undo log page */
575 
576  return(0);
577  }
578 
579  /* Reserve 2 bytes for the pointer to the next undo log record */
580  ptr += 2;
581 
582  /* Store first some general parameters to the undo log */
583 
584  if (!update) {
585  type_cmpl = TRX_UNDO_DEL_MARK_REC;
586  } else if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
587  type_cmpl = TRX_UNDO_UPD_DEL_REC;
588  /* We are about to update a delete marked record.
589  We don't typically need the prefix in this case unless
590  the delete marking is done by the same transaction
591  (which we check below). */
592  ignore_prefix = TRUE;
593  } else {
594  type_cmpl = TRX_UNDO_UPD_EXIST_REC;
595  }
596 
597  type_cmpl |= cmpl_info * TRX_UNDO_CMPL_INFO_MULT;
598  type_cmpl_ptr = ptr;
599 
600  *ptr++ = (byte) type_cmpl;
601  ptr += mach_ull_write_much_compressed(ptr, trx->undo_no);
602 
603  ptr += mach_ull_write_much_compressed(ptr, table->id);
604 
605  /*----------------------------------------*/
606  /* Store the state of the info bits */
607 
608  *ptr++ = (byte) rec_get_info_bits(rec, dict_table_is_comp(table));
609 
610  /* Store the values of the system columns */
611  field = rec_get_nth_field(rec, offsets,
613  index, DATA_TRX_ID), &flen);
614  ut_ad(flen == DATA_TRX_ID_LEN);
615 
616  trx_id = trx_read_trx_id(field);
617 
618  /* If it is an update of a delete marked record, then we are
619  allowed to ignore blob prefixes if the delete marking was done
620  by some other trx as it must have committed by now for us to
621  allow an over-write. */
622  if (ignore_prefix) {
623  ignore_prefix = (trx_id != trx->id);
624  }
625  ptr += mach_ull_write_compressed(ptr, trx_id);
626 
627  field = rec_get_nth_field(rec, offsets,
629  index, DATA_ROLL_PTR), &flen);
630  ut_ad(flen == DATA_ROLL_PTR_LEN);
631 
632  ptr += mach_ull_write_compressed(ptr, trx_read_roll_ptr(field));
633 
634  /*----------------------------------------*/
635  /* Store then the fields required to uniquely determine the
636  record which will be modified in the clustered index */
637 
638  for (i = 0; i < dict_index_get_n_unique(index); i++) {
639 
640  field = rec_get_nth_field(rec, offsets, i, &flen);
641 
642  /* The ordering columns must not be stored externally. */
643  ut_ad(!rec_offs_nth_extern(offsets, i));
644  ut_ad(dict_index_get_nth_col(index, i)->ord_part);
645 
646  if (trx_undo_left(undo_page, ptr) < 5) {
647 
648  return(0);
649  }
650 
651  ptr += mach_write_compressed(ptr, flen);
652 
653  if (flen != UNIV_SQL_NULL) {
654  if (trx_undo_left(undo_page, ptr) < flen) {
655 
656  return(0);
657  }
658 
659  ut_memcpy(ptr, field, flen);
660  ptr += flen;
661  }
662  }
663 
664  /*----------------------------------------*/
665  /* Save to the undo log the old values of the columns to be updated. */
666 
667  if (update) {
668  if (trx_undo_left(undo_page, ptr) < 5) {
669 
670  return(0);
671  }
672 
673  ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
674 
675  for (i = 0; i < upd_get_n_fields(update); i++) {
676 
677  ulint pos = upd_get_nth_field(update, i)->field_no;
678 
679  /* Write field number to undo log */
680  if (trx_undo_left(undo_page, ptr) < 5) {
681 
682  return(0);
683  }
684 
685  ptr += mach_write_compressed(ptr, pos);
686 
687  /* Save the old value of field */
688  field = rec_get_nth_field(rec, offsets, pos, &flen);
689 
690  if (trx_undo_left(undo_page, ptr) < 15) {
691 
692  return(0);
693  }
694 
695  if (rec_offs_nth_extern(offsets, pos)) {
696  ptr = trx_undo_page_report_modify_ext(
697  ptr,
698  dict_index_get_nth_col(index, pos)
699  ->ord_part
700  && !ignore_prefix
701  && flen < REC_MAX_INDEX_COL_LEN
702  ? ext_buf : NULL,
703  dict_table_zip_size(table),
704  &field, &flen);
705 
706  /* Notify purge that it eventually has to
707  free the old externally stored field */
708 
709  trx->update_undo->del_marks = TRUE;
710 
711  *type_cmpl_ptr |= TRX_UNDO_UPD_EXTERN;
712  } else {
713  ptr += mach_write_compressed(ptr, flen);
714  }
715 
716  if (flen != UNIV_SQL_NULL) {
717  if (trx_undo_left(undo_page, ptr) < flen) {
718 
719  return(0);
720  }
721 
722  ut_memcpy(ptr, field, flen);
723  ptr += flen;
724  }
725  }
726  }
727 
728  /*----------------------------------------*/
729  /* In the case of a delete marking, and also in the case of an update
730  where any ordering field of any index changes, store the values of all
731  columns which occur as ordering fields in any index. This info is used
732  in the purge of old versions where we use it to build and search the
733  delete marked index records, to look if we can remove them from the
734  index tree. Note that starting from 4.0.14 also externally stored
735  fields can be ordering in some index. Starting from 5.2, we no longer
736  store REC_MAX_INDEX_COL_LEN first bytes to the undo log record,
737  but we can construct the column prefix fields in the index by
738  fetching the first page of the BLOB that is pointed to by the
739  clustered index. This works also in crash recovery, because all pages
740  (including BLOBs) are recovered before anything is rolled back. */
741 
742  if (!update || !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
743  byte* old_ptr = ptr;
744 
745  trx->update_undo->del_marks = TRUE;
746 
747  if (trx_undo_left(undo_page, ptr) < 5) {
748 
749  return(0);
750  }
751 
752  /* Reserve 2 bytes to write the number of bytes the stored
753  fields take in this undo record */
754 
755  ptr += 2;
756 
757  for (col_no = 0; col_no < dict_table_get_n_cols(table);
758  col_no++) {
759 
760  const dict_col_t* col
761  = dict_table_get_nth_col(table, col_no);
762 
763  if (col->ord_part) {
764  ulint pos;
765 
766  /* Write field number to undo log */
767  if (trx_undo_left(undo_page, ptr) < 5 + 15) {
768 
769  return(0);
770  }
771 
772  pos = dict_index_get_nth_col_pos(index,
773  col_no);
774  ptr += mach_write_compressed(ptr, pos);
775 
776  /* Save the old value of field */
777  field = rec_get_nth_field(rec, offsets, pos,
778  &flen);
779 
780  if (rec_offs_nth_extern(offsets, pos)) {
781  ptr = trx_undo_page_report_modify_ext(
782  ptr,
783  flen < REC_MAX_INDEX_COL_LEN
784  && !ignore_prefix
785  ? ext_buf : NULL,
786  dict_table_zip_size(table),
787  &field, &flen);
788  } else {
789  ptr += mach_write_compressed(
790  ptr, flen);
791  }
792 
793  if (flen != UNIV_SQL_NULL) {
794  if (trx_undo_left(undo_page, ptr)
795  < flen) {
796 
797  return(0);
798  }
799 
800  ut_memcpy(ptr, field, flen);
801  ptr += flen;
802  }
803  }
804  }
805 
806  mach_write_to_2(old_ptr, ptr - old_ptr);
807  }
808 
809  /*----------------------------------------*/
810  /* Write pointers to the previous and the next undo log records */
811  if (trx_undo_left(undo_page, ptr) < 2) {
812 
813  return(0);
814  }
815 
816  mach_write_to_2(ptr, first_free);
817  ptr += 2;
818  mach_write_to_2(undo_page + first_free, ptr - undo_page);
819 
820  mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
821  ptr - undo_page);
822 
823  /* Write to the REDO log about this change in the UNDO log */
824 
825  trx_undof_page_add_undo_rec_log(undo_page, first_free,
826  ptr - undo_page, mtr);
827  return(first_free);
828 }
829 
830 /**********************************************************************/
834 UNIV_INTERN
835 byte*
837 /*=============================*/
838  byte* ptr,
841  trx_id_t* trx_id,
842  roll_ptr_t* roll_ptr,
843  ulint* info_bits)
844 {
845  /* Read the state of the info bits */
846  *info_bits = mach_read_from_1(ptr);
847  ptr += 1;
848 
849  /* Read the values of the system columns */
850 
851  *trx_id = mach_ull_read_compressed(ptr);
852  ptr += mach_ull_get_compressed_size(*trx_id);
853 
854  *roll_ptr = mach_ull_read_compressed(ptr);
855  ptr += mach_ull_get_compressed_size(*roll_ptr);
856 
857  return(ptr);
858 }
859 
860 /**********************************************************************/
863 UNIV_INLINE
864 byte*
865 trx_undo_update_rec_get_n_upd_fields(
866 /*=================================*/
867  byte* ptr,
868  ulint* n)
869 {
870  *n = mach_read_compressed(ptr);
871  ptr += mach_get_compressed_size(*n);
872 
873  return(ptr);
874 }
875 
876 /**********************************************************************/
879 UNIV_INLINE
880 byte*
881 trx_undo_update_rec_get_field_no(
882 /*=============================*/
883  byte* ptr,
884  ulint* field_no)
885 {
886  *field_no = mach_read_compressed(ptr);
887  ptr += mach_get_compressed_size(*field_no);
888 
889  return(ptr);
890 }
891 
892 /*******************************************************************/
896 UNIV_INTERN
897 byte*
899 /*===========================*/
900  byte* ptr,
906  dict_index_t* index,
907  ulint type,
912  trx_id_t trx_id,
913  roll_ptr_t roll_ptr,
914  ulint info_bits,
915  trx_t* trx,
916  mem_heap_t* heap,
918  upd_t** upd)
919 {
920  upd_field_t* upd_field;
921  upd_t* update;
922  ulint n_fields;
923  byte* buf;
924  ulint i;
925 
926  ut_a(dict_index_is_clust(index));
927 
928  if (type != TRX_UNDO_DEL_MARK_REC) {
929  ptr = trx_undo_update_rec_get_n_upd_fields(ptr, &n_fields);
930  } else {
931  n_fields = 0;
932  }
933 
934  update = upd_create(n_fields + 2, heap);
935 
936  update->info_bits = info_bits;
937 
938  /* Store first trx id and roll ptr to update vector */
939 
940  upd_field = upd_get_nth_field(update, n_fields);
941  buf = static_cast<byte *>(mem_heap_alloc(heap, DATA_TRX_ID_LEN));
942  trx_write_trx_id(buf, trx_id);
943 
944  upd_field_set_field_no(upd_field,
945  dict_index_get_sys_col_pos(index, DATA_TRX_ID),
946  index, trx);
947  dfield_set_data(&(upd_field->new_val), buf, DATA_TRX_ID_LEN);
948 
949  upd_field = upd_get_nth_field(update, n_fields + 1);
950  buf = static_cast<byte *>(mem_heap_alloc(heap, DATA_ROLL_PTR_LEN));
951  trx_write_roll_ptr(buf, roll_ptr);
952 
954  upd_field, dict_index_get_sys_col_pos(index, DATA_ROLL_PTR),
955  index, trx);
956  dfield_set_data(&(upd_field->new_val), buf, DATA_ROLL_PTR_LEN);
957 
958  /* Store then the updated ordinary columns to the update vector */
959 
960  for (i = 0; i < n_fields; i++) {
961 
962  byte* field;
963  ulint len;
964  ulint field_no;
965  ulint orig_len;
966 
967  ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
968 
969  if (field_no >= dict_index_get_n_fields(index)) {
970  fprintf(stderr,
971  "InnoDB: Error: trying to access"
972  " update undo rec field %lu in ",
973  (ulong) field_no);
974  dict_index_name_print(stderr, trx, index);
975  fprintf(stderr, "\n"
976  "InnoDB: but index has only %lu fields\n"
977  "InnoDB: Submit a detailed bug report"
978  " to http://bugs.mysql.com\n"
979  "InnoDB: Run also CHECK TABLE ",
980  (ulong) dict_index_get_n_fields(index));
981  ut_print_name(stderr, trx, TRUE, index->table_name);
982  fprintf(stderr, "\n"
983  "InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
984  (ulong) n_fields, (ulong) i, ptr);
985  *upd = NULL;
986  return(NULL);
987  }
988 
989  upd_field = upd_get_nth_field(update, i);
990 
991  upd_field_set_field_no(upd_field, field_no, index, trx);
992 
993  ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
994 
995  upd_field->orig_len = orig_len;
996 
997  if (len == UNIV_SQL_NULL) {
998  dfield_set_null(&upd_field->new_val);
999  } else if (len < UNIV_EXTERN_STORAGE_FIELD) {
1000  dfield_set_data(&upd_field->new_val, field, len);
1001  } else {
1002  len -= UNIV_EXTERN_STORAGE_FIELD;
1003 
1004  dfield_set_data(&upd_field->new_val, field, len);
1005  dfield_set_ext(&upd_field->new_val);
1006  }
1007  }
1008 
1009  *upd = update;
1010 
1011  return(ptr);
1012 }
1013 
1014 /*******************************************************************/
1018 UNIV_INTERN
1019 byte*
1021 /*=========================*/
1022  byte* ptr,
1029  dict_index_t* index,
1030  dtuple_t** row,
1031  ibool ignore_prefix,
1034  mem_heap_t* heap)
1036 {
1037  const byte* end_ptr;
1038  ulint row_len;
1039 
1040  ut_ad(index);
1041  ut_ad(ptr);
1042  ut_ad(row);
1043  ut_ad(heap);
1044  ut_ad(dict_index_is_clust(index));
1045 
1046  row_len = dict_table_get_n_cols(index->table);
1047 
1048  *row = dtuple_create(heap, row_len);
1049 
1050  dict_table_copy_types(*row, index->table);
1051 
1052  end_ptr = ptr + mach_read_from_2(ptr);
1053  ptr += 2;
1054 
1055  while (ptr != end_ptr) {
1056  dfield_t* dfield;
1057  byte* field;
1058  ulint field_no;
1059  const dict_col_t* col;
1060  ulint col_no;
1061  ulint len;
1062  ulint orig_len;
1063 
1064  ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
1065 
1066  col = dict_index_get_nth_col(index, field_no);
1067  col_no = dict_col_get_no(col);
1068 
1069  ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
1070 
1071  dfield = dtuple_get_nth_field(*row, col_no);
1072 
1073  dfield_set_data(dfield, field, len);
1074 
1075  if (len != UNIV_SQL_NULL
1076  && len >= UNIV_EXTERN_STORAGE_FIELD) {
1077  dfield_set_len(dfield,
1078  len - UNIV_EXTERN_STORAGE_FIELD);
1079  dfield_set_ext(dfield);
1080  /* If the prefix of this column is indexed,
1081  ensure that enough prefix is stored in the
1082  undo log record. */
1083  if (!ignore_prefix && col->ord_part) {
1084  ut_a(dfield_get_len(dfield)
1085  >= 2 * BTR_EXTERN_FIELD_REF_SIZE);
1088  || dfield_get_len(dfield)
1089  >= REC_MAX_INDEX_COL_LEN
1090  + BTR_EXTERN_FIELD_REF_SIZE);
1091  }
1092  }
1093  }
1094 
1095  return(ptr);
1096 }
1097 #endif /* !UNIV_HOTBACKUP */
1098 
1099 /***********************************************************************/
1101 static
1102 void
1103 trx_undo_erase_page_end(
1104 /*====================*/
1105  page_t* undo_page,
1106  mtr_t* mtr)
1107 {
1108  ulint first_free;
1109 
1110  first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
1111  + TRX_UNDO_PAGE_FREE);
1112  memset(undo_page + first_free, 0xff,
1113  (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free);
1114 
1116 }
1117 
1118 /***********************************************************/
1121 UNIV_INTERN
1122 byte*
1124 /*==========================*/
1125  byte* ptr,
1126  byte* /*end_ptr*/,
1127  page_t* page,
1128  mtr_t* mtr)
1129 {
1130  ut_ad(ptr && end_ptr);
1131 
1132  if (page == NULL) {
1133 
1134  return(ptr);
1135  }
1136 
1137  trx_undo_erase_page_end(page, mtr);
1138 
1139  return(ptr);
1140 }
1141 
1142 #ifndef UNIV_HOTBACKUP
1143 /***********************************************************************/
1149 UNIV_INTERN
1150 ulint
1152 /*==========================*/
1153  ulint flags,
1155  ulint op_type,
1157  que_thr_t* thr,
1158  dict_index_t* index,
1159  const dtuple_t* clust_entry,
1162  const upd_t* update,
1164  ulint cmpl_info,
1166  const rec_t* rec,
1169  roll_ptr_t* roll_ptr)
1173 {
1174  trx_t* trx;
1175  trx_undo_t* undo;
1176  ulint page_no;
1177  trx_rseg_t* rseg;
1178  mtr_t mtr;
1179  ulint err = DB_SUCCESS;
1180  mem_heap_t* heap = NULL;
1181  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1182  ulint* offsets = offsets_;
1183  rec_offs_init(offsets_);
1184 
1185  ut_a(dict_index_is_clust(index));
1186 
1187  if (flags & BTR_NO_UNDO_LOG_FLAG) {
1188 
1189  *roll_ptr = 0;
1190 
1191  return(DB_SUCCESS);
1192  }
1193 
1194  ut_ad(thr);
1195  ut_ad((op_type != TRX_UNDO_INSERT_OP)
1196  || (clust_entry && !update && !rec));
1197 
1198  trx = thr_get_trx(thr);
1199  rseg = trx->rseg;
1200 
1201  mutex_enter(&(trx->undo_mutex));
1202 
1203  /* If the undo log is not assigned yet, assign one */
1204 
1205  if (op_type == TRX_UNDO_INSERT_OP) {
1206 
1207  if (trx->insert_undo == NULL) {
1208 
1209  err = trx_undo_assign_undo(trx, TRX_UNDO_INSERT);
1210  }
1211 
1212  undo = trx->insert_undo;
1213 
1214  if (UNIV_UNLIKELY(!undo)) {
1215  /* Did not succeed */
1216  mutex_exit(&(trx->undo_mutex));
1217 
1218  return(err);
1219  }
1220  } else {
1221  ut_ad(op_type == TRX_UNDO_MODIFY_OP);
1222 
1223  if (trx->update_undo == NULL) {
1224 
1225  err = trx_undo_assign_undo(trx, TRX_UNDO_UPDATE);
1226 
1227  }
1228 
1229  undo = trx->update_undo;
1230 
1231  if (UNIV_UNLIKELY(!undo)) {
1232  /* Did not succeed */
1233  mutex_exit(&(trx->undo_mutex));
1234  return(err);
1235  }
1236 
1237  offsets = rec_get_offsets(rec, index, offsets,
1238  ULINT_UNDEFINED, &heap);
1239  }
1240 
1241  page_no = undo->last_page_no;
1242 
1243  mtr_start(&mtr);
1244 
1245  for (;;) {
1246  buf_block_t* undo_block;
1247  page_t* undo_page;
1248  ulint offset;
1249 
1250  undo_block = buf_page_get_gen(undo->space, undo->zip_size,
1251  page_no, RW_X_LATCH,
1252  undo->guess_block, BUF_GET,
1253  __FILE__, __LINE__, &mtr);
1254  buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
1255 
1256  undo_page = buf_block_get_frame(undo_block);
1257 
1258  if (op_type == TRX_UNDO_INSERT_OP) {
1259  offset = trx_undo_page_report_insert(
1260  undo_page, trx, index, clust_entry, &mtr);
1261  } else {
1262  offset = trx_undo_page_report_modify(
1263  undo_page, trx, index, rec, offsets, update,
1264  cmpl_info, &mtr);
1265  }
1266 
1267  if (UNIV_UNLIKELY(offset == 0)) {
1268  /* The record did not fit on the page. We erase the
1269  end segment of the undo log page and write a log
1270  record of it: this is to ensure that in the debug
1271  version the replicate page constructed using the log
1272  records stays identical to the original page */
1273 
1274  trx_undo_erase_page_end(undo_page, &mtr);
1275  mtr_commit(&mtr);
1276  } else {
1277  /* Success */
1278 
1279  mtr_commit(&mtr);
1280 
1281  undo->empty = FALSE;
1282  undo->top_page_no = page_no;
1283  undo->top_offset = offset;
1284  undo->top_undo_no = trx->undo_no;
1285  undo->guess_block = undo_block;
1286 
1287  trx->undo_no++;
1288 
1289  mutex_exit(&trx->undo_mutex);
1290 
1291  *roll_ptr = trx_undo_build_roll_ptr(
1292  op_type == TRX_UNDO_INSERT_OP,
1293  rseg->id, page_no, offset);
1294  if (UNIV_LIKELY_NULL(heap)) {
1295  mem_heap_free(heap);
1296  }
1297  return(DB_SUCCESS);
1298  }
1299 
1300  ut_ad(page_no == undo->last_page_no);
1301 
1302  /* We have to extend the undo log by one page */
1303 
1304  mtr_start(&mtr);
1305 
1306  /* When we add a page to an undo log, this is analogous to
1307  a pessimistic insert in a B-tree, and we must reserve the
1308  counterpart of the tree latch, which is the rseg mutex. */
1309 
1310  mutex_enter(&(rseg->mutex));
1311 
1312  page_no = trx_undo_add_page(trx, undo, &mtr);
1313 
1314  mutex_exit(&(rseg->mutex));
1315 
1316  if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
1317  /* Did not succeed: out of space */
1318 
1319  mutex_exit(&(trx->undo_mutex));
1320  mtr_commit(&mtr);
1321  if (UNIV_LIKELY_NULL(heap)) {
1322  mem_heap_free(heap);
1323  }
1324  return(DB_OUT_OF_FILE_SPACE);
1325  }
1326  }
1327 }
1328 
1329 /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
1330 
1331 /******************************************************************/
1335 UNIV_INTERN
1338 /*======================*/
1339  roll_ptr_t roll_ptr,
1340  mem_heap_t* heap)
1341 {
1342  trx_undo_rec_t* undo_rec;
1343  ulint rseg_id;
1344  ulint page_no;
1345  ulint offset;
1346  const page_t* undo_page;
1347  trx_rseg_t* rseg;
1348  ibool is_insert;
1349  mtr_t mtr;
1350 
1351  trx_undo_decode_roll_ptr(roll_ptr, &is_insert, &rseg_id, &page_no,
1352  &offset);
1353  rseg = trx_rseg_get_on_id(rseg_id);
1354 
1355  mtr_start(&mtr);
1356 
1357  undo_page = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
1358  page_no, &mtr);
1359 
1360  undo_rec = trx_undo_rec_copy(undo_page + offset, heap);
1361 
1362  mtr_commit(&mtr);
1363 
1364  return(undo_rec);
1365 }
1366 
1367 /******************************************************************/
1375 UNIV_INTERN
1376 ulint
1378 /*==================*/
1379  roll_ptr_t roll_ptr,
1380  trx_id_t trx_id,
1383  trx_undo_rec_t** undo_rec,
1384  mem_heap_t* heap)
1385 {
1386 #ifdef UNIV_SYNC_DEBUG
1387  ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
1388 #endif /* UNIV_SYNC_DEBUG */
1389 
1390  if (!trx_purge_update_undo_must_exist(trx_id)) {
1391 
1392  /* It may be that the necessary undo log has already been
1393  deleted */
1394 
1395  return(DB_MISSING_HISTORY);
1396  }
1397 
1398  *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap);
1399 
1400  return(DB_SUCCESS);
1401 }
1402 
1403 /*******************************************************************/
1411 UNIV_INTERN
1412 ulint
1414 /*========================*/
1415  const rec_t* index_rec,
1417  mtr_t* /*index_mtr*/,
1420  const rec_t* rec,
1421  dict_index_t* index,
1422  ulint* offsets,
1423  mem_heap_t* heap,
1425  rec_t** old_vers)
1430 {
1431  trx_undo_rec_t* undo_rec = NULL;
1432  dtuple_t* entry;
1433  trx_id_t rec_trx_id;
1434  ulint type;
1435  undo_no_t undo_no;
1436  table_id_t table_id;
1437  trx_id_t trx_id;
1438  roll_ptr_t roll_ptr;
1439  roll_ptr_t old_roll_ptr;
1440  upd_t* update= NULL;
1441  byte* ptr;
1442  ulint info_bits;
1443  ulint cmpl_info;
1444  ibool dummy_extern;
1445  byte* buf;
1446  ulint err;
1447 #ifdef UNIV_SYNC_DEBUG
1448  ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
1449 #endif /* UNIV_SYNC_DEBUG */
1450  ut_ad(mtr_memo_contains_page(index_mtr, index_rec, MTR_MEMO_PAGE_S_FIX)
1451  || mtr_memo_contains_page(index_mtr, index_rec,
1452  MTR_MEMO_PAGE_X_FIX));
1453  ut_ad(rec_offs_validate(rec, index, offsets));
1454 
1455  if (!dict_index_is_clust(index)) {
1456  fprintf(stderr, "InnoDB: Error: trying to access"
1457  " update undo rec for non-clustered index %s\n"
1458  "InnoDB: Submit a detailed bug report to"
1459  " http://bugs.mysql.com\n"
1460  "InnoDB: index record ", index->name);
1461  rec_print(stderr, index_rec, index);
1462  fputs("\n"
1463  "InnoDB: record version ", stderr);
1464  rec_print_new(stderr, rec, offsets);
1465  putc('\n', stderr);
1466  return(DB_ERROR);
1467  }
1468 
1469  roll_ptr = row_get_rec_roll_ptr(rec, index, offsets);
1470  old_roll_ptr = roll_ptr;
1471 
1472  *old_vers = NULL;
1473 
1474  if (trx_undo_roll_ptr_is_insert(roll_ptr)) {
1475 
1476  /* The record rec is the first inserted version */
1477 
1478  return(DB_SUCCESS);
1479  }
1480 
1481  rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1482 
1483  err = trx_undo_get_undo_rec(roll_ptr, rec_trx_id, &undo_rec, heap);
1484 
1485  if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
1486  /* The undo record may already have been purged.
1487  This should never happen in InnoDB. */
1488 
1489  return(err);
1490  }
1491 
1492  ptr = trx_undo_rec_get_pars(undo_rec, &type, &cmpl_info,
1493  &dummy_extern, &undo_no, &table_id);
1494 
1495  ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
1496  &info_bits);
1497 
1498  /* (a) If a clustered index record version is such that the
1499  trx id stamp in it is bigger than purge_sys->view, then the
1500  BLOBs in that version are known to exist (the purge has not
1501  progressed that far);
1502 
1503  (b) if the version is the first version such that trx id in it
1504  is less than purge_sys->view, and it is not delete-marked,
1505  then the BLOBs in that version are known to exist (the purge
1506  cannot have purged the BLOBs referenced by that version
1507  yet).
1508 
1509  This function does not fetch any BLOBs. The callers might, by
1510  possibly invoking row_ext_create() via row_build(). However,
1511  they should have all needed information in the *old_vers
1512  returned by this function. This is because *old_vers is based
1513  on the transaction undo log records. The function
1514  trx_undo_page_fetch_ext() will write BLOB prefixes to the
1515  transaction undo log that are at least as long as the longest
1516  possible column prefix in a secondary index. Thus, secondary
1517  index entries for *old_vers can be constructed without
1518  dereferencing any BLOB pointers. */
1519 
1520  ptr = trx_undo_rec_skip_row_ref(ptr, index);
1521 
1522  ptr = trx_undo_update_rec_get_update(ptr, index, type, trx_id,
1523  roll_ptr, info_bits,
1524  NULL, heap, &update);
1525 
1526  if (UNIV_UNLIKELY(table_id != index->table->id)) {
1527  ptr = NULL;
1528 
1529  fprintf(stderr,
1530  "InnoDB: Error: trying to access update undo rec"
1531  " for table %s\n"
1532  "InnoDB: but the table id in the"
1533  " undo record is wrong\n"
1534  "InnoDB: Submit a detailed bug report"
1535  " to http://bugs.mysql.com\n"
1536  "InnoDB: Run also CHECK TABLE %s\n",
1537  index->table_name, index->table_name);
1538  }
1539 
1540  if (ptr == NULL) {
1541  /* The record was corrupted, return an error; these printfs
1542  should catch an elusive bug in row_vers_old_has_index_entry */
1543 
1544  fprintf(stderr,
1545  "InnoDB: table %s, index %s, n_uniq %lu\n"
1546  "InnoDB: undo rec address %p, type %lu cmpl_info %lu\n"
1547  "InnoDB: undo rec table id %llu,"
1548  " index table id %llu\n"
1549  "InnoDB: dump of 150 bytes in undo rec: ",
1550  index->table_name, index->name,
1551  (ulong) dict_index_get_n_unique(index),
1552  undo_rec, (ulong) type, (ulong) cmpl_info,
1553  (ullint) table_id,
1554  (ullint) index->table->id);
1555  ut_print_buf(stderr, undo_rec, 150);
1556  fputs("\n"
1557  "InnoDB: index record ", stderr);
1558  rec_print(stderr, index_rec, index);
1559  fputs("\n"
1560  "InnoDB: record version ", stderr);
1561  rec_print_new(stderr, rec, offsets);
1562  fprintf(stderr, "\n"
1563  "InnoDB: Record trx id " TRX_ID_FMT
1564  ", update rec trx id " TRX_ID_FMT "\n"
1565  "InnoDB: Roll ptr in rec " TRX_ID_FMT
1566  ", in update rec" TRX_ID_FMT "\n",
1567  rec_trx_id, trx_id,
1568  old_roll_ptr, roll_ptr);
1569 
1571  return(DB_ERROR);
1572  }
1573 
1574  if (row_upd_changes_field_size_or_external(index, offsets, update)) {
1575  ulint n_ext;
1576 
1577  /* We have to set the appropriate extern storage bits in the
1578  old version of the record: the extern bits in rec for those
1579  fields that update does NOT update, as well as the the bits for
1580  those fields that update updates to become externally stored
1581  fields. Store the info: */
1582 
1583  entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index,
1584  offsets, &n_ext, heap);
1585  n_ext += btr_push_update_extern_fields(entry, update, heap);
1586  /* The page containing the clustered index record
1587  corresponding to entry is latched in mtr. Thus the
1588  following call is safe. */
1589  row_upd_index_replace_new_col_vals(entry, index, update, heap);
1590 
1591  buf = static_cast<byte *>(mem_heap_alloc(heap, rec_get_converted_size(index, entry,
1592  n_ext)));
1593 
1594  *old_vers = rec_convert_dtuple_to_rec(buf, index,
1595  entry, n_ext);
1596  } else {
1597  buf = static_cast<byte *>(mem_heap_alloc(heap, rec_offs_size(offsets)));
1598  *old_vers = rec_copy(buf, rec, offsets);
1599  rec_offs_make_valid(*old_vers, index, offsets);
1600  row_upd_rec_in_place(*old_vers, index, offsets, update, NULL);
1601  }
1602 
1603  return(DB_SUCCESS);
1604 }
1605 #endif /* !UNIV_HOTBACKUP */
#define FIL_PAGE_DATA_END
Definition: fil0fil.h:169
UNIV_INTERN byte * trx_undo_rec_get_row_ref(byte *ptr, dict_index_t *index, dtuple_t **ref, mem_heap_t *heap)
Definition: trx0rec.cc:380
UNIV_INTERN byte * trx_undo_parse_erase_page_end(byte *ptr, byte *end_ptr, page_t *page, mtr_t *mtr)
Definition: trx0rec.cc:1123
UNIV_INLINE ulint mach_ull_write_much_compressed(byte *b, ib_uint64_t n)
#define TRX_UNDO_PAGE_HDR
Definition: trx0undo.h:422
undo_no_t top_undo_no
Definition: trx0undo.h:411
buf_block_t * guess_block
Definition: trx0undo.h:412
byte trx_undo_rec_t
Definition: trx0types.h:112
UNIV_INLINE trx_id_t row_get_rec_trx_id(const rec_t *rec, dict_index_t *index, const ulint *offsets)
const char * name
Definition: dict0mem.h:339
ib_id_t roll_ptr_t
Definition: trx0types.h:87
UNIV_INLINE roll_ptr_t row_get_rec_roll_ptr(const rec_t *rec, dict_index_t *index, const ulint *offsets)
trx_id_t id
Definition: trx0trx.h:548
UNIV_INTERN byte * trx_undo_rec_get_partial_row(byte *ptr, dict_index_t *index, dtuple_t **row, ibool ignore_prefix, mem_heap_t *heap)
Definition: trx0rec.cc:1020
UNIV_INLINE void trx_write_trx_id(byte *ptr, trx_id_t id)
UNIV_INLINE ulint mach_get_compressed_size(ulint n) __attribute__((const ))
UNIV_INLINE ulint dict_index_get_n_fields(const dict_index_t *index)
UNIV_INTERN ulint trx_undo_get_undo_rec(roll_ptr_t roll_ptr, trx_id_t trx_id, trx_undo_rec_t **undo_rec, mem_heap_t *heap)
Definition: trx0rec.cc:1377
UNIV_INLINE void dfield_set_len(dfield_t *field, ulint len)
trx_undo_t * insert_undo
Definition: trx0trx.h:696
ulint zip_size
Definition: trx0undo.h:391
UNIV_INTERN trx_rseg_t * trx_rseg_get_on_id(ulint id)
Definition: trx0rseg.cc:47
UNIV_INLINE dtuple_t * dtuple_create(mem_heap_t *heap, ulint n_fields)
UNIV_INLINE ulint mach_read_compressed(const byte *b) __attribute__((nonnull
UNIV_INTERN ulint btr_copy_externally_stored_field_prefix(byte *buf, ulint len, ulint zip_size, const byte *data, ulint local_len)
Definition: btr0cur.cc:5098
mutex_t undo_mutex
Definition: trx0trx.h:675
#define BUF_GET
Definition: buf0buf.h:43
UNIV_INTERN ulint trx_undo_add_page(trx_t *trx, trx_undo_t *undo, mtr_t *mtr)
Definition: trx0undo.cc:881
UNIV_INLINE void * ut_memcpy(void *dest, const void *sour, ulint n)
#define TRX_ID_FMT
Definition: trx0types.h:33
UNIV_INLINE void mlog_close(mtr_t *mtr, byte *ptr)
rw_lock_t latch
Definition: trx0purge.h:139
UNIV_INTERN void ut_print_buf(FILE *file, const void *buf, ulint len)
Definition: ut0ut.cc:444
UNIV_INTERN trx_undo_rec_t * trx_undo_get_undo_rec_low(roll_ptr_t roll_ptr, mem_heap_t *heap)
Definition: trx0rec.cc:1337
UNIV_INTERN void trx_purge_sys_print(void)
Definition: trx0purge.cc:1213
undo_no_t undo_no
Definition: trx0trx.h:681
UNIV_INLINE ibool dict_table_is_comp(const dict_table_t *table)
UNIV_INLINE ulint rec_offs_nth_extern(const ulint *offsets, ulint n)
UNIV_INLINE ulint mach_ull_get_compressed_size(ib_uint64_t n)
UNIV_INTERN void rec_print_new(FILE *file, const rec_t *rec, const ulint *offsets)
Definition: rem0rec.cc:1722
UNIV_INLINE ulint mach_ull_write_compressed(byte *b, ib_uint64_t n)
UNIV_INTERN ulint dict_index_get_nth_col_pos(const dict_index_t *index, ulint n)
Definition: dict0dict.cc:502
UNIV_INTERN byte * trx_undo_update_rec_get_update(byte *ptr, dict_index_t *index, ulint type, trx_id_t trx_id, roll_ptr_t roll_ptr, ulint info_bits, trx_t *trx, mem_heap_t *heap, upd_t **upd)
Definition: trx0rec.cc:898
UNIV_INTERN void rec_print(FILE *file, const rec_t *rec, const dict_index_t *index)
Definition: rem0rec.cc:1750
UNIV_INLINE rec_t * rec_copy(void *buf, const rec_t *rec, const ulint *offsets)
#define DICT_TF_FORMAT_ZIP
Definition: dict0mem.h:88
#define mem_heap_free(heap)
Definition: mem0mem.h:117
UNIV_INTERN rec_t * rec_convert_dtuple_to_rec(byte *buf, const dict_index_t *index, const dtuple_t *dtuple, ulint n_ext)
Definition: rem0rec.cc:1240
unsigned orig_len
Definition: row0upd.h:377
mutex_t mutex
Definition: trx0rseg.h:146
ibool del_marks
Definition: trx0undo.h:372
UNIV_INLINE const dict_col_t * dict_index_get_nth_col(const dict_index_t *index, ulint pos)
UNIV_INTERN void dict_index_copy_types(dtuple_t *tuple, const dict_index_t *index, ulint n_fields)
Definition: dict0dict.cc:1932
UNIV_INLINE roll_ptr_t trx_read_roll_ptr(const byte *ptr)
unsigned ord_part
Definition: dict0mem.h:303
UNIV_INTERN void dict_table_copy_types(dtuple_t *tuple, const dict_table_t *table)
Definition: dict0dict.cc:1963
UNIV_INTERN void row_upd_rec_in_place(rec_t *rec, dict_index_t *index, const ulint *offsets, const upd_t *update, page_zip_des_t *page_zip)
Definition: row0upd.cc:486
UNIV_INLINE ulint rec_get_deleted_flag(const rec_t *rec, ulint comp)
UNIV_INLINE ib_uint64_t mach_ull_read_much_compressed(const byte *b) __attribute__((nonnull
UNIV_INTERN ibool row_upd_changes_field_size_or_external(dict_index_t *index, const ulint *offsets, const upd_t *update)
Definition: row0upd.cc:418
UNIV_INTERN void mtr_commit(mtr_t *mtr) __attribute__((nonnull))
Definition: mtr0mtr.cc:247
UNIV_INTERN void row_upd_index_replace_new_col_vals(dtuple_t *entry, dict_index_t *index, const upd_t *update, mem_heap_t *heap) __attribute__((nonnull))
Definition: row0upd.cc:1108
UNIV_INLINE void dfield_set_data(dfield_t *field, const void *data, ulint len)
UNIV_INLINE ulint dict_table_zip_size(const dict_table_t *table)
UNIV_INLINE byte * mlog_write_initial_log_record_fast(const byte *ptr, byte type, byte *log_ptr, mtr_t *mtr)
UNIV_INLINE ulint dfield_get_len(const dfield_t *field)
UNIV_INLINE roll_ptr_t trx_undo_build_roll_ptr(ibool is_insert, ulint rseg_id, ulint page_no, ulint offset)
UNIV_INLINE ulint dict_table_get_format(const dict_table_t *table)
ulint top_offset
Definition: trx0undo.h:408
trx_rseg_t * rseg
Definition: trx0trx.h:693
UNIV_INLINE void trx_write_roll_ptr(byte *ptr, roll_ptr_t roll_ptr)
table_id_t id
Definition: dict0mem.h:477
UNIV_INLINE ulint dict_col_get_no(const dict_col_t *col)
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
UNIV_INTERN ulint trx_undo_report_row_operation(ulint flags, ulint op_type, que_thr_t *thr, dict_index_t *index, const dtuple_t *clust_entry, const upd_t *update, ulint cmpl_info, const rec_t *rec, roll_ptr_t *roll_ptr)
Definition: trx0rec.cc:1151
UNIV_INTERN ibool trx_purge_update_undo_must_exist(trx_id_t trx_id)
Definition: trx0purge.cc:72
dfield_t new_val
Definition: row0upd.h:385
UNIV_INTERN void mlog_catenate_string(mtr_t *mtr, const byte *str, ulint len)
Definition: mtr0log.cc:44
#define ut_a(EXPR)
Definition: ut0dbg.h:105
UNIV_INTERN void ut_print_name(FILE *f, struct trx_struct *trx, ibool table_id, const char *name)
Definition: ut0ut.cc:528
UNIV_INLINE void * mem_heap_alloc(mem_heap_t *heap, ulint n)
dict_table_t * table
Definition: dict0mem.h:341
UNIV_INTERN byte * trx_undo_parse_add_undo_rec(byte *ptr, byte *end_ptr, page_t *page)
Definition: trx0rec.cc:94
UNIV_INLINE void trx_undo_decode_roll_ptr(roll_ptr_t roll_ptr, ibool *is_insert, ulint *rseg_id, ulint *page_no, ulint *offset)
ulint info_bits
Definition: row0upd.h:390
UNIV_INTERN buf_block_t * buf_page_get_gen(ulint space, ulint zip_size, ulint offset, ulint rw_latch, buf_block_t *guess, ulint mode, const char *file, ulint line, mtr_t *mtr)
Definition: buf0buf.cc:2712
UNIV_INLINE byte * mlog_open(mtr_t *mtr, ulint size)
UNIV_INTERN void mlog_write_initial_log_record(const byte *ptr, byte type, mtr_t *mtr)
Definition: mtr0log.cc:68
UNIV_INTERN byte * trx_undo_rec_skip_row_ref(byte *ptr, dict_index_t *index)
Definition: trx0rec.cc:426
#define MLOG_UNDO_ERASE_END
Definition: mtr0mtr.h:108
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
ib_id_t trx_id_t
Definition: trx0types.h:85
UNIV_INLINE ulint rec_get_converted_size(dict_index_t *index, const dtuple_t *dtuple, ulint n_ext)
UNIV_INLINE void upd_field_set_field_no(upd_field_t *upd_field, ulint field_no, dict_index_t *index, trx_t *trx)
UNIV_INLINE ulint dict_table_get_n_cols(const dict_table_t *table)
UNIV_INLINE trx_id_t trx_read_trx_id(const byte *ptr)
UNIV_INTERN ulint btr_push_update_extern_fields(dtuple_t *tuple, const upd_t *update, mem_heap_t *heap) __attribute__((nonnull))
Definition: btr0cur.cc:3958
#define BTR_EXTERN_FIELD_REF_SIZE
Definition: btr0types.h:170
#define FIL_NULL
Definition: fil0fil.h:48
UNIV_INLINE ulint dict_index_get_n_unique(const dict_index_t *index)
UNIV_INTERN byte * trx_undo_update_rec_get_sys_cols(byte *ptr, trx_id_t *trx_id, roll_ptr_t *roll_ptr, ulint *info_bits)
Definition: trx0rec.cc:836
trx_purge_t * purge_sys
Definition: trx0purge.cc:48
UNIV_INLINE trx_undo_rec_t * trx_undo_rec_copy(const trx_undo_rec_t *undo_rec, mem_heap_t *heap)
const char * table_name
Definition: dict0mem.h:340
ulint top_page_no
Definition: trx0undo.h:404
UNIV_INLINE ulint mach_ull_get_much_compressed_size(ib_uint64_t n) __attribute__((const ))
UNIV_INLINE void dfield_set_null(dfield_t *field)
UNIV_INLINE ulint dict_index_get_sys_col_pos(const dict_index_t *index, ulint type)
UNIV_INTERN ulint trx_undo_assign_undo(trx_t *trx, ulint type)
Definition: trx0undo.cc:1739
UNIV_INLINE ulint mach_write_compressed(byte *b, ulint n)
UNIV_INLINE void mach_write_to_2(byte *b, ulint n)
UNIV_INLINE trx_t * thr_get_trx(que_thr_t *thr)
#define TRX_UNDO_PAGE_TYPE
Definition: trx0undo.h:426
ulint last_page_no
Definition: trx0undo.h:397
byte page_t
Definition: page0types.h:37
#define MLOG_UNDO_INSERT
Definition: mtr0mtr.h:105
UNIV_INLINE void mtr_start(mtr_t *mtr) __attribute__((nonnull))
UNIV_INLINE ulint rec_get_info_bits(const rec_t *rec, ulint comp)
UNIV_INLINE ulint mach_read_from_1(const byte *b) __attribute__((nonnull
UNIV_INLINE ulint upd_get_n_fields(const upd_t *update)
#define TRX_UNDO_PAGE_FREE
Definition: trx0undo.h:438
UNIV_INTERN dtuple_t * row_rec_to_index_entry(ulint type, const rec_t *rec, const dict_index_t *index, ulint *offsets, ulint *n_ext, mem_heap_t *heap)
Definition: row0row.cc:382
UNIV_INLINE ulint rec_offs_size(const ulint *offsets)
UNIV_INTERN ulint trx_undo_prev_version_build(const rec_t *index_rec, mtr_t *index_mtr, const rec_t *rec, dict_index_t *index, ulint *offsets, mem_heap_t *heap, rec_t **old_vers)
Definition: trx0rec.cc:1413
UNIV_INLINE ulint mach_read_from_2(const byte *b) __attribute__((nonnull
trx_undo_t * update_undo
Definition: trx0trx.h:698
UNIV_INLINE void dfield_set_ext(dfield_t *field)
UNIV_INTERN void dict_index_name_print(FILE *file, trx_t *trx, const dict_index_t *index)
Definition: dict0dict.cc:4775
UNIV_INLINE ib_uint64_t mach_ull_read_compressed(const byte *b) __attribute__((nonnull
ib_id_t undo_no_t
Definition: trx0types.h:89
UNIV_INLINE upd_t * upd_create(ulint n, mem_heap_t *heap)
UNIV_INTERN byte * trx_undo_rec_get_pars(trx_undo_rec_t *undo_rec, ulint *type, ulint *cmpl_info, ibool *updated_extern, undo_no_t *undo_no, table_id_t *table_id)
Definition: trx0rec.cc:282
UNIV_INLINE page_t * trx_undo_page_get_s_latched(ulint space, ulint zip_size, ulint page_no, mtr_t *mtr)
UNIV_INLINE ibool rec_offs_validate(const rec_t *rec, const dict_index_t *index, const ulint *offsets)
UNIV_INLINE ibool trx_undo_roll_ptr_is_insert(roll_ptr_t roll_ptr)