Drizzled Public API Documentation

page0zip.cc
1 /*****************************************************************************
2 
3 Copyright (C) 2005, 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 #define THIS_MODULE
27 #include "page0zip.h"
28 #ifdef UNIV_NONINL
29 # include "page0zip.ic"
30 #endif
31 #undef THIS_MODULE
32 #include "page0page.h"
33 #include "mtr0log.h"
34 #include "ut0sort.h"
35 #include "dict0dict.h"
36 #include "btr0cur.h"
37 #include "page0types.h"
38 #include "log0recv.h"
39 #include "zlib.h"
40 #ifndef UNIV_HOTBACKUP
41 # include "buf0lru.h"
42 # include "btr0sea.h"
43 # include "dict0boot.h"
44 # include "lock0lock.h"
45 #else /* !UNIV_HOTBACKUP */
46 # define lock_move_reorganize_page(block, temp_block) ((void) 0)
47 # define buf_LRU_stat_inc_unzip() ((void) 0)
48 #endif /* !UNIV_HOTBACKUP */
49 
50 #ifndef UNIV_HOTBACKUP
51 
52 UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE_MAX - 1];
53 #endif /* !UNIV_HOTBACKUP */
54 
55 /* Please refer to ../include/page0zip.ic for a description of the
56 compressed page format. */
57 
58 /* The infimum and supremum records are omitted from the compressed page.
59 On compress, we compare that the records are there, and on uncompress we
60 restore the records. */
62 static const byte infimum_extra[] = {
63  0x01, /* info_bits=0, n_owned=1 */
64  0x00, 0x02 /* heap_no=0, status=2 */
65  /* ?, ? */ /* next=(first user rec, or supremum) */
66 };
68 static const byte infimum_data[] = {
69  0x69, 0x6e, 0x66, 0x69,
70  0x6d, 0x75, 0x6d, 0x00 /* "infimum\0" */
71 };
73 static const byte supremum_extra_data[] = {
74  /* 0x0?, */ /* info_bits=0, n_owned=1..8 */
75  0x00, 0x0b, /* heap_no=1, status=3 */
76  0x00, 0x00, /* next=0 */
77  0x73, 0x75, 0x70, 0x72,
78  0x65, 0x6d, 0x75, 0x6d /* "supremum" */
79 };
80 
85 #define ASSERT_ZERO(b, s) \
86  ut_ad(!memcmp(b, field_ref_zero, ut_min(s, sizeof field_ref_zero)))
87 
89 #define ASSERT_ZERO_BLOB(b) \
90  ut_ad(!memcmp(b, field_ref_zero, sizeof field_ref_zero))
91 
92 /* Enable some extra debugging output. This code can be enabled
93 independently of any UNIV_ debugging conditions. */
94 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
95 # include <stdarg.h>
96 __attribute__((format (printf, 1, 2)))
97 /**********************************************************************/
100 static
101 int
102 page_zip_fail_func(
103 /*===============*/
104  const char* fmt,
105  ...)
106 {
107  int res;
108  va_list ap;
109 
110  ut_print_timestamp(stderr);
111  fputs(" InnoDB: ", stderr);
112  va_start(ap, fmt);
113  res = vfprintf(stderr, fmt, ap);
114  va_end(ap);
115 
116  return(res);
117 }
120 # define page_zip_fail(fmt_args) page_zip_fail_func fmt_args
121 #else /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
122 
124 # define page_zip_fail(fmt_args) /* empty */
125 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
126 
127 #ifndef UNIV_HOTBACKUP
128 /**********************************************************************/
131 UNIV_INTERN
132 ulint
134 /*================*/
135  ulint n_fields,
136  ulint zip_size)
137 {
138  lint size = zip_size
139  /* subtract the page header and the longest
140  uncompressed data needed for one record */
141  - (PAGE_DATA
142  + PAGE_ZIP_DIR_SLOT_SIZE
143  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN
144  + 1/* encoded heap_no==2 in page_zip_write_rec() */
145  + 1/* end of modification log */
146  - REC_N_NEW_EXTRA_BYTES/* omitted bytes */)
147  /* subtract the space for page_zip_fields_encode() */
148  - compressBound(2 * (n_fields + 1));
149  return(size > 0 ? (ulint) size : 0);
150 }
151 #endif /* !UNIV_HOTBACKUP */
152 
153 /*************************************************************/
157 UNIV_INLINE
158 ulint
159 page_zip_dir_size(
160 /*==============*/
161  const page_zip_des_t* page_zip)
162 {
163  /* Exclude the page infimum and supremum from the record count. */
164  ulint size = PAGE_ZIP_DIR_SLOT_SIZE
165  * (page_dir_get_n_heap(page_zip->data)
166  - PAGE_HEAP_NO_USER_LOW);
167  return(size);
168 }
169 
170 /*************************************************************/
174 UNIV_INLINE
175 ulint
176 page_zip_dir_user_size(
177 /*===================*/
178  const page_zip_des_t* page_zip)
179 {
180  ulint size = PAGE_ZIP_DIR_SLOT_SIZE
181  * page_get_n_recs(page_zip->data);
182  ut_ad(size <= page_zip_dir_size(page_zip));
183  return(size);
184 }
185 
186 /*************************************************************/
189 UNIV_INLINE
190 byte*
191 page_zip_dir_find_low(
192 /*==================*/
193  byte* slot,
194  byte* end,
195  ulint offset)
196 {
197  ut_ad(slot <= end);
198 
199  for (; slot < end; slot += PAGE_ZIP_DIR_SLOT_SIZE) {
200  if ((mach_read_from_2(slot) & PAGE_ZIP_DIR_SLOT_MASK)
201  == offset) {
202  return(slot);
203  }
204  }
205 
206  return(NULL);
207 }
208 
209 /*************************************************************/
212 UNIV_INLINE
213 byte*
214 page_zip_dir_find(
215 /*==============*/
216  page_zip_des_t* page_zip,
217  ulint offset)
218 {
219  byte* end = page_zip->data + page_zip_get_size(page_zip);
220 
221  ut_ad(page_zip_simple_validate(page_zip));
222 
223  return(page_zip_dir_find_low(end - page_zip_dir_user_size(page_zip),
224  end,
225  offset));
226 }
227 
228 /*************************************************************/
231 UNIV_INLINE
232 byte*
233 page_zip_dir_find_free(
234 /*===================*/
235  page_zip_des_t* page_zip,
236  ulint offset)
237 {
238  byte* end = page_zip->data + page_zip_get_size(page_zip);
239 
240  ut_ad(page_zip_simple_validate(page_zip));
241 
242  return(page_zip_dir_find_low(end - page_zip_dir_size(page_zip),
243  end - page_zip_dir_user_size(page_zip),
244  offset));
245 }
246 
247 /*************************************************************/
251 UNIV_INLINE
252 ulint
253 page_zip_dir_get(
254 /*=============*/
255  const page_zip_des_t* page_zip,
256  ulint slot)
258 {
259  ut_ad(page_zip_simple_validate(page_zip));
260  ut_ad(slot < page_zip_dir_size(page_zip) / PAGE_ZIP_DIR_SLOT_SIZE);
261  return(mach_read_from_2(page_zip->data + page_zip_get_size(page_zip)
262  - PAGE_ZIP_DIR_SLOT_SIZE * (slot + 1)));
263 }
264 
265 #ifndef UNIV_HOTBACKUP
266 /**********************************************************************/
268 static
269 void
270 page_zip_compress_write_log(
271 /*========================*/
272  const page_zip_des_t* page_zip,
273  const page_t* page,
274  dict_index_t* index,
275  mtr_t* mtr)
276 {
277  byte* log_ptr;
278  ulint trailer_size;
279 
280  ut_ad(!dict_index_is_ibuf(index));
281 
282  log_ptr = mlog_open(mtr, 11 + 2 + 2);
283 
284  if (!log_ptr) {
285 
286  return;
287  }
288 
289  /* Read the number of user records. */
290  trailer_size = page_dir_get_n_heap(page_zip->data)
291  - PAGE_HEAP_NO_USER_LOW;
292  /* Multiply by uncompressed of size stored per record */
293  if (!page_is_leaf(page)) {
294  trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE;
295  } else if (dict_index_is_clust(index)) {
296  trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE
297  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
298  } else {
299  trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE;
300  }
301  /* Add the space occupied by BLOB pointers. */
302  trailer_size += page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
303  ut_a(page_zip->m_end > PAGE_DATA);
304 #if FIL_PAGE_DATA > PAGE_DATA
305 # error "FIL_PAGE_DATA > PAGE_DATA"
306 #endif
307  ut_a(page_zip->m_end + trailer_size <= page_zip_get_size(page_zip));
308 
309  log_ptr = mlog_write_initial_log_record_fast((page_t*) page,
311  log_ptr, mtr);
312  mach_write_to_2(log_ptr, page_zip->m_end - FIL_PAGE_TYPE);
313  log_ptr += 2;
314  mach_write_to_2(log_ptr, trailer_size);
315  log_ptr += 2;
316  mlog_close(mtr, log_ptr);
317 
318  /* Write FIL_PAGE_PREV and FIL_PAGE_NEXT */
319  mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_PREV, 4);
320  mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_NEXT, 4);
321  /* Write most of the page header, the compressed stream and
322  the modification log. */
323  mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_TYPE,
324  page_zip->m_end - FIL_PAGE_TYPE);
325  /* Write the uncompressed trailer of the compressed page. */
326  mlog_catenate_string(mtr, page_zip->data + page_zip_get_size(page_zip)
327  - trailer_size, trailer_size);
328 }
329 #endif /* !UNIV_HOTBACKUP */
330 
331 /******************************************************/
334 static
335 ulint
336 page_zip_get_n_prev_extern(
337 /*=======================*/
338  const page_zip_des_t* page_zip,
340  const rec_t* rec,
342  dict_index_t* index)
343 {
344  const page_t* page = page_align(rec);
345  ulint n_ext = 0;
346  ulint i;
347  ulint left;
348  ulint heap_no;
349  ulint n_recs = page_get_n_recs(page_zip->data);
350 
351  ut_ad(page_is_leaf(page));
352  ut_ad(page_is_comp(page));
353  ut_ad(dict_table_is_comp(index->table));
354  ut_ad(dict_index_is_clust(index));
355  ut_ad(!dict_index_is_ibuf(index));
356 
357  heap_no = rec_get_heap_no_new(rec);
358  ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW);
359  left = heap_no - PAGE_HEAP_NO_USER_LOW;
360  if (UNIV_UNLIKELY(!left)) {
361  return(0);
362  }
363 
364  for (i = 0; i < n_recs; i++) {
365  const rec_t* r = page + (page_zip_dir_get(page_zip, i)
366  & PAGE_ZIP_DIR_SLOT_MASK);
367 
368  if (rec_get_heap_no_new(r) < heap_no) {
369  n_ext += rec_get_n_extern_new(r, index,
370  ULINT_UNDEFINED);
371  if (!--left) {
372  break;
373  }
374  }
375  }
376 
377  return(n_ext);
378 }
379 
380 /**********************************************************************/
383 static
384 byte*
385 page_zip_fixed_field_encode(
386 /*========================*/
387  byte* buf,
388  ulint val)
389 {
390  ut_ad(val >= 2);
391 
392  if (UNIV_LIKELY(val < 126)) {
393  /*
394  0 = nullable variable field of at most 255 bytes length;
395  1 = not null variable field of at most 255 bytes length;
396  126 = nullable variable field with maximum length >255;
397  127 = not null variable field with maximum length >255
398  */
399  *buf++ = (byte) val;
400  } else {
401  *buf++ = (byte) (0x80 | val >> 8);
402  *buf++ = (byte) val;
403  }
404 
405  return(buf);
406 }
407 
408 /**********************************************************************/
411 static
412 ulint
413 page_zip_fields_encode(
414 /*===================*/
415  ulint n,
416  dict_index_t* index,
417  ulint trx_id_pos,
420  byte* buf)
421 {
422  const byte* buf_start = buf;
423  ulint i;
424  ulint col;
425  ulint trx_id_col = 0;
426  /* sum of lengths of preceding non-nullable fixed fields, or 0 */
427  ulint fixed_sum = 0;
428 
429  ut_ad(trx_id_pos == ULINT_UNDEFINED || trx_id_pos < n);
430 
431  for (i = col = 0; i < n; i++) {
432  dict_field_t* field = dict_index_get_nth_field(index, i);
433  ulint val;
434 
435  if (dict_field_get_col(field)->prtype & DATA_NOT_NULL) {
436  val = 1; /* set the "not nullable" flag */
437  } else {
438  val = 0; /* nullable field */
439  }
440 
441  if (!field->fixed_len) {
442  /* variable-length field */
443  const dict_col_t* column
444  = dict_field_get_col(field);
445 
446  if (UNIV_UNLIKELY(column->len > 255)
447  || UNIV_UNLIKELY(column->mtype == DATA_BLOB)) {
448  val |= 0x7e; /* max > 255 bytes */
449  }
450 
451  if (fixed_sum) {
452  /* write out the length of any
453  preceding non-nullable fields */
454  buf = page_zip_fixed_field_encode(
455  buf, fixed_sum << 1 | 1);
456  fixed_sum = 0;
457  col++;
458  }
459 
460  *buf++ = (byte) val;
461  col++;
462  } else if (val) {
463  /* fixed-length non-nullable field */
464 
465  if (fixed_sum && UNIV_UNLIKELY
466  (fixed_sum + field->fixed_len
468  /* Write out the length of the
469  preceding non-nullable fields,
470  to avoid exceeding the maximum
471  length of a fixed-length column. */
472  buf = page_zip_fixed_field_encode(
473  buf, fixed_sum << 1 | 1);
474  fixed_sum = 0;
475  col++;
476  }
477 
478  if (i && UNIV_UNLIKELY(i == trx_id_pos)) {
479  if (fixed_sum) {
480  /* Write out the length of any
481  preceding non-nullable fields,
482  and start a new trx_id column. */
483  buf = page_zip_fixed_field_encode(
484  buf, fixed_sum << 1 | 1);
485  col++;
486  }
487 
488  trx_id_col = col;
489  fixed_sum = field->fixed_len;
490  } else {
491  /* add to the sum */
492  fixed_sum += field->fixed_len;
493  }
494  } else {
495  /* fixed-length nullable field */
496 
497  if (fixed_sum) {
498  /* write out the length of any
499  preceding non-nullable fields */
500  buf = page_zip_fixed_field_encode(
501  buf, fixed_sum << 1 | 1);
502  fixed_sum = 0;
503  col++;
504  }
505 
506  buf = page_zip_fixed_field_encode(
507  buf, field->fixed_len << 1);
508  col++;
509  }
510  }
511 
512  if (fixed_sum) {
513  /* Write out the lengths of last fixed-length columns. */
514  buf = page_zip_fixed_field_encode(buf, fixed_sum << 1 | 1);
515  }
516 
517  if (trx_id_pos != ULINT_UNDEFINED) {
518  /* Write out the position of the trx_id column */
519  i = trx_id_col;
520  } else {
521  /* Write out the number of nullable fields */
522  i = index->n_nullable;
523  }
524 
525  if (i < 128) {
526  *buf++ = (byte) i;
527  } else {
528  *buf++ = (byte) (0x80 | i >> 8);
529  *buf++ = (byte) i;
530  }
531 
532  ut_ad((ulint) (buf - buf_start) <= (n + 2) * 2);
533  return((ulint) (buf - buf_start));
534 }
535 
536 /**********************************************************************/
538 static
539 void
540 page_zip_dir_encode(
541 /*================*/
542  const page_t* page,
543  byte* buf,
545  const rec_t** recs)
548 {
549  const byte* rec;
550  ulint status;
551  ulint min_mark;
552  ulint heap_no;
553  ulint i;
554  ulint n_heap;
555  ulint offs;
556 
557  min_mark = 0;
558 
559  if (page_is_leaf(page)) {
560  status = REC_STATUS_ORDINARY;
561  } else {
562  status = REC_STATUS_NODE_PTR;
563  if (UNIV_UNLIKELY
564  (mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL)) {
565  min_mark = REC_INFO_MIN_REC_FLAG;
566  }
567  }
568 
569  n_heap = page_dir_get_n_heap(page);
570 
571  /* Traverse the list of stored records in the collation order,
572  starting from the first user record. */
573 
574  rec = page + PAGE_NEW_INFIMUM;
575 
576  i = 0;
577 
578  for (;;) {
579  ulint info_bits;
580  offs = rec_get_next_offs(rec, TRUE);
581  if (UNIV_UNLIKELY(offs == PAGE_NEW_SUPREMUM)) {
582  break;
583  }
584  rec = page + offs;
585  heap_no = rec_get_heap_no_new(rec);
586  ut_a(heap_no >= PAGE_HEAP_NO_USER_LOW);
587  ut_a(heap_no < n_heap);
588  ut_a(offs < UNIV_PAGE_SIZE - PAGE_DIR);
589  ut_a(offs >= PAGE_ZIP_START);
590 #if PAGE_ZIP_DIR_SLOT_MASK & (PAGE_ZIP_DIR_SLOT_MASK + 1)
591 # error "PAGE_ZIP_DIR_SLOT_MASK is not 1 less than a power of 2"
592 #endif
593  if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
594  offs |= PAGE_ZIP_DIR_SLOT_OWNED;
595  }
596 
597  info_bits = rec_get_info_bits(rec, TRUE);
598  if (UNIV_UNLIKELY(info_bits & REC_INFO_DELETED_FLAG)) {
599  info_bits &= ~REC_INFO_DELETED_FLAG;
600  offs |= PAGE_ZIP_DIR_SLOT_DEL;
601  }
602  ut_a(info_bits == min_mark);
603  /* Only the smallest user record can have
604  REC_INFO_MIN_REC_FLAG set. */
605  min_mark = 0;
606 
607  mach_write_to_2(buf - PAGE_ZIP_DIR_SLOT_SIZE * ++i, offs);
608 
609  if (UNIV_LIKELY_NULL(recs)) {
610  /* Ensure that each heap_no occurs at most once. */
611  ut_a(!recs[heap_no - PAGE_HEAP_NO_USER_LOW]);
612  /* exclude infimum and supremum */
613  recs[heap_no - PAGE_HEAP_NO_USER_LOW] = rec;
614  }
615 
616  ut_a(rec_get_status(rec) == status);
617  }
618 
619  offs = page_header_get_field(page, PAGE_FREE);
620 
621  /* Traverse the free list (of deleted records). */
622  while (offs) {
623  ut_ad(!(offs & ~PAGE_ZIP_DIR_SLOT_MASK));
624  rec = page + offs;
625 
626  heap_no = rec_get_heap_no_new(rec);
627  ut_a(heap_no >= PAGE_HEAP_NO_USER_LOW);
628  ut_a(heap_no < n_heap);
629 
630  ut_a(!rec[-REC_N_NEW_EXTRA_BYTES]); /* info_bits and n_owned */
631  ut_a(rec_get_status(rec) == status);
632 
633  mach_write_to_2(buf - PAGE_ZIP_DIR_SLOT_SIZE * ++i, offs);
634 
635  if (UNIV_LIKELY_NULL(recs)) {
636  /* Ensure that each heap_no occurs at most once. */
637  ut_a(!recs[heap_no - PAGE_HEAP_NO_USER_LOW]);
638  /* exclude infimum and supremum */
639  recs[heap_no - PAGE_HEAP_NO_USER_LOW] = rec;
640  }
641 
642  offs = rec_get_next_offs(rec, TRUE);
643  }
644 
645  /* Ensure that each heap no occurs at least once. */
646  ut_a(i + PAGE_HEAP_NO_USER_LOW == n_heap);
647 }
648 
649 /**********************************************************************/
651 extern "C" void* page_zip_zalloc(void* opaque, uInt items, uInt size);
652 
653 extern "C" void* page_zip_zalloc
654 (
655 /*============*/
656  void* opaque,
657  uInt items,
658  uInt size)
659 {
660  return(mem_heap_zalloc(static_cast<mem_block_info_t *>(opaque), items * size));
661 }
662 
663 /**********************************************************************/
665 extern "C" void page_zip_free(void *opaque, void *address);
666 
667 extern "C" void page_zip_free(void *, void *)
668 { }
669 
670 /**********************************************************************/
672 UNIV_INTERN
673 void
675 /*===============*/
676  void* stream,
677  mem_heap_t* heap)
678 {
679  z_stream* strm = static_cast<z_stream *>(stream);
680 
681  strm->zalloc = page_zip_zalloc;
682  strm->zfree = page_zip_free;
683  strm->opaque = heap;
684 }
685 
686 #if 0 || defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
687 
688 # define PAGE_ZIP_COMPRESS_DBG
689 #endif
690 
691 #ifdef PAGE_ZIP_COMPRESS_DBG
692 
694 UNIV_INTERN ibool page_zip_compress_dbg;
699 UNIV_INTERN unsigned page_zip_compress_log;
700 
701 /**********************************************************************/
704 static
705 int
706 page_zip_compress_deflate(
707 /*======================*/
708  FILE* logfile,
709  z_streamp strm,
710  int flush)
711 {
712  int status;
713  if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
714  ut_print_buf(stderr, strm->next_in, strm->avail_in);
715  }
716  if (UNIV_LIKELY_NULL(logfile)) {
717  fwrite(strm->next_in, 1, strm->avail_in, logfile);
718  }
719  status = deflate(strm, flush);
720  if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
721  fprintf(stderr, " -> %d\n", status);
722  }
723  return(status);
724 }
725 
726 /* Redefine deflate(). */
727 # undef deflate
728 
733 # define deflate(strm, flush) page_zip_compress_deflate(logfile, strm, flush)
734 
735 # define FILE_LOGFILE FILE* logfile,
736 
737 # define LOGFILE logfile,
738 #else /* PAGE_ZIP_COMPRESS_DBG */
739 
740 # define FILE_LOGFILE
741 
742 # define LOGFILE
743 #endif /* PAGE_ZIP_COMPRESS_DBG */
744 
745 /**********************************************************************/
748 static
749 int
750 page_zip_compress_node_ptrs(
751 /*========================*/
752  FILE_LOGFILE
753  z_stream* c_stream,
754  const rec_t** recs,
756  ulint n_dense,
757  dict_index_t* index,
758  byte* storage,
759  mem_heap_t* heap)
760 {
761  int err = Z_OK;
762  ulint* offsets = NULL;
763 
764  do {
765  const rec_t* rec = *recs++;
766 
767  offsets = rec_get_offsets(rec, index, offsets,
768  ULINT_UNDEFINED, &heap);
769  /* Only leaf nodes may contain externally stored columns. */
770  ut_ad(!rec_offs_any_extern(offsets));
771 
772  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
773  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
774  rec_offs_extra_size(offsets));
775 
776  /* Compress the extra bytes. */
777  c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
778  - c_stream->next_in;
779 
780  if (c_stream->avail_in) {
781  err = deflate(c_stream, Z_NO_FLUSH);
782  if (UNIV_UNLIKELY(err != Z_OK)) {
783  break;
784  }
785  }
786  ut_ad(!c_stream->avail_in);
787 
788  /* Compress the data bytes, except node_ptr. */
789  c_stream->next_in = (byte*) rec;
790  c_stream->avail_in = rec_offs_data_size(offsets)
791  - REC_NODE_PTR_SIZE;
792  ut_ad(c_stream->avail_in);
793 
794  err = deflate(c_stream, Z_NO_FLUSH);
795  if (UNIV_UNLIKELY(err != Z_OK)) {
796  break;
797  }
798 
799  ut_ad(!c_stream->avail_in);
800 
801  memcpy(storage - REC_NODE_PTR_SIZE
802  * (rec_get_heap_no_new(rec) - 1),
803  c_stream->next_in, REC_NODE_PTR_SIZE);
804  c_stream->next_in += REC_NODE_PTR_SIZE;
805  } while (--n_dense);
806 
807  return(err);
808 }
809 
810 /**********************************************************************/
813 static
814 int
815 page_zip_compress_sec(
816 /*==================*/
817  FILE_LOGFILE
818  z_stream* c_stream,
819  const rec_t** recs,
821  ulint n_dense)
822 {
823  int err = Z_OK;
824 
825  ut_ad(n_dense > 0);
826 
827  do {
828  const rec_t* rec = *recs++;
829 
830  /* Compress everything up to this record. */
831  c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
832  - c_stream->next_in;
833 
834  if (UNIV_LIKELY(c_stream->avail_in)) {
835  UNIV_MEM_ASSERT_RW(c_stream->next_in,
836  c_stream->avail_in);
837  err = deflate(c_stream, Z_NO_FLUSH);
838  if (UNIV_UNLIKELY(err != Z_OK)) {
839  break;
840  }
841  }
842 
843  ut_ad(!c_stream->avail_in);
844  ut_ad(c_stream->next_in == rec - REC_N_NEW_EXTRA_BYTES);
845 
846  /* Skip the REC_N_NEW_EXTRA_BYTES. */
847 
848  c_stream->next_in = (byte*) rec;
849  } while (--n_dense);
850 
851  return(err);
852 }
853 
854 /**********************************************************************/
858 static
859 int
860 page_zip_compress_clust_ext(
861 /*========================*/
862  FILE_LOGFILE
863  z_stream* c_stream,
864  const rec_t* rec,
865  const ulint* offsets,
866  ulint trx_id_col,
867  byte* deleted,
869  byte* storage,
870  byte** externs,
872  ulint* n_blobs)
874 {
875  int err;
876  ulint i;
877 
878  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
879  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
880  rec_offs_extra_size(offsets));
881 
882  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
883  ulint len;
884  const byte* src;
885 
886  if (UNIV_UNLIKELY(i == trx_id_col)) {
887  ut_ad(!rec_offs_nth_extern(offsets, i));
888  /* Store trx_id and roll_ptr
889  in uncompressed form. */
890  src = rec_get_nth_field(rec, offsets, i, &len);
891  ut_ad(src + DATA_TRX_ID_LEN
892  == rec_get_nth_field(rec, offsets,
893  i + 1, &len));
894  ut_ad(len == DATA_ROLL_PTR_LEN);
895 
896  /* Compress any preceding bytes. */
897  c_stream->avail_in
898  = src - c_stream->next_in;
899 
900  if (c_stream->avail_in) {
901  err = deflate(c_stream, Z_NO_FLUSH);
902  if (UNIV_UNLIKELY(err != Z_OK)) {
903 
904  return(err);
905  }
906  }
907 
908  ut_ad(!c_stream->avail_in);
909  ut_ad(c_stream->next_in == src);
910 
911  memcpy(storage
912  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
913  * (rec_get_heap_no_new(rec) - 1),
914  c_stream->next_in,
915  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
916 
917  c_stream->next_in
918  += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
919 
920  /* Skip also roll_ptr */
921  i++;
922  } else if (rec_offs_nth_extern(offsets, i)) {
923  src = rec_get_nth_field(rec, offsets, i, &len);
925  src += len - BTR_EXTERN_FIELD_REF_SIZE;
926 
927  c_stream->avail_in = src
928  - c_stream->next_in;
929  if (UNIV_LIKELY(c_stream->avail_in)) {
930  err = deflate(c_stream, Z_NO_FLUSH);
931  if (UNIV_UNLIKELY(err != Z_OK)) {
932 
933  return(err);
934  }
935  }
936 
937  ut_ad(!c_stream->avail_in);
938  ut_ad(c_stream->next_in == src);
939 
940  /* Reserve space for the data at
941  the end of the space reserved for
942  the compressed data and the page
943  modification log. */
944 
945  if (UNIV_UNLIKELY
946  (c_stream->avail_out
947  <= BTR_EXTERN_FIELD_REF_SIZE)) {
948  /* out of space */
949  return(Z_BUF_ERROR);
950  }
951 
952  ut_ad(*externs == c_stream->next_out
953  + c_stream->avail_out
954  + 1/* end of modif. log */);
955 
956  c_stream->next_in
958 
959  /* Skip deleted records. */
960  if (UNIV_LIKELY_NULL
961  (page_zip_dir_find_low(
962  storage, deleted,
963  page_offset(rec)))) {
964  continue;
965  }
966 
967  (*n_blobs)++;
968  c_stream->avail_out
970  *externs -= BTR_EXTERN_FIELD_REF_SIZE;
971 
972  /* Copy the BLOB pointer */
973  memcpy(*externs, c_stream->next_in
974  - BTR_EXTERN_FIELD_REF_SIZE,
975  BTR_EXTERN_FIELD_REF_SIZE);
976  }
977  }
978 
979  return(Z_OK);
980 }
981 
982 /**********************************************************************/
985 static
986 int
987 page_zip_compress_clust(
988 /*====================*/
989  FILE_LOGFILE
990  z_stream* c_stream,
991  const rec_t** recs,
993  ulint n_dense,
994  dict_index_t* index,
995  ulint* n_blobs,
997  ulint trx_id_col,
998  byte* deleted,
1000  byte* storage,
1001  mem_heap_t* heap)
1002 {
1003  int err = Z_OK;
1004  ulint* offsets = NULL;
1005  /* BTR_EXTERN_FIELD_REF storage */
1006  byte* externs = storage - n_dense
1007  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
1008 
1009  ut_ad(*n_blobs == 0);
1010 
1011  do {
1012  const rec_t* rec = *recs++;
1013 
1014  offsets = rec_get_offsets(rec, index, offsets,
1015  ULINT_UNDEFINED, &heap);
1016  ut_ad(rec_offs_n_fields(offsets)
1017  == dict_index_get_n_fields(index));
1018  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
1019  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
1020  rec_offs_extra_size(offsets));
1021 
1022  /* Compress the extra bytes. */
1023  c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
1024  - c_stream->next_in;
1025 
1026  if (c_stream->avail_in) {
1027  err = deflate(c_stream, Z_NO_FLUSH);
1028  if (UNIV_UNLIKELY(err != Z_OK)) {
1029 
1030  goto func_exit;
1031  }
1032  }
1033  ut_ad(!c_stream->avail_in);
1034  ut_ad(c_stream->next_in == rec - REC_N_NEW_EXTRA_BYTES);
1035 
1036  /* Compress the data bytes. */
1037 
1038  c_stream->next_in = (byte*) rec;
1039 
1040  /* Check if there are any externally stored columns.
1041  For each externally stored column, store the
1042  BTR_EXTERN_FIELD_REF separately. */
1043  if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
1044  ut_ad(dict_index_is_clust(index));
1045 
1046  err = page_zip_compress_clust_ext(
1047  LOGFILE
1048  c_stream, rec, offsets, trx_id_col,
1049  deleted, storage, &externs, n_blobs);
1050 
1051  if (UNIV_UNLIKELY(err != Z_OK)) {
1052 
1053  goto func_exit;
1054  }
1055  } else {
1056  ulint len;
1057  const byte* src;
1058 
1059  /* Store trx_id and roll_ptr in uncompressed form. */
1060  src = rec_get_nth_field(rec, offsets,
1061  trx_id_col, &len);
1062  ut_ad(src + DATA_TRX_ID_LEN
1063  == rec_get_nth_field(rec, offsets,
1064  trx_id_col + 1, &len));
1065  ut_ad(len == DATA_ROLL_PTR_LEN);
1066  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
1067  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
1068  rec_offs_extra_size(offsets));
1069 
1070  /* Compress any preceding bytes. */
1071  c_stream->avail_in = src - c_stream->next_in;
1072 
1073  if (c_stream->avail_in) {
1074  err = deflate(c_stream, Z_NO_FLUSH);
1075  if (UNIV_UNLIKELY(err != Z_OK)) {
1076 
1077  return(err);
1078  }
1079  }
1080 
1081  ut_ad(!c_stream->avail_in);
1082  ut_ad(c_stream->next_in == src);
1083 
1084  memcpy(storage
1085  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
1086  * (rec_get_heap_no_new(rec) - 1),
1087  c_stream->next_in,
1088  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
1089 
1090  c_stream->next_in
1091  += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
1092 
1093  /* Skip also roll_ptr */
1094  ut_ad(trx_id_col + 1 < rec_offs_n_fields(offsets));
1095  }
1096 
1097  /* Compress the last bytes of the record. */
1098  c_stream->avail_in = rec + rec_offs_data_size(offsets)
1099  - c_stream->next_in;
1100 
1101  if (c_stream->avail_in) {
1102  err = deflate(c_stream, Z_NO_FLUSH);
1103  if (UNIV_UNLIKELY(err != Z_OK)) {
1104 
1105  goto func_exit;
1106  }
1107  }
1108  ut_ad(!c_stream->avail_in);
1109  } while (--n_dense);
1110 
1111 func_exit:
1112  return(err);
1113 }
1114 
1115 /**********************************************************************/
1119 UNIV_INTERN
1120 ibool
1122 /*==============*/
1123  page_zip_des_t* page_zip,
1125  const page_t* page,
1126  dict_index_t* index,
1127  mtr_t* mtr)
1128 {
1129  z_stream c_stream;
1130  int err;
1131  ulint n_fields;/* number of index fields needed */
1132  byte* fields;
1133  byte* buf;
1134  byte* buf_end;/* end of buf */
1135  ulint n_dense;
1136  ulint slot_size;/* amount of uncompressed bytes per record */
1137  const rec_t** recs;
1138  mem_heap_t* heap;
1139  ulint trx_id_col;
1140  ulint* offsets = NULL;
1141  ulint n_blobs = 0;
1142  byte* storage;/* storage of uncompressed columns */
1143 #ifndef UNIV_HOTBACKUP
1144  ullint usec = ut_time_us(NULL);
1145 #endif /* !UNIV_HOTBACKUP */
1146 #ifdef PAGE_ZIP_COMPRESS_DBG
1147  FILE* logfile = NULL;
1148 #endif
1149 
1150  ut_a(page_is_comp(page));
1151  ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
1153  ut_ad(page_zip_simple_validate(page_zip));
1154  ut_ad(dict_table_is_comp(index->table));
1155  ut_ad(!dict_index_is_ibuf(index));
1156 
1157  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
1158 
1159  /* Check the data that will be omitted. */
1160  ut_a(!memcmp(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES),
1161  infimum_extra, sizeof infimum_extra));
1162  ut_a(!memcmp(page + PAGE_NEW_INFIMUM,
1163  infimum_data, sizeof infimum_data));
1164  ut_a(page[PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES]
1165  /* info_bits == 0, n_owned <= max */
1166  <= PAGE_DIR_SLOT_MAX_N_OWNED);
1167  ut_a(!memcmp(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
1168  supremum_extra_data, sizeof supremum_extra_data));
1169 
1170  if (UNIV_UNLIKELY(!page_get_n_recs(page))) {
1171  ut_a(rec_get_next_offs(page + PAGE_NEW_INFIMUM, TRUE)
1172  == PAGE_NEW_SUPREMUM);
1173  }
1174 
1175  if (page_is_leaf(page)) {
1176  n_fields = dict_index_get_n_fields(index);
1177  } else {
1178  n_fields = dict_index_get_n_unique_in_tree(index);
1179  }
1180 
1181  /* The dense directory excludes the infimum and supremum records. */
1182  n_dense = page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW;
1183 #ifdef PAGE_ZIP_COMPRESS_DBG
1184  if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
1185  fprintf(stderr, "compress %p %p %lu %lu %lu\n",
1186  (void*) page_zip, (void*) page,
1187  page_is_leaf(page),
1188  n_fields, n_dense);
1189  }
1190  if (UNIV_UNLIKELY(page_zip_compress_log)) {
1191  /* Create a log file for every compression attempt. */
1192  char logfilename[9];
1193  ut_snprintf(logfilename, sizeof logfilename,
1194  "%08x", page_zip_compress_log++);
1195  logfile = fopen(logfilename, "wb");
1196 
1197  if (logfile) {
1198  /* Write the uncompressed page to the log. */
1199  fwrite(page, 1, UNIV_PAGE_SIZE, logfile);
1200  /* Record the compressed size as zero.
1201  This will be overwritten at successful exit. */
1202  putc(0, logfile);
1203  putc(0, logfile);
1204  putc(0, logfile);
1205  putc(0, logfile);
1206  }
1207  }
1208 #endif /* PAGE_ZIP_COMPRESS_DBG */
1209 #ifndef UNIV_HOTBACKUP
1210  page_zip_stat[page_zip->ssize - 1].compressed++;
1211 #endif /* !UNIV_HOTBACKUP */
1212 
1213  if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE
1214  >= page_zip_get_size(page_zip))) {
1215 
1216  goto err_exit;
1217  }
1218 
1219  heap = mem_heap_create(page_zip_get_size(page_zip)
1220  + n_fields * (2 + sizeof *offsets)
1221  + n_dense * ((sizeof *recs)
1222  - PAGE_ZIP_DIR_SLOT_SIZE)
1223  + UNIV_PAGE_SIZE * 4
1224  + (512 << MAX_MEM_LEVEL));
1225 
1226  recs = static_cast<const unsigned char **>(mem_heap_zalloc(heap, n_dense * sizeof *recs));
1227 
1228  fields = static_cast<byte *>(mem_heap_alloc(heap, (n_fields + 1) * 2));
1229 
1230  buf = static_cast<byte *>(mem_heap_alloc(heap, page_zip_get_size(page_zip) - PAGE_DATA));
1231  buf_end = buf + page_zip_get_size(page_zip) - PAGE_DATA;
1232 
1233  /* Compress the data payload. */
1234  page_zip_set_alloc(&c_stream, heap);
1235 
1236  err = deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION,
1237  Z_DEFLATED, UNIV_PAGE_SIZE_SHIFT,
1238  MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
1239  ut_a(err == Z_OK);
1240 
1241  c_stream.next_out = buf;
1242  /* Subtract the space reserved for uncompressed data. */
1243  /* Page header and the end marker of the modification log */
1244  c_stream.avail_out = buf_end - buf - 1;
1245  /* Dense page directory and uncompressed columns, if any */
1246  if (page_is_leaf(page)) {
1247  if (dict_index_is_clust(index)) {
1248  trx_id_col = dict_index_get_sys_col_pos(
1249  index, DATA_TRX_ID);
1250  ut_ad(trx_id_col > 0);
1251  ut_ad(trx_id_col != ULINT_UNDEFINED);
1252 
1253  slot_size = PAGE_ZIP_DIR_SLOT_SIZE
1254  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
1255  } else {
1256  /* Signal the absence of trx_id
1257  in page_zip_fields_encode() */
1258  ut_ad(dict_index_get_sys_col_pos(index, DATA_TRX_ID)
1259  == ULINT_UNDEFINED);
1260  trx_id_col = 0;
1261  slot_size = PAGE_ZIP_DIR_SLOT_SIZE;
1262  }
1263  } else {
1264  slot_size = PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE;
1265  trx_id_col = ULINT_UNDEFINED;
1266  }
1267 
1268  if (UNIV_UNLIKELY(c_stream.avail_out <= n_dense * slot_size
1269  + 6/* sizeof(zlib header and footer) */)) {
1270  goto zlib_error;
1271  }
1272 
1273  c_stream.avail_out -= n_dense * slot_size;
1274  c_stream.avail_in = page_zip_fields_encode(n_fields, index,
1275  trx_id_col, fields);
1276  c_stream.next_in = fields;
1277  if (UNIV_LIKELY(!trx_id_col)) {
1278  trx_id_col = ULINT_UNDEFINED;
1279  }
1280 
1281  UNIV_MEM_ASSERT_RW(c_stream.next_in, c_stream.avail_in);
1282  err = deflate(&c_stream, Z_FULL_FLUSH);
1283  if (err != Z_OK) {
1284  goto zlib_error;
1285  }
1286 
1287  ut_ad(!c_stream.avail_in);
1288 
1289  page_zip_dir_encode(page, buf_end, recs);
1290 
1291  c_stream.next_in = (byte*) page + PAGE_ZIP_START;
1292 
1293  storage = buf_end - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
1294 
1295  /* Compress the records in heap_no order. */
1296  if (UNIV_UNLIKELY(!n_dense)) {
1297  } else if (!page_is_leaf(page)) {
1298  /* This is a node pointer page. */
1299  err = page_zip_compress_node_ptrs(LOGFILE
1300  &c_stream, recs, n_dense,
1301  index, storage, heap);
1302  if (UNIV_UNLIKELY(err != Z_OK)) {
1303  goto zlib_error;
1304  }
1305  } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
1306  /* This is a leaf page in a secondary index. */
1307  err = page_zip_compress_sec(LOGFILE
1308  &c_stream, recs, n_dense);
1309  if (UNIV_UNLIKELY(err != Z_OK)) {
1310  goto zlib_error;
1311  }
1312  } else {
1313  /* This is a leaf page in a clustered index. */
1314  err = page_zip_compress_clust(LOGFILE
1315  &c_stream, recs, n_dense,
1316  index, &n_blobs, trx_id_col,
1317  buf_end - PAGE_ZIP_DIR_SLOT_SIZE
1318  * page_get_n_recs(page),
1319  storage, heap);
1320  if (UNIV_UNLIKELY(err != Z_OK)) {
1321  goto zlib_error;
1322  }
1323  }
1324 
1325  /* Finish the compression. */
1326  ut_ad(!c_stream.avail_in);
1327  /* Compress any trailing garbage, in case the last record was
1328  allocated from an originally longer space on the free list,
1329  or the data of the last record from page_zip_compress_sec(). */
1330  c_stream.avail_in
1331  = page_header_get_field(page, PAGE_HEAP_TOP)
1332  - (c_stream.next_in - page);
1333  ut_a(c_stream.avail_in <= UNIV_PAGE_SIZE - PAGE_ZIP_START - PAGE_DIR);
1334 
1335  UNIV_MEM_ASSERT_RW(c_stream.next_in, c_stream.avail_in);
1336  err = deflate(&c_stream, Z_FINISH);
1337 
1338  if (UNIV_UNLIKELY(err != Z_STREAM_END)) {
1339 zlib_error:
1340  deflateEnd(&c_stream);
1341  mem_heap_free(heap);
1342 err_exit:
1343 #ifdef PAGE_ZIP_COMPRESS_DBG
1344  if (logfile) {
1345  fclose(logfile);
1346  }
1347 #endif /* PAGE_ZIP_COMPRESS_DBG */
1348 #ifndef UNIV_HOTBACKUP
1349  page_zip_stat[page_zip->ssize - 1].compressed_usec
1350  += ut_time_us(NULL) - usec;
1351 #endif /* !UNIV_HOTBACKUP */
1352  return(FALSE);
1353  }
1354 
1355  err = deflateEnd(&c_stream);
1356  ut_a(err == Z_OK);
1357 
1358  ut_ad(buf + c_stream.total_out == c_stream.next_out);
1359  ut_ad((ulint) (storage - c_stream.next_out) >= c_stream.avail_out);
1360 
1361  /* Valgrind believes that zlib does not initialize some bits
1362  in the last 7 or 8 bytes of the stream. Make Valgrind happy. */
1363  UNIV_MEM_VALID(buf, c_stream.total_out);
1364 
1365  /* Zero out the area reserved for the modification log.
1366  Space for the end marker of the modification log is not
1367  included in avail_out. */
1368  memset(c_stream.next_out, 0, c_stream.avail_out + 1/* end marker */);
1369 
1370 #ifdef UNIV_DEBUG
1371  page_zip->m_start =
1372 #endif /* UNIV_DEBUG */
1373  page_zip->m_end = PAGE_DATA + c_stream.total_out;
1374  page_zip->m_nonempty = FALSE;
1375  page_zip->n_blobs = n_blobs;
1376  /* Copy those header fields that will not be written
1377  in buf_flush_init_for_writing() */
1378  memcpy(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
1380  memcpy(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE, 2);
1381  memcpy(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
1382  PAGE_DATA - FIL_PAGE_DATA);
1383  /* Copy the rest of the compressed page */
1384  memcpy(page_zip->data + PAGE_DATA, buf,
1385  page_zip_get_size(page_zip) - PAGE_DATA);
1386  mem_heap_free(heap);
1387 #ifdef UNIV_ZIP_DEBUG
1388  ut_a(page_zip_validate(page_zip, page));
1389 #endif /* UNIV_ZIP_DEBUG */
1390 
1391  if (mtr) {
1392 #ifndef UNIV_HOTBACKUP
1393  page_zip_compress_write_log(page_zip, page, index, mtr);
1394 #endif /* !UNIV_HOTBACKUP */
1395  }
1396 
1397  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
1398 
1399 #ifdef PAGE_ZIP_COMPRESS_DBG
1400  if (logfile) {
1401  /* Record the compressed size of the block. */
1402  byte sz[4];
1403  mach_write_to_4(sz, c_stream.total_out);
1404  fseek(logfile, UNIV_PAGE_SIZE, SEEK_SET);
1405  fwrite(sz, 1, sizeof sz, logfile);
1406  fclose(logfile);
1407  }
1408 #endif /* PAGE_ZIP_COMPRESS_DBG */
1409 #ifndef UNIV_HOTBACKUP
1410  {
1411  page_zip_stat_t* zip_stat
1412  = &page_zip_stat[page_zip->ssize - 1];
1413  zip_stat->compressed_ok++;
1414  zip_stat->compressed_usec += ut_time_us(NULL) - usec;
1415  }
1416 #endif /* !UNIV_HOTBACKUP */
1417 
1418  return(TRUE);
1419 }
1420 
1421 /**********************************************************************/
1424 UNIV_INLINE
1425 ibool
1426 page_zip_dir_cmp(
1427 /*=============*/
1428  const rec_t* rec1,
1429  const rec_t* rec2)
1430 {
1431  return(rec1 > rec2);
1432 }
1433 
1434 /**********************************************************************/
1436 static
1437 void
1438 page_zip_dir_sort(
1439 /*==============*/
1440  rec_t** arr,
1441  rec_t** aux_arr,
1442  ulint low,
1443  ulint high)
1444 {
1445  UT_SORT_FUNCTION_BODY(page_zip_dir_sort, arr, aux_arr, low, high,
1446  page_zip_dir_cmp);
1447 }
1448 
1449 /**********************************************************************/
1451 static
1452 void
1453 page_zip_fields_free(
1454 /*=================*/
1455  dict_index_t* index)
1456 {
1457  if (index) {
1458  dict_table_t* table = index->table;
1459  mem_heap_free(index->heap);
1460  mutex_free(&(table->autoinc_mutex));
1461  ut_free(table->name);
1462  mem_heap_free(table->heap);
1463  }
1464 }
1465 
1466 /**********************************************************************/
1469 static
1470 dict_index_t*
1471 page_zip_fields_decode(
1472 /*===================*/
1473  const byte* buf,
1474  const byte* end,
1475  ulint* trx_id_col)
1478 {
1479  const byte* b;
1480  ulint n;
1481  ulint i;
1482  ulint val;
1483  dict_table_t* table;
1484  dict_index_t* index;
1485 
1486  /* Determine the number of fields. */
1487  for (b = buf, n = 0; b < end; n++) {
1488  if (*b++ & 0x80) {
1489  b++; /* skip the second byte */
1490  }
1491  }
1492 
1493  n--; /* n_nullable or trx_id */
1494 
1495  if (UNIV_UNLIKELY(n > REC_MAX_N_FIELDS)) {
1496 
1497  page_zip_fail(("page_zip_fields_decode: n = %lu\n",
1498  (ulong) n));
1499  return(NULL);
1500  }
1501 
1502  if (UNIV_UNLIKELY(b > end)) {
1503 
1504  page_zip_fail(("page_zip_fields_decode: %p > %p\n",
1505  (const void*) b, (const void*) end));
1506  return(NULL);
1507  }
1508 
1509  table = dict_mem_table_create("ZIP_DUMMY", DICT_HDR_SPACE, n,
1510  DICT_TF_COMPACT);
1511  index = dict_mem_index_create("ZIP_DUMMY", "ZIP_DUMMY",
1512  DICT_HDR_SPACE, 0, n);
1513  index->table = table;
1514  index->n_uniq = n;
1515  /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
1516  index->cached = TRUE;
1517 
1518  /* Initialize the fields. */
1519  for (b = buf, i = 0; i < n; i++) {
1520  ulint mtype;
1521  ulint len;
1522 
1523  val = *b++;
1524 
1525  if (UNIV_UNLIKELY(val & 0x80)) {
1526  /* fixed length > 62 bytes */
1527  val = (val & 0x7f) << 8 | *b++;
1528  len = val >> 1;
1529  mtype = DATA_FIXBINARY;
1530  } else if (UNIV_UNLIKELY(val >= 126)) {
1531  /* variable length with max > 255 bytes */
1532  len = 0x7fff;
1533  mtype = DATA_BINARY;
1534  } else if (val <= 1) {
1535  /* variable length with max <= 255 bytes */
1536  len = 0;
1537  mtype = DATA_BINARY;
1538  } else {
1539  /* fixed length < 62 bytes */
1540  len = val >> 1;
1541  mtype = DATA_FIXBINARY;
1542  }
1543 
1544  dict_mem_table_add_col(table, NULL, NULL, mtype,
1545  val & 1 ? DATA_NOT_NULL : 0, len);
1546  dict_index_add_col(index, table,
1547  dict_table_get_nth_col(table, i), 0);
1548  }
1549 
1550  val = *b++;
1551  if (UNIV_UNLIKELY(val & 0x80)) {
1552  val = (val & 0x7f) << 8 | *b++;
1553  }
1554 
1555  /* Decode the position of the trx_id column. */
1556  if (trx_id_col) {
1557  if (!val) {
1558  val = ULINT_UNDEFINED;
1559  } else if (UNIV_UNLIKELY(val >= n)) {
1560  page_zip_fields_free(index);
1561  index = NULL;
1562  } else {
1563  index->type = DICT_CLUSTERED;
1564  }
1565 
1566  *trx_id_col = val;
1567  } else {
1568  /* Decode the number of nullable fields. */
1569  if (UNIV_UNLIKELY(index->n_nullable > val)) {
1570  page_zip_fields_free(index);
1571  index = NULL;
1572  } else {
1573  index->n_nullable = val;
1574  }
1575  }
1576 
1577  ut_ad(b == end);
1578 
1579  return(index);
1580 }
1581 
1582 /**********************************************************************/
1585 static
1586 ibool
1587 page_zip_dir_decode(
1588 /*================*/
1589  const page_zip_des_t* page_zip,
1591  page_t* page,
1594  rec_t** recs,
1596  rec_t** recs_aux,
1597  ulint n_dense)
1599 {
1600  ulint i;
1601  ulint n_recs;
1602  byte* slot;
1603 
1604  n_recs = page_get_n_recs(page);
1605 
1606  if (UNIV_UNLIKELY(n_recs > n_dense)) {
1607  page_zip_fail(("page_zip_dir_decode 1: %lu > %lu\n",
1608  (ulong) n_recs, (ulong) n_dense));
1609  return(FALSE);
1610  }
1611 
1612  /* Traverse the list of stored records in the sorting order,
1613  starting from the first user record. */
1614 
1615  slot = page + (UNIV_PAGE_SIZE - PAGE_DIR - PAGE_DIR_SLOT_SIZE);
1616  UNIV_PREFETCH_RW(slot);
1617 
1618  /* Zero out the page trailer. */
1619  memset(slot + PAGE_DIR_SLOT_SIZE, 0, PAGE_DIR);
1620 
1621  mach_write_to_2(slot, PAGE_NEW_INFIMUM);
1622  slot -= PAGE_DIR_SLOT_SIZE;
1623  UNIV_PREFETCH_RW(slot);
1624 
1625  /* Initialize the sparse directory and copy the dense directory. */
1626  for (i = 0; i < n_recs; i++) {
1627  ulint offs = page_zip_dir_get(page_zip, i);
1628 
1629  if (offs & PAGE_ZIP_DIR_SLOT_OWNED) {
1630  mach_write_to_2(slot, offs & PAGE_ZIP_DIR_SLOT_MASK);
1631  slot -= PAGE_DIR_SLOT_SIZE;
1632  UNIV_PREFETCH_RW(slot);
1633  }
1634 
1635  if (UNIV_UNLIKELY((offs & PAGE_ZIP_DIR_SLOT_MASK)
1636  < PAGE_ZIP_START + REC_N_NEW_EXTRA_BYTES)) {
1637  page_zip_fail(("page_zip_dir_decode 2: %u %u %lx\n",
1638  (unsigned) i, (unsigned) n_recs,
1639  (ulong) offs));
1640  return(FALSE);
1641  }
1642 
1643  recs[i] = page + (offs & PAGE_ZIP_DIR_SLOT_MASK);
1644  }
1645 
1646  mach_write_to_2(slot, PAGE_NEW_SUPREMUM);
1647  {
1648  const page_dir_slot_t* last_slot = page_dir_get_nth_slot(
1649  page, page_dir_get_n_slots(page) - 1);
1650 
1651  if (UNIV_UNLIKELY(slot != last_slot)) {
1652  page_zip_fail(("page_zip_dir_decode 3: %p != %p\n",
1653  (const void*) slot,
1654  (const void*) last_slot));
1655  return(FALSE);
1656  }
1657  }
1658 
1659  /* Copy the rest of the dense directory. */
1660  for (; i < n_dense; i++) {
1661  ulint offs = page_zip_dir_get(page_zip, i);
1662 
1663  if (UNIV_UNLIKELY(offs & ~PAGE_ZIP_DIR_SLOT_MASK)) {
1664  page_zip_fail(("page_zip_dir_decode 4: %u %u %lx\n",
1665  (unsigned) i, (unsigned) n_dense,
1666  (ulong) offs));
1667  return(FALSE);
1668  }
1669 
1670  recs[i] = page + offs;
1671  }
1672 
1673  if (UNIV_LIKELY(n_dense > 1)) {
1674  page_zip_dir_sort(recs, recs_aux, 0, n_dense);
1675  }
1676  return(TRUE);
1677 }
1678 
1679 /**********************************************************************/
1682 static
1683 ibool
1684 page_zip_set_extra_bytes(
1685 /*=====================*/
1686  const page_zip_des_t* page_zip,
1687  page_t* page,
1688  ulint info_bits)
1689 {
1690  ulint n;
1691  ulint i;
1692  ulint n_owned = 1;
1693  ulint offs;
1694  rec_t* rec;
1695 
1696  n = page_get_n_recs(page);
1697  rec = page + PAGE_NEW_INFIMUM;
1698 
1699  for (i = 0; i < n; i++) {
1700  offs = page_zip_dir_get(page_zip, i);
1701 
1702  if (UNIV_UNLIKELY(offs & PAGE_ZIP_DIR_SLOT_DEL)) {
1703  info_bits |= REC_INFO_DELETED_FLAG;
1704  }
1705  if (UNIV_UNLIKELY(offs & PAGE_ZIP_DIR_SLOT_OWNED)) {
1706  info_bits |= n_owned;
1707  n_owned = 1;
1708  } else {
1709  n_owned++;
1710  }
1711  offs &= PAGE_ZIP_DIR_SLOT_MASK;
1712  if (UNIV_UNLIKELY(offs < PAGE_ZIP_START
1713  + REC_N_NEW_EXTRA_BYTES)) {
1714  page_zip_fail(("page_zip_set_extra_bytes 1:"
1715  " %u %u %lx\n",
1716  (unsigned) i, (unsigned) n,
1717  (ulong) offs));
1718  return(FALSE);
1719  }
1720 
1721  rec_set_next_offs_new(rec, offs);
1722  rec = page + offs;
1723  rec[-REC_N_NEW_EXTRA_BYTES] = (byte) info_bits;
1724  info_bits = 0;
1725  }
1726 
1727  /* Set the next pointer of the last user record. */
1728  rec_set_next_offs_new(rec, PAGE_NEW_SUPREMUM);
1729 
1730  /* Set n_owned of the supremum record. */
1731  page[PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES] = (byte) n_owned;
1732 
1733  /* The dense directory excludes the infimum and supremum records. */
1734  n = page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW;
1735 
1736  if (i >= n) {
1737  if (UNIV_LIKELY(i == n)) {
1738  return(TRUE);
1739  }
1740 
1741  page_zip_fail(("page_zip_set_extra_bytes 2: %u != %u\n",
1742  (unsigned) i, (unsigned) n));
1743  return(FALSE);
1744  }
1745 
1746  offs = page_zip_dir_get(page_zip, i);
1747 
1748  /* Set the extra bytes of deleted records on the free list. */
1749  for (;;) {
1750  if (UNIV_UNLIKELY(!offs)
1751  || UNIV_UNLIKELY(offs & ~PAGE_ZIP_DIR_SLOT_MASK)) {
1752 
1753  page_zip_fail(("page_zip_set_extra_bytes 3: %lx\n",
1754  (ulong) offs));
1755  return(FALSE);
1756  }
1757 
1758  rec = page + offs;
1759  rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
1760 
1761  if (++i == n) {
1762  break;
1763  }
1764 
1765  offs = page_zip_dir_get(page_zip, i);
1766  rec_set_next_offs_new(rec, offs);
1767  }
1768 
1769  /* Terminate the free list. */
1770  rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
1771  rec_set_next_offs_new(rec, 0);
1772 
1773  return(TRUE);
1774 }
1775 
1776 /**********************************************************************/
1780 static
1781 const byte*
1782 page_zip_apply_log_ext(
1783 /*===================*/
1784  rec_t* rec,
1785  const ulint* offsets,
1786  ulint trx_id_col,
1787  const byte* data,
1788  const byte* end)
1789 {
1790  ulint i;
1791  ulint len;
1792  byte* next_out = rec;
1793 
1794  /* Check if there are any externally stored columns.
1795  For each externally stored column, skip the
1796  BTR_EXTERN_FIELD_REF. */
1797 
1798  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
1799  byte* dst;
1800 
1801  if (UNIV_UNLIKELY(i == trx_id_col)) {
1802  /* Skip trx_id and roll_ptr */
1803  dst = rec_get_nth_field(rec, offsets,
1804  i, &len);
1805  if (UNIV_UNLIKELY(dst - next_out >= end - data)
1806  || UNIV_UNLIKELY
1807  (len < (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN))
1808  || rec_offs_nth_extern(offsets, i)) {
1809  page_zip_fail(("page_zip_apply_log_ext:"
1810  " trx_id len %lu,"
1811  " %p - %p >= %p - %p\n",
1812  (ulong) len,
1813  (const void*) dst,
1814  (const void*) next_out,
1815  (const void*) end,
1816  (const void*) data));
1817  return(NULL);
1818  }
1819 
1820  memcpy(next_out, data, dst - next_out);
1821  data += dst - next_out;
1822  next_out = dst + (DATA_TRX_ID_LEN
1823  + DATA_ROLL_PTR_LEN);
1824  } else if (rec_offs_nth_extern(offsets, i)) {
1825  dst = rec_get_nth_field(rec, offsets,
1826  i, &len);
1827  ut_ad(len
1828  >= BTR_EXTERN_FIELD_REF_SIZE);
1829 
1830  len += dst - next_out
1832 
1833  if (UNIV_UNLIKELY(data + len >= end)) {
1834  page_zip_fail(("page_zip_apply_log_ext: "
1835  "ext %p+%lu >= %p\n",
1836  (const void*) data,
1837  (ulong) len,
1838  (const void*) end));
1839  return(NULL);
1840  }
1841 
1842  memcpy(next_out, data, len);
1843  data += len;
1844  next_out += len
1846  }
1847  }
1848 
1849  /* Copy the last bytes of the record. */
1850  len = rec_get_end(rec, offsets) - next_out;
1851  if (UNIV_UNLIKELY(data + len >= end)) {
1852  page_zip_fail(("page_zip_apply_log_ext: "
1853  "last %p+%lu >= %p\n",
1854  (const void*) data,
1855  (ulong) len,
1856  (const void*) end));
1857  return(NULL);
1858  }
1859  memcpy(next_out, data, len);
1860  data += len;
1861 
1862  return(data);
1863 }
1864 
1865 /**********************************************************************/
1869 static
1870 const byte*
1871 page_zip_apply_log(
1872 /*===============*/
1873  const byte* data,
1874  ulint size,
1875  rec_t** recs,
1878  ulint n_dense,
1879  ulint trx_id_col,
1881  ulint heap_status,
1884  dict_index_t* index,
1885  ulint* offsets)
1887 {
1888  const byte* const end = data + size;
1889 
1890  for (;;) {
1891  ulint val;
1892  rec_t* rec;
1893  ulint len;
1894  ulint hs;
1895 
1896  val = *data++;
1897  if (UNIV_UNLIKELY(!val)) {
1898  return(data - 1);
1899  }
1900  if (val & 0x80) {
1901  val = (val & 0x7f) << 8 | *data++;
1902  if (UNIV_UNLIKELY(!val)) {
1903  page_zip_fail(("page_zip_apply_log:"
1904  " invalid val %x%x\n",
1905  data[-2], data[-1]));
1906  return(NULL);
1907  }
1908  }
1909  if (UNIV_UNLIKELY(data >= end)) {
1910  page_zip_fail(("page_zip_apply_log: %p >= %p\n",
1911  (const void*) data,
1912  (const void*) end));
1913  return(NULL);
1914  }
1915  if (UNIV_UNLIKELY((val >> 1) > n_dense)) {
1916  page_zip_fail(("page_zip_apply_log: %lu>>1 > %lu\n",
1917  (ulong) val, (ulong) n_dense));
1918  return(NULL);
1919  }
1920 
1921  /* Determine the heap number and status bits of the record. */
1922  rec = recs[(val >> 1) - 1];
1923 
1924  hs = ((val >> 1) + 1) << REC_HEAP_NO_SHIFT;
1925  hs |= heap_status & ((1 << REC_HEAP_NO_SHIFT) - 1);
1926 
1927  /* This may either be an old record that is being
1928  overwritten (updated in place, or allocated from
1929  the free list), or a new record, with the next
1930  available_heap_no. */
1931  if (UNIV_UNLIKELY(hs > heap_status)) {
1932  page_zip_fail(("page_zip_apply_log: %lu > %lu\n",
1933  (ulong) hs, (ulong) heap_status));
1934  return(NULL);
1935  } else if (hs == heap_status) {
1936  /* A new record was allocated from the heap. */
1937  if (UNIV_UNLIKELY(val & 1)) {
1938  /* Only existing records may be cleared. */
1939  page_zip_fail(("page_zip_apply_log:"
1940  " attempting to create"
1941  " deleted rec %lu\n",
1942  (ulong) hs));
1943  return(NULL);
1944  }
1945  heap_status += 1 << REC_HEAP_NO_SHIFT;
1946  }
1947 
1948  mach_write_to_2(rec - REC_NEW_HEAP_NO, hs);
1949 
1950  if (val & 1) {
1951  /* Clear the data bytes of the record. */
1952  mem_heap_t* heap = NULL;
1953  ulint* offs;
1954  offs = rec_get_offsets(rec, index, offsets,
1955  ULINT_UNDEFINED, &heap);
1956  memset(rec, 0, rec_offs_data_size(offs));
1957 
1958  if (UNIV_LIKELY_NULL(heap)) {
1959  mem_heap_free(heap);
1960  }
1961  continue;
1962  }
1963 
1964 #if REC_STATUS_NODE_PTR != TRUE
1965 # error "REC_STATUS_NODE_PTR != TRUE"
1966 #endif
1967  rec_get_offsets_reverse(data, index,
1968  hs & REC_STATUS_NODE_PTR,
1969  offsets);
1970  rec_offs_make_valid(rec, index, offsets);
1971 
1972  /* Copy the extra bytes (backwards). */
1973  {
1974  byte* start = rec_get_start(rec, offsets);
1975  byte* b = rec - REC_N_NEW_EXTRA_BYTES;
1976  while (b != start) {
1977  *--b = *data++;
1978  }
1979  }
1980 
1981  /* Copy the data bytes. */
1982  if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
1983  /* Non-leaf nodes should not contain any
1984  externally stored columns. */
1985  if (UNIV_UNLIKELY(hs & REC_STATUS_NODE_PTR)) {
1986  page_zip_fail(("page_zip_apply_log: "
1987  "%lu&REC_STATUS_NODE_PTR\n",
1988  (ulong) hs));
1989  return(NULL);
1990  }
1991 
1992  data = page_zip_apply_log_ext(
1993  rec, offsets, trx_id_col, data, end);
1994 
1995  if (UNIV_UNLIKELY(!data)) {
1996  return(NULL);
1997  }
1998  } else if (UNIV_UNLIKELY(hs & REC_STATUS_NODE_PTR)) {
1999  len = rec_offs_data_size(offsets)
2000  - REC_NODE_PTR_SIZE;
2001  /* Copy the data bytes, except node_ptr. */
2002  if (UNIV_UNLIKELY(data + len >= end)) {
2003  page_zip_fail(("page_zip_apply_log: "
2004  "node_ptr %p+%lu >= %p\n",
2005  (const void*) data,
2006  (ulong) len,
2007  (const void*) end));
2008  return(NULL);
2009  }
2010  memcpy(rec, data, len);
2011  data += len;
2012  } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
2013  len = rec_offs_data_size(offsets);
2014 
2015  /* Copy all data bytes of
2016  a record in a secondary index. */
2017  if (UNIV_UNLIKELY(data + len >= end)) {
2018  page_zip_fail(("page_zip_apply_log: "
2019  "sec %p+%lu >= %p\n",
2020  (const void*) data,
2021  (ulong) len,
2022  (const void*) end));
2023  return(NULL);
2024  }
2025 
2026  memcpy(rec, data, len);
2027  data += len;
2028  } else {
2029  /* Skip DB_TRX_ID and DB_ROLL_PTR. */
2030  ulint l = rec_get_nth_field_offs(offsets,
2031  trx_id_col, &len);
2032  byte* b;
2033 
2034  if (UNIV_UNLIKELY(data + l >= end)
2035  || UNIV_UNLIKELY(len < (DATA_TRX_ID_LEN
2036  + DATA_ROLL_PTR_LEN))) {
2037  page_zip_fail(("page_zip_apply_log: "
2038  "trx_id %p+%lu >= %p\n",
2039  (const void*) data,
2040  (ulong) l,
2041  (const void*) end));
2042  return(NULL);
2043  }
2044 
2045  /* Copy any preceding data bytes. */
2046  memcpy(rec, data, l);
2047  data += l;
2048 
2049  /* Copy any bytes following DB_TRX_ID, DB_ROLL_PTR. */
2050  b = rec + l + (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2051  len = rec_get_end(rec, offsets) - b;
2052  if (UNIV_UNLIKELY(data + len >= end)) {
2053  page_zip_fail(("page_zip_apply_log: "
2054  "clust %p+%lu >= %p\n",
2055  (const void*) data,
2056  (ulong) len,
2057  (const void*) end));
2058  return(NULL);
2059  }
2060  memcpy(b, data, len);
2061  data += len;
2062  }
2063  }
2064 }
2065 
2066 /**********************************************************************/
2069 static
2070 ibool
2071 page_zip_decompress_node_ptrs(
2072 /*==========================*/
2073  page_zip_des_t* page_zip,
2074  z_stream* d_stream,
2075  rec_t** recs,
2077  ulint n_dense,
2078  dict_index_t* index,
2079  ulint* offsets,
2080  mem_heap_t* heap)
2081 {
2082  ulint heap_status = REC_STATUS_NODE_PTR
2083  | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
2084  ulint slot;
2085  const byte* storage;
2086 
2087  /* Subtract the space reserved for uncompressed data. */
2088  d_stream->avail_in -= n_dense
2089  * (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
2090 
2091  /* Decompress the records in heap_no order. */
2092  for (slot = 0; slot < n_dense; slot++) {
2093  rec_t* rec = recs[slot];
2094 
2095  d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
2096  - d_stream->next_out;
2097 
2098  ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
2099  - PAGE_ZIP_START - PAGE_DIR);
2100  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2101  case Z_STREAM_END:
2102  /* Apparently, n_dense has grown
2103  since the time the page was last compressed. */
2104  goto zlib_done;
2105  case Z_OK:
2106  case Z_BUF_ERROR:
2107  if (!d_stream->avail_out) {
2108  break;
2109  }
2110  /* fall through */
2111  default:
2112  page_zip_fail(("page_zip_decompress_node_ptrs:"
2113  " 1 inflate(Z_SYNC_FLUSH)=%s\n",
2114  d_stream->msg));
2115  goto zlib_error;
2116  }
2117 
2118  ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
2119  /* Prepare to decompress the data bytes. */
2120  d_stream->next_out = rec;
2121  /* Set heap_no and the status bits. */
2122  mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
2123  heap_status += 1 << REC_HEAP_NO_SHIFT;
2124 
2125  /* Read the offsets. The status bits are needed here. */
2126  offsets = rec_get_offsets(rec, index, offsets,
2127  ULINT_UNDEFINED, &heap);
2128 
2129  /* Non-leaf nodes should not have any externally
2130  stored columns. */
2131  ut_ad(!rec_offs_any_extern(offsets));
2132 
2133  /* Decompress the data bytes, except node_ptr. */
2134  d_stream->avail_out = rec_offs_data_size(offsets)
2135  - REC_NODE_PTR_SIZE;
2136 
2137  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2138  case Z_STREAM_END:
2139  goto zlib_done;
2140  case Z_OK:
2141  case Z_BUF_ERROR:
2142  if (!d_stream->avail_out) {
2143  break;
2144  }
2145  /* fall through */
2146  default:
2147  page_zip_fail(("page_zip_decompress_node_ptrs:"
2148  " 2 inflate(Z_SYNC_FLUSH)=%s\n",
2149  d_stream->msg));
2150  goto zlib_error;
2151  }
2152 
2153  /* Clear the node pointer in case the record
2154  will be deleted and the space will be reallocated
2155  to a smaller record. */
2156  memset(d_stream->next_out, 0, REC_NODE_PTR_SIZE);
2157  d_stream->next_out += REC_NODE_PTR_SIZE;
2158 
2159  ut_ad(d_stream->next_out == rec_get_end(rec, offsets));
2160  }
2161 
2162  /* Decompress any trailing garbage, in case the last record was
2163  allocated from an originally longer space on the free list. */
2164  d_stream->avail_out = page_header_get_field(page_zip->data,
2165  PAGE_HEAP_TOP)
2166  - page_offset(d_stream->next_out);
2167  if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
2168  - PAGE_ZIP_START - PAGE_DIR)) {
2169 
2170  page_zip_fail(("page_zip_decompress_node_ptrs:"
2171  " avail_out = %u\n",
2172  d_stream->avail_out));
2173  goto zlib_error;
2174  }
2175 
2176  if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
2177  page_zip_fail(("page_zip_decompress_node_ptrs:"
2178  " inflate(Z_FINISH)=%s\n",
2179  d_stream->msg));
2180 zlib_error:
2181  inflateEnd(d_stream);
2182  return(FALSE);
2183  }
2184 
2185  /* Note that d_stream->avail_out > 0 may hold here
2186  if the modification log is nonempty. */
2187 
2188 zlib_done:
2189  if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
2190  ut_error;
2191  }
2192 
2193  {
2194  page_t* page = page_align(d_stream->next_out);
2195 
2196  /* Clear the unused heap space on the uncompressed page. */
2197  memset(d_stream->next_out, 0,
2198  page_dir_get_nth_slot(page,
2199  page_dir_get_n_slots(page) - 1)
2200  - d_stream->next_out);
2201  }
2202 
2203 #ifdef UNIV_DEBUG
2204  page_zip->m_start = PAGE_DATA + d_stream->total_in;
2205 #endif /* UNIV_DEBUG */
2206 
2207  /* Apply the modification log. */
2208  {
2209  const byte* mod_log_ptr;
2210  mod_log_ptr = page_zip_apply_log(d_stream->next_in,
2211  d_stream->avail_in + 1,
2212  recs, n_dense,
2213  ULINT_UNDEFINED, heap_status,
2214  index, offsets);
2215 
2216  if (UNIV_UNLIKELY(!mod_log_ptr)) {
2217  return(FALSE);
2218  }
2219  page_zip->m_end = mod_log_ptr - page_zip->data;
2220  page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
2221  }
2222 
2223  if (UNIV_UNLIKELY
2224  (page_zip_get_trailer_len(page_zip,
2225  dict_index_is_clust(index), NULL)
2226  + page_zip->m_end >= page_zip_get_size(page_zip))) {
2227  page_zip_fail(("page_zip_decompress_node_ptrs:"
2228  " %lu + %lu >= %lu, %lu\n",
2229  (ulong) page_zip_get_trailer_len(
2230  page_zip, dict_index_is_clust(index),
2231  NULL),
2232  (ulong) page_zip->m_end,
2233  (ulong) page_zip_get_size(page_zip),
2234  (ulong) dict_index_is_clust(index)));
2235  return(FALSE);
2236  }
2237 
2238  /* Restore the uncompressed columns in heap_no order. */
2239  storage = page_zip->data + page_zip_get_size(page_zip)
2240  - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
2241 
2242  for (slot = 0; slot < n_dense; slot++) {
2243  rec_t* rec = recs[slot];
2244 
2245  offsets = rec_get_offsets(rec, index, offsets,
2246  ULINT_UNDEFINED, &heap);
2247  /* Non-leaf nodes should not have any externally
2248  stored columns. */
2249  ut_ad(!rec_offs_any_extern(offsets));
2250  storage -= REC_NODE_PTR_SIZE;
2251 
2252  memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
2253  storage, REC_NODE_PTR_SIZE);
2254  }
2255 
2256  return(TRUE);
2257 }
2258 
2259 /**********************************************************************/
2262 static
2263 ibool
2264 page_zip_decompress_sec(
2265 /*====================*/
2266  page_zip_des_t* page_zip,
2267  z_stream* d_stream,
2268  rec_t** recs,
2270  ulint n_dense,
2271  dict_index_t* index,
2272  ulint* offsets)
2273 {
2274  ulint heap_status = REC_STATUS_ORDINARY
2275  | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
2276  ulint slot;
2277 
2278  ut_a(!dict_index_is_clust(index));
2279 
2280  /* Subtract the space reserved for uncompressed data. */
2281  d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
2282 
2283  for (slot = 0; slot < n_dense; slot++) {
2284  rec_t* rec = recs[slot];
2285 
2286  /* Decompress everything up to this record. */
2287  d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
2288  - d_stream->next_out;
2289 
2290  if (UNIV_LIKELY(d_stream->avail_out)) {
2291  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2292  case Z_STREAM_END:
2293  /* Apparently, n_dense has grown
2294  since the time the page was last compressed. */
2295  goto zlib_done;
2296  case Z_OK:
2297  case Z_BUF_ERROR:
2298  if (!d_stream->avail_out) {
2299  break;
2300  }
2301  /* fall through */
2302  default:
2303  page_zip_fail(("page_zip_decompress_sec:"
2304  " inflate(Z_SYNC_FLUSH)=%s\n",
2305  d_stream->msg));
2306  goto zlib_error;
2307  }
2308  }
2309 
2310  ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
2311 
2312  /* Skip the REC_N_NEW_EXTRA_BYTES. */
2313 
2314  d_stream->next_out = rec;
2315 
2316  /* Set heap_no and the status bits. */
2317  mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
2318  heap_status += 1 << REC_HEAP_NO_SHIFT;
2319  }
2320 
2321  /* Decompress the data of the last record and any trailing garbage,
2322  in case the last record was allocated from an originally longer space
2323  on the free list. */
2324  d_stream->avail_out = page_header_get_field(page_zip->data,
2325  PAGE_HEAP_TOP)
2326  - page_offset(d_stream->next_out);
2327  if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
2328  - PAGE_ZIP_START - PAGE_DIR)) {
2329 
2330  page_zip_fail(("page_zip_decompress_sec:"
2331  " avail_out = %u\n",
2332  d_stream->avail_out));
2333  goto zlib_error;
2334  }
2335 
2336  if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
2337  page_zip_fail(("page_zip_decompress_sec:"
2338  " inflate(Z_FINISH)=%s\n",
2339  d_stream->msg));
2340 zlib_error:
2341  inflateEnd(d_stream);
2342  return(FALSE);
2343  }
2344 
2345  /* Note that d_stream->avail_out > 0 may hold here
2346  if the modification log is nonempty. */
2347 
2348 zlib_done:
2349  if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
2350  ut_error;
2351  }
2352 
2353  {
2354  page_t* page = page_align(d_stream->next_out);
2355 
2356  /* Clear the unused heap space on the uncompressed page. */
2357  memset(d_stream->next_out, 0,
2358  page_dir_get_nth_slot(page,
2359  page_dir_get_n_slots(page) - 1)
2360  - d_stream->next_out);
2361  }
2362 
2363 #ifdef UNIV_DEBUG
2364  page_zip->m_start = PAGE_DATA + d_stream->total_in;
2365 #endif /* UNIV_DEBUG */
2366 
2367  /* Apply the modification log. */
2368  {
2369  const byte* mod_log_ptr;
2370  mod_log_ptr = page_zip_apply_log(d_stream->next_in,
2371  d_stream->avail_in + 1,
2372  recs, n_dense,
2373  ULINT_UNDEFINED, heap_status,
2374  index, offsets);
2375 
2376  if (UNIV_UNLIKELY(!mod_log_ptr)) {
2377  return(FALSE);
2378  }
2379  page_zip->m_end = mod_log_ptr - page_zip->data;
2380  page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
2381  }
2382 
2383  if (UNIV_UNLIKELY(page_zip_get_trailer_len(page_zip, FALSE, NULL)
2384  + page_zip->m_end >= page_zip_get_size(page_zip))) {
2385 
2386  page_zip_fail(("page_zip_decompress_sec: %lu + %lu >= %lu\n",
2387  (ulong) page_zip_get_trailer_len(
2388  page_zip, FALSE, NULL),
2389  (ulong) page_zip->m_end,
2390  (ulong) page_zip_get_size(page_zip)));
2391  return(FALSE);
2392  }
2393 
2394  /* There are no uncompressed columns on leaf pages of
2395  secondary indexes. */
2396 
2397  return(TRUE);
2398 }
2399 
2400 /**********************************************************************/
2404 static
2405 ibool
2406 page_zip_decompress_clust_ext(
2407 /*==========================*/
2408  z_stream* d_stream,
2409  rec_t* rec,
2410  const ulint* offsets,
2411  ulint trx_id_col)
2412 {
2413  ulint i;
2414 
2415  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
2416  ulint len;
2417  byte* dst;
2418 
2419  if (UNIV_UNLIKELY(i == trx_id_col)) {
2420  /* Skip trx_id and roll_ptr */
2421  dst = rec_get_nth_field(rec, offsets, i, &len);
2422  if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
2423  + DATA_ROLL_PTR_LEN)) {
2424 
2425  page_zip_fail(("page_zip_decompress_clust_ext:"
2426  " len[%lu] = %lu\n",
2427  (ulong) i, (ulong) len));
2428  return(FALSE);
2429  }
2430 
2431  if (rec_offs_nth_extern(offsets, i)) {
2432 
2433  page_zip_fail(("page_zip_decompress_clust_ext:"
2434  " DB_TRX_ID at %lu is ext\n",
2435  (ulong) i));
2436  return(FALSE);
2437  }
2438 
2439  d_stream->avail_out = dst - d_stream->next_out;
2440 
2441  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2442  case Z_STREAM_END:
2443  case Z_OK:
2444  case Z_BUF_ERROR:
2445  if (!d_stream->avail_out) {
2446  break;
2447  }
2448  /* fall through */
2449  default:
2450  page_zip_fail(("page_zip_decompress_clust_ext:"
2451  " 1 inflate(Z_SYNC_FLUSH)=%s\n",
2452  d_stream->msg));
2453  return(FALSE);
2454  }
2455 
2456  ut_ad(d_stream->next_out == dst);
2457 
2458  /* Clear DB_TRX_ID and DB_ROLL_PTR in order to
2459  avoid uninitialized bytes in case the record
2460  is affected by page_zip_apply_log(). */
2461  memset(dst, 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2462 
2463  d_stream->next_out += DATA_TRX_ID_LEN
2464  + DATA_ROLL_PTR_LEN;
2465  } else if (rec_offs_nth_extern(offsets, i)) {
2466  dst = rec_get_nth_field(rec, offsets, i, &len);
2467  ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
2468  dst += len - BTR_EXTERN_FIELD_REF_SIZE;
2469 
2470  d_stream->avail_out = dst - d_stream->next_out;
2471  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2472  case Z_STREAM_END:
2473  case Z_OK:
2474  case Z_BUF_ERROR:
2475  if (!d_stream->avail_out) {
2476  break;
2477  }
2478  /* fall through */
2479  default:
2480  page_zip_fail(("page_zip_decompress_clust_ext:"
2481  " 2 inflate(Z_SYNC_FLUSH)=%s\n",
2482  d_stream->msg));
2483  return(FALSE);
2484  }
2485 
2486  ut_ad(d_stream->next_out == dst);
2487 
2488  /* Clear the BLOB pointer in case
2489  the record will be deleted and the
2490  space will not be reused. Note that
2491  the final initialization of the BLOB
2492  pointers (copying from "externs"
2493  or clearing) will have to take place
2494  only after the page modification log
2495  has been applied. Otherwise, we
2496  could end up with an uninitialized
2497  BLOB pointer when a record is deleted,
2498  reallocated and deleted. */
2499  memset(d_stream->next_out, 0,
2500  BTR_EXTERN_FIELD_REF_SIZE);
2501  d_stream->next_out
2503  }
2504  }
2505 
2506  return(TRUE);
2507 }
2508 
2509 /**********************************************************************/
2512 static
2513 ibool
2514 page_zip_decompress_clust(
2515 /*======================*/
2516  page_zip_des_t* page_zip,
2517  z_stream* d_stream,
2518  rec_t** recs,
2520  ulint n_dense,
2521  dict_index_t* index,
2522  ulint trx_id_col,
2523  ulint* offsets,
2524  mem_heap_t* heap)
2525 {
2526  int err;
2527  ulint slot;
2528  ulint heap_status = REC_STATUS_ORDINARY
2529  | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
2530  const byte* storage;
2531  const byte* externs;
2532 
2533  ut_a(dict_index_is_clust(index));
2534 
2535  /* Subtract the space reserved for uncompressed data. */
2536  d_stream->avail_in -= n_dense * (PAGE_ZIP_DIR_SLOT_SIZE
2537  + DATA_TRX_ID_LEN
2538  + DATA_ROLL_PTR_LEN);
2539 
2540  /* Decompress the records in heap_no order. */
2541  for (slot = 0; slot < n_dense; slot++) {
2542  rec_t* rec = recs[slot];
2543 
2544  d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
2545  - d_stream->next_out;
2546 
2547  ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
2548  - PAGE_ZIP_START - PAGE_DIR);
2549  err = inflate(d_stream, Z_SYNC_FLUSH);
2550  switch (err) {
2551  case Z_STREAM_END:
2552  /* Apparently, n_dense has grown
2553  since the time the page was last compressed. */
2554  goto zlib_done;
2555  case Z_OK:
2556  case Z_BUF_ERROR:
2557  if (UNIV_LIKELY(!d_stream->avail_out)) {
2558  break;
2559  }
2560  /* fall through */
2561  default:
2562  page_zip_fail(("page_zip_decompress_clust:"
2563  " 1 inflate(Z_SYNC_FLUSH)=%s\n",
2564  d_stream->msg));
2565  goto zlib_error;
2566  }
2567 
2568  ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
2569  /* Prepare to decompress the data bytes. */
2570  d_stream->next_out = rec;
2571  /* Set heap_no and the status bits. */
2572  mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
2573  heap_status += 1 << REC_HEAP_NO_SHIFT;
2574 
2575  /* Read the offsets. The status bits are needed here. */
2576  offsets = rec_get_offsets(rec, index, offsets,
2577  ULINT_UNDEFINED, &heap);
2578 
2579  /* This is a leaf page in a clustered index. */
2580 
2581  /* Check if there are any externally stored columns.
2582  For each externally stored column, restore the
2583  BTR_EXTERN_FIELD_REF separately. */
2584 
2585  if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
2586  if (UNIV_UNLIKELY
2587  (!page_zip_decompress_clust_ext(
2588  d_stream, rec, offsets, trx_id_col))) {
2589 
2590  goto zlib_error;
2591  }
2592  } else {
2593  /* Skip trx_id and roll_ptr */
2594  ulint len;
2595  byte* dst = rec_get_nth_field(rec, offsets,
2596  trx_id_col, &len);
2597  if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
2598  + DATA_ROLL_PTR_LEN)) {
2599 
2600  page_zip_fail(("page_zip_decompress_clust:"
2601  " len = %lu\n", (ulong) len));
2602  goto zlib_error;
2603  }
2604 
2605  d_stream->avail_out = dst - d_stream->next_out;
2606 
2607  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2608  case Z_STREAM_END:
2609  case Z_OK:
2610  case Z_BUF_ERROR:
2611  if (!d_stream->avail_out) {
2612  break;
2613  }
2614  /* fall through */
2615  default:
2616  page_zip_fail(("page_zip_decompress_clust:"
2617  " 2 inflate(Z_SYNC_FLUSH)=%s\n",
2618  d_stream->msg));
2619  goto zlib_error;
2620  }
2621 
2622  ut_ad(d_stream->next_out == dst);
2623 
2624  /* Clear DB_TRX_ID and DB_ROLL_PTR in order to
2625  avoid uninitialized bytes in case the record
2626  is affected by page_zip_apply_log(). */
2627  memset(dst, 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2628 
2629  d_stream->next_out += DATA_TRX_ID_LEN
2630  + DATA_ROLL_PTR_LEN;
2631  }
2632 
2633  /* Decompress the last bytes of the record. */
2634  d_stream->avail_out = rec_get_end(rec, offsets)
2635  - d_stream->next_out;
2636 
2637  switch (inflate(d_stream, Z_SYNC_FLUSH)) {
2638  case Z_STREAM_END:
2639  case Z_OK:
2640  case Z_BUF_ERROR:
2641  if (!d_stream->avail_out) {
2642  break;
2643  }
2644  /* fall through */
2645  default:
2646  page_zip_fail(("page_zip_decompress_clust:"
2647  " 3 inflate(Z_SYNC_FLUSH)=%s\n",
2648  d_stream->msg));
2649  goto zlib_error;
2650  }
2651  }
2652 
2653  /* Decompress any trailing garbage, in case the last record was
2654  allocated from an originally longer space on the free list. */
2655  d_stream->avail_out = page_header_get_field(page_zip->data,
2656  PAGE_HEAP_TOP)
2657  - page_offset(d_stream->next_out);
2658  if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
2659  - PAGE_ZIP_START - PAGE_DIR)) {
2660 
2661  page_zip_fail(("page_zip_decompress_clust:"
2662  " avail_out = %u\n",
2663  d_stream->avail_out));
2664  goto zlib_error;
2665  }
2666 
2667  if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
2668  page_zip_fail(("page_zip_decompress_clust:"
2669  " inflate(Z_FINISH)=%s\n",
2670  d_stream->msg));
2671 zlib_error:
2672  inflateEnd(d_stream);
2673  return(FALSE);
2674  }
2675 
2676  /* Note that d_stream->avail_out > 0 may hold here
2677  if the modification log is nonempty. */
2678 
2679 zlib_done:
2680  if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
2681  ut_error;
2682  }
2683 
2684  {
2685  page_t* page = page_align(d_stream->next_out);
2686 
2687  /* Clear the unused heap space on the uncompressed page. */
2688  memset(d_stream->next_out, 0,
2689  page_dir_get_nth_slot(page,
2690  page_dir_get_n_slots(page) - 1)
2691  - d_stream->next_out);
2692  }
2693 
2694 #ifdef UNIV_DEBUG
2695  page_zip->m_start = PAGE_DATA + d_stream->total_in;
2696 #endif /* UNIV_DEBUG */
2697 
2698  /* Apply the modification log. */
2699  {
2700  const byte* mod_log_ptr;
2701  mod_log_ptr = page_zip_apply_log(d_stream->next_in,
2702  d_stream->avail_in + 1,
2703  recs, n_dense,
2704  trx_id_col, heap_status,
2705  index, offsets);
2706 
2707  if (UNIV_UNLIKELY(!mod_log_ptr)) {
2708  return(FALSE);
2709  }
2710  page_zip->m_end = mod_log_ptr - page_zip->data;
2711  page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
2712  }
2713 
2714  if (UNIV_UNLIKELY(page_zip_get_trailer_len(page_zip, TRUE, NULL)
2715  + page_zip->m_end >= page_zip_get_size(page_zip))) {
2716 
2717  page_zip_fail(("page_zip_decompress_clust: %lu + %lu >= %lu\n",
2718  (ulong) page_zip_get_trailer_len(
2719  page_zip, TRUE, NULL),
2720  (ulong) page_zip->m_end,
2721  (ulong) page_zip_get_size(page_zip)));
2722  return(FALSE);
2723  }
2724 
2725  storage = page_zip->data + page_zip_get_size(page_zip)
2726  - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
2727 
2728  externs = storage - n_dense
2729  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2730 
2731  /* Restore the uncompressed columns in heap_no order. */
2732 
2733  for (slot = 0; slot < n_dense; slot++) {
2734  ulint i;
2735  ulint len;
2736  byte* dst;
2737  rec_t* rec = recs[slot];
2738  ibool exists = !page_zip_dir_find_free(
2739  page_zip, page_offset(rec));
2740  offsets = rec_get_offsets(rec, index, offsets,
2741  ULINT_UNDEFINED, &heap);
2742 
2743  dst = rec_get_nth_field(rec, offsets,
2744  trx_id_col, &len);
2745  ut_ad(len >= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2746  storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
2747  memcpy(dst, storage,
2748  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
2749 
2750  /* Check if there are any externally stored
2751  columns in this record. For each externally
2752  stored column, restore or clear the
2753  BTR_EXTERN_FIELD_REF. */
2754  if (!rec_offs_any_extern(offsets)) {
2755  continue;
2756  }
2757 
2758  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
2759  if (!rec_offs_nth_extern(offsets, i)) {
2760  continue;
2761  }
2762  dst = rec_get_nth_field(rec, offsets, i, &len);
2763 
2764  if (UNIV_UNLIKELY(len < BTR_EXTERN_FIELD_REF_SIZE)) {
2765  page_zip_fail(("page_zip_decompress_clust:"
2766  " %lu < 20\n",
2767  (ulong) len));
2768  return(FALSE);
2769  }
2770 
2771  dst += len - BTR_EXTERN_FIELD_REF_SIZE;
2772 
2773  if (UNIV_LIKELY(exists)) {
2774  /* Existing record:
2775  restore the BLOB pointer */
2776  externs -= BTR_EXTERN_FIELD_REF_SIZE;
2777 
2778  if (UNIV_UNLIKELY
2779  (externs < page_zip->data
2780  + page_zip->m_end)) {
2781  page_zip_fail(("page_zip_"
2782  "decompress_clust: "
2783  "%p < %p + %lu\n",
2784  (const void*) externs,
2785  (const void*)
2786  page_zip->data,
2787  (ulong)
2788  page_zip->m_end));
2789  return(FALSE);
2790  }
2791 
2792  memcpy(dst, externs,
2793  BTR_EXTERN_FIELD_REF_SIZE);
2794 
2795  page_zip->n_blobs++;
2796  } else {
2797  /* Deleted record:
2798  clear the BLOB pointer */
2799  memset(dst, 0,
2800  BTR_EXTERN_FIELD_REF_SIZE);
2801  }
2802  }
2803  }
2804 
2805  return(TRUE);
2806 }
2807 
2808 /**********************************************************************/
2813 UNIV_INTERN
2814 ibool
2816 /*================*/
2817  page_zip_des_t* page_zip,
2819  page_t* page,
2820  ibool all)
2824 {
2825  z_stream d_stream;
2826  dict_index_t* index = NULL;
2827  rec_t** recs;
2828  ulint n_dense;/* number of user records on the page */
2829  ulint trx_id_col = ULINT_UNDEFINED;
2830  mem_heap_t* heap;
2831  ulint* offsets;
2832 #ifndef UNIV_HOTBACKUP
2833  ullint usec = ut_time_us(NULL);
2834 #endif /* !UNIV_HOTBACKUP */
2835 
2836  ut_ad(page_zip_simple_validate(page_zip));
2837  UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE);
2838  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
2839 
2840  /* The dense directory excludes the infimum and supremum records. */
2841  n_dense = page_dir_get_n_heap(page_zip->data) - PAGE_HEAP_NO_USER_LOW;
2842  if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE
2843  >= page_zip_get_size(page_zip))) {
2844  page_zip_fail(("page_zip_decompress 1: %lu %lu\n",
2845  (ulong) n_dense,
2846  (ulong) page_zip_get_size(page_zip)));
2847  return(FALSE);
2848  }
2849 
2850  heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE);
2851  recs = static_cast<byte **>(mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)));
2852 
2853  if (all) {
2854  /* Copy the page header. */
2855  memcpy(page, page_zip->data, PAGE_DATA);
2856  } else {
2857  /* Check that the bytes that we skip are identical. */
2858 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
2859  ut_a(!memcmp(FIL_PAGE_TYPE + page,
2860  FIL_PAGE_TYPE + page_zip->data,
2861  PAGE_HEADER - FIL_PAGE_TYPE));
2862  ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page,
2863  PAGE_HEADER + PAGE_LEVEL + page_zip->data,
2864  PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL)));
2865 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
2866 
2867  /* Copy the mutable parts of the page header. */
2868  memcpy(page, page_zip->data, FIL_PAGE_TYPE);
2869  memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data,
2870  PAGE_LEVEL - PAGE_N_DIR_SLOTS);
2871 
2872 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
2873  /* Check that the page headers match after copying. */
2874  ut_a(!memcmp(page, page_zip->data, PAGE_DATA));
2875 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
2876  }
2877 
2878 #ifdef UNIV_ZIP_DEBUG
2879  /* Clear the uncompressed page, except the header. */
2880  memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA);
2881 #endif /* UNIV_ZIP_DEBUG */
2882  UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA);
2883 
2884  /* Copy the page directory. */
2885  if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
2886  recs + n_dense, n_dense))) {
2887 zlib_error:
2888  mem_heap_free(heap);
2889  return(FALSE);
2890  }
2891 
2892  /* Copy the infimum and supremum records. */
2893  memcpy(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES),
2894  infimum_extra, sizeof infimum_extra);
2895  if (UNIV_UNLIKELY(!page_get_n_recs(page))) {
2896  rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
2897  PAGE_NEW_SUPREMUM);
2898  } else {
2899  rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
2900  page_zip_dir_get(page_zip, 0)
2901  & PAGE_ZIP_DIR_SLOT_MASK);
2902  }
2903  memcpy(page + PAGE_NEW_INFIMUM, infimum_data, sizeof infimum_data);
2904  memcpy(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
2905  supremum_extra_data, sizeof supremum_extra_data);
2906 
2907  page_zip_set_alloc(&d_stream, heap);
2908 
2909  d_stream.next_in = page_zip->data + PAGE_DATA;
2910  /* Subtract the space reserved for
2911  the page header and the end marker of the modification log. */
2912  d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1);
2913  d_stream.next_out = page + PAGE_ZIP_START;
2914  d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
2915 
2916  if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT)
2917  != Z_OK)) {
2918  ut_error;
2919  }
2920 
2921  /* Decode the zlib header and the index information. */
2922  if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
2923 
2924  page_zip_fail(("page_zip_decompress:"
2925  " 1 inflate(Z_BLOCK)=%s\n", d_stream.msg));
2926  goto zlib_error;
2927  }
2928 
2929  if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
2930 
2931  page_zip_fail(("page_zip_decompress:"
2932  " 2 inflate(Z_BLOCK)=%s\n", d_stream.msg));
2933  goto zlib_error;
2934  }
2935 
2936  index = page_zip_fields_decode(
2937  page + PAGE_ZIP_START, d_stream.next_out,
2938  page_is_leaf(page) ? &trx_id_col : NULL);
2939 
2940  if (UNIV_UNLIKELY(!index)) {
2941 
2942  goto zlib_error;
2943  }
2944 
2945  /* Decompress the user records. */
2946  page_zip->n_blobs = 0;
2947  d_stream.next_out = page + PAGE_ZIP_START;
2948 
2949  {
2950  /* Pre-allocate the offsets for rec_get_offsets_reverse(). */
2951  ulint n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
2952  + dict_index_get_n_fields(index);
2953  offsets = static_cast<unsigned long *>(mem_heap_alloc(heap, n * sizeof(ulint)));
2954  *offsets = n;
2955  }
2956 
2957  /* Decompress the records in heap_no order. */
2958  if (!page_is_leaf(page)) {
2959  /* This is a node pointer page. */
2960  ulint info_bits;
2961 
2962  if (UNIV_UNLIKELY
2963  (!page_zip_decompress_node_ptrs(page_zip, &d_stream,
2964  recs, n_dense, index,
2965  offsets, heap))) {
2966  goto err_exit;
2967  }
2968 
2969  info_bits = mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL
2970  ? REC_INFO_MIN_REC_FLAG : 0;
2971 
2972  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
2973  info_bits))) {
2974  goto err_exit;
2975  }
2976  } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
2977  /* This is a leaf page in a secondary index. */
2978  if (UNIV_UNLIKELY(!page_zip_decompress_sec(page_zip, &d_stream,
2979  recs, n_dense,
2980  index, offsets))) {
2981  goto err_exit;
2982  }
2983 
2984  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
2985  page, 0))) {
2986 err_exit:
2987  page_zip_fields_free(index);
2988  mem_heap_free(heap);
2989  return(FALSE);
2990  }
2991  } else {
2992  /* This is a leaf page in a clustered index. */
2993  if (UNIV_UNLIKELY(!page_zip_decompress_clust(page_zip,
2994  &d_stream, recs,
2995  n_dense, index,
2996  trx_id_col,
2997  offsets, heap))) {
2998  goto err_exit;
2999  }
3000 
3001  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
3002  page, 0))) {
3003  goto err_exit;
3004  }
3005  }
3006 
3007  ut_a(page_is_comp(page));
3008  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
3009 
3010  page_zip_fields_free(index);
3011  mem_heap_free(heap);
3012 #ifndef UNIV_HOTBACKUP
3013  {
3014  page_zip_stat_t* zip_stat
3015  = &page_zip_stat[page_zip->ssize - 1];
3016  zip_stat->decompressed++;
3017  zip_stat->decompressed_usec += ut_time_us(NULL) - usec;
3018  }
3019 #endif /* !UNIV_HOTBACKUP */
3020 
3021  /* Update the stat counter for LRU policy. */
3023 
3024  return(TRUE);
3025 }
3026 
3027 #ifdef UNIV_ZIP_DEBUG
3028 /**********************************************************************/
3030 static
3031 void
3032 page_zip_hexdump_func(
3033 /*==================*/
3034  const char* name,
3035  const void* buf,
3036  ulint size)
3037 {
3038  const byte* s = buf;
3039  ulint addr;
3040  const ulint width = 32; /* bytes per line */
3041 
3042  fprintf(stderr, "%s:\n", name);
3043 
3044  for (addr = 0; addr < size; addr += width) {
3045  ulint i;
3046 
3047  fprintf(stderr, "%04lx ", (ulong) addr);
3048 
3049  i = ut_min(width, size - addr);
3050 
3051  while (i--) {
3052  fprintf(stderr, "%02x", *s++);
3053  }
3054 
3055  putc('\n', stderr);
3056  }
3057 }
3058 
3062 #define page_zip_hexdump(buf, size) page_zip_hexdump_func(#buf, buf, size)
3063 
3065 UNIV_INTERN ibool page_zip_validate_header_only = FALSE;
3066 
3067 /**********************************************************************/
3070 UNIV_INTERN
3071 ibool
3072 page_zip_validate_low(
3073 /*==================*/
3074  const page_zip_des_t* page_zip,
3075  const page_t* page,
3076  ibool sloppy)
3078 {
3079  page_zip_des_t temp_page_zip;
3080  byte* temp_page_buf;
3081  page_t* temp_page;
3082  ibool valid;
3083 
3084  if (memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
3086  || memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE, 2)
3087  || memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
3088  PAGE_DATA - FIL_PAGE_DATA)) {
3089  page_zip_fail(("page_zip_validate: page header\n"));
3090  page_zip_hexdump(page_zip, sizeof *page_zip);
3091  page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
3092  page_zip_hexdump(page, UNIV_PAGE_SIZE);
3093  return(FALSE);
3094  }
3095 
3096  ut_a(page_is_comp(page));
3097 
3098  if (page_zip_validate_header_only) {
3099  return(TRUE);
3100  }
3101 
3102  /* page_zip_decompress() expects the uncompressed page to be
3103  UNIV_PAGE_SIZE aligned. */
3104  temp_page_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
3105  temp_page = ut_align(temp_page_buf, UNIV_PAGE_SIZE);
3106 
3107 #ifdef UNIV_DEBUG_VALGRIND
3108  /* Get detailed information on the valid bits in case the
3109  UNIV_MEM_ASSERT_RW() checks fail. The v-bits of page[],
3110  page_zip->data[] or page_zip could be viewed at temp_page[] or
3111  temp_page_zip in a debugger when running valgrind --db-attach. */
3112  VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE);
3113  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
3114 # if UNIV_WORD_SIZE == 4
3115  VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip);
3116  /* On 32-bit systems, there is no padding in page_zip_des_t.
3117  On other systems, Valgrind could complain about uninitialized
3118  pad bytes. */
3119  UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip);
3120 # endif
3121  VALGRIND_GET_VBITS(page_zip->data, temp_page,
3122  page_zip_get_size(page_zip));
3123  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3124 #endif /* UNIV_DEBUG_VALGRIND */
3125 
3126  temp_page_zip = *page_zip;
3127  valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE);
3128  if (!valid) {
3129  fputs("page_zip_validate(): failed to decompress\n", stderr);
3130  goto func_exit;
3131  }
3132  if (page_zip->n_blobs != temp_page_zip.n_blobs) {
3133  page_zip_fail(("page_zip_validate: n_blobs: %u!=%u\n",
3134  page_zip->n_blobs, temp_page_zip.n_blobs));
3135  valid = FALSE;
3136  }
3137 #ifdef UNIV_DEBUG
3138  if (page_zip->m_start != temp_page_zip.m_start) {
3139  page_zip_fail(("page_zip_validate: m_start: %u!=%u\n",
3140  page_zip->m_start, temp_page_zip.m_start));
3141  valid = FALSE;
3142  }
3143 #endif /* UNIV_DEBUG */
3144  if (page_zip->m_end != temp_page_zip.m_end) {
3145  page_zip_fail(("page_zip_validate: m_end: %u!=%u\n",
3146  page_zip->m_end, temp_page_zip.m_end));
3147  valid = FALSE;
3148  }
3149  if (page_zip->m_nonempty != temp_page_zip.m_nonempty) {
3150  page_zip_fail(("page_zip_validate(): m_nonempty: %u!=%u\n",
3151  page_zip->m_nonempty,
3152  temp_page_zip.m_nonempty));
3153  valid = FALSE;
3154  }
3155  if (memcmp(page + PAGE_HEADER, temp_page + PAGE_HEADER,
3156  UNIV_PAGE_SIZE - PAGE_HEADER - FIL_PAGE_DATA_END)) {
3157 
3158  /* In crash recovery, the "minimum record" flag may be
3159  set incorrectly until the mini-transaction is
3160  committed. Let us tolerate that difference when we
3161  are performing a sloppy validation. */
3162 
3163  if (sloppy) {
3164  byte info_bits_diff;
3165  ulint offset
3166  = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
3167  TRUE);
3168  ut_a(offset >= PAGE_NEW_SUPREMUM);
3169  offset -= 5 /* REC_NEW_INFO_BITS */;
3170 
3171  info_bits_diff = page[offset] ^ temp_page[offset];
3172 
3173  if (info_bits_diff == REC_INFO_MIN_REC_FLAG) {
3174  temp_page[offset] = page[offset];
3175 
3176  if (!memcmp(page + PAGE_HEADER,
3177  temp_page + PAGE_HEADER,
3178  UNIV_PAGE_SIZE - PAGE_HEADER
3179  - FIL_PAGE_DATA_END)) {
3180 
3181  /* Only the minimum record flag
3182  differed. Let us ignore it. */
3183  page_zip_fail(("page_zip_validate: "
3184  "min_rec_flag "
3185  "(ignored, "
3186  "%lu,%lu,0x%02lx)\n",
3187  page_get_space_id(page),
3188  page_get_page_no(page),
3189  (ulong) page[offset]));
3190  goto func_exit;
3191  }
3192  }
3193  }
3194  page_zip_fail(("page_zip_validate: content\n"));
3195  valid = FALSE;
3196  }
3197 
3198 func_exit:
3199  if (!valid) {
3200  page_zip_hexdump(page_zip, sizeof *page_zip);
3201  page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
3202  page_zip_hexdump(page, UNIV_PAGE_SIZE);
3203  page_zip_hexdump(temp_page, UNIV_PAGE_SIZE);
3204  }
3205  ut_free(temp_page_buf);
3206  return(valid);
3207 }
3208 
3209 /**********************************************************************/
3212 UNIV_INTERN
3213 ibool
3214 page_zip_validate(
3215 /*==============*/
3216  const page_zip_des_t* page_zip,
3217  const page_t* page)
3218 {
3219  return(page_zip_validate_low(page_zip, page,
3220  recv_recovery_is_on()));
3221 }
3222 #endif /* UNIV_ZIP_DEBUG */
3223 
3224 #ifdef UNIV_DEBUG
3225 /**********************************************************************/
3228 static
3229 ibool
3230 page_zip_header_cmp(
3231 /*================*/
3232  const page_zip_des_t* page_zip,
3233  const byte* page)
3234 {
3235  ut_ad(!memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
3237  ut_ad(!memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE,
3238  2));
3239  ut_ad(!memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
3240  PAGE_DATA - FIL_PAGE_DATA));
3241 
3242  return(TRUE);
3243 }
3244 #endif /* UNIV_DEBUG */
3245 
3246 /**********************************************************************/
3250 static
3251 byte*
3252 page_zip_write_rec_ext(
3253 /*===================*/
3254  page_zip_des_t* page_zip,
3255  const page_t* page,
3256  const byte* rec,
3257  dict_index_t* index,
3258  const ulint* offsets,
3259  ulint create,
3260  ulint trx_id_col,
3261  ulint heap_no,
3262  byte* storage,
3263  byte* data)
3264 {
3265  const byte* start = rec;
3266  ulint i;
3267  ulint len;
3268  byte* externs = storage;
3269  ulint n_ext = rec_offs_n_extern(offsets);
3270 
3271  ut_ad(rec_offs_validate(rec, index, offsets));
3272  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3273  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3274  rec_offs_extra_size(offsets));
3275 
3276  externs -= (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3277  * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW);
3278 
3279  /* Note that this will not take into account
3280  the BLOB columns of rec if create==TRUE. */
3281  ut_ad(data + rec_offs_data_size(offsets)
3282  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3283  - n_ext * BTR_EXTERN_FIELD_REF_SIZE
3284  < externs - BTR_EXTERN_FIELD_REF_SIZE * page_zip->n_blobs);
3285 
3286  {
3287  ulint blob_no = page_zip_get_n_prev_extern(
3288  page_zip, rec, index);
3289  byte* ext_end = externs - page_zip->n_blobs
3291  ut_ad(blob_no <= page_zip->n_blobs);
3292  externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
3293 
3294  if (create) {
3295  page_zip->n_blobs += n_ext;
3296  ASSERT_ZERO_BLOB(ext_end - n_ext
3297  * BTR_EXTERN_FIELD_REF_SIZE);
3298  memmove(ext_end - n_ext
3299  * BTR_EXTERN_FIELD_REF_SIZE,
3300  ext_end,
3301  externs - ext_end);
3302  }
3303 
3304  ut_a(blob_no + n_ext <= page_zip->n_blobs);
3305  }
3306 
3307  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
3308  const byte* src;
3309 
3310  if (UNIV_UNLIKELY(i == trx_id_col)) {
3311  ut_ad(!rec_offs_nth_extern(offsets,
3312  i));
3313  ut_ad(!rec_offs_nth_extern(offsets,
3314  i + 1));
3315  /* Locate trx_id and roll_ptr. */
3316  src = rec_get_nth_field(rec, offsets,
3317  i, &len);
3318  ut_ad(len == DATA_TRX_ID_LEN);
3319  ut_ad(src + DATA_TRX_ID_LEN
3320  == rec_get_nth_field(
3321  rec, offsets,
3322  i + 1, &len));
3323  ut_ad(len == DATA_ROLL_PTR_LEN);
3324 
3325  /* Log the preceding fields. */
3326  ASSERT_ZERO(data, src - start);
3327  memcpy(data, start, src - start);
3328  data += src - start;
3329  start = src + (DATA_TRX_ID_LEN
3330  + DATA_ROLL_PTR_LEN);
3331 
3332  /* Store trx_id and roll_ptr. */
3333  memcpy(storage - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3334  * (heap_no - 1),
3335  src, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3336  i++; /* skip also roll_ptr */
3337  } else if (rec_offs_nth_extern(offsets, i)) {
3338  src = rec_get_nth_field(rec, offsets,
3339  i, &len);
3340 
3341  ut_ad(dict_index_is_clust(index));
3342  ut_ad(len
3343  >= BTR_EXTERN_FIELD_REF_SIZE);
3344  src += len - BTR_EXTERN_FIELD_REF_SIZE;
3345 
3346  ASSERT_ZERO(data, src - start);
3347  memcpy(data, start, src - start);
3348  data += src - start;
3349  start = src + BTR_EXTERN_FIELD_REF_SIZE;
3350 
3351  /* Store the BLOB pointer. */
3352  externs -= BTR_EXTERN_FIELD_REF_SIZE;
3353  ut_ad(data < externs);
3354  memcpy(externs, src, BTR_EXTERN_FIELD_REF_SIZE);
3355  }
3356  }
3357 
3358  /* Log the last bytes of the record. */
3359  len = rec_offs_data_size(offsets) - (start - rec);
3360 
3361  ASSERT_ZERO(data, len);
3362  memcpy(data, start, len);
3363  data += len;
3364 
3365  return(data);
3366 }
3367 
3368 /**********************************************************************/
3371 UNIV_INTERN
3372 void
3374 /*===============*/
3375  page_zip_des_t* page_zip,
3376  const byte* rec,
3377  dict_index_t* index,
3378  const ulint* offsets,
3379  ulint create)
3380 {
3381  const page_t* page;
3382  byte* data;
3383  byte* storage;
3384  ulint heap_no;
3385  byte* slot;
3386 
3387  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3388  ut_ad(page_zip_simple_validate(page_zip));
3389  ut_ad(page_zip_get_size(page_zip)
3390  > PAGE_DATA + page_zip_dir_size(page_zip));
3391  ut_ad(rec_offs_comp(offsets));
3392  ut_ad(rec_offs_validate(rec, index, offsets));
3393 
3394  ut_ad(page_zip->m_start >= PAGE_DATA);
3395 
3396  page = page_align(rec);
3397 
3398  ut_ad(page_zip_header_cmp(page_zip, page));
3400 
3401  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3402  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3403  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3404  rec_offs_extra_size(offsets));
3405 
3406  slot = page_zip_dir_find(page_zip, page_offset(rec));
3407  ut_a(slot);
3408  /* Copy the delete mark. */
3409  if (rec_get_deleted_flag(rec, TRUE)) {
3410  *slot |= PAGE_ZIP_DIR_SLOT_DEL >> 8;
3411  } else {
3412  *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
3413  }
3414 
3415  ut_ad(rec_get_start((rec_t*) rec, offsets) >= page + PAGE_ZIP_START);
3416  ut_ad(rec_get_end((rec_t*) rec, offsets) <= page + UNIV_PAGE_SIZE
3417  - PAGE_DIR - PAGE_DIR_SLOT_SIZE
3418  * page_dir_get_n_slots(page));
3419 
3420  heap_no = rec_get_heap_no_new(rec);
3421  ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW); /* not infimum or supremum */
3422  ut_ad(heap_no < page_dir_get_n_heap(page));
3423 
3424  /* Append to the modification log. */
3425  data = page_zip->data + page_zip->m_end;
3426  ut_ad(!*data);
3427 
3428  /* Identify the record by writing its heap number - 1.
3429  0 is reserved to indicate the end of the modification log. */
3430 
3431  if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
3432  *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
3433  ut_ad(!*data);
3434  }
3435  *data++ = (byte) ((heap_no - 1) << 1);
3436  ut_ad(!*data);
3437 
3438  {
3439  const byte* start = rec - rec_offs_extra_size(offsets);
3440  const byte* b = rec - REC_N_NEW_EXTRA_BYTES;
3441 
3442  /* Write the extra bytes backwards, so that
3443  rec_offs_extra_size() can be easily computed in
3444  page_zip_apply_log() by invoking
3445  rec_get_offsets_reverse(). */
3446 
3447  while (b != start) {
3448  *data++ = *--b;
3449  ut_ad(!*data);
3450  }
3451  }
3452 
3453  /* Write the data bytes. Store the uncompressed bytes separately. */
3454  storage = page_zip->data + page_zip_get_size(page_zip)
3455  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3456  * PAGE_ZIP_DIR_SLOT_SIZE;
3457 
3458  if (page_is_leaf(page)) {
3459  ulint len;
3460 
3461  if (dict_index_is_clust(index)) {
3462  ulint trx_id_col;
3463 
3464  trx_id_col = dict_index_get_sys_col_pos(index,
3465  DATA_TRX_ID);
3466  ut_ad(trx_id_col != ULINT_UNDEFINED);
3467 
3468  /* Store separately trx_id, roll_ptr and
3469  the BTR_EXTERN_FIELD_REF of each BLOB column. */
3470  if (rec_offs_any_extern(offsets)) {
3471  data = page_zip_write_rec_ext(
3472  page_zip, page,
3473  rec, index, offsets, create,
3474  trx_id_col, heap_no, storage, data);
3475  } else {
3476  /* Locate trx_id and roll_ptr. */
3477  const byte* src
3478  = rec_get_nth_field(rec, offsets,
3479  trx_id_col, &len);
3480  ut_ad(len == DATA_TRX_ID_LEN);
3481  ut_ad(src + DATA_TRX_ID_LEN
3482  == rec_get_nth_field(
3483  rec, offsets,
3484  trx_id_col + 1, &len));
3485  ut_ad(len == DATA_ROLL_PTR_LEN);
3486 
3487  /* Log the preceding fields. */
3488  ASSERT_ZERO(data, src - rec);
3489  memcpy(data, rec, src - rec);
3490  data += src - rec;
3491 
3492  /* Store trx_id and roll_ptr. */
3493  memcpy(storage
3494  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3495  * (heap_no - 1),
3496  src,
3497  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3498 
3499  src += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
3500 
3501  /* Log the last bytes of the record. */
3502  len = rec_offs_data_size(offsets)
3503  - (src - rec);
3504 
3505  ASSERT_ZERO(data, len);
3506  memcpy(data, src, len);
3507  data += len;
3508  }
3509  } else {
3510  /* Leaf page of a secondary index:
3511  no externally stored columns */
3512  ut_ad(dict_index_get_sys_col_pos(index, DATA_TRX_ID)
3513  == ULINT_UNDEFINED);
3514  ut_ad(!rec_offs_any_extern(offsets));
3515 
3516  /* Log the entire record. */
3517  len = rec_offs_data_size(offsets);
3518 
3519  ASSERT_ZERO(data, len);
3520  memcpy(data, rec, len);
3521  data += len;
3522  }
3523  } else {
3524  /* This is a node pointer page. */
3525  ulint len;
3526 
3527  /* Non-leaf nodes should not have any externally
3528  stored columns. */
3529  ut_ad(!rec_offs_any_extern(offsets));
3530 
3531  /* Copy the data bytes, except node_ptr. */
3532  len = rec_offs_data_size(offsets) - REC_NODE_PTR_SIZE;
3533  ut_ad(data + len < storage - REC_NODE_PTR_SIZE
3534  * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW));
3535  ASSERT_ZERO(data, len);
3536  memcpy(data, rec, len);
3537  data += len;
3538 
3539  /* Copy the node pointer to the uncompressed area. */
3540  memcpy(storage - REC_NODE_PTR_SIZE
3541  * (heap_no - 1),
3542  rec + len,
3543  REC_NODE_PTR_SIZE);
3544  }
3545 
3546  ut_a(!*data);
3547  ut_ad((ulint) (data - page_zip->data) < page_zip_get_size(page_zip));
3548  page_zip->m_end = data - page_zip->data;
3549  page_zip->m_nonempty = TRUE;
3550 
3551 #ifdef UNIV_ZIP_DEBUG
3552  ut_a(page_zip_validate(page_zip, page_align(rec)));
3553 #endif /* UNIV_ZIP_DEBUG */
3554 }
3555 
3556 /***********************************************************/
3559 UNIV_INTERN
3560 byte*
3562 /*==========================*/
3563  byte* ptr,
3564  byte* end_ptr,
3565  page_t* page,
3566  page_zip_des_t* page_zip)
3567 {
3568  ulint offset;
3569  ulint z_offset;
3570 
3571  ut_ad(!page == !page_zip);
3572 
3573  if (UNIV_UNLIKELY
3574  (end_ptr < ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE))) {
3575 
3576  return(NULL);
3577  }
3578 
3579  offset = mach_read_from_2(ptr);
3580  z_offset = mach_read_from_2(ptr + 2);
3581 
3582  if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
3583  || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
3584  || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
3585 corrupt:
3586  recv_sys->found_corrupt_log = TRUE;
3587 
3588  return(NULL);
3589  }
3590 
3591  if (page) {
3592  if (UNIV_UNLIKELY(!page_zip)
3593  || UNIV_UNLIKELY(!page_is_leaf(page))) {
3594 
3595  goto corrupt;
3596  }
3597 
3598 #ifdef UNIV_ZIP_DEBUG
3599  ut_a(page_zip_validate(page_zip, page));
3600 #endif /* UNIV_ZIP_DEBUG */
3601 
3602  memcpy(page + offset,
3603  ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
3604  memcpy(page_zip->data + z_offset,
3605  ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
3606 
3607 #ifdef UNIV_ZIP_DEBUG
3608  ut_a(page_zip_validate(page_zip, page));
3609 #endif /* UNIV_ZIP_DEBUG */
3610  }
3611 
3612  return(ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE));
3613 }
3614 
3615 /**********************************************************************/
3618 UNIV_INTERN
3619 void
3621 /*====================*/
3622  page_zip_des_t* page_zip,
3623  const byte* rec,
3625  dict_index_t* index,
3626  const ulint* offsets,
3627  ulint n,
3628  mtr_t* mtr)
3630 {
3631  const byte* field;
3632  byte* externs;
3633  const page_t* page = page_align(rec);
3634  ulint blob_no;
3635  ulint len;
3636 
3637  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3639  ut_ad(page_zip_simple_validate(page_zip));
3640  ut_ad(page_zip_get_size(page_zip)
3641  > PAGE_DATA + page_zip_dir_size(page_zip));
3642  ut_ad(rec_offs_comp(offsets));
3643  ut_ad(rec_offs_validate(rec, NULL, offsets));
3644  ut_ad(rec_offs_any_extern(offsets));
3645  ut_ad(rec_offs_nth_extern(offsets, n));
3646 
3647  ut_ad(page_zip->m_start >= PAGE_DATA);
3648  ut_ad(page_zip_header_cmp(page_zip, page));
3649 
3650  ut_ad(page_is_leaf(page));
3651  ut_ad(dict_index_is_clust(index));
3652 
3653  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3654  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3655  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3656  rec_offs_extra_size(offsets));
3657 
3658  blob_no = page_zip_get_n_prev_extern(page_zip, rec, index)
3659  + rec_get_n_extern_new(rec, index, n);
3660  ut_a(blob_no < page_zip->n_blobs);
3661 
3662  externs = page_zip->data + page_zip_get_size(page_zip)
3663  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3664  * (PAGE_ZIP_DIR_SLOT_SIZE
3665  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3666 
3667  field = rec_get_nth_field(rec, offsets, n, &len);
3668 
3669  externs -= (blob_no + 1) * BTR_EXTERN_FIELD_REF_SIZE;
3670  field += len - BTR_EXTERN_FIELD_REF_SIZE;
3671 
3672  memcpy(externs, field, BTR_EXTERN_FIELD_REF_SIZE);
3673 
3674 #ifdef UNIV_ZIP_DEBUG
3675  ut_a(page_zip_validate(page_zip, page));
3676 #endif /* UNIV_ZIP_DEBUG */
3677 
3678  if (mtr) {
3679 #ifndef UNIV_HOTBACKUP
3680  byte* log_ptr = mlog_open(
3681  mtr, 11 + 2 + 2 + BTR_EXTERN_FIELD_REF_SIZE);
3682  if (UNIV_UNLIKELY(!log_ptr)) {
3683  return;
3684  }
3685 
3687  (byte*) field, MLOG_ZIP_WRITE_BLOB_PTR, log_ptr, mtr);
3688  mach_write_to_2(log_ptr, page_offset(field));
3689  log_ptr += 2;
3690  mach_write_to_2(log_ptr, externs - page_zip->data);
3691  log_ptr += 2;
3692  memcpy(log_ptr, externs, BTR_EXTERN_FIELD_REF_SIZE);
3693  log_ptr += BTR_EXTERN_FIELD_REF_SIZE;
3694  mlog_close(mtr, log_ptr);
3695 #endif /* !UNIV_HOTBACKUP */
3696  }
3697 }
3698 
3699 /***********************************************************/
3702 UNIV_INTERN
3703 byte*
3705 /*==========================*/
3706  byte* ptr,
3707  byte* end_ptr,
3708  page_t* page,
3709  page_zip_des_t* page_zip)
3710 {
3711  ulint offset;
3712  ulint z_offset;
3713 
3714  ut_ad(!page == !page_zip);
3715 
3716  if (UNIV_UNLIKELY(end_ptr < ptr + (2 + 2 + REC_NODE_PTR_SIZE))) {
3717 
3718  return(NULL);
3719  }
3720 
3721  offset = mach_read_from_2(ptr);
3722  z_offset = mach_read_from_2(ptr + 2);
3723 
3724  if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
3725  || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
3726  || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
3727 corrupt:
3728  recv_sys->found_corrupt_log = TRUE;
3729 
3730  return(NULL);
3731  }
3732 
3733  if (page) {
3734  byte* storage_end;
3735  byte* field;
3736  byte* storage;
3737  ulint heap_no;
3738 
3739  if (UNIV_UNLIKELY(!page_zip)
3740  || UNIV_UNLIKELY(page_is_leaf(page))) {
3741 
3742  goto corrupt;
3743  }
3744 
3745 #ifdef UNIV_ZIP_DEBUG
3746  ut_a(page_zip_validate(page_zip, page));
3747 #endif /* UNIV_ZIP_DEBUG */
3748 
3749  field = page + offset;
3750  storage = page_zip->data + z_offset;
3751 
3752  storage_end = page_zip->data + page_zip_get_size(page_zip)
3753  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3754  * PAGE_ZIP_DIR_SLOT_SIZE;
3755 
3756  heap_no = 1 + (storage_end - storage) / REC_NODE_PTR_SIZE;
3757 
3758  if (UNIV_UNLIKELY((storage_end - storage) % REC_NODE_PTR_SIZE)
3759  || UNIV_UNLIKELY(heap_no < PAGE_HEAP_NO_USER_LOW)
3760  || UNIV_UNLIKELY(heap_no >= page_dir_get_n_heap(page))) {
3761 
3762  goto corrupt;
3763  }
3764 
3765  memcpy(field, ptr + 4, REC_NODE_PTR_SIZE);
3766  memcpy(storage, ptr + 4, REC_NODE_PTR_SIZE);
3767 
3768 #ifdef UNIV_ZIP_DEBUG
3769  ut_a(page_zip_validate(page_zip, page));
3770 #endif /* UNIV_ZIP_DEBUG */
3771  }
3772 
3773  return(ptr + (2 + 2 + REC_NODE_PTR_SIZE));
3774 }
3775 
3776 /**********************************************************************/
3778 UNIV_INTERN
3779 void
3781 /*====================*/
3782  page_zip_des_t* page_zip,
3783  byte* rec,
3784  ulint size,
3785  ulint ptr,
3786  mtr_t* mtr)
3787 {
3788  byte* field;
3789  byte* storage;
3790  page_t* page = page_align(rec);
3791 
3792  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3794  ut_ad(page_zip_simple_validate(page_zip));
3795  ut_ad(page_zip_get_size(page_zip)
3796  > PAGE_DATA + page_zip_dir_size(page_zip));
3797  ut_ad(page_rec_is_comp(rec));
3798 
3799  ut_ad(page_zip->m_start >= PAGE_DATA);
3800  ut_ad(page_zip_header_cmp(page_zip, page));
3801 
3802  ut_ad(!page_is_leaf(page));
3803 
3804  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3805  UNIV_MEM_ASSERT_RW(rec, size);
3806 
3807  storage = page_zip->data + page_zip_get_size(page_zip)
3808  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3809  * PAGE_ZIP_DIR_SLOT_SIZE
3810  - (rec_get_heap_no_new(rec) - 1) * REC_NODE_PTR_SIZE;
3811  field = rec + size - REC_NODE_PTR_SIZE;
3812 
3813 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
3814  ut_a(!memcmp(storage, field, REC_NODE_PTR_SIZE));
3815 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
3816 #if REC_NODE_PTR_SIZE != 4
3817 # error "REC_NODE_PTR_SIZE != 4"
3818 #endif
3819  mach_write_to_4(field, ptr);
3820  memcpy(storage, field, REC_NODE_PTR_SIZE);
3821 
3822  if (mtr) {
3823 #ifndef UNIV_HOTBACKUP
3824  byte* log_ptr = mlog_open(mtr,
3825  11 + 2 + 2 + REC_NODE_PTR_SIZE);
3826  if (UNIV_UNLIKELY(!log_ptr)) {
3827  return;
3828  }
3829 
3831  field, MLOG_ZIP_WRITE_NODE_PTR, log_ptr, mtr);
3832  mach_write_to_2(log_ptr, page_offset(field));
3833  log_ptr += 2;
3834  mach_write_to_2(log_ptr, storage - page_zip->data);
3835  log_ptr += 2;
3836  memcpy(log_ptr, field, REC_NODE_PTR_SIZE);
3837  log_ptr += REC_NODE_PTR_SIZE;
3838  mlog_close(mtr, log_ptr);
3839 #endif /* !UNIV_HOTBACKUP */
3840  }
3841 }
3842 
3843 /**********************************************************************/
3845 UNIV_INTERN
3846 void
3848 /*===============================*/
3849  page_zip_des_t* page_zip,
3850  byte* rec,
3851  const ulint* offsets,
3852  ulint trx_id_col,
3853  trx_id_t trx_id,
3854  roll_ptr_t roll_ptr)
3855 {
3856  byte* field;
3857  byte* storage;
3858  page_t* page = page_align(rec);
3859  ulint len;
3860 
3861  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3863  ut_ad(page_zip_simple_validate(page_zip));
3864  ut_ad(page_zip_get_size(page_zip)
3865  > PAGE_DATA + page_zip_dir_size(page_zip));
3866  ut_ad(rec_offs_validate(rec, NULL, offsets));
3867  ut_ad(rec_offs_comp(offsets));
3868 
3869  ut_ad(page_zip->m_start >= PAGE_DATA);
3870  ut_ad(page_zip_header_cmp(page_zip, page));
3871 
3872  ut_ad(page_is_leaf(page));
3873 
3874  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3875 
3876  storage = page_zip->data + page_zip_get_size(page_zip)
3877  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3878  * PAGE_ZIP_DIR_SLOT_SIZE
3879  - (rec_get_heap_no_new(rec) - 1)
3880  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3881 
3882 #if DATA_TRX_ID + 1 != DATA_ROLL_PTR
3883 # error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
3884 #endif
3885  field = rec_get_nth_field(rec, offsets, trx_id_col, &len);
3886  ut_ad(len == DATA_TRX_ID_LEN);
3887  ut_ad(field + DATA_TRX_ID_LEN
3888  == rec_get_nth_field(rec, offsets, trx_id_col + 1, &len));
3889  ut_ad(len == DATA_ROLL_PTR_LEN);
3890 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
3891  ut_a(!memcmp(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN));
3892 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
3893 #if DATA_TRX_ID_LEN != 6
3894 # error "DATA_TRX_ID_LEN != 6"
3895 #endif
3896  mach_write_to_6(field, trx_id);
3897 #if DATA_ROLL_PTR_LEN != 7
3898 # error "DATA_ROLL_PTR_LEN != 7"
3899 #endif
3900  mach_write_to_7(field + DATA_TRX_ID_LEN, roll_ptr);
3901  memcpy(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3902 
3903  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3904  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3905  rec_offs_extra_size(offsets));
3906  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3907 }
3908 
3909 #ifdef UNIV_ZIP_DEBUG
3910 
3915 UNIV_INTERN ibool page_zip_clear_rec_disable;
3916 #endif /* UNIV_ZIP_DEBUG */
3917 
3918 /**********************************************************************/
3920 static
3921 void
3922 page_zip_clear_rec(
3923 /*===============*/
3924  page_zip_des_t* page_zip,
3925  byte* rec,
3926  dict_index_t* index,
3927  const ulint* offsets)
3928 {
3929  ulint heap_no;
3930  page_t* page = page_align(rec);
3931  /* page_zip_validate() would fail here if a record
3932  containing externally stored columns is being deleted. */
3933  ut_ad(rec_offs_validate(rec, index, offsets));
3934  ut_ad(!page_zip_dir_find(page_zip, page_offset(rec)));
3935  ut_ad(page_zip_dir_find_free(page_zip, page_offset(rec)));
3936  ut_ad(page_zip_header_cmp(page_zip, page));
3937 
3938  heap_no = rec_get_heap_no_new(rec);
3939  ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW);
3940 
3941  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3942  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3943  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3944  rec_offs_extra_size(offsets));
3945 
3946  if (
3947 #ifdef UNIV_ZIP_DEBUG
3948  !page_zip_clear_rec_disable &&
3949 #endif /* UNIV_ZIP_DEBUG */
3950  page_zip->m_end
3951  + 1 + ((heap_no - 1) >= 64)/* size of the log entry */
3952  + page_zip_get_trailer_len(page_zip,
3953  dict_index_is_clust(index), NULL)
3954  < page_zip_get_size(page_zip)) {
3955  byte* data;
3956 
3957  /* Clear only the data bytes, because the allocator and
3958  the decompressor depend on the extra bytes. */
3959  memset(rec, 0, rec_offs_data_size(offsets));
3960 
3961  if (!page_is_leaf(page)) {
3962  /* Clear node_ptr on the compressed page. */
3963  byte* storage = page_zip->data
3964  + page_zip_get_size(page_zip)
3965  - (page_dir_get_n_heap(page)
3966  - PAGE_HEAP_NO_USER_LOW)
3967  * PAGE_ZIP_DIR_SLOT_SIZE;
3968 
3969  memset(storage - (heap_no - 1) * REC_NODE_PTR_SIZE,
3970  0, REC_NODE_PTR_SIZE);
3971  } else if (dict_index_is_clust(index)) {
3972  /* Clear trx_id and roll_ptr on the compressed page. */
3973  byte* storage = page_zip->data
3974  + page_zip_get_size(page_zip)
3975  - (page_dir_get_n_heap(page)
3976  - PAGE_HEAP_NO_USER_LOW)
3977  * PAGE_ZIP_DIR_SLOT_SIZE;
3978 
3979  memset(storage - (heap_no - 1)
3980  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
3981  0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3982  }
3983 
3984  /* Log that the data was zeroed out. */
3985  data = page_zip->data + page_zip->m_end;
3986  ut_ad(!*data);
3987  if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
3988  *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
3989  ut_ad(!*data);
3990  }
3991  *data++ = (byte) ((heap_no - 1) << 1 | 1);
3992  ut_ad(!*data);
3993  ut_ad((ulint) (data - page_zip->data)
3994  < page_zip_get_size(page_zip));
3995  page_zip->m_end = data - page_zip->data;
3996  page_zip->m_nonempty = TRUE;
3997  } else if (page_is_leaf(page) && dict_index_is_clust(index)) {
3998  /* Do not clear the record, because there is not enough space
3999  to log the operation. */
4000 
4001  if (rec_offs_any_extern(offsets)) {
4002  ulint i;
4003 
4004  for (i = rec_offs_n_fields(offsets); i--; ) {
4005  /* Clear all BLOB pointers in order to make
4006  page_zip_validate() pass. */
4007  if (rec_offs_nth_extern(offsets, i)) {
4008  ulint len;
4009  byte* field = rec_get_nth_field(
4010  rec, offsets, i, &len);
4011  memset(field + len
4012  - BTR_EXTERN_FIELD_REF_SIZE,
4013  0, BTR_EXTERN_FIELD_REF_SIZE);
4014  }
4015  }
4016  }
4017  }
4018 
4019 #ifdef UNIV_ZIP_DEBUG
4020  ut_a(page_zip_validate(page_zip, page));
4021 #endif /* UNIV_ZIP_DEBUG */
4022 }
4023 
4024 /**********************************************************************/
4027 UNIV_INTERN
4028 void
4030 /*=====================*/
4031  page_zip_des_t* page_zip,
4032  const byte* rec,
4033  ulint flag)
4034 {
4035  byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
4036  ut_a(slot);
4037  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4038  if (flag) {
4039  *slot |= (PAGE_ZIP_DIR_SLOT_DEL >> 8);
4040  } else {
4041  *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
4042  }
4043 #ifdef UNIV_ZIP_DEBUG
4044  ut_a(page_zip_validate(page_zip, page_align(rec)));
4045 #endif /* UNIV_ZIP_DEBUG */
4046 }
4047 
4048 /**********************************************************************/
4051 UNIV_INTERN
4052 void
4054 /*===================*/
4055  page_zip_des_t* page_zip,
4056  const byte* rec,
4057  ulint flag)
4058 {
4059  byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
4060  ut_a(slot);
4061  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4062  if (flag) {
4063  *slot |= (PAGE_ZIP_DIR_SLOT_OWNED >> 8);
4064  } else {
4065  *slot &= ~(PAGE_ZIP_DIR_SLOT_OWNED >> 8);
4066  }
4067 }
4068 
4069 /**********************************************************************/
4071 UNIV_INTERN
4072 void
4074 /*================*/
4075  page_zip_des_t* page_zip,
4076  const byte* prev_rec,
4077  const byte* free_rec,
4079  byte* rec)
4080 {
4081  ulint n_dense;
4082  byte* slot_rec;
4083  byte* slot_free;
4084 
4085  ut_ad(prev_rec != rec);
4086  ut_ad(page_rec_get_next((rec_t*) prev_rec) == rec);
4087  ut_ad(page_zip_simple_validate(page_zip));
4088 
4089  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4090 
4091  if (page_rec_is_infimum(prev_rec)) {
4092  /* Use the first slot. */
4093  slot_rec = page_zip->data + page_zip_get_size(page_zip);
4094  } else {
4095  byte* end = page_zip->data + page_zip_get_size(page_zip);
4096  byte* start = end - page_zip_dir_user_size(page_zip);
4097 
4098  if (UNIV_LIKELY(!free_rec)) {
4099  /* PAGE_N_RECS was already incremented
4100  in page_cur_insert_rec_zip(), but the
4101  dense directory slot at that position
4102  contains garbage. Skip it. */
4103  start += PAGE_ZIP_DIR_SLOT_SIZE;
4104  }
4105 
4106  slot_rec = page_zip_dir_find_low(start, end,
4107  page_offset(prev_rec));
4108  ut_a(slot_rec);
4109  }
4110 
4111  /* Read the old n_dense (n_heap may have been incremented). */
4112  n_dense = page_dir_get_n_heap(page_zip->data)
4113  - (PAGE_HEAP_NO_USER_LOW + 1);
4114 
4115  if (UNIV_LIKELY_NULL(free_rec)) {
4116  /* The record was allocated from the free list.
4117  Shift the dense directory only up to that slot.
4118  Note that in this case, n_dense is actually
4119  off by one, because page_cur_insert_rec_zip()
4120  did not increment n_heap. */
4121  ut_ad(rec_get_heap_no_new(rec) < n_dense + 1
4122  + PAGE_HEAP_NO_USER_LOW);
4123  ut_ad(rec >= free_rec);
4124  slot_free = page_zip_dir_find(page_zip, page_offset(free_rec));
4125  ut_ad(slot_free);
4126  slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
4127  } else {
4128  /* The record was allocated from the heap.
4129  Shift the entire dense directory. */
4130  ut_ad(rec_get_heap_no_new(rec) == n_dense
4131  + PAGE_HEAP_NO_USER_LOW);
4132 
4133  /* Shift to the end of the dense page directory. */
4134  slot_free = page_zip->data + page_zip_get_size(page_zip)
4135  - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
4136  }
4137 
4138  /* Shift the dense directory to allocate place for rec. */
4139  memmove(slot_free - PAGE_ZIP_DIR_SLOT_SIZE, slot_free,
4140  slot_rec - slot_free);
4141 
4142  /* Write the entry for the inserted record.
4143  The "owned" and "deleted" flags must be zero. */
4144  mach_write_to_2(slot_rec - PAGE_ZIP_DIR_SLOT_SIZE, page_offset(rec));
4145 }
4146 
4147 /**********************************************************************/
4150 UNIV_INTERN
4151 void
4153 /*================*/
4154  page_zip_des_t* page_zip,
4155  byte* rec,
4156  dict_index_t* index,
4157  const ulint* offsets,
4158  const byte* free)
4159 {
4160  byte* slot_rec;
4161  byte* slot_free;
4162  ulint n_ext;
4163  page_t* page = page_align(rec);
4164 
4165  ut_ad(rec_offs_validate(rec, index, offsets));
4166  ut_ad(rec_offs_comp(offsets));
4167 
4168  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4169  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
4170  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
4171  rec_offs_extra_size(offsets));
4172 
4173  slot_rec = page_zip_dir_find(page_zip, page_offset(rec));
4174 
4175  ut_a(slot_rec);
4176 
4177  /* This could not be done before page_zip_dir_find(). */
4178  page_header_set_field(page, page_zip, PAGE_N_RECS,
4179  (ulint)(page_get_n_recs(page) - 1));
4180 
4181  if (UNIV_UNLIKELY(!free)) {
4182  /* Make the last slot the start of the free list. */
4183  slot_free = page_zip->data + page_zip_get_size(page_zip)
4184  - PAGE_ZIP_DIR_SLOT_SIZE
4185  * (page_dir_get_n_heap(page_zip->data)
4186  - PAGE_HEAP_NO_USER_LOW);
4187  } else {
4188  slot_free = page_zip_dir_find_free(page_zip,
4189  page_offset(free));
4190  ut_a(slot_free < slot_rec);
4191  /* Grow the free list by one slot by moving the start. */
4192  slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
4193  }
4194 
4195  if (UNIV_LIKELY(slot_rec > slot_free)) {
4196  memmove(slot_free + PAGE_ZIP_DIR_SLOT_SIZE,
4197  slot_free,
4198  slot_rec - slot_free);
4199  }
4200 
4201  /* Write the entry for the deleted record.
4202  The "owned" and "deleted" flags will be cleared. */
4203  mach_write_to_2(slot_free, page_offset(rec));
4204 
4205  if (!page_is_leaf(page) || !dict_index_is_clust(index)) {
4206  ut_ad(!rec_offs_any_extern(offsets));
4207  goto skip_blobs;
4208  }
4209 
4210  n_ext = rec_offs_n_extern(offsets);
4211  if (UNIV_UNLIKELY(n_ext)) {
4212  /* Shift and zero fill the array of BLOB pointers. */
4213  ulint blob_no;
4214  byte* externs;
4215  byte* ext_end;
4216 
4217  blob_no = page_zip_get_n_prev_extern(page_zip, rec, index);
4218  ut_a(blob_no + n_ext <= page_zip->n_blobs);
4219 
4220  externs = page_zip->data + page_zip_get_size(page_zip)
4221  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
4222  * (PAGE_ZIP_DIR_SLOT_SIZE
4223  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4224 
4225  ext_end = externs - page_zip->n_blobs
4227  externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
4228 
4229  page_zip->n_blobs -= n_ext;
4230  /* Shift and zero fill the array. */
4231  memmove(ext_end + n_ext * BTR_EXTERN_FIELD_REF_SIZE, ext_end,
4232  (page_zip->n_blobs - blob_no)
4233  * BTR_EXTERN_FIELD_REF_SIZE);
4234  memset(ext_end, 0, n_ext * BTR_EXTERN_FIELD_REF_SIZE);
4235  }
4236 
4237 skip_blobs:
4238  /* The compression algorithm expects info_bits and n_owned
4239  to be 0 for deleted records. */
4240  rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
4241 
4242  page_zip_clear_rec(page_zip, rec, index, offsets);
4243 }
4244 
4245 /**********************************************************************/
4247 UNIV_INTERN
4248 void
4250 /*==================*/
4251  page_zip_des_t* page_zip,
4252  ulint is_clustered)
4254 {
4255  ulint n_dense;
4256  byte* dir;
4257  byte* stored;
4258 
4259  ut_ad(page_is_comp(page_zip->data));
4260  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4261 
4262  /* Read the old n_dense (n_heap has already been incremented). */
4263  n_dense = page_dir_get_n_heap(page_zip->data)
4264  - (PAGE_HEAP_NO_USER_LOW + 1);
4265 
4266  dir = page_zip->data + page_zip_get_size(page_zip)
4267  - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
4268 
4269  if (!page_is_leaf(page_zip->data)) {
4270  ut_ad(!page_zip->n_blobs);
4271  stored = dir - n_dense * REC_NODE_PTR_SIZE;
4272  } else if (UNIV_UNLIKELY(is_clustered)) {
4273  /* Move the BLOB pointer array backwards to make space for the
4274  roll_ptr and trx_id columns and the dense directory slot. */
4275  byte* externs;
4276 
4277  stored = dir - n_dense
4278  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4279  externs = stored
4280  - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
4281  ASSERT_ZERO(externs
4282  - (PAGE_ZIP_DIR_SLOT_SIZE
4283  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
4284  PAGE_ZIP_DIR_SLOT_SIZE
4285  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4286  memmove(externs - (PAGE_ZIP_DIR_SLOT_SIZE
4287  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
4288  externs, stored - externs);
4289  } else {
4290  stored = dir
4291  - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
4292  ASSERT_ZERO(stored - PAGE_ZIP_DIR_SLOT_SIZE,
4293  PAGE_ZIP_DIR_SLOT_SIZE);
4294  }
4295 
4296  /* Move the uncompressed area backwards to make space
4297  for one directory slot. */
4298  memmove(stored - PAGE_ZIP_DIR_SLOT_SIZE, stored, dir - stored);
4299 }
4300 
4301 /***********************************************************/
4304 UNIV_INTERN
4305 byte*
4307 /*========================*/
4308  byte* ptr,
4309  byte* end_ptr,
4310  page_t* page,
4311  page_zip_des_t* page_zip)
4312 {
4313  ulint offset;
4314  ulint len;
4315 
4316  ut_ad(ptr && end_ptr);
4317  ut_ad(!page == !page_zip);
4318 
4319  if (UNIV_UNLIKELY(end_ptr < ptr + (1 + 1))) {
4320 
4321  return(NULL);
4322  }
4323 
4324  offset = (ulint) *ptr++;
4325  len = (ulint) *ptr++;
4326 
4327  if (UNIV_UNLIKELY(!len) || UNIV_UNLIKELY(offset + len >= PAGE_DATA)) {
4328 corrupt:
4329  recv_sys->found_corrupt_log = TRUE;
4330 
4331  return(NULL);
4332  }
4333 
4334  if (UNIV_UNLIKELY(end_ptr < ptr + len)) {
4335 
4336  return(NULL);
4337  }
4338 
4339  if (page) {
4340  if (UNIV_UNLIKELY(!page_zip)) {
4341 
4342  goto corrupt;
4343  }
4344 #ifdef UNIV_ZIP_DEBUG
4345  ut_a(page_zip_validate(page_zip, page));
4346 #endif /* UNIV_ZIP_DEBUG */
4347 
4348  memcpy(page + offset, ptr, len);
4349  memcpy(page_zip->data + offset, ptr, len);
4350 
4351 #ifdef UNIV_ZIP_DEBUG
4352  ut_a(page_zip_validate(page_zip, page));
4353 #endif /* UNIV_ZIP_DEBUG */
4354  }
4355 
4356  return(ptr + len);
4357 }
4358 
4359 #ifndef UNIV_HOTBACKUP
4360 /**********************************************************************/
4362 UNIV_INTERN
4363 void
4364 page_zip_write_header_log(
4365 /*======================*/
4366  const byte* data,
4367  ulint length,
4368  mtr_t* mtr)
4369 {
4370  byte* log_ptr = mlog_open(mtr, 11 + 1 + 1);
4371  ulint offset = page_offset(data);
4372 
4373  ut_ad(offset < PAGE_DATA);
4374  ut_ad(offset + length < PAGE_DATA);
4375 #if PAGE_DATA > 255
4376 # error "PAGE_DATA > 255"
4377 #endif
4378  ut_ad(length < 256);
4379 
4380  /* If no logging is requested, we may return now */
4381  if (UNIV_UNLIKELY(!log_ptr)) {
4382 
4383  return;
4384  }
4385 
4387  (byte*) data, MLOG_ZIP_WRITE_HEADER, log_ptr, mtr);
4388  *log_ptr++ = (byte) offset;
4389  *log_ptr++ = (byte) length;
4390  mlog_close(mtr, log_ptr);
4391 
4392  mlog_catenate_string(mtr, data, length);
4393 }
4394 #endif /* !UNIV_HOTBACKUP */
4395 
4396 /**********************************************************************/
4407 UNIV_INTERN
4408 ibool
4410 /*================*/
4411  buf_block_t* block,
4415  dict_index_t* index,
4416  mtr_t* mtr)
4417 {
4418  buf_pool_t* buf_pool = buf_pool_from_block(block);
4419  page_zip_des_t* page_zip = buf_block_get_page_zip(block);
4420  page_t* page = buf_block_get_frame(block);
4421  buf_block_t* temp_block;
4422  page_t* temp_page;
4423  ulint log_mode;
4424 
4425  ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
4426  ut_ad(page_is_comp(page));
4427  ut_ad(!dict_index_is_ibuf(index));
4428  /* Note that page_zip_validate(page_zip, page) may fail here. */
4429  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
4430  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4431 
4432  /* Disable logging */
4433  log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
4434 
4435 #ifndef UNIV_HOTBACKUP
4436  temp_block = buf_block_alloc(buf_pool);
4437  btr_search_drop_page_hash_index(block);
4438  block->check_index_page_at_flush = TRUE;
4439 #else /* !UNIV_HOTBACKUP */
4440  ut_ad(block == back_block1);
4441  temp_block = back_block2;
4442 #endif /* !UNIV_HOTBACKUP */
4443  temp_page = temp_block->frame;
4444 
4445  /* Copy the old page to temporary space */
4446  buf_frame_copy(temp_page, page);
4447 
4448  btr_blob_dbg_remove(page, index, "zip_reorg");
4449 
4450  /* Recreate the page: note that global data on page (possible
4451  segment headers, next page-field, etc.) is preserved intact */
4452 
4453  page_create(block, mtr, TRUE);
4454 
4455  /* Copy the records from the temporary space to the recreated page;
4456  do not copy the lock bits yet */
4457 
4458  page_copy_rec_list_end_no_locks(block, temp_block,
4459  page_get_infimum_rec(temp_page),
4460  index, mtr);
4461 
4462  if (!dict_index_is_clust(index) && page_is_leaf(temp_page)) {
4463  /* Copy max trx id to recreated page */
4464  trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
4465  page_set_max_trx_id(block, NULL, max_trx_id, NULL);
4466  ut_ad(max_trx_id != 0);
4467  }
4468 
4469  /* Restore logging. */
4470  mtr_set_log_mode(mtr, log_mode);
4471 
4472  if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
4473 
4474 #ifndef UNIV_HOTBACKUP
4475  buf_block_free(temp_block);
4476 #endif /* !UNIV_HOTBACKUP */
4477  return(FALSE);
4478  }
4479 
4480  lock_move_reorganize_page(block, temp_block);
4481 
4482 #ifndef UNIV_HOTBACKUP
4483  buf_block_free(temp_block);
4484 #endif /* !UNIV_HOTBACKUP */
4485  return(TRUE);
4486 }
4487 
4488 #ifndef UNIV_HOTBACKUP
4489 /**********************************************************************/
4494 UNIV_INTERN
4495 void
4497 /*===============*/
4498  page_zip_des_t* page_zip,
4501  page_t* page,
4502  const page_zip_des_t* src_zip,
4503  const page_t* src,
4504  dict_index_t* index,
4505  mtr_t* mtr)
4506 {
4507  ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
4508  ut_ad(mtr_memo_contains_page(mtr, src, MTR_MEMO_PAGE_X_FIX));
4509  ut_ad(!dict_index_is_ibuf(index));
4510 #ifdef UNIV_ZIP_DEBUG
4511  /* The B-tree operations that call this function may set
4512  FIL_PAGE_PREV or PAGE_LEVEL, causing a temporary min_rec_flag
4513  mismatch. A strict page_zip_validate() will be executed later
4514  during the B-tree operations. */
4515  ut_a(page_zip_validate_low(src_zip, src, TRUE));
4516 #endif /* UNIV_ZIP_DEBUG */
4517  ut_a(page_zip_get_size(page_zip) == page_zip_get_size(src_zip));
4518  if (UNIV_UNLIKELY(src_zip->n_blobs)) {
4519  ut_a(page_is_leaf(src));
4520  ut_a(dict_index_is_clust(index));
4521  }
4522 
4523  /* The PAGE_MAX_TRX_ID must be set on leaf pages of secondary
4524  indexes. It does not matter on other pages. */
4525  ut_a(dict_index_is_clust(index) || !page_is_leaf(src)
4526  || page_get_max_trx_id(src));
4527 
4528  UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE);
4529  UNIV_MEM_ASSERT_W(page_zip->data, page_zip_get_size(page_zip));
4530  UNIV_MEM_ASSERT_RW(src, UNIV_PAGE_SIZE);
4531  UNIV_MEM_ASSERT_RW(src_zip->data, page_zip_get_size(page_zip));
4532 
4533  /* Copy those B-tree page header fields that are related to
4534  the records stored in the page. Also copy the field
4535  PAGE_MAX_TRX_ID. Skip the rest of the page header and
4536  trailer. On the compressed page, there is no trailer. */
4537 #if PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END
4538 # error "PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END"
4539 #endif
4540  memcpy(PAGE_HEADER + page, PAGE_HEADER + src,
4541  PAGE_HEADER_PRIV_END);
4542  memcpy(PAGE_DATA + page, PAGE_DATA + src,
4543  UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END);
4544  memcpy(PAGE_HEADER + page_zip->data, PAGE_HEADER + src_zip->data,
4545  PAGE_HEADER_PRIV_END);
4546  memcpy(PAGE_DATA + page_zip->data, PAGE_DATA + src_zip->data,
4547  page_zip_get_size(page_zip) - PAGE_DATA);
4548 
4549  /* Copy all fields of src_zip to page_zip, except the pointer
4550  to the compressed data page. */
4551  {
4552  page_zip_t* data = page_zip->data;
4553  memcpy(page_zip, src_zip, sizeof *page_zip);
4554  page_zip->data = data;
4555  }
4556  ut_ad(page_zip_get_trailer_len(page_zip,
4557  dict_index_is_clust(index), NULL)
4558  + page_zip->m_end < page_zip_get_size(page_zip));
4559 
4560  if (!page_is_leaf(src)
4561  && UNIV_UNLIKELY(mach_read_from_4(src + FIL_PAGE_PREV) == FIL_NULL)
4562  && UNIV_LIKELY(mach_read_from_4(page
4563  + FIL_PAGE_PREV) != FIL_NULL)) {
4564  /* Clear the REC_INFO_MIN_REC_FLAG of the first user record. */
4565  ulint offs = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
4566  TRUE);
4567  if (UNIV_LIKELY(offs != PAGE_NEW_SUPREMUM)) {
4568  rec_t* rec = page + offs;
4569  ut_a(rec[-REC_N_NEW_EXTRA_BYTES]
4570  & REC_INFO_MIN_REC_FLAG);
4571  rec[-REC_N_NEW_EXTRA_BYTES] &= ~ REC_INFO_MIN_REC_FLAG;
4572  }
4573  }
4574 
4575 #ifdef UNIV_ZIP_DEBUG
4576  ut_a(page_zip_validate(page_zip, page));
4577 #endif /* UNIV_ZIP_DEBUG */
4578  btr_blob_dbg_add(page, index, "page_zip_copy_recs");
4579 
4580  page_zip_compress_write_log(page_zip, page, index, mtr);
4581 }
4582 #endif /* !UNIV_HOTBACKUP */
4583 
4584 /**********************************************************************/
4587 UNIV_INTERN
4588 byte*
4590 /*====================*/
4591  byte* ptr,
4592  byte* end_ptr,
4593  page_t* page,
4594  page_zip_des_t* page_zip)
4595 {
4596  ulint size;
4597  ulint trailer_size;
4598 
4599  ut_ad(ptr && end_ptr);
4600  ut_ad(!page == !page_zip);
4601 
4602  if (UNIV_UNLIKELY(ptr + (2 + 2) > end_ptr)) {
4603 
4604  return(NULL);
4605  }
4606 
4607  size = mach_read_from_2(ptr);
4608  ptr += 2;
4609  trailer_size = mach_read_from_2(ptr);
4610  ptr += 2;
4611 
4612  if (UNIV_UNLIKELY(ptr + 8 + size + trailer_size > end_ptr)) {
4613 
4614  return(NULL);
4615  }
4616 
4617  if (page) {
4618  if (UNIV_UNLIKELY(!page_zip)
4619  || UNIV_UNLIKELY(page_zip_get_size(page_zip) < size)) {
4620 corrupt:
4621  recv_sys->found_corrupt_log = TRUE;
4622 
4623  return(NULL);
4624  }
4625 
4626  memcpy(page_zip->data + FIL_PAGE_PREV, ptr, 4);
4627  memcpy(page_zip->data + FIL_PAGE_NEXT, ptr + 4, 4);
4628  memcpy(page_zip->data + FIL_PAGE_TYPE, ptr + 8, size);
4629  memset(page_zip->data + FIL_PAGE_TYPE + size, 0,
4630  page_zip_get_size(page_zip) - trailer_size
4631  - (FIL_PAGE_TYPE + size));
4632  memcpy(page_zip->data + page_zip_get_size(page_zip)
4633  - trailer_size, ptr + 8 + size, trailer_size);
4634 
4635  if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page,
4636  TRUE))) {
4637 
4638  goto corrupt;
4639  }
4640  }
4641 
4642  return(ptr + 8 + size + trailer_size);
4643 }
4644 
4645 /**********************************************************************/
4648 UNIV_INTERN
4649 ulint
4651 /*===================*/
4652  const void* data,
4653  ulint size)
4654 {
4655  /* Exclude FIL_PAGE_SPACE_OR_CHKSUM, FIL_PAGE_LSN,
4656  and FIL_PAGE_FILE_FLUSH_LSN from the checksum. */
4657 
4658  const Bytef* s = static_cast<const Bytef *>(data);
4659  uLong adler;
4660 
4662 
4663  adler = adler32(0L, s + FIL_PAGE_OFFSET,
4665  adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
4666  adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
4668 
4669  return((ulint) adler);
4670 }