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_malloc(void* opaque, uInt items, uInt size);
652 
653 extern "C" void* page_zip_malloc
654 (
655 /*============*/
656  void* opaque,
657  uInt items,
658  uInt size)
659 {
660  return(mem_heap_alloc(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_malloc;
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  if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT)
2910  != Z_OK)) {
2911  ut_error;
2912  }
2913 
2914  d_stream.next_in = page_zip->data + PAGE_DATA;
2915  /* Subtract the space reserved for
2916  the page header and the end marker of the modification log. */
2917  d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1);
2918 
2919  d_stream.next_out = page + PAGE_ZIP_START;
2920  d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
2921 
2922  /* Decode the zlib header and the index information. */
2923  if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
2924 
2925  page_zip_fail(("page_zip_decompress:"
2926  " 1 inflate(Z_BLOCK)=%s\n", d_stream.msg));
2927  goto zlib_error;
2928  }
2929 
2930  if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
2931 
2932  page_zip_fail(("page_zip_decompress:"
2933  " 2 inflate(Z_BLOCK)=%s\n", d_stream.msg));
2934  goto zlib_error;
2935  }
2936 
2937  index = page_zip_fields_decode(
2938  page + PAGE_ZIP_START, d_stream.next_out,
2939  page_is_leaf(page) ? &trx_id_col : NULL);
2940 
2941  if (UNIV_UNLIKELY(!index)) {
2942 
2943  goto zlib_error;
2944  }
2945 
2946  /* Decompress the user records. */
2947  page_zip->n_blobs = 0;
2948  d_stream.next_out = page + PAGE_ZIP_START;
2949 
2950  {
2951  /* Pre-allocate the offsets for rec_get_offsets_reverse(). */
2952  ulint n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
2953  + dict_index_get_n_fields(index);
2954  offsets = static_cast<unsigned long *>(mem_heap_alloc(heap, n * sizeof(ulint)));
2955  *offsets = n;
2956  }
2957 
2958  /* Decompress the records in heap_no order. */
2959  if (!page_is_leaf(page)) {
2960  /* This is a node pointer page. */
2961  ulint info_bits;
2962 
2963  if (UNIV_UNLIKELY
2964  (!page_zip_decompress_node_ptrs(page_zip, &d_stream,
2965  recs, n_dense, index,
2966  offsets, heap))) {
2967  goto err_exit;
2968  }
2969 
2970  info_bits = mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL
2971  ? REC_INFO_MIN_REC_FLAG : 0;
2972 
2973  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
2974  info_bits))) {
2975  goto err_exit;
2976  }
2977  } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
2978  /* This is a leaf page in a secondary index. */
2979  if (UNIV_UNLIKELY(!page_zip_decompress_sec(page_zip, &d_stream,
2980  recs, n_dense,
2981  index, offsets))) {
2982  goto err_exit;
2983  }
2984 
2985  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
2986  page, 0))) {
2987 err_exit:
2988  page_zip_fields_free(index);
2989  mem_heap_free(heap);
2990  return(FALSE);
2991  }
2992  } else {
2993  /* This is a leaf page in a clustered index. */
2994  if (UNIV_UNLIKELY(!page_zip_decompress_clust(page_zip,
2995  &d_stream, recs,
2996  n_dense, index,
2997  trx_id_col,
2998  offsets, heap))) {
2999  goto err_exit;
3000  }
3001 
3002  if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
3003  page, 0))) {
3004  goto err_exit;
3005  }
3006  }
3007 
3008  ut_a(page_is_comp(page));
3009  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
3010 
3011  page_zip_fields_free(index);
3012  mem_heap_free(heap);
3013 #ifndef UNIV_HOTBACKUP
3014  {
3015  page_zip_stat_t* zip_stat
3016  = &page_zip_stat[page_zip->ssize - 1];
3017  zip_stat->decompressed++;
3018  zip_stat->decompressed_usec += ut_time_us(NULL) - usec;
3019  }
3020 #endif /* !UNIV_HOTBACKUP */
3021 
3022  /* Update the stat counter for LRU policy. */
3024 
3025  return(TRUE);
3026 }
3027 
3028 #ifdef UNIV_ZIP_DEBUG
3029 /**********************************************************************/
3031 static
3032 void
3033 page_zip_hexdump_func(
3034 /*==================*/
3035  const char* name,
3036  const void* buf,
3037  ulint size)
3038 {
3039  const byte* s = buf;
3040  ulint addr;
3041  const ulint width = 32; /* bytes per line */
3042 
3043  fprintf(stderr, "%s:\n", name);
3044 
3045  for (addr = 0; addr < size; addr += width) {
3046  ulint i;
3047 
3048  fprintf(stderr, "%04lx ", (ulong) addr);
3049 
3050  i = ut_min(width, size - addr);
3051 
3052  while (i--) {
3053  fprintf(stderr, "%02x", *s++);
3054  }
3055 
3056  putc('\n', stderr);
3057  }
3058 }
3059 
3063 #define page_zip_hexdump(buf, size) page_zip_hexdump_func(#buf, buf, size)
3064 
3066 UNIV_INTERN ibool page_zip_validate_header_only = FALSE;
3067 
3068 /**********************************************************************/
3071 UNIV_INTERN
3072 ibool
3073 page_zip_validate_low(
3074 /*==================*/
3075  const page_zip_des_t* page_zip,
3076  const page_t* page,
3077  ibool sloppy)
3079 {
3080  page_zip_des_t temp_page_zip;
3081  byte* temp_page_buf;
3082  page_t* temp_page;
3083  ibool valid;
3084 
3085  if (memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
3087  || memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE, 2)
3088  || memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
3089  PAGE_DATA - FIL_PAGE_DATA)) {
3090  page_zip_fail(("page_zip_validate: page header\n"));
3091  page_zip_hexdump(page_zip, sizeof *page_zip);
3092  page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
3093  page_zip_hexdump(page, UNIV_PAGE_SIZE);
3094  return(FALSE);
3095  }
3096 
3097  ut_a(page_is_comp(page));
3098 
3099  if (page_zip_validate_header_only) {
3100  return(TRUE);
3101  }
3102 
3103  /* page_zip_decompress() expects the uncompressed page to be
3104  UNIV_PAGE_SIZE aligned. */
3105  temp_page_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
3106  temp_page = ut_align(temp_page_buf, UNIV_PAGE_SIZE);
3107 
3108 #ifdef UNIV_DEBUG_VALGRIND
3109  /* Get detailed information on the valid bits in case the
3110  UNIV_MEM_ASSERT_RW() checks fail. The v-bits of page[],
3111  page_zip->data[] or page_zip could be viewed at temp_page[] or
3112  temp_page_zip in a debugger when running valgrind --db-attach. */
3113  VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE);
3114  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
3115 # if UNIV_WORD_SIZE == 4
3116  VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip);
3117  /* On 32-bit systems, there is no padding in page_zip_des_t.
3118  On other systems, Valgrind could complain about uninitialized
3119  pad bytes. */
3120  UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip);
3121 # endif
3122  VALGRIND_GET_VBITS(page_zip->data, temp_page,
3123  page_zip_get_size(page_zip));
3124  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3125 #endif /* UNIV_DEBUG_VALGRIND */
3126 
3127  temp_page_zip = *page_zip;
3128  valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE);
3129  if (!valid) {
3130  fputs("page_zip_validate(): failed to decompress\n", stderr);
3131  goto func_exit;
3132  }
3133  if (page_zip->n_blobs != temp_page_zip.n_blobs) {
3134  page_zip_fail(("page_zip_validate: n_blobs: %u!=%u\n",
3135  page_zip->n_blobs, temp_page_zip.n_blobs));
3136  valid = FALSE;
3137  }
3138 #ifdef UNIV_DEBUG
3139  if (page_zip->m_start != temp_page_zip.m_start) {
3140  page_zip_fail(("page_zip_validate: m_start: %u!=%u\n",
3141  page_zip->m_start, temp_page_zip.m_start));
3142  valid = FALSE;
3143  }
3144 #endif /* UNIV_DEBUG */
3145  if (page_zip->m_end != temp_page_zip.m_end) {
3146  page_zip_fail(("page_zip_validate: m_end: %u!=%u\n",
3147  page_zip->m_end, temp_page_zip.m_end));
3148  valid = FALSE;
3149  }
3150  if (page_zip->m_nonempty != temp_page_zip.m_nonempty) {
3151  page_zip_fail(("page_zip_validate(): m_nonempty: %u!=%u\n",
3152  page_zip->m_nonempty,
3153  temp_page_zip.m_nonempty));
3154  valid = FALSE;
3155  }
3156  if (memcmp(page + PAGE_HEADER, temp_page + PAGE_HEADER,
3157  UNIV_PAGE_SIZE - PAGE_HEADER - FIL_PAGE_DATA_END)) {
3158 
3159  /* In crash recovery, the "minimum record" flag may be
3160  set incorrectly until the mini-transaction is
3161  committed. Let us tolerate that difference when we
3162  are performing a sloppy validation. */
3163 
3164  if (sloppy) {
3165  byte info_bits_diff;
3166  ulint offset
3167  = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
3168  TRUE);
3169  ut_a(offset >= PAGE_NEW_SUPREMUM);
3170  offset -= 5 /* REC_NEW_INFO_BITS */;
3171 
3172  info_bits_diff = page[offset] ^ temp_page[offset];
3173 
3174  if (info_bits_diff == REC_INFO_MIN_REC_FLAG) {
3175  temp_page[offset] = page[offset];
3176 
3177  if (!memcmp(page + PAGE_HEADER,
3178  temp_page + PAGE_HEADER,
3179  UNIV_PAGE_SIZE - PAGE_HEADER
3180  - FIL_PAGE_DATA_END)) {
3181 
3182  /* Only the minimum record flag
3183  differed. Let us ignore it. */
3184  page_zip_fail(("page_zip_validate: "
3185  "min_rec_flag "
3186  "(ignored, "
3187  "%lu,%lu,0x%02lx)\n",
3188  page_get_space_id(page),
3189  page_get_page_no(page),
3190  (ulong) page[offset]));
3191  goto func_exit;
3192  }
3193  }
3194  }
3195  page_zip_fail(("page_zip_validate: content\n"));
3196  valid = FALSE;
3197  }
3198 
3199 func_exit:
3200  if (!valid) {
3201  page_zip_hexdump(page_zip, sizeof *page_zip);
3202  page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
3203  page_zip_hexdump(page, UNIV_PAGE_SIZE);
3204  page_zip_hexdump(temp_page, UNIV_PAGE_SIZE);
3205  }
3206  ut_free(temp_page_buf);
3207  return(valid);
3208 }
3209 
3210 /**********************************************************************/
3213 UNIV_INTERN
3214 ibool
3215 page_zip_validate(
3216 /*==============*/
3217  const page_zip_des_t* page_zip,
3218  const page_t* page)
3219 {
3220  return(page_zip_validate_low(page_zip, page,
3221  recv_recovery_is_on()));
3222 }
3223 #endif /* UNIV_ZIP_DEBUG */
3224 
3225 #ifdef UNIV_DEBUG
3226 /**********************************************************************/
3229 static
3230 ibool
3231 page_zip_header_cmp(
3232 /*================*/
3233  const page_zip_des_t* page_zip,
3234  const byte* page)
3235 {
3236  ut_ad(!memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
3238  ut_ad(!memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE,
3239  2));
3240  ut_ad(!memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
3241  PAGE_DATA - FIL_PAGE_DATA));
3242 
3243  return(TRUE);
3244 }
3245 #endif /* UNIV_DEBUG */
3246 
3247 /**********************************************************************/
3251 static
3252 byte*
3253 page_zip_write_rec_ext(
3254 /*===================*/
3255  page_zip_des_t* page_zip,
3256  const page_t* page,
3257  const byte* rec,
3258  dict_index_t* index,
3259  const ulint* offsets,
3260  ulint create,
3261  ulint trx_id_col,
3262  ulint heap_no,
3263  byte* storage,
3264  byte* data)
3265 {
3266  const byte* start = rec;
3267  ulint i;
3268  ulint len;
3269  byte* externs = storage;
3270  ulint n_ext = rec_offs_n_extern(offsets);
3271 
3272  ut_ad(rec_offs_validate(rec, index, offsets));
3273  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3274  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3275  rec_offs_extra_size(offsets));
3276 
3277  externs -= (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3278  * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW);
3279 
3280  /* Note that this will not take into account
3281  the BLOB columns of rec if create==TRUE. */
3282  ut_ad(data + rec_offs_data_size(offsets)
3283  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3284  - n_ext * BTR_EXTERN_FIELD_REF_SIZE
3285  < externs - BTR_EXTERN_FIELD_REF_SIZE * page_zip->n_blobs);
3286 
3287  {
3288  ulint blob_no = page_zip_get_n_prev_extern(
3289  page_zip, rec, index);
3290  byte* ext_end = externs - page_zip->n_blobs
3292  ut_ad(blob_no <= page_zip->n_blobs);
3293  externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
3294 
3295  if (create) {
3296  page_zip->n_blobs += n_ext;
3297  ASSERT_ZERO_BLOB(ext_end - n_ext
3298  * BTR_EXTERN_FIELD_REF_SIZE);
3299  memmove(ext_end - n_ext
3300  * BTR_EXTERN_FIELD_REF_SIZE,
3301  ext_end,
3302  externs - ext_end);
3303  }
3304 
3305  ut_a(blob_no + n_ext <= page_zip->n_blobs);
3306  }
3307 
3308  for (i = 0; i < rec_offs_n_fields(offsets); i++) {
3309  const byte* src;
3310 
3311  if (UNIV_UNLIKELY(i == trx_id_col)) {
3312  ut_ad(!rec_offs_nth_extern(offsets,
3313  i));
3314  ut_ad(!rec_offs_nth_extern(offsets,
3315  i + 1));
3316  /* Locate trx_id and roll_ptr. */
3317  src = rec_get_nth_field(rec, offsets,
3318  i, &len);
3319  ut_ad(len == DATA_TRX_ID_LEN);
3320  ut_ad(src + DATA_TRX_ID_LEN
3321  == rec_get_nth_field(
3322  rec, offsets,
3323  i + 1, &len));
3324  ut_ad(len == DATA_ROLL_PTR_LEN);
3325 
3326  /* Log the preceding fields. */
3327  ASSERT_ZERO(data, src - start);
3328  memcpy(data, start, src - start);
3329  data += src - start;
3330  start = src + (DATA_TRX_ID_LEN
3331  + DATA_ROLL_PTR_LEN);
3332 
3333  /* Store trx_id and roll_ptr. */
3334  memcpy(storage - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3335  * (heap_no - 1),
3336  src, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3337  i++; /* skip also roll_ptr */
3338  } else if (rec_offs_nth_extern(offsets, i)) {
3339  src = rec_get_nth_field(rec, offsets,
3340  i, &len);
3341 
3342  ut_ad(dict_index_is_clust(index));
3343  ut_ad(len
3344  >= BTR_EXTERN_FIELD_REF_SIZE);
3345  src += len - BTR_EXTERN_FIELD_REF_SIZE;
3346 
3347  ASSERT_ZERO(data, src - start);
3348  memcpy(data, start, src - start);
3349  data += src - start;
3350  start = src + BTR_EXTERN_FIELD_REF_SIZE;
3351 
3352  /* Store the BLOB pointer. */
3353  externs -= BTR_EXTERN_FIELD_REF_SIZE;
3354  ut_ad(data < externs);
3355  memcpy(externs, src, BTR_EXTERN_FIELD_REF_SIZE);
3356  }
3357  }
3358 
3359  /* Log the last bytes of the record. */
3360  len = rec_offs_data_size(offsets) - (start - rec);
3361 
3362  ASSERT_ZERO(data, len);
3363  memcpy(data, start, len);
3364  data += len;
3365 
3366  return(data);
3367 }
3368 
3369 /**********************************************************************/
3372 UNIV_INTERN
3373 void
3375 /*===============*/
3376  page_zip_des_t* page_zip,
3377  const byte* rec,
3378  dict_index_t* index,
3379  const ulint* offsets,
3380  ulint create)
3381 {
3382  const page_t* page;
3383  byte* data;
3384  byte* storage;
3385  ulint heap_no;
3386  byte* slot;
3387 
3388  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3389  ut_ad(page_zip_simple_validate(page_zip));
3390  ut_ad(page_zip_get_size(page_zip)
3391  > PAGE_DATA + page_zip_dir_size(page_zip));
3392  ut_ad(rec_offs_comp(offsets));
3393  ut_ad(rec_offs_validate(rec, index, offsets));
3394 
3395  ut_ad(page_zip->m_start >= PAGE_DATA);
3396 
3397  page = page_align(rec);
3398 
3399  ut_ad(page_zip_header_cmp(page_zip, page));
3401 
3402  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3403  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3404  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3405  rec_offs_extra_size(offsets));
3406 
3407  slot = page_zip_dir_find(page_zip, page_offset(rec));
3408  ut_a(slot);
3409  /* Copy the delete mark. */
3410  if (rec_get_deleted_flag(rec, TRUE)) {
3411  *slot |= PAGE_ZIP_DIR_SLOT_DEL >> 8;
3412  } else {
3413  *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
3414  }
3415 
3416  ut_ad(rec_get_start((rec_t*) rec, offsets) >= page + PAGE_ZIP_START);
3417  ut_ad(rec_get_end((rec_t*) rec, offsets) <= page + UNIV_PAGE_SIZE
3418  - PAGE_DIR - PAGE_DIR_SLOT_SIZE
3419  * page_dir_get_n_slots(page));
3420 
3421  heap_no = rec_get_heap_no_new(rec);
3422  ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW); /* not infimum or supremum */
3423  ut_ad(heap_no < page_dir_get_n_heap(page));
3424 
3425  /* Append to the modification log. */
3426  data = page_zip->data + page_zip->m_end;
3427  ut_ad(!*data);
3428 
3429  /* Identify the record by writing its heap number - 1.
3430  0 is reserved to indicate the end of the modification log. */
3431 
3432  if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
3433  *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
3434  ut_ad(!*data);
3435  }
3436  *data++ = (byte) ((heap_no - 1) << 1);
3437  ut_ad(!*data);
3438 
3439  {
3440  const byte* start = rec - rec_offs_extra_size(offsets);
3441  const byte* b = rec - REC_N_NEW_EXTRA_BYTES;
3442 
3443  /* Write the extra bytes backwards, so that
3444  rec_offs_extra_size() can be easily computed in
3445  page_zip_apply_log() by invoking
3446  rec_get_offsets_reverse(). */
3447 
3448  while (b != start) {
3449  *data++ = *--b;
3450  ut_ad(!*data);
3451  }
3452  }
3453 
3454  /* Write the data bytes. Store the uncompressed bytes separately. */
3455  storage = page_zip->data + page_zip_get_size(page_zip)
3456  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3457  * PAGE_ZIP_DIR_SLOT_SIZE;
3458 
3459  if (page_is_leaf(page)) {
3460  ulint len;
3461 
3462  if (dict_index_is_clust(index)) {
3463  ulint trx_id_col;
3464 
3465  trx_id_col = dict_index_get_sys_col_pos(index,
3466  DATA_TRX_ID);
3467  ut_ad(trx_id_col != ULINT_UNDEFINED);
3468 
3469  /* Store separately trx_id, roll_ptr and
3470  the BTR_EXTERN_FIELD_REF of each BLOB column. */
3471  if (rec_offs_any_extern(offsets)) {
3472  data = page_zip_write_rec_ext(
3473  page_zip, page,
3474  rec, index, offsets, create,
3475  trx_id_col, heap_no, storage, data);
3476  } else {
3477  /* Locate trx_id and roll_ptr. */
3478  const byte* src
3479  = rec_get_nth_field(rec, offsets,
3480  trx_id_col, &len);
3481  ut_ad(len == DATA_TRX_ID_LEN);
3482  ut_ad(src + DATA_TRX_ID_LEN
3483  == rec_get_nth_field(
3484  rec, offsets,
3485  trx_id_col + 1, &len));
3486  ut_ad(len == DATA_ROLL_PTR_LEN);
3487 
3488  /* Log the preceding fields. */
3489  ASSERT_ZERO(data, src - rec);
3490  memcpy(data, rec, src - rec);
3491  data += src - rec;
3492 
3493  /* Store trx_id and roll_ptr. */
3494  memcpy(storage
3495  - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
3496  * (heap_no - 1),
3497  src,
3498  DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3499 
3500  src += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
3501 
3502  /* Log the last bytes of the record. */
3503  len = rec_offs_data_size(offsets)
3504  - (src - rec);
3505 
3506  ASSERT_ZERO(data, len);
3507  memcpy(data, src, len);
3508  data += len;
3509  }
3510  } else {
3511  /* Leaf page of a secondary index:
3512  no externally stored columns */
3513  ut_ad(dict_index_get_sys_col_pos(index, DATA_TRX_ID)
3514  == ULINT_UNDEFINED);
3515  ut_ad(!rec_offs_any_extern(offsets));
3516 
3517  /* Log the entire record. */
3518  len = rec_offs_data_size(offsets);
3519 
3520  ASSERT_ZERO(data, len);
3521  memcpy(data, rec, len);
3522  data += len;
3523  }
3524  } else {
3525  /* This is a node pointer page. */
3526  ulint len;
3527 
3528  /* Non-leaf nodes should not have any externally
3529  stored columns. */
3530  ut_ad(!rec_offs_any_extern(offsets));
3531 
3532  /* Copy the data bytes, except node_ptr. */
3533  len = rec_offs_data_size(offsets) - REC_NODE_PTR_SIZE;
3534  ut_ad(data + len < storage - REC_NODE_PTR_SIZE
3535  * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW));
3536  ASSERT_ZERO(data, len);
3537  memcpy(data, rec, len);
3538  data += len;
3539 
3540  /* Copy the node pointer to the uncompressed area. */
3541  memcpy(storage - REC_NODE_PTR_SIZE
3542  * (heap_no - 1),
3543  rec + len,
3544  REC_NODE_PTR_SIZE);
3545  }
3546 
3547  ut_a(!*data);
3548  ut_ad((ulint) (data - page_zip->data) < page_zip_get_size(page_zip));
3549  page_zip->m_end = data - page_zip->data;
3550  page_zip->m_nonempty = TRUE;
3551 
3552 #ifdef UNIV_ZIP_DEBUG
3553  ut_a(page_zip_validate(page_zip, page_align(rec)));
3554 #endif /* UNIV_ZIP_DEBUG */
3555 }
3556 
3557 /***********************************************************/
3560 UNIV_INTERN
3561 byte*
3563 /*==========================*/
3564  byte* ptr,
3565  byte* end_ptr,
3566  page_t* page,
3567  page_zip_des_t* page_zip)
3568 {
3569  ulint offset;
3570  ulint z_offset;
3571 
3572  ut_ad(!page == !page_zip);
3573 
3574  if (UNIV_UNLIKELY
3575  (end_ptr < ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE))) {
3576 
3577  return(NULL);
3578  }
3579 
3580  offset = mach_read_from_2(ptr);
3581  z_offset = mach_read_from_2(ptr + 2);
3582 
3583  if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
3584  || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
3585  || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
3586 corrupt:
3587  recv_sys->found_corrupt_log = TRUE;
3588 
3589  return(NULL);
3590  }
3591 
3592  if (page) {
3593  if (UNIV_UNLIKELY(!page_zip)
3594  || UNIV_UNLIKELY(!page_is_leaf(page))) {
3595 
3596  goto corrupt;
3597  }
3598 
3599 #ifdef UNIV_ZIP_DEBUG
3600  ut_a(page_zip_validate(page_zip, page));
3601 #endif /* UNIV_ZIP_DEBUG */
3602 
3603  memcpy(page + offset,
3604  ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
3605  memcpy(page_zip->data + z_offset,
3606  ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
3607 
3608 #ifdef UNIV_ZIP_DEBUG
3609  ut_a(page_zip_validate(page_zip, page));
3610 #endif /* UNIV_ZIP_DEBUG */
3611  }
3612 
3613  return(ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE));
3614 }
3615 
3616 /**********************************************************************/
3619 UNIV_INTERN
3620 void
3622 /*====================*/
3623  page_zip_des_t* page_zip,
3624  const byte* rec,
3626  dict_index_t* index,
3627  const ulint* offsets,
3628  ulint n,
3629  mtr_t* mtr)
3631 {
3632  const byte* field;
3633  byte* externs;
3634  const page_t* page = page_align(rec);
3635  ulint blob_no;
3636  ulint len;
3637 
3638  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3640  ut_ad(page_zip_simple_validate(page_zip));
3641  ut_ad(page_zip_get_size(page_zip)
3642  > PAGE_DATA + page_zip_dir_size(page_zip));
3643  ut_ad(rec_offs_comp(offsets));
3644  ut_ad(rec_offs_validate(rec, NULL, offsets));
3645  ut_ad(rec_offs_any_extern(offsets));
3646  ut_ad(rec_offs_nth_extern(offsets, n));
3647 
3648  ut_ad(page_zip->m_start >= PAGE_DATA);
3649  ut_ad(page_zip_header_cmp(page_zip, page));
3650 
3651  ut_ad(page_is_leaf(page));
3652  ut_ad(dict_index_is_clust(index));
3653 
3654  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3655  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3656  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3657  rec_offs_extra_size(offsets));
3658 
3659  blob_no = page_zip_get_n_prev_extern(page_zip, rec, index)
3660  + rec_get_n_extern_new(rec, index, n);
3661  ut_a(blob_no < page_zip->n_blobs);
3662 
3663  externs = page_zip->data + page_zip_get_size(page_zip)
3664  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3665  * (PAGE_ZIP_DIR_SLOT_SIZE
3666  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3667 
3668  field = rec_get_nth_field(rec, offsets, n, &len);
3669 
3670  externs -= (blob_no + 1) * BTR_EXTERN_FIELD_REF_SIZE;
3671  field += len - BTR_EXTERN_FIELD_REF_SIZE;
3672 
3673  memcpy(externs, field, BTR_EXTERN_FIELD_REF_SIZE);
3674 
3675 #ifdef UNIV_ZIP_DEBUG
3676  ut_a(page_zip_validate(page_zip, page));
3677 #endif /* UNIV_ZIP_DEBUG */
3678 
3679  if (mtr) {
3680 #ifndef UNIV_HOTBACKUP
3681  byte* log_ptr = mlog_open(
3682  mtr, 11 + 2 + 2 + BTR_EXTERN_FIELD_REF_SIZE);
3683  if (UNIV_UNLIKELY(!log_ptr)) {
3684  return;
3685  }
3686 
3688  (byte*) field, MLOG_ZIP_WRITE_BLOB_PTR, log_ptr, mtr);
3689  mach_write_to_2(log_ptr, page_offset(field));
3690  log_ptr += 2;
3691  mach_write_to_2(log_ptr, externs - page_zip->data);
3692  log_ptr += 2;
3693  memcpy(log_ptr, externs, BTR_EXTERN_FIELD_REF_SIZE);
3694  log_ptr += BTR_EXTERN_FIELD_REF_SIZE;
3695  mlog_close(mtr, log_ptr);
3696 #endif /* !UNIV_HOTBACKUP */
3697  }
3698 }
3699 
3700 /***********************************************************/
3703 UNIV_INTERN
3704 byte*
3706 /*==========================*/
3707  byte* ptr,
3708  byte* end_ptr,
3709  page_t* page,
3710  page_zip_des_t* page_zip)
3711 {
3712  ulint offset;
3713  ulint z_offset;
3714 
3715  ut_ad(!page == !page_zip);
3716 
3717  if (UNIV_UNLIKELY(end_ptr < ptr + (2 + 2 + REC_NODE_PTR_SIZE))) {
3718 
3719  return(NULL);
3720  }
3721 
3722  offset = mach_read_from_2(ptr);
3723  z_offset = mach_read_from_2(ptr + 2);
3724 
3725  if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
3726  || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
3727  || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
3728 corrupt:
3729  recv_sys->found_corrupt_log = TRUE;
3730 
3731  return(NULL);
3732  }
3733 
3734  if (page) {
3735  byte* storage_end;
3736  byte* field;
3737  byte* storage;
3738  ulint heap_no;
3739 
3740  if (UNIV_UNLIKELY(!page_zip)
3741  || UNIV_UNLIKELY(page_is_leaf(page))) {
3742 
3743  goto corrupt;
3744  }
3745 
3746 #ifdef UNIV_ZIP_DEBUG
3747  ut_a(page_zip_validate(page_zip, page));
3748 #endif /* UNIV_ZIP_DEBUG */
3749 
3750  field = page + offset;
3751  storage = page_zip->data + z_offset;
3752 
3753  storage_end = page_zip->data + page_zip_get_size(page_zip)
3754  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3755  * PAGE_ZIP_DIR_SLOT_SIZE;
3756 
3757  heap_no = 1 + (storage_end - storage) / REC_NODE_PTR_SIZE;
3758 
3759  if (UNIV_UNLIKELY((storage_end - storage) % REC_NODE_PTR_SIZE)
3760  || UNIV_UNLIKELY(heap_no < PAGE_HEAP_NO_USER_LOW)
3761  || UNIV_UNLIKELY(heap_no >= page_dir_get_n_heap(page))) {
3762 
3763  goto corrupt;
3764  }
3765 
3766  memcpy(field, ptr + 4, REC_NODE_PTR_SIZE);
3767  memcpy(storage, ptr + 4, REC_NODE_PTR_SIZE);
3768 
3769 #ifdef UNIV_ZIP_DEBUG
3770  ut_a(page_zip_validate(page_zip, page));
3771 #endif /* UNIV_ZIP_DEBUG */
3772  }
3773 
3774  return(ptr + (2 + 2 + REC_NODE_PTR_SIZE));
3775 }
3776 
3777 /**********************************************************************/
3779 UNIV_INTERN
3780 void
3782 /*====================*/
3783  page_zip_des_t* page_zip,
3784  byte* rec,
3785  ulint size,
3786  ulint ptr,
3787  mtr_t* mtr)
3788 {
3789  byte* field;
3790  byte* storage;
3791  page_t* page = page_align(rec);
3792 
3793  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3795  ut_ad(page_zip_simple_validate(page_zip));
3796  ut_ad(page_zip_get_size(page_zip)
3797  > PAGE_DATA + page_zip_dir_size(page_zip));
3798  ut_ad(page_rec_is_comp(rec));
3799 
3800  ut_ad(page_zip->m_start >= PAGE_DATA);
3801  ut_ad(page_zip_header_cmp(page_zip, page));
3802 
3803  ut_ad(!page_is_leaf(page));
3804 
3805  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3806  UNIV_MEM_ASSERT_RW(rec, size);
3807 
3808  storage = page_zip->data + page_zip_get_size(page_zip)
3809  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3810  * PAGE_ZIP_DIR_SLOT_SIZE
3811  - (rec_get_heap_no_new(rec) - 1) * REC_NODE_PTR_SIZE;
3812  field = rec + size - REC_NODE_PTR_SIZE;
3813 
3814 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
3815  ut_a(!memcmp(storage, field, REC_NODE_PTR_SIZE));
3816 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
3817 #if REC_NODE_PTR_SIZE != 4
3818 # error "REC_NODE_PTR_SIZE != 4"
3819 #endif
3820  mach_write_to_4(field, ptr);
3821  memcpy(storage, field, REC_NODE_PTR_SIZE);
3822 
3823  if (mtr) {
3824 #ifndef UNIV_HOTBACKUP
3825  byte* log_ptr = mlog_open(mtr,
3826  11 + 2 + 2 + REC_NODE_PTR_SIZE);
3827  if (UNIV_UNLIKELY(!log_ptr)) {
3828  return;
3829  }
3830 
3832  field, MLOG_ZIP_WRITE_NODE_PTR, log_ptr, mtr);
3833  mach_write_to_2(log_ptr, page_offset(field));
3834  log_ptr += 2;
3835  mach_write_to_2(log_ptr, storage - page_zip->data);
3836  log_ptr += 2;
3837  memcpy(log_ptr, field, REC_NODE_PTR_SIZE);
3838  log_ptr += REC_NODE_PTR_SIZE;
3839  mlog_close(mtr, log_ptr);
3840 #endif /* !UNIV_HOTBACKUP */
3841  }
3842 }
3843 
3844 /**********************************************************************/
3846 UNIV_INTERN
3847 void
3849 /*===============================*/
3850  page_zip_des_t* page_zip,
3851  byte* rec,
3852  const ulint* offsets,
3853  ulint trx_id_col,
3854  trx_id_t trx_id,
3855  roll_ptr_t roll_ptr)
3856 {
3857  byte* field;
3858  byte* storage;
3859  page_t* page = page_align(rec);
3860  ulint len;
3861 
3862  ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
3864  ut_ad(page_zip_simple_validate(page_zip));
3865  ut_ad(page_zip_get_size(page_zip)
3866  > PAGE_DATA + page_zip_dir_size(page_zip));
3867  ut_ad(rec_offs_validate(rec, NULL, offsets));
3868  ut_ad(rec_offs_comp(offsets));
3869 
3870  ut_ad(page_zip->m_start >= PAGE_DATA);
3871  ut_ad(page_zip_header_cmp(page_zip, page));
3872 
3873  ut_ad(page_is_leaf(page));
3874 
3875  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3876 
3877  storage = page_zip->data + page_zip_get_size(page_zip)
3878  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
3879  * PAGE_ZIP_DIR_SLOT_SIZE
3880  - (rec_get_heap_no_new(rec) - 1)
3881  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3882 
3883 #if DATA_TRX_ID + 1 != DATA_ROLL_PTR
3884 # error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
3885 #endif
3886  field = rec_get_nth_field(rec, offsets, trx_id_col, &len);
3887  ut_ad(len == DATA_TRX_ID_LEN);
3888  ut_ad(field + DATA_TRX_ID_LEN
3889  == rec_get_nth_field(rec, offsets, trx_id_col + 1, &len));
3890  ut_ad(len == DATA_ROLL_PTR_LEN);
3891 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
3892  ut_a(!memcmp(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN));
3893 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
3894 #if DATA_TRX_ID_LEN != 6
3895 # error "DATA_TRX_ID_LEN != 6"
3896 #endif
3897  mach_write_to_6(field, trx_id);
3898 #if DATA_ROLL_PTR_LEN != 7
3899 # error "DATA_ROLL_PTR_LEN != 7"
3900 #endif
3901  mach_write_to_7(field + DATA_TRX_ID_LEN, roll_ptr);
3902  memcpy(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3903 
3904  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3905  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3906  rec_offs_extra_size(offsets));
3907  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3908 }
3909 
3910 #ifdef UNIV_ZIP_DEBUG
3911 
3916 UNIV_INTERN ibool page_zip_clear_rec_disable;
3917 #endif /* UNIV_ZIP_DEBUG */
3918 
3919 /**********************************************************************/
3921 static
3922 void
3923 page_zip_clear_rec(
3924 /*===============*/
3925  page_zip_des_t* page_zip,
3926  byte* rec,
3927  dict_index_t* index,
3928  const ulint* offsets)
3929 {
3930  ulint heap_no;
3931  page_t* page = page_align(rec);
3932  /* page_zip_validate() would fail here if a record
3933  containing externally stored columns is being deleted. */
3934  ut_ad(rec_offs_validate(rec, index, offsets));
3935  ut_ad(!page_zip_dir_find(page_zip, page_offset(rec)));
3936  ut_ad(page_zip_dir_find_free(page_zip, page_offset(rec)));
3937  ut_ad(page_zip_header_cmp(page_zip, page));
3938 
3939  heap_no = rec_get_heap_no_new(rec);
3940  ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW);
3941 
3942  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
3943  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
3944  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
3945  rec_offs_extra_size(offsets));
3946 
3947  if (
3948 #ifdef UNIV_ZIP_DEBUG
3949  !page_zip_clear_rec_disable &&
3950 #endif /* UNIV_ZIP_DEBUG */
3951  page_zip->m_end
3952  + 1 + ((heap_no - 1) >= 64)/* size of the log entry */
3953  + page_zip_get_trailer_len(page_zip,
3954  dict_index_is_clust(index), NULL)
3955  < page_zip_get_size(page_zip)) {
3956  byte* data;
3957 
3958  /* Clear only the data bytes, because the allocator and
3959  the decompressor depend on the extra bytes. */
3960  memset(rec, 0, rec_offs_data_size(offsets));
3961 
3962  if (!page_is_leaf(page)) {
3963  /* Clear node_ptr on the compressed page. */
3964  byte* storage = page_zip->data
3965  + page_zip_get_size(page_zip)
3966  - (page_dir_get_n_heap(page)
3967  - PAGE_HEAP_NO_USER_LOW)
3968  * PAGE_ZIP_DIR_SLOT_SIZE;
3969 
3970  memset(storage - (heap_no - 1) * REC_NODE_PTR_SIZE,
3971  0, REC_NODE_PTR_SIZE);
3972  } else if (dict_index_is_clust(index)) {
3973  /* Clear trx_id and roll_ptr on the compressed page. */
3974  byte* storage = page_zip->data
3975  + page_zip_get_size(page_zip)
3976  - (page_dir_get_n_heap(page)
3977  - PAGE_HEAP_NO_USER_LOW)
3978  * PAGE_ZIP_DIR_SLOT_SIZE;
3979 
3980  memset(storage - (heap_no - 1)
3981  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
3982  0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
3983  }
3984 
3985  /* Log that the data was zeroed out. */
3986  data = page_zip->data + page_zip->m_end;
3987  ut_ad(!*data);
3988  if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
3989  *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
3990  ut_ad(!*data);
3991  }
3992  *data++ = (byte) ((heap_no - 1) << 1 | 1);
3993  ut_ad(!*data);
3994  ut_ad((ulint) (data - page_zip->data)
3995  < page_zip_get_size(page_zip));
3996  page_zip->m_end = data - page_zip->data;
3997  page_zip->m_nonempty = TRUE;
3998  } else if (page_is_leaf(page) && dict_index_is_clust(index)) {
3999  /* Do not clear the record, because there is not enough space
4000  to log the operation. */
4001 
4002  if (rec_offs_any_extern(offsets)) {
4003  ulint i;
4004 
4005  for (i = rec_offs_n_fields(offsets); i--; ) {
4006  /* Clear all BLOB pointers in order to make
4007  page_zip_validate() pass. */
4008  if (rec_offs_nth_extern(offsets, i)) {
4009  ulint len;
4010  byte* field = rec_get_nth_field(
4011  rec, offsets, i, &len);
4012  memset(field + len
4013  - BTR_EXTERN_FIELD_REF_SIZE,
4014  0, BTR_EXTERN_FIELD_REF_SIZE);
4015  }
4016  }
4017  }
4018  }
4019 
4020 #ifdef UNIV_ZIP_DEBUG
4021  ut_a(page_zip_validate(page_zip, page));
4022 #endif /* UNIV_ZIP_DEBUG */
4023 }
4024 
4025 /**********************************************************************/
4028 UNIV_INTERN
4029 void
4031 /*=====================*/
4032  page_zip_des_t* page_zip,
4033  const byte* rec,
4034  ulint flag)
4035 {
4036  byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
4037  ut_a(slot);
4038  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4039  if (flag) {
4040  *slot |= (PAGE_ZIP_DIR_SLOT_DEL >> 8);
4041  } else {
4042  *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
4043  }
4044 #ifdef UNIV_ZIP_DEBUG
4045  ut_a(page_zip_validate(page_zip, page_align(rec)));
4046 #endif /* UNIV_ZIP_DEBUG */
4047 }
4048 
4049 /**********************************************************************/
4052 UNIV_INTERN
4053 void
4055 /*===================*/
4056  page_zip_des_t* page_zip,
4057  const byte* rec,
4058  ulint flag)
4059 {
4060  byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
4061  ut_a(slot);
4062  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4063  if (flag) {
4064  *slot |= (PAGE_ZIP_DIR_SLOT_OWNED >> 8);
4065  } else {
4066  *slot &= ~(PAGE_ZIP_DIR_SLOT_OWNED >> 8);
4067  }
4068 }
4069 
4070 /**********************************************************************/
4072 UNIV_INTERN
4073 void
4075 /*================*/
4076  page_zip_des_t* page_zip,
4077  const byte* prev_rec,
4078  const byte* free_rec,
4080  byte* rec)
4081 {
4082  ulint n_dense;
4083  byte* slot_rec;
4084  byte* slot_free;
4085 
4086  ut_ad(prev_rec != rec);
4087  ut_ad(page_rec_get_next((rec_t*) prev_rec) == rec);
4088  ut_ad(page_zip_simple_validate(page_zip));
4089 
4090  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4091 
4092  if (page_rec_is_infimum(prev_rec)) {
4093  /* Use the first slot. */
4094  slot_rec = page_zip->data + page_zip_get_size(page_zip);
4095  } else {
4096  byte* end = page_zip->data + page_zip_get_size(page_zip);
4097  byte* start = end - page_zip_dir_user_size(page_zip);
4098 
4099  if (UNIV_LIKELY(!free_rec)) {
4100  /* PAGE_N_RECS was already incremented
4101  in page_cur_insert_rec_zip(), but the
4102  dense directory slot at that position
4103  contains garbage. Skip it. */
4104  start += PAGE_ZIP_DIR_SLOT_SIZE;
4105  }
4106 
4107  slot_rec = page_zip_dir_find_low(start, end,
4108  page_offset(prev_rec));
4109  ut_a(slot_rec);
4110  }
4111 
4112  /* Read the old n_dense (n_heap may have been incremented). */
4113  n_dense = page_dir_get_n_heap(page_zip->data)
4114  - (PAGE_HEAP_NO_USER_LOW + 1);
4115 
4116  if (UNIV_LIKELY_NULL(free_rec)) {
4117  /* The record was allocated from the free list.
4118  Shift the dense directory only up to that slot.
4119  Note that in this case, n_dense is actually
4120  off by one, because page_cur_insert_rec_zip()
4121  did not increment n_heap. */
4122  ut_ad(rec_get_heap_no_new(rec) < n_dense + 1
4123  + PAGE_HEAP_NO_USER_LOW);
4124  ut_ad(rec >= free_rec);
4125  slot_free = page_zip_dir_find(page_zip, page_offset(free_rec));
4126  ut_ad(slot_free);
4127  slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
4128  } else {
4129  /* The record was allocated from the heap.
4130  Shift the entire dense directory. */
4131  ut_ad(rec_get_heap_no_new(rec) == n_dense
4132  + PAGE_HEAP_NO_USER_LOW);
4133 
4134  /* Shift to the end of the dense page directory. */
4135  slot_free = page_zip->data + page_zip_get_size(page_zip)
4136  - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
4137  }
4138 
4139  /* Shift the dense directory to allocate place for rec. */
4140  memmove(slot_free - PAGE_ZIP_DIR_SLOT_SIZE, slot_free,
4141  slot_rec - slot_free);
4142 
4143  /* Write the entry for the inserted record.
4144  The "owned" and "deleted" flags must be zero. */
4145  mach_write_to_2(slot_rec - PAGE_ZIP_DIR_SLOT_SIZE, page_offset(rec));
4146 }
4147 
4148 /**********************************************************************/
4151 UNIV_INTERN
4152 void
4154 /*================*/
4155  page_zip_des_t* page_zip,
4156  byte* rec,
4157  dict_index_t* index,
4158  const ulint* offsets,
4159  const byte* free)
4160 {
4161  byte* slot_rec;
4162  byte* slot_free;
4163  ulint n_ext;
4164  page_t* page = page_align(rec);
4165 
4166  ut_ad(rec_offs_validate(rec, index, offsets));
4167  ut_ad(rec_offs_comp(offsets));
4168 
4169  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4170  UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
4171  UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
4172  rec_offs_extra_size(offsets));
4173 
4174  slot_rec = page_zip_dir_find(page_zip, page_offset(rec));
4175 
4176  ut_a(slot_rec);
4177 
4178  /* This could not be done before page_zip_dir_find(). */
4179  page_header_set_field(page, page_zip, PAGE_N_RECS,
4180  (ulint)(page_get_n_recs(page) - 1));
4181 
4182  if (UNIV_UNLIKELY(!free)) {
4183  /* Make the last slot the start of the free list. */
4184  slot_free = page_zip->data + page_zip_get_size(page_zip)
4185  - PAGE_ZIP_DIR_SLOT_SIZE
4186  * (page_dir_get_n_heap(page_zip->data)
4187  - PAGE_HEAP_NO_USER_LOW);
4188  } else {
4189  slot_free = page_zip_dir_find_free(page_zip,
4190  page_offset(free));
4191  ut_a(slot_free < slot_rec);
4192  /* Grow the free list by one slot by moving the start. */
4193  slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
4194  }
4195 
4196  if (UNIV_LIKELY(slot_rec > slot_free)) {
4197  memmove(slot_free + PAGE_ZIP_DIR_SLOT_SIZE,
4198  slot_free,
4199  slot_rec - slot_free);
4200  }
4201 
4202  /* Write the entry for the deleted record.
4203  The "owned" and "deleted" flags will be cleared. */
4204  mach_write_to_2(slot_free, page_offset(rec));
4205 
4206  if (!page_is_leaf(page) || !dict_index_is_clust(index)) {
4207  ut_ad(!rec_offs_any_extern(offsets));
4208  goto skip_blobs;
4209  }
4210 
4211  n_ext = rec_offs_n_extern(offsets);
4212  if (UNIV_UNLIKELY(n_ext)) {
4213  /* Shift and zero fill the array of BLOB pointers. */
4214  ulint blob_no;
4215  byte* externs;
4216  byte* ext_end;
4217 
4218  blob_no = page_zip_get_n_prev_extern(page_zip, rec, index);
4219  ut_a(blob_no + n_ext <= page_zip->n_blobs);
4220 
4221  externs = page_zip->data + page_zip_get_size(page_zip)
4222  - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
4223  * (PAGE_ZIP_DIR_SLOT_SIZE
4224  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4225 
4226  ext_end = externs - page_zip->n_blobs
4228  externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
4229 
4230  page_zip->n_blobs -= n_ext;
4231  /* Shift and zero fill the array. */
4232  memmove(ext_end + n_ext * BTR_EXTERN_FIELD_REF_SIZE, ext_end,
4233  (page_zip->n_blobs - blob_no)
4234  * BTR_EXTERN_FIELD_REF_SIZE);
4235  memset(ext_end, 0, n_ext * BTR_EXTERN_FIELD_REF_SIZE);
4236  }
4237 
4238 skip_blobs:
4239  /* The compression algorithm expects info_bits and n_owned
4240  to be 0 for deleted records. */
4241  rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
4242 
4243  page_zip_clear_rec(page_zip, rec, index, offsets);
4244 }
4245 
4246 /**********************************************************************/
4248 UNIV_INTERN
4249 void
4251 /*==================*/
4252  page_zip_des_t* page_zip,
4253  ulint is_clustered)
4255 {
4256  ulint n_dense;
4257  byte* dir;
4258  byte* stored;
4259 
4260  ut_ad(page_is_comp(page_zip->data));
4261  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4262 
4263  /* Read the old n_dense (n_heap has already been incremented). */
4264  n_dense = page_dir_get_n_heap(page_zip->data)
4265  - (PAGE_HEAP_NO_USER_LOW + 1);
4266 
4267  dir = page_zip->data + page_zip_get_size(page_zip)
4268  - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
4269 
4270  if (!page_is_leaf(page_zip->data)) {
4271  ut_ad(!page_zip->n_blobs);
4272  stored = dir - n_dense * REC_NODE_PTR_SIZE;
4273  } else if (UNIV_UNLIKELY(is_clustered)) {
4274  /* Move the BLOB pointer array backwards to make space for the
4275  roll_ptr and trx_id columns and the dense directory slot. */
4276  byte* externs;
4277 
4278  stored = dir - n_dense
4279  * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4280  externs = stored
4281  - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
4282  ASSERT_ZERO(externs
4283  - (PAGE_ZIP_DIR_SLOT_SIZE
4284  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
4285  PAGE_ZIP_DIR_SLOT_SIZE
4286  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
4287  memmove(externs - (PAGE_ZIP_DIR_SLOT_SIZE
4288  + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
4289  externs, stored - externs);
4290  } else {
4291  stored = dir
4292  - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
4293  ASSERT_ZERO(stored - PAGE_ZIP_DIR_SLOT_SIZE,
4294  PAGE_ZIP_DIR_SLOT_SIZE);
4295  }
4296 
4297  /* Move the uncompressed area backwards to make space
4298  for one directory slot. */
4299  memmove(stored - PAGE_ZIP_DIR_SLOT_SIZE, stored, dir - stored);
4300 }
4301 
4302 /***********************************************************/
4305 UNIV_INTERN
4306 byte*
4308 /*========================*/
4309  byte* ptr,
4310  byte* end_ptr,
4311  page_t* page,
4312  page_zip_des_t* page_zip)
4313 {
4314  ulint offset;
4315  ulint len;
4316 
4317  ut_ad(ptr && end_ptr);
4318  ut_ad(!page == !page_zip);
4319 
4320  if (UNIV_UNLIKELY(end_ptr < ptr + (1 + 1))) {
4321 
4322  return(NULL);
4323  }
4324 
4325  offset = (ulint) *ptr++;
4326  len = (ulint) *ptr++;
4327 
4328  if (UNIV_UNLIKELY(!len) || UNIV_UNLIKELY(offset + len >= PAGE_DATA)) {
4329 corrupt:
4330  recv_sys->found_corrupt_log = TRUE;
4331 
4332  return(NULL);
4333  }
4334 
4335  if (UNIV_UNLIKELY(end_ptr < ptr + len)) {
4336 
4337  return(NULL);
4338  }
4339 
4340  if (page) {
4341  if (UNIV_UNLIKELY(!page_zip)) {
4342 
4343  goto corrupt;
4344  }
4345 #ifdef UNIV_ZIP_DEBUG
4346  ut_a(page_zip_validate(page_zip, page));
4347 #endif /* UNIV_ZIP_DEBUG */
4348 
4349  memcpy(page + offset, ptr, len);
4350  memcpy(page_zip->data + offset, ptr, len);
4351 
4352 #ifdef UNIV_ZIP_DEBUG
4353  ut_a(page_zip_validate(page_zip, page));
4354 #endif /* UNIV_ZIP_DEBUG */
4355  }
4356 
4357  return(ptr + len);
4358 }
4359 
4360 #ifndef UNIV_HOTBACKUP
4361 /**********************************************************************/
4363 UNIV_INTERN
4364 void
4365 page_zip_write_header_log(
4366 /*======================*/
4367  const byte* data,
4368  ulint length,
4369  mtr_t* mtr)
4370 {
4371  byte* log_ptr = mlog_open(mtr, 11 + 1 + 1);
4372  ulint offset = page_offset(data);
4373 
4374  ut_ad(offset < PAGE_DATA);
4375  ut_ad(offset + length < PAGE_DATA);
4376 #if PAGE_DATA > 255
4377 # error "PAGE_DATA > 255"
4378 #endif
4379  ut_ad(length < 256);
4380 
4381  /* If no logging is requested, we may return now */
4382  if (UNIV_UNLIKELY(!log_ptr)) {
4383 
4384  return;
4385  }
4386 
4388  (byte*) data, MLOG_ZIP_WRITE_HEADER, log_ptr, mtr);
4389  *log_ptr++ = (byte) offset;
4390  *log_ptr++ = (byte) length;
4391  mlog_close(mtr, log_ptr);
4392 
4393  mlog_catenate_string(mtr, data, length);
4394 }
4395 #endif /* !UNIV_HOTBACKUP */
4396 
4397 /**********************************************************************/
4408 UNIV_INTERN
4409 ibool
4411 /*================*/
4412  buf_block_t* block,
4416  dict_index_t* index,
4417  mtr_t* mtr)
4418 {
4419  buf_pool_t* buf_pool = buf_pool_from_block(block);
4420  page_zip_des_t* page_zip = buf_block_get_page_zip(block);
4421  page_t* page = buf_block_get_frame(block);
4422  buf_block_t* temp_block;
4423  page_t* temp_page;
4424  ulint log_mode;
4425 
4426  ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
4427  ut_ad(page_is_comp(page));
4428  ut_ad(!dict_index_is_ibuf(index));
4429  /* Note that page_zip_validate(page_zip, page) may fail here. */
4430  UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
4431  UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
4432 
4433  /* Disable logging */
4434  log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
4435 
4436 #ifndef UNIV_HOTBACKUP
4437  temp_block = buf_block_alloc(buf_pool, 0);
4438  btr_search_drop_page_hash_index(block);
4439  block->check_index_page_at_flush = TRUE;
4440 #else /* !UNIV_HOTBACKUP */
4441  ut_ad(block == back_block1);
4442  temp_block = back_block2;
4443 #endif /* !UNIV_HOTBACKUP */
4444  temp_page = temp_block->frame;
4445 
4446  /* Copy the old page to temporary space */
4447  buf_frame_copy(temp_page, page);
4448 
4449  /* Recreate the page: note that global data on page (possible
4450  segment headers, next page-field, etc.) is preserved intact */
4451 
4452  page_create(block, mtr, TRUE);
4453 
4454  /* Copy the records from the temporary space to the recreated page;
4455  do not copy the lock bits yet */
4456 
4457  page_copy_rec_list_end_no_locks(block, temp_block,
4458  page_get_infimum_rec(temp_page),
4459  index, mtr);
4460 
4461  if (!dict_index_is_clust(index) && page_is_leaf(temp_page)) {
4462  /* Copy max trx id to recreated page */
4463  trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
4464  page_set_max_trx_id(block, NULL, max_trx_id, NULL);
4465  ut_ad(max_trx_id != 0);
4466  }
4467 
4468  /* Restore logging. */
4469  mtr_set_log_mode(mtr, log_mode);
4470 
4471  if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
4472 
4473 #ifndef UNIV_HOTBACKUP
4474  buf_block_free(temp_block);
4475 #endif /* !UNIV_HOTBACKUP */
4476  return(FALSE);
4477  }
4478 
4479  lock_move_reorganize_page(block, temp_block);
4480 
4481 #ifndef UNIV_HOTBACKUP
4482  buf_block_free(temp_block);
4483 #endif /* !UNIV_HOTBACKUP */
4484  return(TRUE);
4485 }
4486 
4487 #ifndef UNIV_HOTBACKUP
4488 /**********************************************************************/
4493 UNIV_INTERN
4494 void
4496 /*===============*/
4497  page_zip_des_t* page_zip,
4500  page_t* page,
4501  const page_zip_des_t* src_zip,
4502  const page_t* src,
4503  dict_index_t* index,
4504  mtr_t* mtr)
4505 {
4506  ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
4507  ut_ad(mtr_memo_contains_page(mtr, (page_t*) src, MTR_MEMO_PAGE_X_FIX));
4508  ut_ad(!dict_index_is_ibuf(index));
4509 #ifdef UNIV_ZIP_DEBUG
4510  /* The B-tree operations that call this function may set
4511  FIL_PAGE_PREV or PAGE_LEVEL, causing a temporary min_rec_flag
4512  mismatch. A strict page_zip_validate() will be executed later
4513  during the B-tree operations. */
4514  ut_a(page_zip_validate_low(src_zip, src, TRUE));
4515 #endif /* UNIV_ZIP_DEBUG */
4516  ut_a(page_zip_get_size(page_zip) == page_zip_get_size(src_zip));
4517  if (UNIV_UNLIKELY(src_zip->n_blobs)) {
4518  ut_a(page_is_leaf(src));
4519  ut_a(dict_index_is_clust(index));
4520  }
4521 
4522  /* The PAGE_MAX_TRX_ID must be set on leaf pages of secondary
4523  indexes. It does not matter on other pages. */
4524  ut_a(dict_index_is_clust(index) || !page_is_leaf(src)
4525  || page_get_max_trx_id(src));
4526 
4527  UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE);
4528  UNIV_MEM_ASSERT_W(page_zip->data, page_zip_get_size(page_zip));
4529  UNIV_MEM_ASSERT_RW(src, UNIV_PAGE_SIZE);
4530  UNIV_MEM_ASSERT_RW(src_zip->data, page_zip_get_size(page_zip));
4531 
4532  /* Copy those B-tree page header fields that are related to
4533  the records stored in the page. Also copy the field
4534  PAGE_MAX_TRX_ID. Skip the rest of the page header and
4535  trailer. On the compressed page, there is no trailer. */
4536 #if PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END
4537 # error "PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END"
4538 #endif
4539  memcpy(PAGE_HEADER + page, PAGE_HEADER + src,
4540  PAGE_HEADER_PRIV_END);
4541  memcpy(PAGE_DATA + page, PAGE_DATA + src,
4542  UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END);
4543  memcpy(PAGE_HEADER + page_zip->data, PAGE_HEADER + src_zip->data,
4544  PAGE_HEADER_PRIV_END);
4545  memcpy(PAGE_DATA + page_zip->data, PAGE_DATA + src_zip->data,
4546  page_zip_get_size(page_zip) - PAGE_DATA);
4547 
4548  /* Copy all fields of src_zip to page_zip, except the pointer
4549  to the compressed data page. */
4550  {
4551  page_zip_t* data = page_zip->data;
4552  memcpy(page_zip, src_zip, sizeof *page_zip);
4553  page_zip->data = data;
4554  }
4555  ut_ad(page_zip_get_trailer_len(page_zip,
4556  dict_index_is_clust(index), NULL)
4557  + page_zip->m_end < page_zip_get_size(page_zip));
4558 
4559  if (!page_is_leaf(src)
4560  && UNIV_UNLIKELY(mach_read_from_4(src + FIL_PAGE_PREV) == FIL_NULL)
4561  && UNIV_LIKELY(mach_read_from_4(page
4562  + FIL_PAGE_PREV) != FIL_NULL)) {
4563  /* Clear the REC_INFO_MIN_REC_FLAG of the first user record. */
4564  ulint offs = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
4565  TRUE);
4566  if (UNIV_LIKELY(offs != PAGE_NEW_SUPREMUM)) {
4567  rec_t* rec = page + offs;
4568  ut_a(rec[-REC_N_NEW_EXTRA_BYTES]
4569  & REC_INFO_MIN_REC_FLAG);
4570  rec[-REC_N_NEW_EXTRA_BYTES] &= ~ REC_INFO_MIN_REC_FLAG;
4571  }
4572  }
4573 
4574 #ifdef UNIV_ZIP_DEBUG
4575  ut_a(page_zip_validate(page_zip, page));
4576 #endif /* UNIV_ZIP_DEBUG */
4577 
4578  page_zip_compress_write_log(page_zip, page, index, mtr);
4579 }
4580 #endif /* !UNIV_HOTBACKUP */
4581 
4582 /**********************************************************************/
4585 UNIV_INTERN
4586 byte*
4588 /*====================*/
4589  byte* ptr,
4590  byte* end_ptr,
4591  page_t* page,
4592  page_zip_des_t* page_zip)
4593 {
4594  ulint size;
4595  ulint trailer_size;
4596 
4597  ut_ad(ptr && end_ptr);
4598  ut_ad(!page == !page_zip);
4599 
4600  if (UNIV_UNLIKELY(ptr + (2 + 2) > end_ptr)) {
4601 
4602  return(NULL);
4603  }
4604 
4605  size = mach_read_from_2(ptr);
4606  ptr += 2;
4607  trailer_size = mach_read_from_2(ptr);
4608  ptr += 2;
4609 
4610  if (UNIV_UNLIKELY(ptr + 8 + size + trailer_size > end_ptr)) {
4611 
4612  return(NULL);
4613  }
4614 
4615  if (page) {
4616  if (UNIV_UNLIKELY(!page_zip)
4617  || UNIV_UNLIKELY(page_zip_get_size(page_zip) < size)) {
4618 corrupt:
4619  recv_sys->found_corrupt_log = TRUE;
4620 
4621  return(NULL);
4622  }
4623 
4624  memcpy(page_zip->data + FIL_PAGE_PREV, ptr, 4);
4625  memcpy(page_zip->data + FIL_PAGE_NEXT, ptr + 4, 4);
4626  memcpy(page_zip->data + FIL_PAGE_TYPE, ptr + 8, size);
4627  memset(page_zip->data + FIL_PAGE_TYPE + size, 0,
4628  page_zip_get_size(page_zip) - trailer_size
4629  - (FIL_PAGE_TYPE + size));
4630  memcpy(page_zip->data + page_zip_get_size(page_zip)
4631  - trailer_size, ptr + 8 + size, trailer_size);
4632 
4633  if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page,
4634  TRUE))) {
4635 
4636  goto corrupt;
4637  }
4638  }
4639 
4640  return(ptr + 8 + size + trailer_size);
4641 }
4642 
4643 /**********************************************************************/
4646 UNIV_INTERN
4647 ulint
4649 /*===================*/
4650  const void* data,
4651  ulint size)
4652 {
4653  /* Exclude FIL_PAGE_SPACE_OR_CHKSUM, FIL_PAGE_LSN,
4654  and FIL_PAGE_FILE_FLUSH_LSN from the checksum. */
4655 
4656  const Bytef* s = static_cast<const Bytef *>(data);
4657  uLong adler;
4658 
4660 
4661  adler = adler32(0L, s + FIL_PAGE_OFFSET,
4663  adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
4664  adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
4666 
4667  return((ulint) adler);
4668 }