Drizzled Public API Documentation

page0cur.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1994, 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 /********************************************************************/
26 #include "page0cur.h"
27 #ifdef UNIV_NONINL
28 #include "page0cur.ic"
29 #endif
30 
31 #include "page0zip.h"
32 #include "mtr0log.h"
33 #include "log0recv.h"
34 #include "ut0ut.h"
35 #ifndef UNIV_HOTBACKUP
36 #include "rem0cmp.h"
37 
38 #ifdef PAGE_CUR_ADAPT
39 # ifdef UNIV_SEARCH_PERF_STAT
40 static ulint page_cur_short_succ = 0;
41 # endif /* UNIV_SEARCH_PERF_STAT */
42 
43 /*******************************************************************/
55 static
56 ib_uint64_t
57 page_cur_lcg_prng(void)
58 /*===================*/
59 {
60 #define LCG_a 1103515245
61 #define LCG_c 12345
62  static ib_uint64_t lcg_current = 0;
63  static ibool initialized = FALSE;
64 
65  if (!initialized) {
66  lcg_current = (ib_uint64_t) ut_time_us(NULL);
67  initialized = TRUE;
68  }
69 
70  /* no need to "% 2^64" explicitly because lcg_current is
71  64 bit and this will be done anyway */
72  lcg_current = LCG_a * lcg_current + LCG_c;
73 
74  return(lcg_current);
75 }
76 
77 /****************************************************************/
80 UNIV_INLINE
81 ibool
82 page_cur_try_search_shortcut(
83 /*=========================*/
84  const buf_block_t* block,
85  const dict_index_t* index,
86  const dtuple_t* tuple,
87  ulint* iup_matched_fields,
90  ulint* iup_matched_bytes,
94  ulint* ilow_matched_fields,
97  ulint* ilow_matched_bytes,
101  page_cur_t* cursor)
102 {
103  const rec_t* rec;
104  const rec_t* next_rec;
105  ulint low_match;
106  ulint low_bytes;
107  ulint up_match;
108  ulint up_bytes;
109 #ifdef UNIV_SEARCH_DEBUG
110  page_cur_t cursor2;
111 #endif
112  ibool success = FALSE;
113  const page_t* page = buf_block_get_frame(block);
114  mem_heap_t* heap = NULL;
115  ulint offsets_[REC_OFFS_NORMAL_SIZE];
116  ulint* offsets = offsets_;
117  rec_offs_init(offsets_);
118 
119  ut_ad(dtuple_check_typed(tuple));
120 
121  rec = page_header_get_ptr(page, PAGE_LAST_INSERT);
122  offsets = rec_get_offsets(rec, index, offsets,
123  dtuple_get_n_fields(tuple), &heap);
124 
125  ut_ad(rec);
127 
128  ut_pair_min(&low_match, &low_bytes,
129  *ilow_matched_fields, *ilow_matched_bytes,
130  *iup_matched_fields, *iup_matched_bytes);
131 
132  up_match = low_match;
133  up_bytes = low_bytes;
134 
135  if (page_cmp_dtuple_rec_with_match(tuple, rec, offsets,
136  &low_match, &low_bytes) < 0) {
137  goto exit_func;
138  }
139 
140  next_rec = page_rec_get_next_const(rec);
141  offsets = rec_get_offsets(next_rec, index, offsets,
142  dtuple_get_n_fields(tuple), &heap);
143 
144  if (page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets,
145  &up_match, &up_bytes) >= 0) {
146  goto exit_func;
147  }
148 
149  page_cur_position(rec, block, cursor);
150 
151 #ifdef UNIV_SEARCH_DEBUG
152  page_cur_search_with_match(block, index, tuple, PAGE_CUR_DBG,
153  iup_matched_fields,
154  iup_matched_bytes,
155  ilow_matched_fields,
156  ilow_matched_bytes,
157  &cursor2);
158  ut_a(cursor2.rec == cursor->rec);
159 
160  if (!page_rec_is_supremum(next_rec)) {
161 
162  ut_a(*iup_matched_fields == up_match);
163  ut_a(*iup_matched_bytes == up_bytes);
164  }
165 
166  ut_a(*ilow_matched_fields == low_match);
167  ut_a(*ilow_matched_bytes == low_bytes);
168 #endif
169  if (!page_rec_is_supremum(next_rec)) {
170 
171  *iup_matched_fields = up_match;
172  *iup_matched_bytes = up_bytes;
173  }
174 
175  *ilow_matched_fields = low_match;
176  *ilow_matched_bytes = low_bytes;
177 
178 #ifdef UNIV_SEARCH_PERF_STAT
179  page_cur_short_succ++;
180 #endif
181  success = TRUE;
182 exit_func:
183  if (UNIV_LIKELY_NULL(heap)) {
184  mem_heap_free(heap);
185  }
186  return(success);
187 }
188 
189 #endif
190 
191 #ifdef PAGE_CUR_LE_OR_EXTENDS
192 /****************************************************************/
197 static
198 ibool
199 page_cur_rec_field_extends(
200 /*=======================*/
201  const dtuple_t* tuple,
202  const rec_t* rec,
203  const ulint* offsets,
204  ulint n)
205 {
206  const dtype_t* type;
207  const dfield_t* dfield;
208  const byte* rec_f;
209  ulint rec_f_len;
210 
211  ut_ad(rec_offs_validate(rec, NULL, offsets));
212  dfield = dtuple_get_nth_field(tuple, n);
213 
214  type = dfield_get_type(dfield);
215 
216  rec_f = rec_get_nth_field(rec, offsets, n, &rec_f_len);
217 
218  if (type->mtype == DATA_VARCHAR
219  || type->mtype == DATA_CHAR
220  || type->mtype == DATA_FIXBINARY
221  || type->mtype == DATA_BINARY
222  || type->mtype == DATA_BLOB
223  || type->mtype == DATA_VARMYSQL
224  || type->mtype == DATA_MYSQL) {
225 
226  if (dfield_get_len(dfield) != UNIV_SQL_NULL
227  && rec_f_len != UNIV_SQL_NULL
228  && rec_f_len >= dfield_get_len(dfield)
229  && !cmp_data_data_slow(type->mtype, type->prtype,
230  dfield_get_data(dfield),
231  dfield_get_len(dfield),
232  rec_f, dfield_get_len(dfield))) {
233 
234  return(TRUE);
235  }
236  }
237 
238  return(FALSE);
239 }
240 #endif /* PAGE_CUR_LE_OR_EXTENDS */
241 
242 /****************************************************************/
244 UNIV_INTERN
245 void
247 /*=======================*/
248  const buf_block_t* block,
249  const dict_index_t* index,
250  const dtuple_t* tuple,
251  ulint mode,
254  ulint* iup_matched_fields,
257  ulint* iup_matched_bytes,
261  ulint* ilow_matched_fields,
264  ulint* ilow_matched_bytes,
268  page_cur_t* cursor)
269 {
270  ulint up;
271  ulint low;
272  ulint mid;
273  const page_t* page;
274  const page_dir_slot_t* slot;
275  const rec_t* up_rec;
276  const rec_t* low_rec;
277  const rec_t* mid_rec;
278  ulint up_matched_fields;
279  ulint up_matched_bytes;
280  ulint low_matched_fields;
281  ulint low_matched_bytes;
282  ulint cur_matched_fields;
283  ulint cur_matched_bytes;
284  int cmp;
285 #ifdef UNIV_SEARCH_DEBUG
286  int dbg_cmp;
287  ulint dbg_matched_fields;
288  ulint dbg_matched_bytes;
289 #endif
290 #ifdef UNIV_ZIP_DEBUG
291  const page_zip_des_t* page_zip = buf_block_get_page_zip(block);
292 #endif /* UNIV_ZIP_DEBUG */
293  mem_heap_t* heap = NULL;
294  ulint offsets_[REC_OFFS_NORMAL_SIZE];
295  ulint* offsets = offsets_;
296  rec_offs_init(offsets_);
297 
298  ut_ad(block && tuple && iup_matched_fields && iup_matched_bytes
299  && ilow_matched_fields && ilow_matched_bytes && cursor);
300  ut_ad(dtuple_validate(tuple));
301 #ifdef UNIV_DEBUG
302 # ifdef PAGE_CUR_DBG
303  if (mode != PAGE_CUR_DBG)
304 # endif /* PAGE_CUR_DBG */
305 # ifdef PAGE_CUR_LE_OR_EXTENDS
306  if (mode != PAGE_CUR_LE_OR_EXTENDS)
307 # endif /* PAGE_CUR_LE_OR_EXTENDS */
308  ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
309  || mode == PAGE_CUR_G || mode == PAGE_CUR_GE);
310 #endif /* UNIV_DEBUG */
311  page = buf_block_get_frame(block);
312 #ifdef UNIV_ZIP_DEBUG
313  ut_a(!page_zip || page_zip_validate(page_zip, page));
314 #endif /* UNIV_ZIP_DEBUG */
315 
316  page_check_dir(page);
317 
318 #ifdef PAGE_CUR_ADAPT
319  if (page_is_leaf(page)
320  && (mode == PAGE_CUR_LE)
321  && (page_header_get_field(page, PAGE_N_DIRECTION) > 3)
322  && (page_header_get_ptr(page, PAGE_LAST_INSERT))
323  && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) {
324 
325  if (page_cur_try_search_shortcut(
326  block, index, tuple,
327  iup_matched_fields, iup_matched_bytes,
328  ilow_matched_fields, ilow_matched_bytes,
329  cursor)) {
330  return;
331  }
332  }
333 # ifdef PAGE_CUR_DBG
334  if (mode == PAGE_CUR_DBG) {
335  mode = PAGE_CUR_LE;
336  }
337 # endif
338 #endif
339 
340  /* The following flag does not work for non-latin1 char sets because
341  cmp_full_field does not tell how many bytes matched */
342 #ifdef PAGE_CUR_LE_OR_EXTENDS
343  ut_a(mode != PAGE_CUR_LE_OR_EXTENDS);
344 #endif /* PAGE_CUR_LE_OR_EXTENDS */
345 
346  /* If mode PAGE_CUR_G is specified, we are trying to position the
347  cursor to answer a query of the form "tuple < X", where tuple is
348  the input parameter, and X denotes an arbitrary physical record on
349  the page. We want to position the cursor on the first X which
350  satisfies the condition. */
351 
352  up_matched_fields = *iup_matched_fields;
353  up_matched_bytes = *iup_matched_bytes;
354  low_matched_fields = *ilow_matched_fields;
355  low_matched_bytes = *ilow_matched_bytes;
356 
357  /* Perform binary search. First the search is done through the page
358  directory, after that as a linear search in the list of records
359  owned by the upper limit directory slot. */
360 
361  low = 0;
362  up = page_dir_get_n_slots(page) - 1;
363 
364  /* Perform binary search until the lower and upper limit directory
365  slots come to the distance 1 of each other */
366 
367  while (up - low > 1) {
368  mid = (low + up) / 2;
369  slot = page_dir_get_nth_slot(page, mid);
370  mid_rec = page_dir_slot_get_rec(slot);
371 
372  ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
373  low_matched_fields, low_matched_bytes,
374  up_matched_fields, up_matched_bytes);
375 
376  offsets = rec_get_offsets(mid_rec, index, offsets,
378  &heap);
379 
380  cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
381  &cur_matched_fields,
382  &cur_matched_bytes);
383  if (UNIV_LIKELY(cmp > 0)) {
384 low_slot_match:
385  low = mid;
386  low_matched_fields = cur_matched_fields;
387  low_matched_bytes = cur_matched_bytes;
388 
389  } else if (UNIV_EXPECT(cmp, -1)) {
390 #ifdef PAGE_CUR_LE_OR_EXTENDS
391  if (mode == PAGE_CUR_LE_OR_EXTENDS
392  && page_cur_rec_field_extends(
393  tuple, mid_rec, offsets,
394  cur_matched_fields)) {
395 
396  goto low_slot_match;
397  }
398 #endif /* PAGE_CUR_LE_OR_EXTENDS */
399 up_slot_match:
400  up = mid;
401  up_matched_fields = cur_matched_fields;
402  up_matched_bytes = cur_matched_bytes;
403 
404  } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
405 #ifdef PAGE_CUR_LE_OR_EXTENDS
406  || mode == PAGE_CUR_LE_OR_EXTENDS
407 #endif /* PAGE_CUR_LE_OR_EXTENDS */
408  ) {
409 
410  goto low_slot_match;
411  } else {
412 
413  goto up_slot_match;
414  }
415  }
416 
417  slot = page_dir_get_nth_slot(page, low);
418  low_rec = page_dir_slot_get_rec(slot);
419  slot = page_dir_get_nth_slot(page, up);
420  up_rec = page_dir_slot_get_rec(slot);
421 
422  /* Perform linear search until the upper and lower records come to
423  distance 1 of each other. */
424 
425  while (page_rec_get_next_const(low_rec) != up_rec) {
426 
427  mid_rec = page_rec_get_next_const(low_rec);
428 
429  ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
430  low_matched_fields, low_matched_bytes,
431  up_matched_fields, up_matched_bytes);
432 
433  offsets = rec_get_offsets(mid_rec, index, offsets,
435  &heap);
436 
437  cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
438  &cur_matched_fields,
439  &cur_matched_bytes);
440  if (UNIV_LIKELY(cmp > 0)) {
441 low_rec_match:
442  low_rec = mid_rec;
443  low_matched_fields = cur_matched_fields;
444  low_matched_bytes = cur_matched_bytes;
445 
446  } else if (UNIV_EXPECT(cmp, -1)) {
447 #ifdef PAGE_CUR_LE_OR_EXTENDS
448  if (mode == PAGE_CUR_LE_OR_EXTENDS
449  && page_cur_rec_field_extends(
450  tuple, mid_rec, offsets,
451  cur_matched_fields)) {
452 
453  goto low_rec_match;
454  }
455 #endif /* PAGE_CUR_LE_OR_EXTENDS */
456 up_rec_match:
457  up_rec = mid_rec;
458  up_matched_fields = cur_matched_fields;
459  up_matched_bytes = cur_matched_bytes;
460  } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
461 #ifdef PAGE_CUR_LE_OR_EXTENDS
462  || mode == PAGE_CUR_LE_OR_EXTENDS
463 #endif /* PAGE_CUR_LE_OR_EXTENDS */
464  ) {
465 
466  goto low_rec_match;
467  } else {
468 
469  goto up_rec_match;
470  }
471  }
472 
473 #ifdef UNIV_SEARCH_DEBUG
474 
475  /* Check that the lower and upper limit records have the
476  right alphabetical order compared to tuple. */
477  dbg_matched_fields = 0;
478  dbg_matched_bytes = 0;
479 
480  offsets = rec_get_offsets(low_rec, index, offsets,
481  ULINT_UNDEFINED, &heap);
482  dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec, offsets,
483  &dbg_matched_fields,
484  &dbg_matched_bytes);
485  if (mode == PAGE_CUR_G) {
486  ut_a(dbg_cmp >= 0);
487  } else if (mode == PAGE_CUR_GE) {
488  ut_a(dbg_cmp == 1);
489  } else if (mode == PAGE_CUR_L) {
490  ut_a(dbg_cmp == 1);
491  } else if (mode == PAGE_CUR_LE) {
492  ut_a(dbg_cmp >= 0);
493  }
494 
495  if (!page_rec_is_infimum(low_rec)) {
496 
497  ut_a(low_matched_fields == dbg_matched_fields);
498  ut_a(low_matched_bytes == dbg_matched_bytes);
499  }
500 
501  dbg_matched_fields = 0;
502  dbg_matched_bytes = 0;
503 
504  offsets = rec_get_offsets(up_rec, index, offsets,
505  ULINT_UNDEFINED, &heap);
506  dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec, offsets,
507  &dbg_matched_fields,
508  &dbg_matched_bytes);
509  if (mode == PAGE_CUR_G) {
510  ut_a(dbg_cmp == -1);
511  } else if (mode == PAGE_CUR_GE) {
512  ut_a(dbg_cmp <= 0);
513  } else if (mode == PAGE_CUR_L) {
514  ut_a(dbg_cmp <= 0);
515  } else if (mode == PAGE_CUR_LE) {
516  ut_a(dbg_cmp == -1);
517  }
518 
519  if (!page_rec_is_supremum(up_rec)) {
520 
521  ut_a(up_matched_fields == dbg_matched_fields);
522  ut_a(up_matched_bytes == dbg_matched_bytes);
523  }
524 #endif
525  if (mode <= PAGE_CUR_GE) {
526  page_cur_position(up_rec, block, cursor);
527  } else {
528  page_cur_position(low_rec, block, cursor);
529  }
530 
531  *iup_matched_fields = up_matched_fields;
532  *iup_matched_bytes = up_matched_bytes;
533  *ilow_matched_fields = low_matched_fields;
534  *ilow_matched_bytes = low_matched_bytes;
535  if (UNIV_LIKELY_NULL(heap)) {
536  mem_heap_free(heap);
537  }
538 }
539 
540 /***********************************************************/
543 UNIV_INTERN
544 void
546 /*==========================*/
547  buf_block_t* block,
548  page_cur_t* cursor)
549 {
550  ulint rnd;
551  ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
552 
553  page_cur_set_before_first(block, cursor);
554 
555  if (UNIV_UNLIKELY(n_recs == 0)) {
556 
557  return;
558  }
559 
560  rnd = (ulint) (page_cur_lcg_prng() % n_recs);
561 
562  do {
563  page_cur_move_to_next(cursor);
564  } while (rnd--);
565 }
566 
567 /***********************************************************/
569 static
570 void
571 page_cur_insert_rec_write_log(
572 /*==========================*/
573  rec_t* insert_rec,
574  ulint rec_size,
575  rec_t* cursor_rec,
577  dict_index_t* index,
578  mtr_t* mtr)
579 {
580  ulint cur_rec_size;
581  ulint extra_size;
582  ulint cur_extra_size;
583  const byte* ins_ptr;
584  byte* log_ptr;
585  const byte* log_end;
586  ulint i;
587 
588  ut_a(rec_size < UNIV_PAGE_SIZE);
589  ut_ad(page_align(insert_rec) == page_align(cursor_rec));
590  ut_ad(!page_rec_is_comp(insert_rec)
591  == !dict_table_is_comp(index->table));
592 
593  {
594  mem_heap_t* heap = NULL;
595  ulint cur_offs_[REC_OFFS_NORMAL_SIZE];
596  ulint ins_offs_[REC_OFFS_NORMAL_SIZE];
597 
598  ulint* cur_offs;
599  ulint* ins_offs;
600 
601  rec_offs_init(cur_offs_);
602  rec_offs_init(ins_offs_);
603 
604  cur_offs = rec_get_offsets(cursor_rec, index, cur_offs_,
605  ULINT_UNDEFINED, &heap);
606  ins_offs = rec_get_offsets(insert_rec, index, ins_offs_,
607  ULINT_UNDEFINED, &heap);
608 
609  extra_size = rec_offs_extra_size(ins_offs);
610  cur_extra_size = rec_offs_extra_size(cur_offs);
611  ut_ad(rec_size == rec_offs_size(ins_offs));
612  cur_rec_size = rec_offs_size(cur_offs);
613 
614  if (UNIV_LIKELY_NULL(heap)) {
615  mem_heap_free(heap);
616  }
617  }
618 
619  ins_ptr = insert_rec - extra_size;
620 
621  i = 0;
622 
623  if (cur_extra_size == extra_size) {
624  ulint min_rec_size = ut_min(cur_rec_size, rec_size);
625 
626  const byte* cur_ptr = cursor_rec - cur_extra_size;
627 
628  /* Find out the first byte in insert_rec which differs from
629  cursor_rec; skip the bytes in the record info */
630 
631  do {
632  if (*ins_ptr == *cur_ptr) {
633  i++;
634  ins_ptr++;
635  cur_ptr++;
636  } else if ((i < extra_size)
637  && (i >= extra_size
639  (insert_rec))) {
640  i = extra_size;
641  ins_ptr = insert_rec;
642  cur_ptr = cursor_rec;
643  } else {
644  break;
645  }
646  } while (i < min_rec_size);
647  }
648 
649  if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
650 
651  if (page_rec_is_comp(insert_rec)) {
652  log_ptr = mlog_open_and_write_index(
653  mtr, insert_rec, index, MLOG_COMP_REC_INSERT,
654  2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
655  if (UNIV_UNLIKELY(!log_ptr)) {
656  /* Logging in mtr is switched off
657  during crash recovery: in that case
658  mlog_open returns NULL */
659  return;
660  }
661  } else {
662  log_ptr = mlog_open(mtr, 11
663  + 2 + 5 + 1 + 5 + 5
664  + MLOG_BUF_MARGIN);
665  if (UNIV_UNLIKELY(!log_ptr)) {
666  /* Logging in mtr is switched off
667  during crash recovery: in that case
668  mlog_open returns NULL */
669  return;
670  }
671 
673  insert_rec, MLOG_REC_INSERT, log_ptr, mtr);
674  }
675 
676  log_end = &log_ptr[2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
677  /* Write the cursor rec offset as a 2-byte ulint */
678  mach_write_to_2(log_ptr, page_offset(cursor_rec));
679  log_ptr += 2;
680  } else {
681  log_ptr = mlog_open(mtr, 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
682  if (!log_ptr) {
683  /* Logging in mtr is switched off during crash
684  recovery: in that case mlog_open returns NULL */
685  return;
686  }
687  log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
688  }
689 
690  if (page_rec_is_comp(insert_rec)) {
691  if (UNIV_UNLIKELY
692  (rec_get_info_and_status_bits(insert_rec, TRUE)
693  != rec_get_info_and_status_bits(cursor_rec, TRUE))) {
694 
695  goto need_extra_info;
696  }
697  } else {
698  if (UNIV_UNLIKELY
699  (rec_get_info_and_status_bits(insert_rec, FALSE)
700  != rec_get_info_and_status_bits(cursor_rec, FALSE))) {
701 
702  goto need_extra_info;
703  }
704  }
705 
706  if (extra_size != cur_extra_size || rec_size != cur_rec_size) {
707 need_extra_info:
708  /* Write the record end segment length
709  and the extra info storage flag */
710  log_ptr += mach_write_compressed(log_ptr,
711  2 * (rec_size - i) + 1);
712 
713  /* Write the info bits */
714  mach_write_to_1(log_ptr,
716  insert_rec,
717  page_rec_is_comp(insert_rec)));
718  log_ptr++;
719 
720  /* Write the record origin offset */
721  log_ptr += mach_write_compressed(log_ptr, extra_size);
722 
723  /* Write the mismatch index */
724  log_ptr += mach_write_compressed(log_ptr, i);
725 
726  ut_a(i < UNIV_PAGE_SIZE);
727  ut_a(extra_size < UNIV_PAGE_SIZE);
728  } else {
729  /* Write the record end segment length
730  and the extra info storage flag */
731  log_ptr += mach_write_compressed(log_ptr, 2 * (rec_size - i));
732  }
733 
734  /* Write to the log the inserted index record end segment which
735  differs from the cursor record */
736 
737  rec_size -= i;
738 
739  if (log_ptr + rec_size <= log_end) {
740  memcpy(log_ptr, ins_ptr, rec_size);
741  mlog_close(mtr, log_ptr + rec_size);
742  } else {
743  mlog_close(mtr, log_ptr);
744  ut_a(rec_size < UNIV_PAGE_SIZE);
745  mlog_catenate_string(mtr, ins_ptr, rec_size);
746  }
747 }
748 #else /* !UNIV_HOTBACKUP */
749 # define page_cur_insert_rec_write_log(ins_rec,size,cur,index,mtr) ((void) 0)
750 #endif /* !UNIV_HOTBACKUP */
751 
752 /***********************************************************/
755 UNIV_INTERN
756 byte*
758 /*======================*/
759  ibool is_short,
760  byte* ptr,
761  byte* end_ptr,
762  buf_block_t* block,
763  dict_index_t* index,
764  mtr_t* mtr)
765 {
766  ulint origin_offset;
767  ulint end_seg_len;
768  ulint mismatch_index;
769  page_t* page;
770  rec_t* cursor_rec;
771  byte buf1[1024];
772  byte* buf;
773  byte* ptr2 = ptr;
774  ulint info_and_status_bits = 0; /* remove warning */
775  page_cur_t cursor;
776  mem_heap_t* heap = NULL;
777  ulint offsets_[REC_OFFS_NORMAL_SIZE];
778  ulint* offsets = offsets_;
779  rec_offs_init(offsets_);
780 
781  page = block ? buf_block_get_frame(block) : NULL;
782 
783  if (is_short) {
784  cursor_rec = page_rec_get_prev(page_get_supremum_rec(page));
785  } else {
786  ulint offset;
787 
788  /* Read the cursor rec offset as a 2-byte ulint */
789 
790  if (UNIV_UNLIKELY(end_ptr < ptr + 2)) {
791 
792  return(NULL);
793  }
794 
795  offset = mach_read_from_2(ptr);
796  ptr += 2;
797 
798  cursor_rec = page + offset;
799 
800  if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)) {
801 
802  recv_sys->found_corrupt_log = TRUE;
803 
804  return(NULL);
805  }
806  }
807 
808  ptr = mach_parse_compressed(ptr, end_ptr, &end_seg_len);
809 
810  if (ptr == NULL) {
811 
812  return(NULL);
813  }
814 
815  if (UNIV_UNLIKELY(end_seg_len >= UNIV_PAGE_SIZE << 1)) {
816  recv_sys->found_corrupt_log = TRUE;
817 
818  return(NULL);
819  }
820 
821  if (end_seg_len & 0x1UL) {
822  /* Read the info bits */
823 
824  if (end_ptr < ptr + 1) {
825 
826  return(NULL);
827  }
828 
829  info_and_status_bits = mach_read_from_1(ptr);
830  ptr++;
831 
832  ptr = mach_parse_compressed(ptr, end_ptr, &origin_offset);
833 
834  if (ptr == NULL) {
835 
836  return(NULL);
837  }
838 
839  ut_a(origin_offset < UNIV_PAGE_SIZE);
840 
841  ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index);
842 
843  if (ptr == NULL) {
844 
845  return(NULL);
846  }
847 
848  ut_a(mismatch_index < UNIV_PAGE_SIZE);
849  }
850 
851  if (UNIV_UNLIKELY(end_ptr < ptr + (end_seg_len >> 1))) {
852 
853  return(NULL);
854  }
855 
856  if (!block) {
857 
858  return(ptr + (end_seg_len >> 1));
859  }
860 
861  ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
862  ut_ad(!buf_block_get_page_zip(block) || page_is_comp(page));
863 
864  /* Read from the log the inserted index record end segment which
865  differs from the cursor record */
866 
867  offsets = rec_get_offsets(cursor_rec, index, offsets,
868  ULINT_UNDEFINED, &heap);
869 
870  if (!(end_seg_len & 0x1UL)) {
871  info_and_status_bits = rec_get_info_and_status_bits(
872  cursor_rec, page_is_comp(page));
873  origin_offset = rec_offs_extra_size(offsets);
874  mismatch_index = rec_offs_size(offsets) - (end_seg_len >> 1);
875  }
876 
877  end_seg_len >>= 1;
878 
879  if (mismatch_index + end_seg_len < sizeof buf1) {
880  buf = buf1;
881  } else {
882  buf = static_cast<byte *>(mem_alloc(mismatch_index + end_seg_len));
883  }
884 
885  /* Build the inserted record to buf */
886 
887  if (UNIV_UNLIKELY(mismatch_index >= UNIV_PAGE_SIZE)) {
888  fprintf(stderr,
889  "Is short %lu, info_and_status_bits %lu, offset %lu, "
890  "o_offset %lu\n"
891  "mismatch index %lu, end_seg_len %lu\n"
892  "parsed len %lu\n",
893  (ulong) is_short, (ulong) info_and_status_bits,
894  (ulong) page_offset(cursor_rec),
895  (ulong) origin_offset,
896  (ulong) mismatch_index, (ulong) end_seg_len,
897  (ulong) (ptr - ptr2));
898 
899  fputs("Dump of 300 bytes of log:\n", stderr);
900  ut_print_buf(stderr, ptr2, 300);
901  putc('\n', stderr);
902 
903  buf_page_print(page, 0);
904 
905  ut_error;
906  }
907 
908  ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
909  ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
910 
911  if (page_is_comp(page)) {
912  rec_set_info_and_status_bits(buf + origin_offset,
913  info_and_status_bits);
914  } else {
915  rec_set_info_bits_old(buf + origin_offset,
916  info_and_status_bits);
917  }
918 
919  page_cur_position(cursor_rec, block, &cursor);
920 
921  offsets = rec_get_offsets(buf + origin_offset, index, offsets,
922  ULINT_UNDEFINED, &heap);
923  if (UNIV_UNLIKELY(!page_cur_rec_insert(&cursor,
924  buf + origin_offset,
925  index, offsets, mtr))) {
926  /* The redo log record should only have been written
927  after the write was successful. */
928  ut_error;
929  }
930 
931  if (buf != buf1) {
932 
933  mem_free(buf);
934  }
935 
936  if (UNIV_LIKELY_NULL(heap)) {
937  mem_heap_free(heap);
938  }
939 
940  return(ptr + end_seg_len);
941 }
942 
943 /***********************************************************/
948 UNIV_INTERN
949 rec_t*
951 /*====================*/
952  rec_t* current_rec,
954  dict_index_t* index,
955  const rec_t* rec,
956  ulint* offsets,
957  mtr_t* mtr)
958 {
959  byte* insert_buf;
960  ulint rec_size;
961  page_t* page;
962  rec_t* last_insert;
964  rec_t* free_rec;
966  rec_t* insert_rec;
967  ulint heap_no;
970  ut_ad(rec_offs_validate(rec, index, offsets));
971 
972  page = page_align(current_rec);
974  == (ibool) !!page_is_comp(page));
975 
976  ut_ad(!page_rec_is_supremum(current_rec));
977 
978  /* 1. Get the size of the physical record in the page */
979  rec_size = rec_offs_size(offsets);
980 
981 #ifdef UNIV_DEBUG_VALGRIND
982  {
983  const void* rec_start
984  = rec - rec_offs_extra_size(offsets);
985  ulint extra_size
986  = rec_offs_extra_size(offsets)
987  - (rec_offs_comp(offsets)
988  ? REC_N_NEW_EXTRA_BYTES
989  : REC_N_OLD_EXTRA_BYTES);
990 
991  /* All data bytes of the record must be valid. */
992  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
993  /* The variable-length header must be valid. */
994  UNIV_MEM_ASSERT_RW(rec_start, extra_size);
995  }
996 #endif /* UNIV_DEBUG_VALGRIND */
997 
998  /* 2. Try to find suitable space from page memory management */
999 
1000  free_rec = page_header_get_ptr(page, PAGE_FREE);
1001  if (UNIV_LIKELY_NULL(free_rec)) {
1002  /* Try to allocate from the head of the free list. */
1003  ulint foffsets_[REC_OFFS_NORMAL_SIZE];
1004  ulint* foffsets = foffsets_;
1005  mem_heap_t* heap = NULL;
1006 
1007  rec_offs_init(foffsets_);
1008 
1009  foffsets = rec_get_offsets(free_rec, index, foffsets,
1010  ULINT_UNDEFINED, &heap);
1011  if (rec_offs_size(foffsets) < rec_size) {
1012  if (UNIV_LIKELY_NULL(heap)) {
1013  mem_heap_free(heap);
1014  }
1015 
1016  goto use_heap;
1017  }
1018 
1019  insert_buf = free_rec - rec_offs_extra_size(foffsets);
1020 
1021  if (page_is_comp(page)) {
1022  heap_no = rec_get_heap_no_new(free_rec);
1023  page_mem_alloc_free(page, NULL,
1024  rec_get_next_ptr(free_rec, TRUE),
1025  rec_size);
1026  } else {
1027  heap_no = rec_get_heap_no_old(free_rec);
1028  page_mem_alloc_free(page, NULL,
1029  rec_get_next_ptr(free_rec, FALSE),
1030  rec_size);
1031  }
1032 
1033  if (UNIV_LIKELY_NULL(heap)) {
1034  mem_heap_free(heap);
1035  }
1036  } else {
1037 use_heap:
1038  free_rec = NULL;
1039  insert_buf = page_mem_alloc_heap(page, NULL,
1040  rec_size, &heap_no);
1041 
1042  if (UNIV_UNLIKELY(insert_buf == NULL)) {
1043  return(NULL);
1044  }
1045  }
1046 
1047  /* 3. Create the record */
1048  insert_rec = rec_copy(insert_buf, rec, offsets);
1049  rec_offs_make_valid(insert_rec, index, offsets);
1050 
1051  /* 4. Insert the record in the linked list of records */
1052  ut_ad(current_rec != insert_rec);
1053 
1054  {
1055  /* next record after current before the insertion */
1056  rec_t* next_rec = page_rec_get_next(current_rec);
1057 #ifdef UNIV_DEBUG
1058  if (page_is_comp(page)) {
1059  ut_ad(rec_get_status(current_rec)
1060  <= REC_STATUS_INFIMUM);
1061  ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
1062  ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
1063  }
1064 #endif
1065  page_rec_set_next(insert_rec, next_rec);
1066  page_rec_set_next(current_rec, insert_rec);
1067  }
1068 
1069  page_header_set_field(page, NULL, PAGE_N_RECS,
1070  1 + page_get_n_recs(page));
1071 
1072  /* 5. Set the n_owned field in the inserted record to zero,
1073  and set the heap_no field */
1074  if (page_is_comp(page)) {
1075  rec_set_n_owned_new(insert_rec, NULL, 0);
1076  rec_set_heap_no_new(insert_rec, heap_no);
1077  } else {
1078  rec_set_n_owned_old(insert_rec, 0);
1079  rec_set_heap_no_old(insert_rec, heap_no);
1080  }
1081 
1082  UNIV_MEM_ASSERT_RW(rec_get_start(insert_rec, offsets),
1083  rec_offs_size(offsets));
1084  /* 6. Update the last insertion info in page header */
1085 
1086  last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
1087  ut_ad(!last_insert || !page_is_comp(page)
1088  || rec_get_node_ptr_flag(last_insert)
1089  == rec_get_node_ptr_flag(insert_rec));
1090 
1091  if (UNIV_UNLIKELY(last_insert == NULL)) {
1092  page_header_set_field(page, NULL, PAGE_DIRECTION,
1093  PAGE_NO_DIRECTION);
1094  page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
1095 
1096  } else if ((last_insert == current_rec)
1097  && (page_header_get_field(page, PAGE_DIRECTION)
1098  != PAGE_LEFT)) {
1099 
1100  page_header_set_field(page, NULL, PAGE_DIRECTION,
1101  PAGE_RIGHT);
1102  page_header_set_field(page, NULL, PAGE_N_DIRECTION,
1104  page, PAGE_N_DIRECTION) + 1);
1105 
1106  } else if ((page_rec_get_next(insert_rec) == last_insert)
1107  && (page_header_get_field(page, PAGE_DIRECTION)
1108  != PAGE_RIGHT)) {
1109 
1110  page_header_set_field(page, NULL, PAGE_DIRECTION,
1111  PAGE_LEFT);
1112  page_header_set_field(page, NULL, PAGE_N_DIRECTION,
1114  page, PAGE_N_DIRECTION) + 1);
1115  } else {
1116  page_header_set_field(page, NULL, PAGE_DIRECTION,
1117  PAGE_NO_DIRECTION);
1118  page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
1119  }
1120 
1121  page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, insert_rec);
1122 
1123  /* 7. It remains to update the owner record. */
1124  {
1125  rec_t* owner_rec = page_rec_find_owner_rec(insert_rec);
1126  ulint n_owned;
1127  if (page_is_comp(page)) {
1128  n_owned = rec_get_n_owned_new(owner_rec);
1129  rec_set_n_owned_new(owner_rec, NULL, n_owned + 1);
1130  } else {
1131  n_owned = rec_get_n_owned_old(owner_rec);
1132  rec_set_n_owned_old(owner_rec, n_owned + 1);
1133  }
1134 
1135  /* 8. Now we have incremented the n_owned field of the owner
1136  record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
1137  we have to split the corresponding directory slot in two. */
1138 
1139  if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) {
1141  page, NULL,
1142  page_dir_find_owner_slot(owner_rec));
1143  }
1144  }
1145 
1146  /* 9. Write log record of the insert */
1147  if (UNIV_LIKELY(mtr != NULL)) {
1148  page_cur_insert_rec_write_log(insert_rec, rec_size,
1149  current_rec, index, mtr);
1150  }
1151 
1152  btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert");
1153 
1154  return(insert_rec);
1155 }
1156 
1157 /***********************************************************/
1160 static
1161 rec_t*
1162 page_cur_insert_rec_zip_reorg(
1163 /*==========================*/
1164  rec_t** current_rec,
1166  buf_block_t* block,
1167  dict_index_t* index,
1168  rec_t* rec,
1169  page_t* page,
1170  page_zip_des_t* page_zip,
1171  mtr_t* mtr)
1172 {
1173  ulint pos;
1174 
1175  /* Recompress or reorganize and recompress the page. */
1176  if (UNIV_LIKELY(page_zip_compress(page_zip, page, index, mtr))) {
1177  return(rec);
1178  }
1179 
1180  /* Before trying to reorganize the page,
1181  store the number of preceding records on the page. */
1182  pos = page_rec_get_n_recs_before(rec);
1183 
1184  if (page_zip_reorganize(block, index, mtr)) {
1185  /* The page was reorganized: Find rec by seeking to pos,
1186  and update *current_rec. */
1187  rec = page + PAGE_NEW_INFIMUM;
1188 
1189  while (--pos) {
1190  rec = page + rec_get_next_offs(rec, TRUE);
1191  }
1192 
1193  *current_rec = rec;
1194  rec = page + rec_get_next_offs(rec, TRUE);
1195 
1196  return(rec);
1197  }
1198 
1199  /* Out of space: restore the page */
1200  btr_blob_dbg_remove(page, index, "insert_zip_fail");
1201  if (!page_zip_decompress(page_zip, page, FALSE)) {
1202  ut_error; /* Memory corrupted? */
1203  }
1204  ut_ad(page_validate(page, index));
1205  btr_blob_dbg_add(page, index, "insert_zip_fail");
1206  return(NULL);
1207 }
1208 
1209 /***********************************************************/
1215 UNIV_INTERN
1216 rec_t*
1218 /*====================*/
1219  rec_t** current_rec,
1221  buf_block_t* block,
1222  dict_index_t* index,
1223  const rec_t* rec,
1224  ulint* offsets,
1225  mtr_t* mtr)
1226 {
1227  byte* insert_buf;
1228  ulint rec_size;
1229  page_t* page;
1230  rec_t* last_insert;
1232  rec_t* free_rec;
1234  rec_t* insert_rec;
1235  ulint heap_no;
1237  page_zip_des_t* page_zip;
1238 
1239  page_zip = buf_block_get_page_zip(block);
1240  ut_ad(page_zip);
1241 
1242  ut_ad(rec_offs_validate(rec, index, offsets));
1243 
1244  page = page_align(*current_rec);
1245  ut_ad(dict_table_is_comp(index->table));
1246  ut_ad(page_is_comp(page));
1247 
1248  ut_ad(!page_rec_is_supremum(*current_rec));
1249 #ifdef UNIV_ZIP_DEBUG
1250  ut_a(page_zip_validate(page_zip, page));
1251 #endif /* UNIV_ZIP_DEBUG */
1252 
1253  /* 1. Get the size of the physical record in the page */
1254  rec_size = rec_offs_size(offsets);
1255 
1256 #ifdef UNIV_DEBUG_VALGRIND
1257  {
1258  const void* rec_start
1259  = rec - rec_offs_extra_size(offsets);
1260  ulint extra_size
1261  = rec_offs_extra_size(offsets)
1262  - (rec_offs_comp(offsets)
1263  ? REC_N_NEW_EXTRA_BYTES
1264  : REC_N_OLD_EXTRA_BYTES);
1265 
1266  /* All data bytes of the record must be valid. */
1267  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
1268  /* The variable-length header must be valid. */
1269  UNIV_MEM_ASSERT_RW(rec_start, extra_size);
1270  }
1271 #endif /* UNIV_DEBUG_VALGRIND */
1272 
1273  /* 2. Try to find suitable space from page memory management */
1274  if (!page_zip_available(page_zip, dict_index_is_clust(index),
1275  rec_size, 1)) {
1276 
1277  /* Try compressing the whole page afterwards. */
1278  insert_rec = page_cur_insert_rec_low(*current_rec,
1279  index, rec, offsets,
1280  NULL);
1281 
1282  if (UNIV_LIKELY(insert_rec != NULL)) {
1283  insert_rec = page_cur_insert_rec_zip_reorg(
1284  current_rec, block, index, insert_rec,
1285  page, page_zip, mtr);
1286  }
1287 
1288  return(insert_rec);
1289  }
1290 
1291  free_rec = page_header_get_ptr(page, PAGE_FREE);
1292  if (UNIV_LIKELY_NULL(free_rec)) {
1293  /* Try to allocate from the head of the free list. */
1294  lint extra_size_diff;
1295  ulint foffsets_[REC_OFFS_NORMAL_SIZE];
1296  ulint* foffsets = foffsets_;
1297  mem_heap_t* heap = NULL;
1298 
1299  rec_offs_init(foffsets_);
1300 
1301  foffsets = rec_get_offsets(free_rec, index, foffsets,
1302  ULINT_UNDEFINED, &heap);
1303  if (rec_offs_size(foffsets) < rec_size) {
1304 too_small:
1305  if (UNIV_LIKELY_NULL(heap)) {
1306  mem_heap_free(heap);
1307  }
1308 
1309  goto use_heap;
1310  }
1311 
1312  insert_buf = free_rec - rec_offs_extra_size(foffsets);
1313 
1314  /* On compressed pages, do not relocate records from
1315  the free list. If extra_size would grow, use the heap. */
1316  extra_size_diff
1317  = rec_offs_extra_size(offsets)
1318  - rec_offs_extra_size(foffsets);
1319 
1320  if (UNIV_UNLIKELY(extra_size_diff < 0)) {
1321  /* Add an offset to the extra_size. */
1322  if (rec_offs_size(foffsets)
1323  < rec_size - extra_size_diff) {
1324 
1325  goto too_small;
1326  }
1327 
1328  insert_buf -= extra_size_diff;
1329  } else if (UNIV_UNLIKELY(extra_size_diff)) {
1330  /* Do not allow extra_size to grow */
1331 
1332  goto too_small;
1333  }
1334 
1335  heap_no = rec_get_heap_no_new(free_rec);
1336  page_mem_alloc_free(page, page_zip,
1337  rec_get_next_ptr(free_rec, TRUE),
1338  rec_size);
1339 
1340  if (!page_is_leaf(page)) {
1341  /* Zero out the node pointer of free_rec,
1342  in case it will not be overwritten by
1343  insert_rec. */
1344 
1345  ut_ad(rec_size > REC_NODE_PTR_SIZE);
1346 
1347  if (rec_offs_extra_size(foffsets)
1348  + rec_offs_data_size(foffsets) > rec_size) {
1349 
1350  memset(rec_get_end(free_rec, foffsets)
1351  - REC_NODE_PTR_SIZE, 0,
1352  REC_NODE_PTR_SIZE);
1353  }
1354  } else if (dict_index_is_clust(index)) {
1355  /* Zero out the DB_TRX_ID and DB_ROLL_PTR
1356  columns of free_rec, in case it will not be
1357  overwritten by insert_rec. */
1358 
1359  ulint trx_id_col;
1360  ulint trx_id_offs;
1361  ulint len;
1362 
1363  trx_id_col = dict_index_get_sys_col_pos(index,
1364  DATA_TRX_ID);
1365  ut_ad(trx_id_col > 0);
1366  ut_ad(trx_id_col != ULINT_UNDEFINED);
1367 
1368  trx_id_offs = rec_get_nth_field_offs(foffsets,
1369  trx_id_col, &len);
1370  ut_ad(len == DATA_TRX_ID_LEN);
1371 
1372  if (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN + trx_id_offs
1373  + rec_offs_extra_size(foffsets) > rec_size) {
1374  /* We will have to zero out the
1375  DB_TRX_ID and DB_ROLL_PTR, because
1376  they will not be fully overwritten by
1377  insert_rec. */
1378 
1379  memset(free_rec + trx_id_offs, 0,
1380  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
1381  }
1382 
1383  ut_ad(free_rec + trx_id_offs + DATA_TRX_ID_LEN
1384  == rec_get_nth_field(free_rec, foffsets,
1385  trx_id_col + 1, &len));
1386  ut_ad(len == DATA_ROLL_PTR_LEN);
1387  }
1388 
1389  if (UNIV_LIKELY_NULL(heap)) {
1390  mem_heap_free(heap);
1391  }
1392  } else {
1393 use_heap:
1394  free_rec = NULL;
1395  insert_buf = page_mem_alloc_heap(page, page_zip,
1396  rec_size, &heap_no);
1397 
1398  if (UNIV_UNLIKELY(insert_buf == NULL)) {
1399  return(NULL);
1400  }
1401 
1402  page_zip_dir_add_slot(page_zip, dict_index_is_clust(index));
1403  }
1404 
1405  /* 3. Create the record */
1406  insert_rec = rec_copy(insert_buf, rec, offsets);
1407  rec_offs_make_valid(insert_rec, index, offsets);
1408 
1409  /* 4. Insert the record in the linked list of records */
1410  ut_ad(*current_rec != insert_rec);
1411 
1412  {
1413  /* next record after current before the insertion */
1414  rec_t* next_rec = page_rec_get_next(*current_rec);
1415  ut_ad(rec_get_status(*current_rec)
1416  <= REC_STATUS_INFIMUM);
1417  ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
1418  ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
1419 
1420  page_rec_set_next(insert_rec, next_rec);
1421  page_rec_set_next(*current_rec, insert_rec);
1422  }
1423 
1424  page_header_set_field(page, page_zip, PAGE_N_RECS,
1425  1 + page_get_n_recs(page));
1426 
1427  /* 5. Set the n_owned field in the inserted record to zero,
1428  and set the heap_no field */
1429  rec_set_n_owned_new(insert_rec, NULL, 0);
1430  rec_set_heap_no_new(insert_rec, heap_no);
1431 
1432  UNIV_MEM_ASSERT_RW(rec_get_start(insert_rec, offsets),
1433  rec_offs_size(offsets));
1434 
1435  page_zip_dir_insert(page_zip, *current_rec, free_rec, insert_rec);
1436 
1437  /* 6. Update the last insertion info in page header */
1438 
1439  last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
1440  ut_ad(!last_insert
1441  || rec_get_node_ptr_flag(last_insert)
1442  == rec_get_node_ptr_flag(insert_rec));
1443 
1444  if (UNIV_UNLIKELY(last_insert == NULL)) {
1445  page_header_set_field(page, page_zip, PAGE_DIRECTION,
1446  PAGE_NO_DIRECTION);
1447  page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
1448 
1449  } else if ((last_insert == *current_rec)
1450  && (page_header_get_field(page, PAGE_DIRECTION)
1451  != PAGE_LEFT)) {
1452 
1453  page_header_set_field(page, page_zip, PAGE_DIRECTION,
1454  PAGE_RIGHT);
1455  page_header_set_field(page, page_zip, PAGE_N_DIRECTION,
1457  page, PAGE_N_DIRECTION) + 1);
1458 
1459  } else if ((page_rec_get_next(insert_rec) == last_insert)
1460  && (page_header_get_field(page, PAGE_DIRECTION)
1461  != PAGE_RIGHT)) {
1462 
1463  page_header_set_field(page, page_zip, PAGE_DIRECTION,
1464  PAGE_LEFT);
1465  page_header_set_field(page, page_zip, PAGE_N_DIRECTION,
1467  page, PAGE_N_DIRECTION) + 1);
1468  } else {
1469  page_header_set_field(page, page_zip, PAGE_DIRECTION,
1470  PAGE_NO_DIRECTION);
1471  page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
1472  }
1473 
1474  page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, insert_rec);
1475 
1476  /* 7. It remains to update the owner record. */
1477  {
1478  rec_t* owner_rec = page_rec_find_owner_rec(insert_rec);
1479  ulint n_owned;
1480 
1481  n_owned = rec_get_n_owned_new(owner_rec);
1482  rec_set_n_owned_new(owner_rec, page_zip, n_owned + 1);
1483 
1484  /* 8. Now we have incremented the n_owned field of the owner
1485  record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
1486  we have to split the corresponding directory slot in two. */
1487 
1488  if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) {
1490  page, page_zip,
1491  page_dir_find_owner_slot(owner_rec));
1492  }
1493  }
1494 
1495  page_zip_write_rec(page_zip, insert_rec, index, offsets, 1);
1496 
1497  btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert_zip_ok");
1498 
1499  /* 9. Write log record of the insert */
1500  if (UNIV_LIKELY(mtr != NULL)) {
1501  page_cur_insert_rec_write_log(insert_rec, rec_size,
1502  *current_rec, index, mtr);
1503  }
1504 
1505  return(insert_rec);
1506 }
1507 
1508 #ifndef UNIV_HOTBACKUP
1509 /**********************************************************/
1513 UNIV_INLINE
1514 byte*
1515 page_copy_rec_list_to_created_page_write_log(
1516 /*=========================================*/
1517  page_t* page,
1518  dict_index_t* index,
1519  mtr_t* mtr)
1520 {
1521  byte* log_ptr;
1522 
1523  ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
1524 
1525  log_ptr = mlog_open_and_write_index(mtr, page, index,
1526  page_is_comp(page)
1529  if (UNIV_LIKELY(log_ptr != NULL)) {
1530  mlog_close(mtr, log_ptr + 4);
1531  }
1532 
1533  return(log_ptr);
1534 }
1535 #endif /* !UNIV_HOTBACKUP */
1536 
1537 /**********************************************************/
1540 UNIV_INTERN
1541 byte*
1543 /*=====================================*/
1544  byte* ptr,
1545  byte* end_ptr,
1546  buf_block_t* block,
1547  dict_index_t* index,
1548  mtr_t* mtr)
1549 {
1550  byte* rec_end;
1551  ulint log_data_len;
1552  page_t* page;
1553  page_zip_des_t* page_zip;
1554 
1555  if (ptr + 4 > end_ptr) {
1556 
1557  return(NULL);
1558  }
1559 
1560  log_data_len = mach_read_from_4(ptr);
1561  ptr += 4;
1562 
1563  rec_end = ptr + log_data_len;
1564 
1565  if (rec_end > end_ptr) {
1566 
1567  return(NULL);
1568  }
1569 
1570  if (!block) {
1571 
1572  return(rec_end);
1573  }
1574 
1575  while (ptr < rec_end) {
1576  ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr,
1577  block, index, mtr);
1578  }
1579 
1580  ut_a(ptr == rec_end);
1581 
1582  page = buf_block_get_frame(block);
1583  page_zip = buf_block_get_page_zip(block);
1584 
1585  page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
1586  page_header_set_field(page, page_zip, PAGE_DIRECTION,
1587  PAGE_NO_DIRECTION);
1588  page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
1589 
1590  return(rec_end);
1591 }
1592 
1593 #ifndef UNIV_HOTBACKUP
1594 /*************************************************************/
1597 UNIV_INTERN
1598 void
1600 /*===================================*/
1601  page_t* new_page,
1602  rec_t* rec,
1603  dict_index_t* index,
1604  mtr_t* mtr)
1605 {
1606  page_dir_slot_t* slot = 0; /* remove warning */
1607  byte* heap_top;
1608  rec_t* insert_rec = 0; /* remove warning */
1609  rec_t* prev_rec;
1610  ulint count;
1611  ulint n_recs;
1612  ulint slot_index;
1613  ulint rec_size;
1614  ulint log_mode;
1615  byte* log_ptr;
1616  ulint log_data_len;
1617  mem_heap_t* heap = NULL;
1618  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1619  ulint* offsets = offsets_;
1620  rec_offs_init(offsets_);
1621 
1622  ut_ad(page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW);
1623  ut_ad(page_align(rec) != new_page);
1624  ut_ad(page_rec_is_comp(rec) == page_is_comp(new_page));
1625 
1626  if (page_rec_is_infimum(rec)) {
1627 
1628  rec = page_rec_get_next(rec);
1629  }
1630 
1631  if (page_rec_is_supremum(rec)) {
1632 
1633  return;
1634  }
1635 
1636 #ifdef UNIV_DEBUG
1637  /* To pass the debug tests we have to set these dummy values
1638  in the debug version */
1639  page_dir_set_n_slots(new_page, NULL, UNIV_PAGE_SIZE / 2);
1640  page_header_set_ptr(new_page, NULL, PAGE_HEAP_TOP,
1641  new_page + UNIV_PAGE_SIZE - 1);
1642 #endif
1643 
1644  log_ptr = page_copy_rec_list_to_created_page_write_log(new_page,
1645  index, mtr);
1646 
1647  log_data_len = dyn_array_get_data_size(&(mtr->log));
1648 
1649  /* Individual inserts are logged in a shorter form */
1650 
1651  log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
1652 
1653  prev_rec = page_get_infimum_rec(new_page);
1654  if (page_is_comp(new_page)) {
1655  heap_top = new_page + PAGE_NEW_SUPREMUM_END;
1656  } else {
1657  heap_top = new_page + PAGE_OLD_SUPREMUM_END;
1658  }
1659  count = 0;
1660  slot_index = 0;
1661  n_recs = 0;
1662 
1663  do {
1664  offsets = rec_get_offsets(rec, index, offsets,
1665  ULINT_UNDEFINED, &heap);
1666  insert_rec = rec_copy(heap_top, rec, offsets);
1667 
1668  if (page_is_comp(new_page)) {
1669  rec_set_next_offs_new(prev_rec,
1670  page_offset(insert_rec));
1671 
1672  rec_set_n_owned_new(insert_rec, NULL, 0);
1673  rec_set_heap_no_new(insert_rec,
1674  PAGE_HEAP_NO_USER_LOW + n_recs);
1675  } else {
1676  rec_set_next_offs_old(prev_rec,
1677  page_offset(insert_rec));
1678 
1679  rec_set_n_owned_old(insert_rec, 0);
1680  rec_set_heap_no_old(insert_rec,
1681  PAGE_HEAP_NO_USER_LOW + n_recs);
1682  }
1683 
1684  count++;
1685  n_recs++;
1686 
1687  if (UNIV_UNLIKELY
1688  (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2)) {
1689 
1690  slot_index++;
1691 
1692  slot = page_dir_get_nth_slot(new_page, slot_index);
1693 
1694  page_dir_slot_set_rec(slot, insert_rec);
1695  page_dir_slot_set_n_owned(slot, NULL, count);
1696 
1697  count = 0;
1698  }
1699 
1700  rec_size = rec_offs_size(offsets);
1701 
1702  ut_ad(heap_top < new_page + UNIV_PAGE_SIZE);
1703 
1704  heap_top += rec_size;
1705 
1706  rec_offs_make_valid(insert_rec, index, offsets);
1707  btr_blob_dbg_add_rec(insert_rec, index, offsets, "copy_end");
1708 
1709  page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
1710  index, mtr);
1711  prev_rec = insert_rec;
1712  rec = page_rec_get_next(rec);
1713  } while (!page_rec_is_supremum(rec));
1714 
1715  if ((slot_index > 0) && (count + 1
1716  + (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2
1717  <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
1718  /* We can merge the two last dir slots. This operation is
1719  here to make this function imitate exactly the equivalent
1720  task made using page_cur_insert_rec, which we use in database
1721  recovery to reproduce the task performed by this function.
1722  To be able to check the correctness of recovery, it is good
1723  that it imitates exactly. */
1724 
1725  count += (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2;
1726 
1727  page_dir_slot_set_n_owned(slot, NULL, 0);
1728 
1729  slot_index--;
1730  }
1731 
1732  if (UNIV_LIKELY_NULL(heap)) {
1733  mem_heap_free(heap);
1734  }
1735 
1736  log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len;
1737 
1738  ut_a(log_data_len < 100 * UNIV_PAGE_SIZE);
1739 
1740  if (UNIV_LIKELY(log_ptr != NULL)) {
1741  mach_write_to_4(log_ptr, log_data_len);
1742  }
1743 
1744  if (page_is_comp(new_page)) {
1745  rec_set_next_offs_new(insert_rec, PAGE_NEW_SUPREMUM);
1746  } else {
1747  rec_set_next_offs_old(insert_rec, PAGE_OLD_SUPREMUM);
1748  }
1749 
1750  slot = page_dir_get_nth_slot(new_page, 1 + slot_index);
1751 
1752  page_dir_slot_set_rec(slot, page_get_supremum_rec(new_page));
1753  page_dir_slot_set_n_owned(slot, NULL, count + 1);
1754 
1755  page_dir_set_n_slots(new_page, NULL, 2 + slot_index);
1756  page_header_set_ptr(new_page, NULL, PAGE_HEAP_TOP, heap_top);
1757  page_dir_set_n_heap(new_page, NULL, PAGE_HEAP_NO_USER_LOW + n_recs);
1758  page_header_set_field(new_page, NULL, PAGE_N_RECS, n_recs);
1759 
1760  page_header_set_ptr(new_page, NULL, PAGE_LAST_INSERT, NULL);
1761  page_header_set_field(new_page, NULL, PAGE_DIRECTION,
1762  PAGE_NO_DIRECTION);
1763  page_header_set_field(new_page, NULL, PAGE_N_DIRECTION, 0);
1764 
1765  /* Restore the log mode */
1766 
1767  mtr_set_log_mode(mtr, log_mode);
1768 }
1769 
1770 /***********************************************************/
1772 UNIV_INLINE
1773 void
1774 page_cur_delete_rec_write_log(
1775 /*==========================*/
1776  rec_t* rec,
1777  dict_index_t* index,
1778  mtr_t* mtr)
1779 {
1780  byte* log_ptr;
1781 
1782  ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
1783 
1784  log_ptr = mlog_open_and_write_index(mtr, rec, index,
1785  page_rec_is_comp(rec)
1787  : MLOG_REC_DELETE, 2);
1788 
1789  if (!log_ptr) {
1790  /* Logging in mtr is switched off during crash recovery:
1791  in that case mlog_open returns NULL */
1792  return;
1793  }
1794 
1795  /* Write the cursor rec offset as a 2-byte ulint */
1796  mach_write_to_2(log_ptr, page_offset(rec));
1797 
1798  mlog_close(mtr, log_ptr + 2);
1799 }
1800 #else /* !UNIV_HOTBACKUP */
1801 # define page_cur_delete_rec_write_log(rec,index,mtr) ((void) 0)
1802 #endif /* !UNIV_HOTBACKUP */
1803 
1804 /***********************************************************/
1807 UNIV_INTERN
1808 byte*
1810 /*======================*/
1811  byte* ptr,
1812  byte* end_ptr,
1813  buf_block_t* block,
1814  dict_index_t* index,
1815  mtr_t* mtr)
1816 {
1817  ulint offset;
1818  page_cur_t cursor;
1819 
1820  if (end_ptr < ptr + 2) {
1821 
1822  return(NULL);
1823  }
1824 
1825  /* Read the cursor rec offset as a 2-byte ulint */
1826  offset = mach_read_from_2(ptr);
1827  ptr += 2;
1828 
1829  ut_a(offset <= UNIV_PAGE_SIZE);
1830 
1831  if (block) {
1832  page_t* page = buf_block_get_frame(block);
1833  mem_heap_t* heap = NULL;
1834  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1835  rec_t* rec = page + offset;
1836  rec_offs_init(offsets_);
1837 
1838  page_cur_position(rec, block, &cursor);
1839  ut_ad(!buf_block_get_page_zip(block) || page_is_comp(page));
1840 
1841  page_cur_delete_rec(&cursor, index,
1842  rec_get_offsets(rec, index, offsets_,
1843  ULINT_UNDEFINED, &heap),
1844  mtr);
1845  if (UNIV_LIKELY_NULL(heap)) {
1846  mem_heap_free(heap);
1847  }
1848  }
1849 
1850  return(ptr);
1851 }
1852 
1853 /***********************************************************/
1856 UNIV_INTERN
1857 void
1859 /*================*/
1860  page_cur_t* cursor,
1861  dict_index_t* index,
1862  const ulint* offsets,
1863  mtr_t* mtr)
1864 {
1865  page_dir_slot_t* cur_dir_slot;
1866  page_dir_slot_t* prev_slot;
1867  page_t* page;
1868  page_zip_des_t* page_zip;
1869  rec_t* current_rec;
1870  rec_t* prev_rec = NULL;
1871  rec_t* next_rec;
1872  ulint cur_slot_no;
1873  ulint cur_n_owned;
1874  rec_t* rec;
1875 
1876  ut_ad(cursor && mtr);
1877 
1878  page = page_cur_get_page(cursor);
1879  page_zip = page_cur_get_page_zip(cursor);
1880 
1881  /* page_zip_validate() will fail here when
1882  btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark().
1883  Then, both "page_zip" and "page" would have the min-rec-mark
1884  set on the smallest user record, but "page" would additionally
1885  have it set on the smallest-but-one record. Because sloppy
1886  page_zip_validate_low() only ignores min-rec-flag differences
1887  in the smallest user record, it cannot be used here either. */
1888 
1889  current_rec = cursor->rec;
1890  ut_ad(rec_offs_validate(current_rec, index, offsets));
1891  ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
1892 
1893  /* The record must not be the supremum or infimum record. */
1894  ut_ad(page_rec_is_user_rec(current_rec));
1895 
1896  /* Save to local variables some data associated with current_rec */
1897  cur_slot_no = page_dir_find_owner_slot(current_rec);
1898  cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
1899  cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
1900 
1901  /* 0. Write the log record */
1902  page_cur_delete_rec_write_log(current_rec, index, mtr);
1903 
1904  /* 1. Reset the last insert info in the page header and increment
1905  the modify clock for the frame */
1906 
1907  page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
1908 
1909  /* The page gets invalid for optimistic searches: increment the
1910  frame modify clock */
1911 
1912  buf_block_modify_clock_inc(page_cur_get_block(cursor));
1913 
1914  /* 2. Find the next and the previous record. Note that the cursor is
1915  left at the next record. */
1916 
1917  ut_ad(cur_slot_no > 0);
1918  prev_slot = page_dir_get_nth_slot(page, cur_slot_no - 1);
1919 
1920  rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
1921 
1922  /* rec now points to the record of the previous directory slot. Look
1923  for the immediate predecessor of current_rec in a loop. */
1924 
1925  while(current_rec != rec) {
1926  prev_rec = rec;
1927  rec = page_rec_get_next(rec);
1928  }
1929 
1930  page_cur_move_to_next(cursor);
1931  next_rec = cursor->rec;
1932 
1933  /* 3. Remove the record from the linked list of records */
1934 
1935  page_rec_set_next(prev_rec, next_rec);
1936 
1937  /* 4. If the deleted record is pointed to by a dir slot, update the
1938  record pointer in slot. In the following if-clause we assume that
1939  prev_rec is owned by the same slot, i.e., PAGE_DIR_SLOT_MIN_N_OWNED
1940  >= 2. */
1941 
1942 #if PAGE_DIR_SLOT_MIN_N_OWNED < 2
1943 # error "PAGE_DIR_SLOT_MIN_N_OWNED < 2"
1944 #endif
1945  ut_ad(cur_n_owned > 1);
1946 
1947  if (current_rec == page_dir_slot_get_rec(cur_dir_slot)) {
1948  page_dir_slot_set_rec(cur_dir_slot, prev_rec);
1949  }
1950 
1951  /* 5. Update the number of owned records of the slot */
1952 
1953  page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
1954 
1955  /* 6. Free the memory occupied by the record */
1956  btr_blob_dbg_remove_rec(current_rec, index, offsets, "delete");
1957  page_mem_free(page, page_zip, current_rec, index, offsets);
1958 
1959  /* 7. Now we have decremented the number of owned records of the slot.
1960  If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
1961  slots. */
1962 
1963  if (UNIV_UNLIKELY(cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED)) {
1964  page_dir_balance_slot(page, page_zip, cur_slot_no);
1965  }
1966 
1967 #ifdef UNIV_ZIP_DEBUG
1968  ut_a(!page_zip || page_zip_validate(page_zip, page));
1969 #endif /* UNIV_ZIP_DEBUG */
1970 }
1971 
1972 #ifdef UNIV_COMPILE_TEST_FUNCS
1973 
1974 /*******************************************************************/
1977 void
1978 test_page_cur_lcg_prng(
1979 /*===================*/
1980  int n)
1981 {
1982  int i;
1983  unsigned long long rnd;
1984 
1985  for (i = 0; i < n; i++) {
1986  rnd = page_cur_lcg_prng();
1987  printf("%llu\t%%2=%llu %%3=%llu %%5=%llu %%7=%llu %%11=%llu\n",
1988  rnd,
1989  rnd % 2,
1990  rnd % 3,
1991  rnd % 5,
1992  rnd % 7,
1993  rnd % 11);
1994  }
1995 }
1996 
1997 #endif /* UNIV_COMPILE_TEST_FUNCS */
UNIV_INTERN void page_zip_dir_insert(page_zip_des_t *page_zip, const byte *prev_rec, const byte *free_rec, byte *rec)
Definition: page0zip.cc:4073
UNIV_INTERN ibool UNIV_INTERN ibool page_zip_decompress(page_zip_des_t *page_zip, page_t *page, ibool all) __attribute__((nonnull(1
recv_sys_t * recv_sys
Definition: log0recv.cc:73
UNIV_INLINE ulint dyn_array_get_data_size(dyn_array_t *arr)
UNIV_INLINE ulint page_is_comp(const page_t *page)
UNIV_INTERN ibool page_zip_reorganize(buf_block_t *block, dict_index_t *index, mtr_t *mtr) __attribute__((nonnull))
Definition: page0zip.cc:4409
UNIV_INLINE ulint page_rec_get_base_extra_size(const rec_t *rec)
UNIV_INTERN void page_cur_search_with_match(const buf_block_t *block, const dict_index_t *index, const dtuple_t *tuple, ulint mode, ulint *iup_matched_fields, ulint *iup_matched_bytes, ulint *ilow_matched_fields, ulint *ilow_matched_bytes, page_cur_t *cursor)
Definition: page0cur.cc:246
UNIV_INLINE rec_t * page_cur_rec_insert(page_cur_t *cursor, const rec_t *rec, dict_index_t *index, ulint *offsets, mtr_t *mtr)
UNIV_INLINE page_t * page_align(const void *ptr) __attribute__((const ))
UNIV_INLINE void page_rec_set_next(rec_t *rec, rec_t *next)
UNIV_INLINE void mach_write_to_4(byte *b, ulint n)
UNIV_INTERN ibool page_zip_compress(page_zip_des_t *page_zip, const page_t *page, dict_index_t *index, mtr_t *mtr) __attribute__((nonnull(1
UNIV_INLINE ulint mtr_set_log_mode(mtr_t *mtr, ulint mode)
UNIV_INTERN void page_dir_balance_slot(page_t *page, page_zip_des_t *page_zip, ulint slot_no) __attribute__((nonnull(1)))
Definition: page0page.cc:1423
UNIV_INLINE void page_header_set_field(page_t *page, page_zip_des_t *page_zip, ulint field, ulint val)
UNIV_INTERN byte * page_parse_copy_rec_list_to_created_page(byte *ptr, byte *end_ptr, buf_block_t *block, dict_index_t *index, mtr_t *mtr)
Definition: page0cur.cc:1542
UNIV_INLINE ibool page_zip_available(const page_zip_des_t *page_zip, ibool is_clust, ulint length, ulint create) __attribute__((nonnull
UNIV_INLINE ulint page_get_n_recs(const page_t *page)
UNIV_INTERN void buf_page_print(const byte *read_buf, ulint zip_size)
Definition: buf0buf.cc:601
#define mem_free(PTR)
Definition: mem0mem.h:249
UNIV_INLINE void page_dir_set_n_heap(page_t *page, page_zip_des_t *page_zip, ulint n_heap)
UNIV_INTERN void page_cur_delete_rec(page_cur_t *cursor, dict_index_t *index, const ulint *offsets, mtr_t *mtr)
Definition: page0cur.cc:1858
UNIV_INLINE ulint rec_offs_data_size(const ulint *offsets)
UNIV_INLINE ulint rec_get_next_offs(const rec_t *rec, ulint comp)
UNIV_INLINE void * ut_memcpy(void *dest, const void *sour, ulint n)
UNIV_INLINE void mlog_close(mtr_t *mtr, byte *ptr)
UNIV_INTERN void ut_print_buf(FILE *file, const void *buf, ulint len)
Definition: ut0ut.cc:444
UNIV_INTERN byte * page_cur_parse_delete_rec(byte *ptr, byte *end_ptr, buf_block_t *block, dict_index_t *index, mtr_t *mtr)
Definition: page0cur.cc:1809
UNIV_INTERN int cmp_data_data_slow(ulint mtype, ulint prtype, const byte *data1, ulint len1, const byte *data2, ulint len2)
Definition: rem0cmp.cc:292
UNIV_INTERN byte * page_mem_alloc_heap(page_t *page, page_zip_des_t *page_zip, ulint need, ulint *heap_no)
Definition: page0page.cc:255
UNIV_INLINE void ut_pair_min(ulint *a, ulint *b, ulint a1, ulint b1, ulint a2, ulint b2)
UNIV_INLINE ibool dict_table_is_comp(const dict_table_t *table)
UNIV_INLINE ulint page_dir_get_n_heap(const page_t *page)
UNIV_INLINE void buf_block_modify_clock_inc(buf_block_t *block)
UNIV_INLINE ulint rec_offs_extra_size(const ulint *offsets)
UNIV_INLINE void rec_set_next_offs_old(rec_t *rec, ulint next)
UNIV_INLINE int page_cmp_dtuple_rec_with_match(const dtuple_t *dtuple, const rec_t *rec, const ulint *offsets, ulint *matched_fields, ulint *matched_bytes)
UNIV_INLINE ulint rec_get_info_and_status_bits(const rec_t *rec, ulint comp)
UNIV_INLINE ulint mtr_get_log_mode(mtr_t *mtr)
UNIV_INLINE const rec_t * page_dir_slot_get_rec(const page_dir_slot_t *slot)
UNIV_INTERN void page_cur_open_on_rnd_user_rec(buf_block_t *block, page_cur_t *cursor)
Definition: page0cur.cc:545
UNIV_INLINE rec_t * page_rec_get_next(rec_t *rec)
UNIV_INLINE void page_cur_set_before_first(const buf_block_t *block, page_cur_t *cur)
UNIV_INTERN byte * mlog_open_and_write_index(mtr_t *mtr, const byte *rec, dict_index_t *index, byte type, ulint size)
Definition: mtr0log.cc:440
UNIV_INTERN ullint ut_time_us(ullint *tloc)
Definition: ut0ut.cc:194
UNIV_INLINE rec_t * rec_copy(void *buf, const rec_t *rec, const ulint *offsets)
#define mem_heap_free(heap)
Definition: mem0mem.h:117
UNIV_INTERN byte * page_cur_parse_insert_rec(ibool is_short, byte *ptr, byte *end_ptr, buf_block_t *block, dict_index_t *index, mtr_t *mtr)
Definition: page0cur.cc:757
UNIV_INLINE ulint page_header_get_field(const page_t *page, ulint field)
UNIV_INLINE void rec_set_heap_no_old(rec_t *rec, ulint heap_no)
UNIV_INLINE void page_dir_set_n_slots(page_t *page, page_zip_des_t *page_zip, ulint n_slots)
UNIV_INLINE void page_dir_slot_set_rec(page_dir_slot_t *slot, rec_t *rec)
#define MLOG_COMP_REC_INSERT
Definition: mtr0mtr.h:186
UNIV_INLINE ulint dtuple_get_n_fields(const dtuple_t *tuple)
UNIV_INLINE void rec_set_heap_no_new(rec_t *rec, ulint heap_no)
ibool found_corrupt_log
Definition: log0recv.h:427
UNIV_INLINE rec_t * page_rec_get_prev(rec_t *rec)
UNIV_INTERN ulint page_dir_find_owner_slot(const rec_t *rec)
Definition: page0page.cc:89
UNIV_INLINE ulint ut_min(ulint n1, ulint n2)
UNIV_INLINE ulint rec_get_nth_field_offs(const ulint *offsets, ulint n, ulint *len)
dyn_array_t log
Definition: mtr0mtr.h:446
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 ulint rec_get_n_owned_new(const rec_t *rec)
UNIV_INLINE ulint page_rec_is_comp(const rec_t *rec)
UNIV_INLINE ulint rec_offs_comp(const ulint *offsets)
UNIV_INLINE ibool page_is_leaf(const page_t *page) __attribute__((nonnull
UNIV_INTERN int cmp_dtuple_rec_with_match(const dtuple_t *dtuple, const rec_t *rec, const ulint *offsets, ulint *matched_fields, ulint *matched_bytes)
Definition: rem0cmp.cc:411
UNIV_INTERN rec_t * page_cur_insert_rec_low(rec_t *current_rec, dict_index_t *index, const rec_t *rec, ulint *offsets, mtr_t *mtr)
Definition: page0cur.cc:950
UNIV_INLINE ulint rec_get_status(const rec_t *rec)
UNIV_INTERN byte * mach_parse_compressed(byte *ptr, byte *end_ptr, ulint *val)
Definition: mach0data.cc:38
UNIV_INLINE void rec_set_info_bits_old(rec_t *rec, ulint bits)
#define MLOG_COMP_LIST_END_COPY_CREATED
Definition: mtr0mtr.h:222
UNIV_INTERN ibool page_validate(const page_t *page, dict_index_t *index)
Definition: page0page.cc:2307
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
UNIV_INLINE ulint dtuple_get_n_fields_cmp(const dtuple_t *tuple)
UNIV_INTERN ibool dtuple_check_typed(const dtuple_t *tuple)
UNIV_INLINE ulint page_offset(const void *ptr) __attribute__((const ))
#define buf_block_get_page_zip(block)
Definition: buf0buf.h:1034
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_INLINE void page_header_set_ptr(page_t *page, page_zip_des_t *page_zip, ulint field, const byte *ptr)
UNIV_INLINE void page_cur_move_to_next(page_cur_t *cur)
#define MLOG_REC_INSERT
Definition: mtr0mtr.h:77
UNIV_INTERN void page_check_dir(const page_t *page)
Definition: page0page.cc:1850
UNIV_INLINE ibool page_rec_is_supremum(const rec_t *rec) __attribute__((const ))
dict_table_t * table
Definition: dict0mem.h:341
UNIV_INLINE void page_dir_slot_set_n_owned(page_dir_slot_t *slot, page_zip_des_t *page_zip, ulint n)
UNIV_INLINE void mach_write_to_1(byte *b, ulint n)
UNIV_INLINE void page_mem_alloc_free(page_t *page, page_zip_des_t *page_zip, rec_t *next_rec, ulint need)
UNIV_INLINE void rec_set_n_owned_new(rec_t *rec, page_zip_des_t *page_zip, ulint n_owned)
UNIV_INTERN void page_copy_rec_list_end_to_created_page(page_t *new_page, rec_t *rec, dict_index_t *index, mtr_t *mtr)
Definition: page0cur.cc:1599
UNIV_INLINE byte * mlog_open(mtr_t *mtr, ulint size)
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
UNIV_INLINE void UNIV_INTERN void page_zip_write_rec(page_zip_des_t *page_zip, const byte *rec, dict_index_t *index, const ulint *offsets, ulint create) __attribute__((nonnull))
Definition: page0zip.cc:3373
#define MLOG_COMP_REC_DELETE
Definition: mtr0mtr.h:213
UNIV_INLINE ulint rec_get_heap_no_old(const rec_t *rec)
#define ut_error
Definition: ut0dbg.h:115
unsigned prtype
Definition: data0type.h:486
UNIV_INLINE ibool rec_get_node_ptr_flag(const rec_t *rec)
UNIV_INLINE const rec_t * page_rec_get_next_const(const rec_t *rec)
UNIV_INLINE rec_t * rec_get_next_ptr(rec_t *rec, ulint comp)
UNIV_INLINE void page_mem_free(page_t *page, page_zip_des_t *page_zip, rec_t *rec, dict_index_t *index, const ulint *offsets)
UNIV_INLINE ibool page_rec_is_user_rec(const rec_t *rec) __attribute__((const ))
UNIV_INLINE ulint dict_index_get_sys_col_pos(const dict_index_t *index, ulint type)
UNIV_INLINE ulint mach_read_from_4(const byte *b) __attribute__((nonnull
UNIV_INLINE ulint mach_write_compressed(byte *b, ulint n)
UNIV_INLINE void mach_write_to_2(byte *b, ulint n)
UNIV_INLINE void rec_set_next_offs_new(rec_t *rec, ulint next)
UNIV_INLINE void rec_set_info_and_status_bits(rec_t *rec, ulint bits)
byte page_t
Definition: page0types.h:37
#define page_header_get_ptr(page, field)
Definition: page0page.h:243
UNIV_INLINE ulint page_dir_slot_get_n_owned(const page_dir_slot_t *slot)
UNIV_INLINE rec_t * page_rec_find_owner_rec(rec_t *rec)
UNIV_INTERN rec_t * page_cur_insert_rec_zip(rec_t **current_rec, buf_block_t *block, dict_index_t *index, const rec_t *rec, ulint *offsets, mtr_t *mtr)
Definition: page0cur.cc:1217
UNIV_INLINE ulint rec_get_heap_no_new(const rec_t *rec)
UNIV_INLINE ibool page_rec_is_infimum(const rec_t *rec) __attribute__((const ))
UNIV_INLINE ulint mach_read_from_1(const byte *b) __attribute__((nonnull
UNIV_INLINE ulint rec_offs_size(const ulint *offsets)
UNIV_INLINE ulint mach_read_from_2(const byte *b) __attribute__((nonnull
UNIV_INTERN ibool UNIV_INTERN ibool UNIV_INTERN void page_dir_split_slot(page_t *page, page_zip_des_t *page_zip, ulint slot_no) __attribute__((nonnull(1)))
Definition: page0page.cc:1360
UNIV_INTERN ulint page_rec_get_n_recs_before(const rec_t *rec)
Definition: page0page.cc:1544
UNIV_INLINE ulint page_dir_get_n_slots(const page_t *page)
UNIV_INLINE void rec_set_n_owned_old(rec_t *rec, ulint n_owned)
UNIV_INLINE void page_cur_position(const rec_t *rec, const buf_block_t *block, page_cur_t *cur)
UNIV_INTERN void UNIV_INTERN void page_zip_dir_add_slot(page_zip_des_t *page_zip, ulint is_clustered) __attribute__((nonnull))
Definition: page0zip.cc:4249
#define MLOG_REC_DELETE
Definition: mtr0mtr.h:87
UNIV_INLINE ulint rec_get_n_owned_old(const rec_t *rec)
UNIV_INLINE ibool rec_offs_validate(const rec_t *rec, const dict_index_t *index, const ulint *offsets)
#define MLOG_LIST_END_COPY_CREATED
Definition: mtr0mtr.h:96
unsigned mtype
Definition: data0type.h:485