Drizzled Public API Documentation

page0zip.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 2005, 2009, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /**************************************************/
00026 #define THIS_MODULE
00027 #include "page0zip.h"
00028 #ifdef UNIV_NONINL
00029 # include "page0zip.ic"
00030 #endif
00031 #undef THIS_MODULE
00032 #include "page0page.h"
00033 #include "mtr0log.h"
00034 #include "ut0sort.h"
00035 #include "dict0dict.h"
00036 #include "btr0cur.h"
00037 #include "page0types.h"
00038 #include "log0recv.h"
00039 #include "zlib.h"
00040 #ifndef UNIV_HOTBACKUP
00041 # include "buf0lru.h"
00042 # include "btr0sea.h"
00043 # include "dict0boot.h"
00044 # include "lock0lock.h"
00045 #else /* !UNIV_HOTBACKUP */
00046 # define lock_move_reorganize_page(block, temp_block) ((void) 0)
00047 # define buf_LRU_stat_inc_unzip()     ((void) 0)
00048 #endif /* !UNIV_HOTBACKUP */
00049 
00050 #ifndef UNIV_HOTBACKUP
00051 
00052 UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE - 1];
00053 #endif /* !UNIV_HOTBACKUP */
00054 
00055 /* Please refer to ../include/page0zip.ic for a description of the
00056 compressed page format. */
00057 
00058 /* The infimum and supremum records are omitted from the compressed page.
00059 On compress, we compare that the records are there, and on uncompress we
00060 restore the records. */
00062 static const byte infimum_extra[] = {
00063   0x01,     /* info_bits=0, n_owned=1 */
00064   0x00, 0x02    /* heap_no=0, status=2 */
00065   /* ?, ? */    /* next=(first user rec, or supremum) */
00066 };
00068 static const byte infimum_data[] = {
00069   0x69, 0x6e, 0x66, 0x69,
00070   0x6d, 0x75, 0x6d, 0x00  /* "infimum\0" */
00071 };
00073 static const byte supremum_extra_data[] = {
00074   /* 0x0?, */   /* info_bits=0, n_owned=1..8 */
00075   0x00, 0x0b,   /* heap_no=1, status=3 */
00076   0x00, 0x00,   /* next=0 */
00077   0x73, 0x75, 0x70, 0x72,
00078   0x65, 0x6d, 0x75, 0x6d  /* "supremum" */
00079 };
00080 
00085 #define ASSERT_ZERO(b, s) \
00086   ut_ad(!memcmp(b, field_ref_zero, ut_min(s, sizeof field_ref_zero)))
00087 
00089 #define ASSERT_ZERO_BLOB(b) \
00090   ut_ad(!memcmp(b, field_ref_zero, sizeof field_ref_zero))
00091 
00092 /* Enable some extra debugging output.  This code can be enabled
00093 independently of any UNIV_ debugging conditions. */
00094 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
00095 # include <stdarg.h>
00096 __attribute__((format (printf, 1, 2)))
00097 /**********************************************************************/
00100 static
00101 int
00102 page_zip_fail_func(
00103 /*===============*/
00104   const char* fmt,  
00105   ...)      
00106 {
00107   int res;
00108   va_list ap;
00109 
00110   ut_print_timestamp(stderr);
00111   fputs("  InnoDB: ", stderr);
00112   va_start(ap, fmt);
00113   res = vfprintf(stderr, fmt, ap);
00114   va_end(ap);
00115 
00116   return(res);
00117 }
00120 # define page_zip_fail(fmt_args) page_zip_fail_func fmt_args
00121 #else /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
00122 
00124 # define page_zip_fail(fmt_args) /* empty */
00125 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
00126 
00127 #ifndef UNIV_HOTBACKUP
00128 /**********************************************************************/
00131 UNIV_INTERN
00132 ulint
00133 page_zip_empty_size(
00134 /*================*/
00135   ulint n_fields, 
00136   ulint zip_size) 
00137 {
00138   lint  size = zip_size
00139     /* subtract the page header and the longest
00140     uncompressed data needed for one record */
00141     - (PAGE_DATA
00142        + PAGE_ZIP_DIR_SLOT_SIZE
00143        + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN
00144        + 1/* encoded heap_no==2 in page_zip_write_rec() */
00145        + 1/* end of modification log */
00146        - REC_N_NEW_EXTRA_BYTES/* omitted bytes */)
00147     /* subtract the space for page_zip_fields_encode() */
00148     - compressBound(2 * (n_fields + 1));
00149   return(size > 0 ? (ulint) size : 0);
00150 }
00151 #endif /* !UNIV_HOTBACKUP */
00152 
00153 /*************************************************************/
00157 UNIV_INLINE
00158 ulint
00159 page_zip_dir_size(
00160 /*==============*/
00161   const page_zip_des_t* page_zip) 
00162 {
00163   /* Exclude the page infimum and supremum from the record count. */
00164   ulint size = PAGE_ZIP_DIR_SLOT_SIZE
00165     * (page_dir_get_n_heap(page_zip->data)
00166        - PAGE_HEAP_NO_USER_LOW);
00167   return(size);
00168 }
00169 
00170 /*************************************************************/
00174 UNIV_INLINE
00175 ulint
00176 page_zip_dir_user_size(
00177 /*===================*/
00178   const page_zip_des_t* page_zip) 
00179 {
00180   ulint size = PAGE_ZIP_DIR_SLOT_SIZE
00181     * page_get_n_recs(page_zip->data);
00182   ut_ad(size <= page_zip_dir_size(page_zip));
00183   return(size);
00184 }
00185 
00186 /*************************************************************/
00189 UNIV_INLINE
00190 byte*
00191 page_zip_dir_find_low(
00192 /*==================*/
00193   byte* slot,     
00194   byte* end,      
00195   ulint offset)     
00196 {
00197   ut_ad(slot <= end);
00198 
00199   for (; slot < end; slot += PAGE_ZIP_DIR_SLOT_SIZE) {
00200     if ((mach_read_from_2(slot) & PAGE_ZIP_DIR_SLOT_MASK)
00201         == offset) {
00202       return(slot);
00203     }
00204   }
00205 
00206   return(NULL);
00207 }
00208 
00209 /*************************************************************/
00212 UNIV_INLINE
00213 byte*
00214 page_zip_dir_find(
00215 /*==============*/
00216   page_zip_des_t* page_zip,   
00217   ulint   offset)     
00218 {
00219   byte* end = page_zip->data + page_zip_get_size(page_zip);
00220 
00221   ut_ad(page_zip_simple_validate(page_zip));
00222 
00223   return(page_zip_dir_find_low(end - page_zip_dir_user_size(page_zip),
00224              end,
00225              offset));
00226 }
00227 
00228 /*************************************************************/
00231 UNIV_INLINE
00232 byte*
00233 page_zip_dir_find_free(
00234 /*===================*/
00235   page_zip_des_t* page_zip,   
00236   ulint   offset)     
00237 {
00238   byte* end = page_zip->data + page_zip_get_size(page_zip);
00239 
00240   ut_ad(page_zip_simple_validate(page_zip));
00241 
00242   return(page_zip_dir_find_low(end - page_zip_dir_size(page_zip),
00243              end - page_zip_dir_user_size(page_zip),
00244              offset));
00245 }
00246 
00247 /*************************************************************/
00251 UNIV_INLINE
00252 ulint
00253 page_zip_dir_get(
00254 /*=============*/
00255   const page_zip_des_t* page_zip, 
00256   ulint     slot)   
00258 {
00259   ut_ad(page_zip_simple_validate(page_zip));
00260   ut_ad(slot < page_zip_dir_size(page_zip) / PAGE_ZIP_DIR_SLOT_SIZE);
00261   return(mach_read_from_2(page_zip->data + page_zip_get_size(page_zip)
00262         - PAGE_ZIP_DIR_SLOT_SIZE * (slot + 1)));
00263 }
00264 
00265 #ifndef UNIV_HOTBACKUP
00266 /**********************************************************************/
00268 static
00269 void
00270 page_zip_compress_write_log(
00271 /*========================*/
00272   const page_zip_des_t* page_zip,
00273   const page_t*   page, 
00274   dict_index_t*   index,  
00275   mtr_t*      mtr)  
00276 {
00277   byte* log_ptr;
00278   ulint trailer_size;
00279 
00280   ut_ad(!dict_index_is_ibuf(index));
00281 
00282   log_ptr = mlog_open(mtr, 11 + 2 + 2);
00283 
00284   if (!log_ptr) {
00285 
00286     return;
00287   }
00288 
00289   /* Read the number of user records. */
00290   trailer_size = page_dir_get_n_heap(page_zip->data)
00291     - PAGE_HEAP_NO_USER_LOW;
00292   /* Multiply by uncompressed of size stored per record */
00293   if (!page_is_leaf(page)) {
00294     trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE;
00295   } else if (dict_index_is_clust(index)) {
00296     trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE
00297       + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
00298   } else {
00299     trailer_size *= PAGE_ZIP_DIR_SLOT_SIZE;
00300   }
00301   /* Add the space occupied by BLOB pointers. */
00302   trailer_size += page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
00303   ut_a(page_zip->m_end > PAGE_DATA);
00304 #if FIL_PAGE_DATA > PAGE_DATA
00305 # error "FIL_PAGE_DATA > PAGE_DATA"
00306 #endif
00307   ut_a(page_zip->m_end + trailer_size <= page_zip_get_size(page_zip));
00308 
00309   log_ptr = mlog_write_initial_log_record_fast((page_t*) page,
00310                  MLOG_ZIP_PAGE_COMPRESS,
00311                  log_ptr, mtr);
00312   mach_write_to_2(log_ptr, page_zip->m_end - FIL_PAGE_TYPE);
00313   log_ptr += 2;
00314   mach_write_to_2(log_ptr, trailer_size);
00315   log_ptr += 2;
00316   mlog_close(mtr, log_ptr);
00317 
00318   /* Write FIL_PAGE_PREV and FIL_PAGE_NEXT */
00319   mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_PREV, 4);
00320   mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_NEXT, 4);
00321   /* Write most of the page header, the compressed stream and
00322   the modification log. */
00323   mlog_catenate_string(mtr, page_zip->data + FIL_PAGE_TYPE,
00324            page_zip->m_end - FIL_PAGE_TYPE);
00325   /* Write the uncompressed trailer of the compressed page. */
00326   mlog_catenate_string(mtr, page_zip->data + page_zip_get_size(page_zip)
00327            - trailer_size, trailer_size);
00328 }
00329 #endif /* !UNIV_HOTBACKUP */
00330 
00331 /******************************************************/
00334 static
00335 ulint
00336 page_zip_get_n_prev_extern(
00337 /*=======================*/
00338   const page_zip_des_t* page_zip,
00340   const rec_t*    rec,  
00342   dict_index_t*   index)  
00343 {
00344   const page_t* page  = page_align(rec);
00345   ulint   n_ext = 0;
00346   ulint   i;
00347   ulint   left;
00348   ulint   heap_no;
00349   ulint   n_recs  = page_get_n_recs(page_zip->data);
00350 
00351   ut_ad(page_is_leaf(page));
00352   ut_ad(page_is_comp(page));
00353   ut_ad(dict_table_is_comp(index->table));
00354   ut_ad(dict_index_is_clust(index));
00355   ut_ad(!dict_index_is_ibuf(index));
00356 
00357   heap_no = rec_get_heap_no_new(rec);
00358   ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW);
00359   left = heap_no - PAGE_HEAP_NO_USER_LOW;
00360   if (UNIV_UNLIKELY(!left)) {
00361     return(0);
00362   }
00363 
00364   for (i = 0; i < n_recs; i++) {
00365     const rec_t*  r = page + (page_zip_dir_get(page_zip, i)
00366               & PAGE_ZIP_DIR_SLOT_MASK);
00367 
00368     if (rec_get_heap_no_new(r) < heap_no) {
00369       n_ext += rec_get_n_extern_new(r, index,
00370                   ULINT_UNDEFINED);
00371       if (!--left) {
00372         break;
00373       }
00374     }
00375   }
00376 
00377   return(n_ext);
00378 }
00379 
00380 /**********************************************************************/
00383 static
00384 byte*
00385 page_zip_fixed_field_encode(
00386 /*========================*/
00387   byte* buf,  
00388   ulint val)  
00389 {
00390   ut_ad(val >= 2);
00391 
00392   if (UNIV_LIKELY(val < 126)) {
00393     /*
00394     0 = nullable variable field of at most 255 bytes length;
00395     1 = not null variable field of at most 255 bytes length;
00396     126 = nullable variable field with maximum length >255;
00397     127 = not null variable field with maximum length >255
00398     */
00399     *buf++ = (byte) val;
00400   } else {
00401     *buf++ = (byte) (0x80 | val >> 8);
00402     *buf++ = (byte) val;
00403   }
00404 
00405   return(buf);
00406 }
00407 
00408 /**********************************************************************/
00411 static
00412 ulint
00413 page_zip_fields_encode(
00414 /*===================*/
00415   ulint   n,  
00416   dict_index_t* index,  
00417   ulint   trx_id_pos,
00420   byte*   buf)  
00421 {
00422   const byte* buf_start = buf;
00423   ulint   i;
00424   ulint   col;
00425   ulint   trx_id_col  = 0;
00426   /* sum of lengths of preceding non-nullable fixed fields, or 0 */
00427   ulint   fixed_sum = 0;
00428 
00429   ut_ad(trx_id_pos == ULINT_UNDEFINED || trx_id_pos < n);
00430 
00431   for (i = col = 0; i < n; i++) {
00432     dict_field_t* field = dict_index_get_nth_field(index, i);
00433     ulint   val;
00434 
00435     if (dict_field_get_col(field)->prtype & DATA_NOT_NULL) {
00436       val = 1; /* set the "not nullable" flag */
00437     } else {
00438       val = 0; /* nullable field */
00439     }
00440 
00441     if (!field->fixed_len) {
00442       /* variable-length field */
00443       const dict_col_t* column
00444         = dict_field_get_col(field);
00445 
00446       if (UNIV_UNLIKELY(column->len > 255)
00447           || UNIV_UNLIKELY(column->mtype == DATA_BLOB)) {
00448         val |= 0x7e; /* max > 255 bytes */
00449       }
00450 
00451       if (fixed_sum) {
00452         /* write out the length of any
00453         preceding non-nullable fields */
00454         buf = page_zip_fixed_field_encode(
00455           buf, fixed_sum << 1 | 1);
00456         fixed_sum = 0;
00457         col++;
00458       }
00459 
00460       *buf++ = (byte) val;
00461       col++;
00462     } else if (val) {
00463       /* fixed-length non-nullable field */
00464 
00465       if (fixed_sum && UNIV_UNLIKELY
00466           (fixed_sum + field->fixed_len
00467            > DICT_MAX_INDEX_COL_LEN)) {
00468         /* Write out the length of the
00469         preceding non-nullable fields,
00470         to avoid exceeding the maximum
00471         length of a fixed-length column. */
00472         buf = page_zip_fixed_field_encode(
00473           buf, fixed_sum << 1 | 1);
00474         fixed_sum = 0;
00475         col++;
00476       }
00477 
00478       if (i && UNIV_UNLIKELY(i == trx_id_pos)) {
00479         if (fixed_sum) {
00480           /* Write out the length of any
00481           preceding non-nullable fields,
00482           and start a new trx_id column. */
00483           buf = page_zip_fixed_field_encode(
00484             buf, fixed_sum << 1 | 1);
00485           col++;
00486         }
00487 
00488         trx_id_col = col;
00489         fixed_sum = field->fixed_len;
00490       } else {
00491         /* add to the sum */
00492         fixed_sum += field->fixed_len;
00493       }
00494     } else {
00495       /* fixed-length nullable field */
00496 
00497       if (fixed_sum) {
00498         /* write out the length of any
00499         preceding non-nullable fields */
00500         buf = page_zip_fixed_field_encode(
00501           buf, fixed_sum << 1 | 1);
00502         fixed_sum = 0;
00503         col++;
00504       }
00505 
00506       buf = page_zip_fixed_field_encode(
00507         buf, field->fixed_len << 1);
00508       col++;
00509     }
00510   }
00511 
00512   if (fixed_sum) {
00513     /* Write out the lengths of last fixed-length columns. */
00514     buf = page_zip_fixed_field_encode(buf, fixed_sum << 1 | 1);
00515   }
00516 
00517   if (trx_id_pos != ULINT_UNDEFINED) {
00518     /* Write out the position of the trx_id column */
00519     i = trx_id_col;
00520   } else {
00521     /* Write out the number of nullable fields */
00522     i = index->n_nullable;
00523   }
00524 
00525   if (i < 128) {
00526     *buf++ = (byte) i;
00527   } else {
00528     *buf++ = (byte) (0x80 | i >> 8);
00529     *buf++ = (byte) i;
00530   }
00531 
00532   ut_ad((ulint) (buf - buf_start) <= (n + 2) * 2);
00533   return((ulint) (buf - buf_start));
00534 }
00535 
00536 /**********************************************************************/
00538 static
00539 void
00540 page_zip_dir_encode(
00541 /*================*/
00542   const page_t* page, 
00543   byte*   buf,  
00545   const rec_t** recs) 
00548 {
00549   const byte* rec;
00550   ulint   status;
00551   ulint   min_mark;
00552   ulint   heap_no;
00553   ulint   i;
00554   ulint   n_heap;
00555   ulint   offs;
00556 
00557   min_mark = 0;
00558 
00559   if (page_is_leaf(page)) {
00560     status = REC_STATUS_ORDINARY;
00561   } else {
00562     status = REC_STATUS_NODE_PTR;
00563     if (UNIV_UNLIKELY
00564         (mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL)) {
00565       min_mark = REC_INFO_MIN_REC_FLAG;
00566     }
00567   }
00568 
00569   n_heap = page_dir_get_n_heap(page);
00570 
00571   /* Traverse the list of stored records in the collation order,
00572   starting from the first user record. */
00573 
00574   rec = page + PAGE_NEW_INFIMUM;
00575 
00576   i = 0;
00577 
00578   for (;;) {
00579     ulint info_bits;
00580     offs = rec_get_next_offs(rec, TRUE);
00581     if (UNIV_UNLIKELY(offs == PAGE_NEW_SUPREMUM)) {
00582       break;
00583     }
00584     rec = page + offs;
00585     heap_no = rec_get_heap_no_new(rec);
00586     ut_a(heap_no >= PAGE_HEAP_NO_USER_LOW);
00587     ut_a(heap_no < n_heap);
00588     ut_a(offs < UNIV_PAGE_SIZE - PAGE_DIR);
00589     ut_a(offs >= PAGE_ZIP_START);
00590 #if PAGE_ZIP_DIR_SLOT_MASK & (PAGE_ZIP_DIR_SLOT_MASK + 1)
00591 # error "PAGE_ZIP_DIR_SLOT_MASK is not 1 less than a power of 2"
00592 #endif
00593 #if PAGE_ZIP_DIR_SLOT_MASK < UNIV_PAGE_SIZE - 1
00594 # error "PAGE_ZIP_DIR_SLOT_MASK < UNIV_PAGE_SIZE - 1"
00595 #endif
00596     if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
00597       offs |= PAGE_ZIP_DIR_SLOT_OWNED;
00598     }
00599 
00600     info_bits = rec_get_info_bits(rec, TRUE);
00601     if (UNIV_UNLIKELY(info_bits & REC_INFO_DELETED_FLAG)) {
00602       info_bits &= ~REC_INFO_DELETED_FLAG;
00603       offs |= PAGE_ZIP_DIR_SLOT_DEL;
00604     }
00605     ut_a(info_bits == min_mark);
00606     /* Only the smallest user record can have
00607     REC_INFO_MIN_REC_FLAG set. */
00608     min_mark = 0;
00609 
00610     mach_write_to_2(buf - PAGE_ZIP_DIR_SLOT_SIZE * ++i, offs);
00611 
00612     if (UNIV_LIKELY_NULL(recs)) {
00613       /* Ensure that each heap_no occurs at most once. */
00614       ut_a(!recs[heap_no - PAGE_HEAP_NO_USER_LOW]);
00615       /* exclude infimum and supremum */
00616       recs[heap_no - PAGE_HEAP_NO_USER_LOW] = rec;
00617     }
00618 
00619     ut_a(rec_get_status(rec) == status);
00620   }
00621 
00622   offs = page_header_get_field(page, PAGE_FREE);
00623 
00624   /* Traverse the free list (of deleted records). */
00625   while (offs) {
00626     ut_ad(!(offs & ~PAGE_ZIP_DIR_SLOT_MASK));
00627     rec = page + offs;
00628 
00629     heap_no = rec_get_heap_no_new(rec);
00630     ut_a(heap_no >= PAGE_HEAP_NO_USER_LOW);
00631     ut_a(heap_no < n_heap);
00632 
00633     ut_a(!rec[-REC_N_NEW_EXTRA_BYTES]); /* info_bits and n_owned */
00634     ut_a(rec_get_status(rec) == status);
00635 
00636     mach_write_to_2(buf - PAGE_ZIP_DIR_SLOT_SIZE * ++i, offs);
00637 
00638     if (UNIV_LIKELY_NULL(recs)) {
00639       /* Ensure that each heap_no occurs at most once. */
00640       ut_a(!recs[heap_no - PAGE_HEAP_NO_USER_LOW]);
00641       /* exclude infimum and supremum */
00642       recs[heap_no - PAGE_HEAP_NO_USER_LOW] = rec;
00643     }
00644 
00645     offs = rec_get_next_offs(rec, TRUE);
00646   }
00647 
00648   /* Ensure that each heap no occurs at least once. */
00649   ut_a(i + PAGE_HEAP_NO_USER_LOW == n_heap);
00650 }
00651 
00652 /**********************************************************************/
00654 extern "C" void* page_zip_malloc(void* opaque, uInt items, uInt size);
00655 
00656 extern "C" void* page_zip_malloc
00657 (
00658 /*============*/
00659   void* opaque, 
00660   uInt  items,  
00661   uInt  size) 
00662 {
00663   return(mem_heap_alloc(static_cast<mem_block_info_t *>(opaque), items * size));
00664 }
00665 
00666 /**********************************************************************/
00668 extern "C" void page_zip_free(void *opaque, void *address);
00669 
00670 extern "C" void page_zip_free(void *, void *)
00671 { }
00672 
00673 /**********************************************************************/
00675 UNIV_INTERN
00676 void
00677 page_zip_set_alloc(
00678 /*===============*/
00679   void*   stream,   
00680   mem_heap_t* heap)   
00681 {
00682   z_stream* strm = static_cast<z_stream *>(stream);
00683 
00684   strm->zalloc = page_zip_malloc;
00685   strm->zfree = page_zip_free;
00686   strm->opaque = heap;
00687 }
00688 
00689 #if 0 || defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
00690 
00691 # define PAGE_ZIP_COMPRESS_DBG
00692 #endif
00693 
00694 #ifdef PAGE_ZIP_COMPRESS_DBG
00695 
00697 UNIV_INTERN ibool page_zip_compress_dbg;
00702 UNIV_INTERN unsigned  page_zip_compress_log;
00703 
00704 /**********************************************************************/
00707 static
00708 int
00709 page_zip_compress_deflate(
00710 /*======================*/
00711   FILE*   logfile,
00712   z_streamp strm, 
00713   int   flush)  
00714 {
00715   int status;
00716   if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
00717     ut_print_buf(stderr, strm->next_in, strm->avail_in);
00718   }
00719   if (UNIV_LIKELY_NULL(logfile)) {
00720     fwrite(strm->next_in, 1, strm->avail_in, logfile);
00721   }
00722   status = deflate(strm, flush);
00723   if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
00724     fprintf(stderr, " -> %d\n", status);
00725   }
00726   return(status);
00727 }
00728 
00729 /* Redefine deflate(). */
00730 # undef deflate
00731 
00736 # define deflate(strm, flush) page_zip_compress_deflate(logfile, strm, flush)
00737 
00738 # define FILE_LOGFILE FILE* logfile,
00739 
00740 # define LOGFILE logfile,
00741 #else /* PAGE_ZIP_COMPRESS_DBG */
00742 
00743 # define FILE_LOGFILE
00744 
00745 # define LOGFILE
00746 #endif /* PAGE_ZIP_COMPRESS_DBG */
00747 
00748 /**********************************************************************/
00751 static
00752 int
00753 page_zip_compress_node_ptrs(
00754 /*========================*/
00755   FILE_LOGFILE
00756   z_stream* c_stream, 
00757   const rec_t** recs,   
00759   ulint   n_dense,  
00760   dict_index_t* index,    
00761   byte*   storage,  
00762   mem_heap_t* heap)   
00763 {
00764   int err = Z_OK;
00765   ulint*  offsets = NULL;
00766 
00767   do {
00768     const rec_t*  rec = *recs++;
00769 
00770     offsets = rec_get_offsets(rec, index, offsets,
00771             ULINT_UNDEFINED, &heap);
00772     /* Only leaf nodes may contain externally stored columns. */
00773     ut_ad(!rec_offs_any_extern(offsets));
00774 
00775     UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
00776     UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
00777            rec_offs_extra_size(offsets));
00778 
00779     /* Compress the extra bytes. */
00780     c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
00781       - c_stream->next_in;
00782 
00783     if (c_stream->avail_in) {
00784       err = deflate(c_stream, Z_NO_FLUSH);
00785       if (UNIV_UNLIKELY(err != Z_OK)) {
00786         break;
00787       }
00788     }
00789     ut_ad(!c_stream->avail_in);
00790 
00791     /* Compress the data bytes, except node_ptr. */
00792     c_stream->next_in = (byte*) rec;
00793     c_stream->avail_in = rec_offs_data_size(offsets)
00794       - REC_NODE_PTR_SIZE;
00795     ut_ad(c_stream->avail_in);
00796 
00797     err = deflate(c_stream, Z_NO_FLUSH);
00798     if (UNIV_UNLIKELY(err != Z_OK)) {
00799       break;
00800     }
00801 
00802     ut_ad(!c_stream->avail_in);
00803 
00804     memcpy(storage - REC_NODE_PTR_SIZE
00805            * (rec_get_heap_no_new(rec) - 1),
00806            c_stream->next_in, REC_NODE_PTR_SIZE);
00807     c_stream->next_in += REC_NODE_PTR_SIZE;
00808   } while (--n_dense);
00809 
00810   return(err);
00811 }
00812 
00813 /**********************************************************************/
00816 static
00817 int
00818 page_zip_compress_sec(
00819 /*==================*/
00820   FILE_LOGFILE
00821   z_stream* c_stream, 
00822   const rec_t** recs,   
00824   ulint   n_dense)  
00825 {
00826   int   err = Z_OK;
00827 
00828   ut_ad(n_dense > 0);
00829 
00830   do {
00831     const rec_t*  rec = *recs++;
00832 
00833     /* Compress everything up to this record. */
00834     c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
00835       - c_stream->next_in;
00836 
00837     if (UNIV_LIKELY(c_stream->avail_in)) {
00838       UNIV_MEM_ASSERT_RW(c_stream->next_in,
00839              c_stream->avail_in);
00840       err = deflate(c_stream, Z_NO_FLUSH);
00841       if (UNIV_UNLIKELY(err != Z_OK)) {
00842         break;
00843       }
00844     }
00845 
00846     ut_ad(!c_stream->avail_in);
00847     ut_ad(c_stream->next_in == rec - REC_N_NEW_EXTRA_BYTES);
00848 
00849     /* Skip the REC_N_NEW_EXTRA_BYTES. */
00850 
00851     c_stream->next_in = (byte*) rec;
00852   } while (--n_dense);
00853 
00854   return(err);
00855 }
00856 
00857 /**********************************************************************/
00861 static
00862 int
00863 page_zip_compress_clust_ext(
00864 /*========================*/
00865   FILE_LOGFILE
00866   z_stream* c_stream, 
00867   const rec_t*  rec,    
00868   const ulint*  offsets,  
00869   ulint   trx_id_col, 
00870   byte*   deleted,  
00872   byte*   storage,  
00873   byte**    externs,  
00875   ulint*    n_blobs)  
00877 {
00878   int err;
00879   ulint i;
00880 
00881   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
00882   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
00883          rec_offs_extra_size(offsets));
00884 
00885   for (i = 0; i < rec_offs_n_fields(offsets); i++) {
00886     ulint   len;
00887     const byte* src;
00888 
00889     if (UNIV_UNLIKELY(i == trx_id_col)) {
00890       ut_ad(!rec_offs_nth_extern(offsets, i));
00891       /* Store trx_id and roll_ptr
00892       in uncompressed form. */
00893       src = rec_get_nth_field(rec, offsets, i, &len);
00894       ut_ad(src + DATA_TRX_ID_LEN
00895             == rec_get_nth_field(rec, offsets,
00896                i + 1, &len));
00897       ut_ad(len == DATA_ROLL_PTR_LEN);
00898 
00899       /* Compress any preceding bytes. */
00900       c_stream->avail_in
00901         = src - c_stream->next_in;
00902 
00903       if (c_stream->avail_in) {
00904         err = deflate(c_stream, Z_NO_FLUSH);
00905         if (UNIV_UNLIKELY(err != Z_OK)) {
00906 
00907           return(err);
00908         }
00909       }
00910 
00911       ut_ad(!c_stream->avail_in);
00912       ut_ad(c_stream->next_in == src);
00913 
00914       memcpy(storage
00915              - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
00916              * (rec_get_heap_no_new(rec) - 1),
00917              c_stream->next_in,
00918              DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
00919 
00920       c_stream->next_in
00921         += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
00922 
00923       /* Skip also roll_ptr */
00924       i++;
00925     } else if (rec_offs_nth_extern(offsets, i)) {
00926       src = rec_get_nth_field(rec, offsets, i, &len);
00927       ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
00928       src += len - BTR_EXTERN_FIELD_REF_SIZE;
00929 
00930       c_stream->avail_in = src
00931         - c_stream->next_in;
00932       if (UNIV_LIKELY(c_stream->avail_in)) {
00933         err = deflate(c_stream, Z_NO_FLUSH);
00934         if (UNIV_UNLIKELY(err != Z_OK)) {
00935 
00936           return(err);
00937         }
00938       }
00939 
00940       ut_ad(!c_stream->avail_in);
00941       ut_ad(c_stream->next_in == src);
00942 
00943       /* Reserve space for the data at
00944       the end of the space reserved for
00945       the compressed data and the page
00946       modification log. */
00947 
00948       if (UNIV_UNLIKELY
00949           (c_stream->avail_out
00950            <= BTR_EXTERN_FIELD_REF_SIZE)) {
00951         /* out of space */
00952         return(Z_BUF_ERROR);
00953       }
00954 
00955       ut_ad(*externs == c_stream->next_out
00956             + c_stream->avail_out
00957             + 1/* end of modif. log */);
00958 
00959       c_stream->next_in
00960         += BTR_EXTERN_FIELD_REF_SIZE;
00961 
00962       /* Skip deleted records. */
00963       if (UNIV_LIKELY_NULL
00964           (page_zip_dir_find_low(
00965             storage, deleted,
00966             page_offset(rec)))) {
00967         continue;
00968       }
00969 
00970       (*n_blobs)++;
00971       c_stream->avail_out
00972         -= BTR_EXTERN_FIELD_REF_SIZE;
00973       *externs -= BTR_EXTERN_FIELD_REF_SIZE;
00974 
00975       /* Copy the BLOB pointer */
00976       memcpy(*externs, c_stream->next_in
00977              - BTR_EXTERN_FIELD_REF_SIZE,
00978              BTR_EXTERN_FIELD_REF_SIZE);
00979     }
00980   }
00981 
00982   return(Z_OK);
00983 }
00984 
00985 /**********************************************************************/
00988 static
00989 int
00990 page_zip_compress_clust(
00991 /*====================*/
00992   FILE_LOGFILE
00993   z_stream* c_stream, 
00994   const rec_t** recs,   
00996   ulint   n_dense,  
00997   dict_index_t* index,    
00998   ulint*    n_blobs,  
01000   ulint   trx_id_col, 
01001   byte*   deleted,  
01003   byte*   storage,  
01004   mem_heap_t* heap)   
01005 {
01006   int err   = Z_OK;
01007   ulint*  offsets   = NULL;
01008   /* BTR_EXTERN_FIELD_REF storage */
01009   byte* externs   = storage - n_dense
01010     * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
01011 
01012   ut_ad(*n_blobs == 0);
01013 
01014   do {
01015     const rec_t*  rec = *recs++;
01016 
01017     offsets = rec_get_offsets(rec, index, offsets,
01018             ULINT_UNDEFINED, &heap);
01019     ut_ad(rec_offs_n_fields(offsets)
01020           == dict_index_get_n_fields(index));
01021     UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
01022     UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
01023            rec_offs_extra_size(offsets));
01024 
01025     /* Compress the extra bytes. */
01026     c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
01027       - c_stream->next_in;
01028 
01029     if (c_stream->avail_in) {
01030       err = deflate(c_stream, Z_NO_FLUSH);
01031       if (UNIV_UNLIKELY(err != Z_OK)) {
01032 
01033         goto func_exit;
01034       }
01035     }
01036     ut_ad(!c_stream->avail_in);
01037     ut_ad(c_stream->next_in == rec - REC_N_NEW_EXTRA_BYTES);
01038 
01039     /* Compress the data bytes. */
01040 
01041     c_stream->next_in = (byte*) rec;
01042 
01043     /* Check if there are any externally stored columns.
01044     For each externally stored column, store the
01045     BTR_EXTERN_FIELD_REF separately. */
01046     if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
01047       ut_ad(dict_index_is_clust(index));
01048 
01049       err = page_zip_compress_clust_ext(
01050         LOGFILE
01051         c_stream, rec, offsets, trx_id_col,
01052         deleted, storage, &externs, n_blobs);
01053 
01054       if (UNIV_UNLIKELY(err != Z_OK)) {
01055 
01056         goto func_exit;
01057       }
01058     } else {
01059       ulint   len;
01060       const byte* src;
01061 
01062       /* Store trx_id and roll_ptr in uncompressed form. */
01063       src = rec_get_nth_field(rec, offsets,
01064             trx_id_col, &len);
01065       ut_ad(src + DATA_TRX_ID_LEN
01066             == rec_get_nth_field(rec, offsets,
01067                trx_id_col + 1, &len));
01068       ut_ad(len == DATA_ROLL_PTR_LEN);
01069       UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
01070       UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
01071              rec_offs_extra_size(offsets));
01072 
01073       /* Compress any preceding bytes. */
01074       c_stream->avail_in = src - c_stream->next_in;
01075 
01076       if (c_stream->avail_in) {
01077         err = deflate(c_stream, Z_NO_FLUSH);
01078         if (UNIV_UNLIKELY(err != Z_OK)) {
01079 
01080           return(err);
01081         }
01082       }
01083 
01084       ut_ad(!c_stream->avail_in);
01085       ut_ad(c_stream->next_in == src);
01086 
01087       memcpy(storage
01088              - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
01089              * (rec_get_heap_no_new(rec) - 1),
01090              c_stream->next_in,
01091              DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
01092 
01093       c_stream->next_in
01094         += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
01095 
01096       /* Skip also roll_ptr */
01097       ut_ad(trx_id_col + 1 < rec_offs_n_fields(offsets));
01098     }
01099 
01100     /* Compress the last bytes of the record. */
01101     c_stream->avail_in = rec + rec_offs_data_size(offsets)
01102       - c_stream->next_in;
01103 
01104     if (c_stream->avail_in) {
01105       err = deflate(c_stream, Z_NO_FLUSH);
01106       if (UNIV_UNLIKELY(err != Z_OK)) {
01107 
01108         goto func_exit;
01109       }
01110     }
01111     ut_ad(!c_stream->avail_in);
01112   } while (--n_dense);
01113 
01114 func_exit:
01115   return(err);
01116 }
01117 
01118 /**********************************************************************/
01122 UNIV_INTERN
01123 ibool
01124 page_zip_compress(
01125 /*==============*/
01126   page_zip_des_t* page_zip,
01128   const page_t* page, 
01129   dict_index_t* index,  
01130   mtr_t*    mtr)  
01131 {
01132   z_stream  c_stream;
01133   int   err;
01134   ulint   n_fields;/* number of index fields needed */
01135   byte*   fields; 
01136   byte*   buf;  
01137   byte*   buf_end;/* end of buf */
01138   ulint   n_dense;
01139   ulint   slot_size;/* amount of uncompressed bytes per record */
01140   const rec_t** recs; 
01141   mem_heap_t* heap;
01142   ulint   trx_id_col;
01143   ulint*    offsets = NULL;
01144   ulint   n_blobs = 0;
01145   byte*   storage;/* storage of uncompressed columns */
01146 #ifndef UNIV_HOTBACKUP
01147   ullint    usec = ut_time_us(NULL);
01148 #endif /* !UNIV_HOTBACKUP */
01149 #ifdef PAGE_ZIP_COMPRESS_DBG
01150   FILE*   logfile = NULL;
01151 #endif
01152 
01153   ut_a(page_is_comp(page));
01154   ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
01155   ut_ad(page_simple_validate_new((page_t*) page));
01156   ut_ad(page_zip_simple_validate(page_zip));
01157   ut_ad(dict_table_is_comp(index->table));
01158   ut_ad(!dict_index_is_ibuf(index));
01159 
01160   UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
01161 
01162   /* Check the data that will be omitted. */
01163   ut_a(!memcmp(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES),
01164          infimum_extra, sizeof infimum_extra));
01165   ut_a(!memcmp(page + PAGE_NEW_INFIMUM,
01166          infimum_data, sizeof infimum_data));
01167   ut_a(page[PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES]
01168        /* info_bits == 0, n_owned <= max */
01169        <= PAGE_DIR_SLOT_MAX_N_OWNED);
01170   ut_a(!memcmp(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
01171          supremum_extra_data, sizeof supremum_extra_data));
01172 
01173   if (UNIV_UNLIKELY(!page_get_n_recs(page))) {
01174     ut_a(rec_get_next_offs(page + PAGE_NEW_INFIMUM, TRUE)
01175          == PAGE_NEW_SUPREMUM);
01176   }
01177 
01178   if (page_is_leaf(page)) {
01179     n_fields = dict_index_get_n_fields(index);
01180   } else {
01181     n_fields = dict_index_get_n_unique_in_tree(index);
01182   }
01183 
01184   /* The dense directory excludes the infimum and supremum records. */
01185   n_dense = page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW;
01186 #ifdef PAGE_ZIP_COMPRESS_DBG
01187   if (UNIV_UNLIKELY(page_zip_compress_dbg)) {
01188     fprintf(stderr, "compress %p %p %lu %lu %lu\n",
01189       (void*) page_zip, (void*) page,
01190       page_is_leaf(page),
01191       n_fields, n_dense);
01192   }
01193   if (UNIV_UNLIKELY(page_zip_compress_log)) {
01194     /* Create a log file for every compression attempt. */
01195     char  logfilename[9];
01196     ut_snprintf(logfilename, sizeof logfilename,
01197           "%08x", page_zip_compress_log++);
01198     logfile = fopen(logfilename, "wb");
01199 
01200     if (logfile) {
01201       /* Write the uncompressed page to the log. */
01202       fwrite(page, 1, UNIV_PAGE_SIZE, logfile);
01203       /* Record the compressed size as zero.
01204       This will be overwritten at successful exit. */
01205       putc(0, logfile);
01206       putc(0, logfile);
01207       putc(0, logfile);
01208       putc(0, logfile);
01209     }
01210   }
01211 #endif /* PAGE_ZIP_COMPRESS_DBG */
01212 #ifndef UNIV_HOTBACKUP
01213   page_zip_stat[page_zip->ssize - 1].compressed++;
01214 #endif /* !UNIV_HOTBACKUP */
01215 
01216   if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE
01217         >= page_zip_get_size(page_zip))) {
01218 
01219     goto err_exit;
01220   }
01221 
01222   heap = mem_heap_create(page_zip_get_size(page_zip)
01223              + n_fields * (2 + sizeof *offsets)
01224              + n_dense * ((sizeof *recs)
01225               - PAGE_ZIP_DIR_SLOT_SIZE)
01226              + UNIV_PAGE_SIZE * 4
01227              + (512 << MAX_MEM_LEVEL));
01228 
01229   recs = static_cast<const unsigned char **>(mem_heap_zalloc(heap, n_dense * sizeof *recs));
01230 
01231   fields = static_cast<byte *>(mem_heap_alloc(heap, (n_fields + 1) * 2));
01232 
01233   buf = static_cast<byte *>(mem_heap_alloc(heap, page_zip_get_size(page_zip) - PAGE_DATA));
01234   buf_end = buf + page_zip_get_size(page_zip) - PAGE_DATA;
01235 
01236   /* Compress the data payload. */
01237   page_zip_set_alloc(&c_stream, heap);
01238 
01239   err = deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION,
01240          Z_DEFLATED, UNIV_PAGE_SIZE_SHIFT,
01241          MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
01242   ut_a(err == Z_OK);
01243 
01244   c_stream.next_out = buf;
01245   /* Subtract the space reserved for uncompressed data. */
01246   /* Page header and the end marker of the modification log */
01247   c_stream.avail_out = buf_end - buf - 1;
01248   /* Dense page directory and uncompressed columns, if any */
01249   if (page_is_leaf(page)) {
01250     if (dict_index_is_clust(index)) {
01251       trx_id_col = dict_index_get_sys_col_pos(
01252         index, DATA_TRX_ID);
01253       ut_ad(trx_id_col > 0);
01254       ut_ad(trx_id_col != ULINT_UNDEFINED);
01255 
01256       slot_size = PAGE_ZIP_DIR_SLOT_SIZE
01257         + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
01258     } else {
01259       /* Signal the absence of trx_id
01260       in page_zip_fields_encode() */
01261       ut_ad(dict_index_get_sys_col_pos(index, DATA_TRX_ID)
01262             == ULINT_UNDEFINED);
01263       trx_id_col = 0;
01264       slot_size = PAGE_ZIP_DIR_SLOT_SIZE;
01265     }
01266   } else {
01267     slot_size = PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE;
01268     trx_id_col = ULINT_UNDEFINED;
01269   }
01270 
01271   if (UNIV_UNLIKELY(c_stream.avail_out <= n_dense * slot_size
01272         + 6/* sizeof(zlib header and footer) */)) {
01273     goto zlib_error;
01274   }
01275 
01276   c_stream.avail_out -= n_dense * slot_size;
01277   c_stream.avail_in = page_zip_fields_encode(n_fields, index,
01278                trx_id_col, fields);
01279   c_stream.next_in = fields;
01280   if (UNIV_LIKELY(!trx_id_col)) {
01281     trx_id_col = ULINT_UNDEFINED;
01282   }
01283 
01284   UNIV_MEM_ASSERT_RW(c_stream.next_in, c_stream.avail_in);
01285   err = deflate(&c_stream, Z_FULL_FLUSH);
01286   if (err != Z_OK) {
01287     goto zlib_error;
01288   }
01289 
01290   ut_ad(!c_stream.avail_in);
01291 
01292   page_zip_dir_encode(page, buf_end, recs);
01293 
01294   c_stream.next_in = (byte*) page + PAGE_ZIP_START;
01295 
01296   storage = buf_end - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
01297 
01298   /* Compress the records in heap_no order. */
01299   if (UNIV_UNLIKELY(!n_dense)) {
01300   } else if (!page_is_leaf(page)) {
01301     /* This is a node pointer page. */
01302     err = page_zip_compress_node_ptrs(LOGFILE
01303               &c_stream, recs, n_dense,
01304               index, storage, heap);
01305     if (UNIV_UNLIKELY(err != Z_OK)) {
01306       goto zlib_error;
01307     }
01308   } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
01309     /* This is a leaf page in a secondary index. */
01310     err = page_zip_compress_sec(LOGFILE
01311               &c_stream, recs, n_dense);
01312     if (UNIV_UNLIKELY(err != Z_OK)) {
01313       goto zlib_error;
01314     }
01315   } else {
01316     /* This is a leaf page in a clustered index. */
01317     err = page_zip_compress_clust(LOGFILE
01318                 &c_stream, recs, n_dense,
01319                 index, &n_blobs, trx_id_col,
01320                 buf_end - PAGE_ZIP_DIR_SLOT_SIZE
01321                 * page_get_n_recs(page),
01322                 storage, heap);
01323     if (UNIV_UNLIKELY(err != Z_OK)) {
01324       goto zlib_error;
01325     }
01326   }
01327 
01328   /* Finish the compression. */
01329   ut_ad(!c_stream.avail_in);
01330   /* Compress any trailing garbage, in case the last record was
01331   allocated from an originally longer space on the free list,
01332   or the data of the last record from page_zip_compress_sec(). */
01333   c_stream.avail_in
01334     = page_header_get_field(page, PAGE_HEAP_TOP)
01335     - (c_stream.next_in - page);
01336   ut_a(c_stream.avail_in <= UNIV_PAGE_SIZE - PAGE_ZIP_START - PAGE_DIR);
01337 
01338   UNIV_MEM_ASSERT_RW(c_stream.next_in, c_stream.avail_in);
01339   err = deflate(&c_stream, Z_FINISH);
01340 
01341   if (UNIV_UNLIKELY(err != Z_STREAM_END)) {
01342 zlib_error:
01343     deflateEnd(&c_stream);
01344     mem_heap_free(heap);
01345 err_exit:
01346 #ifdef PAGE_ZIP_COMPRESS_DBG
01347     if (logfile) {
01348       fclose(logfile);
01349     }
01350 #endif /* PAGE_ZIP_COMPRESS_DBG */
01351 #ifndef UNIV_HOTBACKUP
01352     page_zip_stat[page_zip->ssize - 1].compressed_usec
01353       += ut_time_us(NULL) - usec;
01354 #endif /* !UNIV_HOTBACKUP */
01355     return(FALSE);
01356   }
01357 
01358   err = deflateEnd(&c_stream);
01359   ut_a(err == Z_OK);
01360 
01361   ut_ad(buf + c_stream.total_out == c_stream.next_out);
01362   ut_ad((ulint) (storage - c_stream.next_out) >= c_stream.avail_out);
01363 
01364   /* Valgrind believes that zlib does not initialize some bits
01365   in the last 7 or 8 bytes of the stream.  Make Valgrind happy. */
01366   UNIV_MEM_VALID(buf, c_stream.total_out);
01367 
01368   /* Zero out the area reserved for the modification log.
01369   Space for the end marker of the modification log is not
01370   included in avail_out. */
01371   memset(c_stream.next_out, 0, c_stream.avail_out + 1/* end marker */);
01372 
01373 #ifdef UNIV_DEBUG
01374   page_zip->m_start =
01375 #endif /* UNIV_DEBUG */
01376     page_zip->m_end = PAGE_DATA + c_stream.total_out;
01377   page_zip->m_nonempty = FALSE;
01378   page_zip->n_blobs = n_blobs;
01379   /* Copy those header fields that will not be written
01380   in buf_flush_init_for_writing() */
01381   memcpy(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
01382          FIL_PAGE_LSN - FIL_PAGE_PREV);
01383   memcpy(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE, 2);
01384   memcpy(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
01385          PAGE_DATA - FIL_PAGE_DATA);
01386   /* Copy the rest of the compressed page */
01387   memcpy(page_zip->data + PAGE_DATA, buf,
01388          page_zip_get_size(page_zip) - PAGE_DATA);
01389   mem_heap_free(heap);
01390 #ifdef UNIV_ZIP_DEBUG
01391   ut_a(page_zip_validate(page_zip, page));
01392 #endif /* UNIV_ZIP_DEBUG */
01393 
01394   if (mtr) {
01395 #ifndef UNIV_HOTBACKUP
01396     page_zip_compress_write_log(page_zip, page, index, mtr);
01397 #endif /* !UNIV_HOTBACKUP */
01398   }
01399 
01400   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
01401 
01402 #ifdef PAGE_ZIP_COMPRESS_DBG
01403   if (logfile) {
01404     /* Record the compressed size of the block. */
01405     byte sz[4];
01406     mach_write_to_4(sz, c_stream.total_out);
01407     fseek(logfile, UNIV_PAGE_SIZE, SEEK_SET);
01408     fwrite(sz, 1, sizeof sz, logfile);
01409     fclose(logfile);
01410   }
01411 #endif /* PAGE_ZIP_COMPRESS_DBG */
01412 #ifndef UNIV_HOTBACKUP
01413   {
01414     page_zip_stat_t*  zip_stat
01415       = &page_zip_stat[page_zip->ssize - 1];
01416     zip_stat->compressed_ok++;
01417     zip_stat->compressed_usec += ut_time_us(NULL) - usec;
01418   }
01419 #endif /* !UNIV_HOTBACKUP */
01420 
01421   return(TRUE);
01422 }
01423 
01424 /**********************************************************************/
01427 UNIV_INLINE
01428 ibool
01429 page_zip_dir_cmp(
01430 /*=============*/
01431   const rec_t*  rec1, 
01432   const rec_t*  rec2) 
01433 {
01434   return(rec1 > rec2);
01435 }
01436 
01437 /**********************************************************************/
01439 static
01440 void
01441 page_zip_dir_sort(
01442 /*==============*/
01443   rec_t** arr,  
01444   rec_t** aux_arr,
01445   ulint low,  
01446   ulint high) 
01447 {
01448   UT_SORT_FUNCTION_BODY(page_zip_dir_sort, arr, aux_arr, low, high,
01449             page_zip_dir_cmp);
01450 }
01451 
01452 /**********************************************************************/
01454 static
01455 void
01456 page_zip_fields_free(
01457 /*=================*/
01458   dict_index_t* index)  
01459 {
01460   if (index) {
01461     dict_table_t* table = index->table;
01462     mem_heap_free(index->heap);
01463     mutex_free(&(table->autoinc_mutex));
01464     ut_free(table->name);
01465     mem_heap_free(table->heap);
01466   }
01467 }
01468 
01469 /**********************************************************************/
01472 static
01473 dict_index_t*
01474 page_zip_fields_decode(
01475 /*===================*/
01476   const byte* buf,  
01477   const byte* end,  
01478   ulint*    trx_id_col)
01481 {
01482   const byte* b;
01483   ulint   n;
01484   ulint   i;
01485   ulint   val;
01486   dict_table_t* table;
01487   dict_index_t* index;
01488 
01489   /* Determine the number of fields. */
01490   for (b = buf, n = 0; b < end; n++) {
01491     if (*b++ & 0x80) {
01492       b++; /* skip the second byte */
01493     }
01494   }
01495 
01496   n--; /* n_nullable or trx_id */
01497 
01498   if (UNIV_UNLIKELY(n > REC_MAX_N_FIELDS)) {
01499 
01500     page_zip_fail(("page_zip_fields_decode: n = %lu\n",
01501              (ulong) n));
01502     return(NULL);
01503   }
01504 
01505   if (UNIV_UNLIKELY(b > end)) {
01506 
01507     page_zip_fail(("page_zip_fields_decode: %p > %p\n",
01508              (const void*) b, (const void*) end));
01509     return(NULL);
01510   }
01511 
01512   table = dict_mem_table_create("ZIP_DUMMY", DICT_HDR_SPACE, n,
01513               DICT_TF_COMPACT);
01514   index = dict_mem_index_create("ZIP_DUMMY", "ZIP_DUMMY",
01515               DICT_HDR_SPACE, 0, n);
01516   index->table = table;
01517   index->n_uniq = n;
01518   /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
01519   index->cached = TRUE;
01520 
01521   /* Initialize the fields. */
01522   for (b = buf, i = 0; i < n; i++) {
01523     ulint mtype;
01524     ulint len;
01525 
01526     val = *b++;
01527 
01528     if (UNIV_UNLIKELY(val & 0x80)) {
01529       /* fixed length > 62 bytes */
01530       val = (val & 0x7f) << 8 | *b++;
01531       len = val >> 1;
01532       mtype = DATA_FIXBINARY;
01533     } else if (UNIV_UNLIKELY(val >= 126)) {
01534       /* variable length with max > 255 bytes */
01535       len = 0x7fff;
01536       mtype = DATA_BINARY;
01537     } else if (val <= 1) {
01538       /* variable length with max <= 255 bytes */
01539       len = 0;
01540       mtype = DATA_BINARY;
01541     } else {
01542       /* fixed length < 62 bytes */
01543       len = val >> 1;
01544       mtype = DATA_FIXBINARY;
01545     }
01546 
01547     dict_mem_table_add_col(table, NULL, NULL, mtype,
01548                val & 1 ? DATA_NOT_NULL : 0, len);
01549     dict_index_add_col(index, table,
01550            dict_table_get_nth_col(table, i), 0);
01551   }
01552 
01553   val = *b++;
01554   if (UNIV_UNLIKELY(val & 0x80)) {
01555     val = (val & 0x7f) << 8 | *b++;
01556   }
01557 
01558   /* Decode the position of the trx_id column. */
01559   if (trx_id_col) {
01560     if (!val) {
01561       val = ULINT_UNDEFINED;
01562     } else if (UNIV_UNLIKELY(val >= n)) {
01563       page_zip_fields_free(index);
01564       index = NULL;
01565     } else {
01566       index->type = DICT_CLUSTERED;
01567     }
01568 
01569     *trx_id_col = val;
01570   } else {
01571     /* Decode the number of nullable fields. */
01572     if (UNIV_UNLIKELY(index->n_nullable > val)) {
01573       page_zip_fields_free(index);
01574       index = NULL;
01575     } else {
01576       index->n_nullable = val;
01577     }
01578   }
01579 
01580   ut_ad(b == end);
01581 
01582   return(index);
01583 }
01584 
01585 /**********************************************************************/
01588 static
01589 ibool
01590 page_zip_dir_decode(
01591 /*================*/
01592   const page_zip_des_t* page_zip,
01594   page_t*     page, 
01597   rec_t**     recs, 
01599   rec_t**     recs_aux,
01600   ulint     n_dense)
01602 {
01603   ulint i;
01604   ulint n_recs;
01605   byte* slot;
01606 
01607   n_recs = page_get_n_recs(page);
01608 
01609   if (UNIV_UNLIKELY(n_recs > n_dense)) {
01610     page_zip_fail(("page_zip_dir_decode 1: %lu > %lu\n",
01611              (ulong) n_recs, (ulong) n_dense));
01612     return(FALSE);
01613   }
01614 
01615   /* Traverse the list of stored records in the sorting order,
01616   starting from the first user record. */
01617 
01618   slot = page + (UNIV_PAGE_SIZE - PAGE_DIR - PAGE_DIR_SLOT_SIZE);
01619   UNIV_PREFETCH_RW(slot);
01620 
01621   /* Zero out the page trailer. */
01622   memset(slot + PAGE_DIR_SLOT_SIZE, 0, PAGE_DIR);
01623 
01624   mach_write_to_2(slot, PAGE_NEW_INFIMUM);
01625   slot -= PAGE_DIR_SLOT_SIZE;
01626   UNIV_PREFETCH_RW(slot);
01627 
01628   /* Initialize the sparse directory and copy the dense directory. */
01629   for (i = 0; i < n_recs; i++) {
01630     ulint offs = page_zip_dir_get(page_zip, i);
01631 
01632     if (offs & PAGE_ZIP_DIR_SLOT_OWNED) {
01633       mach_write_to_2(slot, offs & PAGE_ZIP_DIR_SLOT_MASK);
01634       slot -= PAGE_DIR_SLOT_SIZE;
01635       UNIV_PREFETCH_RW(slot);
01636     }
01637 
01638     if (UNIV_UNLIKELY((offs & PAGE_ZIP_DIR_SLOT_MASK)
01639           < PAGE_ZIP_START + REC_N_NEW_EXTRA_BYTES)) {
01640       page_zip_fail(("page_zip_dir_decode 2: %u %u %lx\n",
01641                (unsigned) i, (unsigned) n_recs,
01642                (ulong) offs));
01643       return(FALSE);
01644     }
01645 
01646     recs[i] = page + (offs & PAGE_ZIP_DIR_SLOT_MASK);
01647   }
01648 
01649   mach_write_to_2(slot, PAGE_NEW_SUPREMUM);
01650   {
01651     const page_dir_slot_t*  last_slot = page_dir_get_nth_slot(
01652       page, page_dir_get_n_slots(page) - 1);
01653 
01654     if (UNIV_UNLIKELY(slot != last_slot)) {
01655       page_zip_fail(("page_zip_dir_decode 3: %p != %p\n",
01656                (const void*) slot,
01657                (const void*) last_slot));
01658       return(FALSE);
01659     }
01660   }
01661 
01662   /* Copy the rest of the dense directory. */
01663   for (; i < n_dense; i++) {
01664     ulint offs = page_zip_dir_get(page_zip, i);
01665 
01666     if (UNIV_UNLIKELY(offs & ~PAGE_ZIP_DIR_SLOT_MASK)) {
01667       page_zip_fail(("page_zip_dir_decode 4: %u %u %lx\n",
01668                (unsigned) i, (unsigned) n_dense,
01669                (ulong) offs));
01670       return(FALSE);
01671     }
01672 
01673     recs[i] = page + offs;
01674   }
01675 
01676   if (UNIV_LIKELY(n_dense > 1)) {
01677     page_zip_dir_sort(recs, recs_aux, 0, n_dense);
01678   }
01679   return(TRUE);
01680 }
01681 
01682 /**********************************************************************/
01685 static
01686 ibool
01687 page_zip_set_extra_bytes(
01688 /*=====================*/
01689   const page_zip_des_t* page_zip,
01690   page_t*     page, 
01691   ulint     info_bits)
01692 {
01693   ulint n;
01694   ulint i;
01695   ulint n_owned = 1;
01696   ulint offs;
01697   rec_t*  rec;
01698 
01699   n = page_get_n_recs(page);
01700   rec = page + PAGE_NEW_INFIMUM;
01701 
01702   for (i = 0; i < n; i++) {
01703     offs = page_zip_dir_get(page_zip, i);
01704 
01705     if (UNIV_UNLIKELY(offs & PAGE_ZIP_DIR_SLOT_DEL)) {
01706       info_bits |= REC_INFO_DELETED_FLAG;
01707     }
01708     if (UNIV_UNLIKELY(offs & PAGE_ZIP_DIR_SLOT_OWNED)) {
01709       info_bits |= n_owned;
01710       n_owned = 1;
01711     } else {
01712       n_owned++;
01713     }
01714     offs &= PAGE_ZIP_DIR_SLOT_MASK;
01715     if (UNIV_UNLIKELY(offs < PAGE_ZIP_START
01716           + REC_N_NEW_EXTRA_BYTES)) {
01717       page_zip_fail(("page_zip_set_extra_bytes 1:"
01718                " %u %u %lx\n",
01719                (unsigned) i, (unsigned) n,
01720                (ulong) offs));
01721       return(FALSE);
01722     }
01723 
01724     rec_set_next_offs_new(rec, offs);
01725     rec = page + offs;
01726     rec[-REC_N_NEW_EXTRA_BYTES] = (byte) info_bits;
01727     info_bits = 0;
01728   }
01729 
01730   /* Set the next pointer of the last user record. */
01731   rec_set_next_offs_new(rec, PAGE_NEW_SUPREMUM);
01732 
01733   /* Set n_owned of the supremum record. */
01734   page[PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES] = (byte) n_owned;
01735 
01736   /* The dense directory excludes the infimum and supremum records. */
01737   n = page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW;
01738 
01739   if (i >= n) {
01740     if (UNIV_LIKELY(i == n)) {
01741       return(TRUE);
01742     }
01743 
01744     page_zip_fail(("page_zip_set_extra_bytes 2: %u != %u\n",
01745              (unsigned) i, (unsigned) n));
01746     return(FALSE);
01747   }
01748 
01749   offs = page_zip_dir_get(page_zip, i);
01750 
01751   /* Set the extra bytes of deleted records on the free list. */
01752   for (;;) {
01753     if (UNIV_UNLIKELY(!offs)
01754         || UNIV_UNLIKELY(offs & ~PAGE_ZIP_DIR_SLOT_MASK)) {
01755 
01756       page_zip_fail(("page_zip_set_extra_bytes 3: %lx\n",
01757                (ulong) offs));
01758       return(FALSE);
01759     }
01760 
01761     rec = page + offs;
01762     rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
01763 
01764     if (++i == n) {
01765       break;
01766     }
01767 
01768     offs = page_zip_dir_get(page_zip, i);
01769     rec_set_next_offs_new(rec, offs);
01770   }
01771 
01772   /* Terminate the free list. */
01773   rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
01774   rec_set_next_offs_new(rec, 0);
01775 
01776   return(TRUE);
01777 }
01778 
01779 /**********************************************************************/
01783 static
01784 const byte*
01785 page_zip_apply_log_ext(
01786 /*===================*/
01787   rec_t*    rec,    
01788   const ulint*  offsets,  
01789   ulint   trx_id_col, 
01790   const byte* data,   
01791   const byte* end)    
01792 {
01793   ulint i;
01794   ulint len;
01795   byte* next_out = rec;
01796 
01797   /* Check if there are any externally stored columns.
01798   For each externally stored column, skip the
01799   BTR_EXTERN_FIELD_REF. */
01800 
01801   for (i = 0; i < rec_offs_n_fields(offsets); i++) {
01802     byte* dst;
01803 
01804     if (UNIV_UNLIKELY(i == trx_id_col)) {
01805       /* Skip trx_id and roll_ptr */
01806       dst = rec_get_nth_field(rec, offsets,
01807             i, &len);
01808       if (UNIV_UNLIKELY(dst - next_out >= end - data)
01809           || UNIV_UNLIKELY
01810           (len < (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN))
01811           || rec_offs_nth_extern(offsets, i)) {
01812         page_zip_fail(("page_zip_apply_log_ext:"
01813                  " trx_id len %lu,"
01814                  " %p - %p >= %p - %p\n",
01815                  (ulong) len,
01816                  (const void*) dst,
01817                  (const void*) next_out,
01818                  (const void*) end,
01819                  (const void*) data));
01820         return(NULL);
01821       }
01822 
01823       memcpy(next_out, data, dst - next_out);
01824       data += dst - next_out;
01825       next_out = dst + (DATA_TRX_ID_LEN
01826             + DATA_ROLL_PTR_LEN);
01827     } else if (rec_offs_nth_extern(offsets, i)) {
01828       dst = rec_get_nth_field(rec, offsets,
01829             i, &len);
01830       ut_ad(len
01831             >= BTR_EXTERN_FIELD_REF_SIZE);
01832 
01833       len += dst - next_out
01834         - BTR_EXTERN_FIELD_REF_SIZE;
01835 
01836       if (UNIV_UNLIKELY(data + len >= end)) {
01837         page_zip_fail(("page_zip_apply_log_ext: "
01838                  "ext %p+%lu >= %p\n",
01839                  (const void*) data,
01840                  (ulong) len,
01841                  (const void*) end));
01842         return(NULL);
01843       }
01844 
01845       memcpy(next_out, data, len);
01846       data += len;
01847       next_out += len
01848         + BTR_EXTERN_FIELD_REF_SIZE;
01849     }
01850   }
01851 
01852   /* Copy the last bytes of the record. */
01853   len = rec_get_end(rec, offsets) - next_out;
01854   if (UNIV_UNLIKELY(data + len >= end)) {
01855     page_zip_fail(("page_zip_apply_log_ext: "
01856              "last %p+%lu >= %p\n",
01857              (const void*) data,
01858              (ulong) len,
01859              (const void*) end));
01860     return(NULL);
01861   }
01862   memcpy(next_out, data, len);
01863   data += len;
01864 
01865   return(data);
01866 }
01867 
01868 /**********************************************************************/
01872 static
01873 const byte*
01874 page_zip_apply_log(
01875 /*===============*/
01876   const byte* data, 
01877   ulint   size, 
01878   rec_t**   recs, 
01881   ulint   n_dense,
01882   ulint   trx_id_col,
01884   ulint   heap_status,
01887   dict_index_t* index,  
01888   ulint*    offsets)
01890 {
01891   const byte* const end = data + size;
01892 
01893   for (;;) {
01894     ulint val;
01895     rec_t*  rec;
01896     ulint len;
01897     ulint hs;
01898 
01899     val = *data++;
01900     if (UNIV_UNLIKELY(!val)) {
01901       return(data - 1);
01902     }
01903     if (val & 0x80) {
01904       val = (val & 0x7f) << 8 | *data++;
01905       if (UNIV_UNLIKELY(!val)) {
01906         page_zip_fail(("page_zip_apply_log:"
01907                  " invalid val %x%x\n",
01908                  data[-2], data[-1]));
01909         return(NULL);
01910       }
01911     }
01912     if (UNIV_UNLIKELY(data >= end)) {
01913       page_zip_fail(("page_zip_apply_log: %p >= %p\n",
01914                (const void*) data,
01915                (const void*) end));
01916       return(NULL);
01917     }
01918     if (UNIV_UNLIKELY((val >> 1) > n_dense)) {
01919       page_zip_fail(("page_zip_apply_log: %lu>>1 > %lu\n",
01920                (ulong) val, (ulong) n_dense));
01921       return(NULL);
01922     }
01923 
01924     /* Determine the heap number and status bits of the record. */
01925     rec = recs[(val >> 1) - 1];
01926 
01927     hs = ((val >> 1) + 1) << REC_HEAP_NO_SHIFT;
01928     hs |= heap_status & ((1 << REC_HEAP_NO_SHIFT) - 1);
01929 
01930     /* This may either be an old record that is being
01931     overwritten (updated in place, or allocated from
01932     the free list), or a new record, with the next
01933     available_heap_no. */
01934     if (UNIV_UNLIKELY(hs > heap_status)) {
01935       page_zip_fail(("page_zip_apply_log: %lu > %lu\n",
01936                (ulong) hs, (ulong) heap_status));
01937       return(NULL);
01938     } else if (hs == heap_status) {
01939       /* A new record was allocated from the heap. */
01940       if (UNIV_UNLIKELY(val & 1)) {
01941         /* Only existing records may be cleared. */
01942         page_zip_fail(("page_zip_apply_log:"
01943                  " attempting to create"
01944                  " deleted rec %lu\n",
01945                  (ulong) hs));
01946         return(NULL);
01947       }
01948       heap_status += 1 << REC_HEAP_NO_SHIFT;
01949     }
01950 
01951     mach_write_to_2(rec - REC_NEW_HEAP_NO, hs);
01952 
01953     if (val & 1) {
01954       /* Clear the data bytes of the record. */
01955       mem_heap_t* heap  = NULL;
01956       ulint*    offs;
01957       offs = rec_get_offsets(rec, index, offsets,
01958                  ULINT_UNDEFINED, &heap);
01959       memset(rec, 0, rec_offs_data_size(offs));
01960 
01961       if (UNIV_LIKELY_NULL(heap)) {
01962         mem_heap_free(heap);
01963       }
01964       continue;
01965     }
01966 
01967 #if REC_STATUS_NODE_PTR != TRUE
01968 # error "REC_STATUS_NODE_PTR != TRUE"
01969 #endif
01970     rec_get_offsets_reverse(data, index,
01971           hs & REC_STATUS_NODE_PTR,
01972           offsets);
01973     rec_offs_make_valid(rec, index, offsets);
01974 
01975     /* Copy the extra bytes (backwards). */
01976     {
01977       byte* start = rec_get_start(rec, offsets);
01978       byte* b = rec - REC_N_NEW_EXTRA_BYTES;
01979       while (b != start) {
01980         *--b = *data++;
01981       }
01982     }
01983 
01984     /* Copy the data bytes. */
01985     if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
01986       /* Non-leaf nodes should not contain any
01987       externally stored columns. */
01988       if (UNIV_UNLIKELY(hs & REC_STATUS_NODE_PTR)) {
01989         page_zip_fail(("page_zip_apply_log: "
01990                  "%lu&REC_STATUS_NODE_PTR\n",
01991                  (ulong) hs));
01992         return(NULL);
01993       }
01994 
01995       data = page_zip_apply_log_ext(
01996         rec, offsets, trx_id_col, data, end);
01997 
01998       if (UNIV_UNLIKELY(!data)) {
01999         return(NULL);
02000       }
02001     } else if (UNIV_UNLIKELY(hs & REC_STATUS_NODE_PTR)) {
02002       len = rec_offs_data_size(offsets)
02003         - REC_NODE_PTR_SIZE;
02004       /* Copy the data bytes, except node_ptr. */
02005       if (UNIV_UNLIKELY(data + len >= end)) {
02006         page_zip_fail(("page_zip_apply_log: "
02007                  "node_ptr %p+%lu >= %p\n",
02008                  (const void*) data,
02009                  (ulong) len,
02010                  (const void*) end));
02011         return(NULL);
02012       }
02013       memcpy(rec, data, len);
02014       data += len;
02015     } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
02016       len = rec_offs_data_size(offsets);
02017 
02018       /* Copy all data bytes of
02019       a record in a secondary index. */
02020       if (UNIV_UNLIKELY(data + len >= end)) {
02021         page_zip_fail(("page_zip_apply_log: "
02022                  "sec %p+%lu >= %p\n",
02023                  (const void*) data,
02024                  (ulong) len,
02025                  (const void*) end));
02026         return(NULL);
02027       }
02028 
02029       memcpy(rec, data, len);
02030       data += len;
02031     } else {
02032       /* Skip DB_TRX_ID and DB_ROLL_PTR. */
02033       ulint l = rec_get_nth_field_offs(offsets,
02034                  trx_id_col, &len);
02035       byte* b;
02036 
02037       if (UNIV_UNLIKELY(data + l >= end)
02038           || UNIV_UNLIKELY(len < (DATA_TRX_ID_LEN
02039                 + DATA_ROLL_PTR_LEN))) {
02040         page_zip_fail(("page_zip_apply_log: "
02041                  "trx_id %p+%lu >= %p\n",
02042                  (const void*) data,
02043                  (ulong) l,
02044                  (const void*) end));
02045         return(NULL);
02046       }
02047 
02048       /* Copy any preceding data bytes. */
02049       memcpy(rec, data, l);
02050       data += l;
02051 
02052       /* Copy any bytes following DB_TRX_ID, DB_ROLL_PTR. */
02053       b = rec + l + (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02054       len = rec_get_end(rec, offsets) - b;
02055       if (UNIV_UNLIKELY(data + len >= end)) {
02056         page_zip_fail(("page_zip_apply_log: "
02057                  "clust %p+%lu >= %p\n",
02058                  (const void*) data,
02059                  (ulong) len,
02060                  (const void*) end));
02061         return(NULL);
02062       }
02063       memcpy(b, data, len);
02064       data += len;
02065     }
02066   }
02067 }
02068 
02069 /**********************************************************************/
02072 static
02073 ibool
02074 page_zip_decompress_node_ptrs(
02075 /*==========================*/
02076   page_zip_des_t* page_zip, 
02077   z_stream* d_stream, 
02078   rec_t**   recs,   
02080   ulint   n_dense,  
02081   dict_index_t* index,    
02082   ulint*    offsets,  
02083   mem_heap_t* heap)   
02084 {
02085   ulint   heap_status = REC_STATUS_NODE_PTR
02086     | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
02087   ulint   slot;
02088   const byte* storage;
02089 
02090   /* Subtract the space reserved for uncompressed data. */
02091   d_stream->avail_in -= n_dense
02092     * (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
02093 
02094   /* Decompress the records in heap_no order. */
02095   for (slot = 0; slot < n_dense; slot++) {
02096     rec_t*  rec = recs[slot];
02097 
02098     d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
02099       - d_stream->next_out;
02100 
02101     ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
02102           - PAGE_ZIP_START - PAGE_DIR);
02103     switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02104     case Z_STREAM_END:
02105       /* Apparently, n_dense has grown
02106       since the time the page was last compressed. */
02107       goto zlib_done;
02108     case Z_OK:
02109     case Z_BUF_ERROR:
02110       if (!d_stream->avail_out) {
02111         break;
02112       }
02113       /* fall through */
02114     default:
02115       page_zip_fail(("page_zip_decompress_node_ptrs:"
02116                " 1 inflate(Z_SYNC_FLUSH)=%s\n",
02117                d_stream->msg));
02118       goto zlib_error;
02119     }
02120 
02121     ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
02122     /* Prepare to decompress the data bytes. */
02123     d_stream->next_out = rec;
02124     /* Set heap_no and the status bits. */
02125     mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
02126     heap_status += 1 << REC_HEAP_NO_SHIFT;
02127 
02128     /* Read the offsets. The status bits are needed here. */
02129     offsets = rec_get_offsets(rec, index, offsets,
02130             ULINT_UNDEFINED, &heap);
02131 
02132     /* Non-leaf nodes should not have any externally
02133     stored columns. */
02134     ut_ad(!rec_offs_any_extern(offsets));
02135 
02136     /* Decompress the data bytes, except node_ptr. */
02137     d_stream->avail_out = rec_offs_data_size(offsets)
02138       - REC_NODE_PTR_SIZE;
02139 
02140     switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02141     case Z_STREAM_END:
02142       goto zlib_done;
02143     case Z_OK:
02144     case Z_BUF_ERROR:
02145       if (!d_stream->avail_out) {
02146         break;
02147       }
02148       /* fall through */
02149     default:
02150       page_zip_fail(("page_zip_decompress_node_ptrs:"
02151                " 2 inflate(Z_SYNC_FLUSH)=%s\n",
02152                d_stream->msg));
02153       goto zlib_error;
02154     }
02155 
02156     /* Clear the node pointer in case the record
02157     will be deleted and the space will be reallocated
02158     to a smaller record. */
02159     memset(d_stream->next_out, 0, REC_NODE_PTR_SIZE);
02160     d_stream->next_out += REC_NODE_PTR_SIZE;
02161 
02162     ut_ad(d_stream->next_out == rec_get_end(rec, offsets));
02163   }
02164 
02165   /* Decompress any trailing garbage, in case the last record was
02166   allocated from an originally longer space on the free list. */
02167   d_stream->avail_out = page_header_get_field(page_zip->data,
02168                 PAGE_HEAP_TOP)
02169     - page_offset(d_stream->next_out);
02170   if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
02171         - PAGE_ZIP_START - PAGE_DIR)) {
02172 
02173     page_zip_fail(("page_zip_decompress_node_ptrs:"
02174              " avail_out = %u\n",
02175              d_stream->avail_out));
02176     goto zlib_error;
02177   }
02178 
02179   if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
02180     page_zip_fail(("page_zip_decompress_node_ptrs:"
02181              " inflate(Z_FINISH)=%s\n",
02182              d_stream->msg));
02183 zlib_error:
02184     inflateEnd(d_stream);
02185     return(FALSE);
02186   }
02187 
02188   /* Note that d_stream->avail_out > 0 may hold here
02189   if the modification log is nonempty. */
02190 
02191 zlib_done:
02192   if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
02193     ut_error;
02194   }
02195 
02196   {
02197     page_t* page = page_align(d_stream->next_out);
02198 
02199     /* Clear the unused heap space on the uncompressed page. */
02200     memset(d_stream->next_out, 0,
02201            page_dir_get_nth_slot(page,
02202                page_dir_get_n_slots(page) - 1)
02203            - d_stream->next_out);
02204   }
02205 
02206 #ifdef UNIV_DEBUG
02207   page_zip->m_start = PAGE_DATA + d_stream->total_in;
02208 #endif /* UNIV_DEBUG */
02209 
02210   /* Apply the modification log. */
02211   {
02212     const byte* mod_log_ptr;
02213     mod_log_ptr = page_zip_apply_log(d_stream->next_in,
02214              d_stream->avail_in + 1,
02215              recs, n_dense,
02216              ULINT_UNDEFINED, heap_status,
02217              index, offsets);
02218 
02219     if (UNIV_UNLIKELY(!mod_log_ptr)) {
02220       return(FALSE);
02221     }
02222     page_zip->m_end = mod_log_ptr - page_zip->data;
02223     page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
02224   }
02225 
02226   if (UNIV_UNLIKELY
02227       (page_zip_get_trailer_len(page_zip,
02228               dict_index_is_clust(index), NULL)
02229        + page_zip->m_end >= page_zip_get_size(page_zip))) {
02230     page_zip_fail(("page_zip_decompress_node_ptrs:"
02231              " %lu + %lu >= %lu, %lu\n",
02232              (ulong) page_zip_get_trailer_len(
02233                page_zip, dict_index_is_clust(index),
02234                NULL),
02235              (ulong) page_zip->m_end,
02236              (ulong) page_zip_get_size(page_zip),
02237              (ulong) dict_index_is_clust(index)));
02238     return(FALSE);
02239   }
02240 
02241   /* Restore the uncompressed columns in heap_no order. */
02242   storage = page_zip->data + page_zip_get_size(page_zip)
02243     - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
02244 
02245   for (slot = 0; slot < n_dense; slot++) {
02246     rec_t*    rec = recs[slot];
02247 
02248     offsets = rec_get_offsets(rec, index, offsets,
02249             ULINT_UNDEFINED, &heap);
02250     /* Non-leaf nodes should not have any externally
02251     stored columns. */
02252     ut_ad(!rec_offs_any_extern(offsets));
02253     storage -= REC_NODE_PTR_SIZE;
02254 
02255     memcpy(rec_get_end(rec, offsets) - REC_NODE_PTR_SIZE,
02256            storage, REC_NODE_PTR_SIZE);
02257   }
02258 
02259   return(TRUE);
02260 }
02261 
02262 /**********************************************************************/
02265 static
02266 ibool
02267 page_zip_decompress_sec(
02268 /*====================*/
02269   page_zip_des_t* page_zip, 
02270   z_stream* d_stream, 
02271   rec_t**   recs,   
02273   ulint   n_dense,  
02274   dict_index_t* index,    
02275   ulint*    offsets)  
02276 {
02277   ulint heap_status = REC_STATUS_ORDINARY
02278     | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
02279   ulint slot;
02280 
02281   ut_a(!dict_index_is_clust(index));
02282 
02283   /* Subtract the space reserved for uncompressed data. */
02284   d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
02285 
02286   for (slot = 0; slot < n_dense; slot++) {
02287     rec_t*  rec = recs[slot];
02288 
02289     /* Decompress everything up to this record. */
02290     d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
02291       - d_stream->next_out;
02292 
02293     if (UNIV_LIKELY(d_stream->avail_out)) {
02294       switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02295       case Z_STREAM_END:
02296         /* Apparently, n_dense has grown
02297         since the time the page was last compressed. */
02298         goto zlib_done;
02299       case Z_OK:
02300       case Z_BUF_ERROR:
02301         if (!d_stream->avail_out) {
02302           break;
02303         }
02304         /* fall through */
02305       default:
02306         page_zip_fail(("page_zip_decompress_sec:"
02307                  " inflate(Z_SYNC_FLUSH)=%s\n",
02308                  d_stream->msg));
02309         goto zlib_error;
02310       }
02311     }
02312 
02313     ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
02314 
02315     /* Skip the REC_N_NEW_EXTRA_BYTES. */
02316 
02317     d_stream->next_out = rec;
02318 
02319     /* Set heap_no and the status bits. */
02320     mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
02321     heap_status += 1 << REC_HEAP_NO_SHIFT;
02322   }
02323 
02324   /* Decompress the data of the last record and any trailing garbage,
02325   in case the last record was allocated from an originally longer space
02326   on the free list. */
02327   d_stream->avail_out = page_header_get_field(page_zip->data,
02328                 PAGE_HEAP_TOP)
02329     - page_offset(d_stream->next_out);
02330   if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
02331         - PAGE_ZIP_START - PAGE_DIR)) {
02332 
02333     page_zip_fail(("page_zip_decompress_sec:"
02334              " avail_out = %u\n",
02335              d_stream->avail_out));
02336     goto zlib_error;
02337   }
02338 
02339   if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
02340     page_zip_fail(("page_zip_decompress_sec:"
02341              " inflate(Z_FINISH)=%s\n",
02342              d_stream->msg));
02343 zlib_error:
02344     inflateEnd(d_stream);
02345     return(FALSE);
02346   }
02347 
02348   /* Note that d_stream->avail_out > 0 may hold here
02349   if the modification log is nonempty. */
02350 
02351 zlib_done:
02352   if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
02353     ut_error;
02354   }
02355 
02356   {
02357     page_t* page = page_align(d_stream->next_out);
02358 
02359     /* Clear the unused heap space on the uncompressed page. */
02360     memset(d_stream->next_out, 0,
02361            page_dir_get_nth_slot(page,
02362                page_dir_get_n_slots(page) - 1)
02363            - d_stream->next_out);
02364   }
02365 
02366 #ifdef UNIV_DEBUG
02367   page_zip->m_start = PAGE_DATA + d_stream->total_in;
02368 #endif /* UNIV_DEBUG */
02369 
02370   /* Apply the modification log. */
02371   {
02372     const byte* mod_log_ptr;
02373     mod_log_ptr = page_zip_apply_log(d_stream->next_in,
02374              d_stream->avail_in + 1,
02375              recs, n_dense,
02376              ULINT_UNDEFINED, heap_status,
02377              index, offsets);
02378 
02379     if (UNIV_UNLIKELY(!mod_log_ptr)) {
02380       return(FALSE);
02381     }
02382     page_zip->m_end = mod_log_ptr - page_zip->data;
02383     page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
02384   }
02385 
02386   if (UNIV_UNLIKELY(page_zip_get_trailer_len(page_zip, FALSE, NULL)
02387         + page_zip->m_end >= page_zip_get_size(page_zip))) {
02388 
02389     page_zip_fail(("page_zip_decompress_sec: %lu + %lu >= %lu\n",
02390              (ulong) page_zip_get_trailer_len(
02391                page_zip, FALSE, NULL),
02392              (ulong) page_zip->m_end,
02393              (ulong) page_zip_get_size(page_zip)));
02394     return(FALSE);
02395   }
02396 
02397   /* There are no uncompressed columns on leaf pages of
02398   secondary indexes. */
02399 
02400   return(TRUE);
02401 }
02402 
02403 /**********************************************************************/
02407 static
02408 ibool
02409 page_zip_decompress_clust_ext(
02410 /*==========================*/
02411   z_stream* d_stream, 
02412   rec_t*    rec,    
02413   const ulint*  offsets,  
02414   ulint   trx_id_col) 
02415 {
02416   ulint i;
02417 
02418   for (i = 0; i < rec_offs_n_fields(offsets); i++) {
02419     ulint len;
02420     byte* dst;
02421 
02422     if (UNIV_UNLIKELY(i == trx_id_col)) {
02423       /* Skip trx_id and roll_ptr */
02424       dst = rec_get_nth_field(rec, offsets, i, &len);
02425       if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
02426             + DATA_ROLL_PTR_LEN)) {
02427 
02428         page_zip_fail(("page_zip_decompress_clust_ext:"
02429                  " len[%lu] = %lu\n",
02430                  (ulong) i, (ulong) len));
02431         return(FALSE);
02432       }
02433 
02434       if (rec_offs_nth_extern(offsets, i)) {
02435 
02436         page_zip_fail(("page_zip_decompress_clust_ext:"
02437                  " DB_TRX_ID at %lu is ext\n",
02438                  (ulong) i));
02439         return(FALSE);
02440       }
02441 
02442       d_stream->avail_out = dst - d_stream->next_out;
02443 
02444       switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02445       case Z_STREAM_END:
02446       case Z_OK:
02447       case Z_BUF_ERROR:
02448         if (!d_stream->avail_out) {
02449           break;
02450         }
02451         /* fall through */
02452       default:
02453         page_zip_fail(("page_zip_decompress_clust_ext:"
02454                  " 1 inflate(Z_SYNC_FLUSH)=%s\n",
02455                  d_stream->msg));
02456         return(FALSE);
02457       }
02458 
02459       ut_ad(d_stream->next_out == dst);
02460 
02461       /* Clear DB_TRX_ID and DB_ROLL_PTR in order to
02462       avoid uninitialized bytes in case the record
02463       is affected by page_zip_apply_log(). */
02464       memset(dst, 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02465 
02466       d_stream->next_out += DATA_TRX_ID_LEN
02467         + DATA_ROLL_PTR_LEN;
02468     } else if (rec_offs_nth_extern(offsets, i)) {
02469       dst = rec_get_nth_field(rec, offsets, i, &len);
02470       ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
02471       dst += len - BTR_EXTERN_FIELD_REF_SIZE;
02472 
02473       d_stream->avail_out = dst - d_stream->next_out;
02474       switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02475       case Z_STREAM_END:
02476       case Z_OK:
02477       case Z_BUF_ERROR:
02478         if (!d_stream->avail_out) {
02479           break;
02480         }
02481         /* fall through */
02482       default:
02483         page_zip_fail(("page_zip_decompress_clust_ext:"
02484                  " 2 inflate(Z_SYNC_FLUSH)=%s\n",
02485                  d_stream->msg));
02486         return(FALSE);
02487       }
02488 
02489       ut_ad(d_stream->next_out == dst);
02490 
02491       /* Clear the BLOB pointer in case
02492       the record will be deleted and the
02493       space will not be reused.  Note that
02494       the final initialization of the BLOB
02495       pointers (copying from "externs"
02496       or clearing) will have to take place
02497       only after the page modification log
02498       has been applied.  Otherwise, we
02499       could end up with an uninitialized
02500       BLOB pointer when a record is deleted,
02501       reallocated and deleted. */
02502       memset(d_stream->next_out, 0,
02503              BTR_EXTERN_FIELD_REF_SIZE);
02504       d_stream->next_out
02505         += BTR_EXTERN_FIELD_REF_SIZE;
02506     }
02507   }
02508 
02509   return(TRUE);
02510 }
02511 
02512 /**********************************************************************/
02515 static
02516 ibool
02517 page_zip_decompress_clust(
02518 /*======================*/
02519   page_zip_des_t* page_zip, 
02520   z_stream* d_stream, 
02521   rec_t**   recs,   
02523   ulint   n_dense,  
02524   dict_index_t* index,    
02525   ulint   trx_id_col, 
02526   ulint*    offsets,  
02527   mem_heap_t* heap)   
02528 {
02529   int   err;
02530   ulint   slot;
02531   ulint   heap_status = REC_STATUS_ORDINARY
02532     | PAGE_HEAP_NO_USER_LOW << REC_HEAP_NO_SHIFT;
02533   const byte* storage;
02534   const byte* externs;
02535 
02536   ut_a(dict_index_is_clust(index));
02537 
02538   /* Subtract the space reserved for uncompressed data. */
02539   d_stream->avail_in -= n_dense * (PAGE_ZIP_DIR_SLOT_SIZE
02540            + DATA_TRX_ID_LEN
02541            + DATA_ROLL_PTR_LEN);
02542 
02543   /* Decompress the records in heap_no order. */
02544   for (slot = 0; slot < n_dense; slot++) {
02545     rec_t*  rec = recs[slot];
02546 
02547     d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
02548       - d_stream->next_out;
02549 
02550     ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
02551           - PAGE_ZIP_START - PAGE_DIR);
02552     err = inflate(d_stream, Z_SYNC_FLUSH);
02553     switch (err) {
02554     case Z_STREAM_END:
02555       /* Apparently, n_dense has grown
02556       since the time the page was last compressed. */
02557       goto zlib_done;
02558     case Z_OK:
02559     case Z_BUF_ERROR:
02560       if (UNIV_LIKELY(!d_stream->avail_out)) {
02561         break;
02562       }
02563       /* fall through */
02564     default:
02565       page_zip_fail(("page_zip_decompress_clust:"
02566                " 1 inflate(Z_SYNC_FLUSH)=%s\n",
02567                d_stream->msg));
02568       goto zlib_error;
02569     }
02570 
02571     ut_ad(d_stream->next_out == rec - REC_N_NEW_EXTRA_BYTES);
02572     /* Prepare to decompress the data bytes. */
02573     d_stream->next_out = rec;
02574     /* Set heap_no and the status bits. */
02575     mach_write_to_2(rec - REC_NEW_HEAP_NO, heap_status);
02576     heap_status += 1 << REC_HEAP_NO_SHIFT;
02577 
02578     /* Read the offsets. The status bits are needed here. */
02579     offsets = rec_get_offsets(rec, index, offsets,
02580             ULINT_UNDEFINED, &heap);
02581 
02582     /* This is a leaf page in a clustered index. */
02583 
02584     /* Check if there are any externally stored columns.
02585     For each externally stored column, restore the
02586     BTR_EXTERN_FIELD_REF separately. */
02587 
02588     if (UNIV_UNLIKELY(rec_offs_any_extern(offsets))) {
02589       if (UNIV_UNLIKELY
02590           (!page_zip_decompress_clust_ext(
02591             d_stream, rec, offsets, trx_id_col))) {
02592 
02593         goto zlib_error;
02594       }
02595     } else {
02596       /* Skip trx_id and roll_ptr */
02597       ulint len;
02598       byte* dst = rec_get_nth_field(rec, offsets,
02599               trx_id_col, &len);
02600       if (UNIV_UNLIKELY(len < DATA_TRX_ID_LEN
02601             + DATA_ROLL_PTR_LEN)) {
02602 
02603         page_zip_fail(("page_zip_decompress_clust:"
02604                  " len = %lu\n", (ulong) len));
02605         goto zlib_error;
02606       }
02607 
02608       d_stream->avail_out = dst - d_stream->next_out;
02609 
02610       switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02611       case Z_STREAM_END:
02612       case Z_OK:
02613       case Z_BUF_ERROR:
02614         if (!d_stream->avail_out) {
02615           break;
02616         }
02617         /* fall through */
02618       default:
02619         page_zip_fail(("page_zip_decompress_clust:"
02620                  " 2 inflate(Z_SYNC_FLUSH)=%s\n",
02621                  d_stream->msg));
02622         goto zlib_error;
02623       }
02624 
02625       ut_ad(d_stream->next_out == dst);
02626 
02627       /* Clear DB_TRX_ID and DB_ROLL_PTR in order to
02628       avoid uninitialized bytes in case the record
02629       is affected by page_zip_apply_log(). */
02630       memset(dst, 0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02631 
02632       d_stream->next_out += DATA_TRX_ID_LEN
02633         + DATA_ROLL_PTR_LEN;
02634     }
02635 
02636     /* Decompress the last bytes of the record. */
02637     d_stream->avail_out = rec_get_end(rec, offsets)
02638       - d_stream->next_out;
02639 
02640     switch (inflate(d_stream, Z_SYNC_FLUSH)) {
02641     case Z_STREAM_END:
02642     case Z_OK:
02643     case Z_BUF_ERROR:
02644       if (!d_stream->avail_out) {
02645         break;
02646       }
02647       /* fall through */
02648     default:
02649       page_zip_fail(("page_zip_decompress_clust:"
02650                " 3 inflate(Z_SYNC_FLUSH)=%s\n",
02651                d_stream->msg));
02652       goto zlib_error;
02653     }
02654   }
02655 
02656   /* Decompress any trailing garbage, in case the last record was
02657   allocated from an originally longer space on the free list. */
02658   d_stream->avail_out = page_header_get_field(page_zip->data,
02659                 PAGE_HEAP_TOP)
02660     - page_offset(d_stream->next_out);
02661   if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
02662         - PAGE_ZIP_START - PAGE_DIR)) {
02663 
02664     page_zip_fail(("page_zip_decompress_clust:"
02665              " avail_out = %u\n",
02666              d_stream->avail_out));
02667     goto zlib_error;
02668   }
02669 
02670   if (UNIV_UNLIKELY(inflate(d_stream, Z_FINISH) != Z_STREAM_END)) {
02671     page_zip_fail(("page_zip_decompress_clust:"
02672              " inflate(Z_FINISH)=%s\n",
02673              d_stream->msg));
02674 zlib_error:
02675     inflateEnd(d_stream);
02676     return(FALSE);
02677   }
02678 
02679   /* Note that d_stream->avail_out > 0 may hold here
02680   if the modification log is nonempty. */
02681 
02682 zlib_done:
02683   if (UNIV_UNLIKELY(inflateEnd(d_stream) != Z_OK)) {
02684     ut_error;
02685   }
02686 
02687   {
02688     page_t* page = page_align(d_stream->next_out);
02689 
02690     /* Clear the unused heap space on the uncompressed page. */
02691     memset(d_stream->next_out, 0,
02692            page_dir_get_nth_slot(page,
02693                page_dir_get_n_slots(page) - 1)
02694            - d_stream->next_out);
02695   }
02696 
02697 #ifdef UNIV_DEBUG
02698   page_zip->m_start = PAGE_DATA + d_stream->total_in;
02699 #endif /* UNIV_DEBUG */
02700 
02701   /* Apply the modification log. */
02702   {
02703     const byte* mod_log_ptr;
02704     mod_log_ptr = page_zip_apply_log(d_stream->next_in,
02705              d_stream->avail_in + 1,
02706              recs, n_dense,
02707              trx_id_col, heap_status,
02708              index, offsets);
02709 
02710     if (UNIV_UNLIKELY(!mod_log_ptr)) {
02711       return(FALSE);
02712     }
02713     page_zip->m_end = mod_log_ptr - page_zip->data;
02714     page_zip->m_nonempty = mod_log_ptr != d_stream->next_in;
02715   }
02716 
02717   if (UNIV_UNLIKELY(page_zip_get_trailer_len(page_zip, TRUE, NULL)
02718         + page_zip->m_end >= page_zip_get_size(page_zip))) {
02719 
02720     page_zip_fail(("page_zip_decompress_clust: %lu + %lu >= %lu\n",
02721              (ulong) page_zip_get_trailer_len(
02722                page_zip, TRUE, NULL),
02723              (ulong) page_zip->m_end,
02724              (ulong) page_zip_get_size(page_zip)));
02725     return(FALSE);
02726   }
02727 
02728   storage = page_zip->data + page_zip_get_size(page_zip)
02729     - n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
02730 
02731   externs = storage - n_dense
02732     * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02733 
02734   /* Restore the uncompressed columns in heap_no order. */
02735 
02736   for (slot = 0; slot < n_dense; slot++) {
02737     ulint i;
02738     ulint len;
02739     byte* dst;
02740     rec_t*  rec = recs[slot];
02741     ibool exists  = !page_zip_dir_find_free(
02742       page_zip, page_offset(rec));
02743     offsets = rec_get_offsets(rec, index, offsets,
02744             ULINT_UNDEFINED, &heap);
02745 
02746     dst = rec_get_nth_field(rec, offsets,
02747           trx_id_col, &len);
02748     ut_ad(len >= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02749     storage -= DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
02750     memcpy(dst, storage,
02751            DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
02752 
02753     /* Check if there are any externally stored
02754     columns in this record.  For each externally
02755     stored column, restore or clear the
02756     BTR_EXTERN_FIELD_REF. */
02757     if (!rec_offs_any_extern(offsets)) {
02758       continue;
02759     }
02760 
02761     for (i = 0; i < rec_offs_n_fields(offsets); i++) {
02762       if (!rec_offs_nth_extern(offsets, i)) {
02763         continue;
02764       }
02765       dst = rec_get_nth_field(rec, offsets, i, &len);
02766 
02767       if (UNIV_UNLIKELY(len < BTR_EXTERN_FIELD_REF_SIZE)) {
02768         page_zip_fail(("page_zip_decompress_clust:"
02769                  " %lu < 20\n",
02770                  (ulong) len));
02771         return(FALSE);
02772       }
02773 
02774       dst += len - BTR_EXTERN_FIELD_REF_SIZE;
02775 
02776       if (UNIV_LIKELY(exists)) {
02777         /* Existing record:
02778         restore the BLOB pointer */
02779         externs -= BTR_EXTERN_FIELD_REF_SIZE;
02780 
02781         if (UNIV_UNLIKELY
02782             (externs < page_zip->data
02783              + page_zip->m_end)) {
02784           page_zip_fail(("page_zip_"
02785                    "decompress_clust: "
02786                    "%p < %p + %lu\n",
02787                    (const void*) externs,
02788                    (const void*)
02789                    page_zip->data,
02790                    (ulong)
02791                    page_zip->m_end));
02792           return(FALSE);
02793         }
02794 
02795         memcpy(dst, externs,
02796                BTR_EXTERN_FIELD_REF_SIZE);
02797 
02798         page_zip->n_blobs++;
02799       } else {
02800         /* Deleted record:
02801         clear the BLOB pointer */
02802         memset(dst, 0,
02803                BTR_EXTERN_FIELD_REF_SIZE);
02804       }
02805     }
02806   }
02807 
02808   return(TRUE);
02809 }
02810 
02811 /**********************************************************************/
02816 UNIV_INTERN
02817 ibool
02818 page_zip_decompress(
02819 /*================*/
02820   page_zip_des_t* page_zip,
02822   page_t*   page, 
02823   ibool   all)  
02827 {
02828   z_stream  d_stream;
02829   dict_index_t* index = NULL;
02830   rec_t**   recs; 
02831   ulint   n_dense;/* number of user records on the page */
02832   ulint   trx_id_col = ULINT_UNDEFINED;
02833   mem_heap_t* heap;
02834   ulint*    offsets;
02835 #ifndef UNIV_HOTBACKUP
02836   ullint    usec = ut_time_us(NULL);
02837 #endif /* !UNIV_HOTBACKUP */
02838 
02839   ut_ad(page_zip_simple_validate(page_zip));
02840   UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE);
02841   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
02842 
02843   /* The dense directory excludes the infimum and supremum records. */
02844   n_dense = page_dir_get_n_heap(page_zip->data) - PAGE_HEAP_NO_USER_LOW;
02845   if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE
02846         >= page_zip_get_size(page_zip))) {
02847     page_zip_fail(("page_zip_decompress 1: %lu %lu\n",
02848              (ulong) n_dense,
02849              (ulong) page_zip_get_size(page_zip)));
02850     return(FALSE);
02851   }
02852 
02853   heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE);
02854   recs = static_cast<byte **>(mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)));
02855 
02856   if (all) {
02857     /* Copy the page header. */
02858     memcpy(page, page_zip->data, PAGE_DATA);
02859   } else {
02860     /* Check that the bytes that we skip are identical. */
02861 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
02862     ut_a(!memcmp(FIL_PAGE_TYPE + page,
02863            FIL_PAGE_TYPE + page_zip->data,
02864            PAGE_HEADER - FIL_PAGE_TYPE));
02865     ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page,
02866            PAGE_HEADER + PAGE_LEVEL + page_zip->data,
02867            PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL)));
02868 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
02869 
02870     /* Copy the mutable parts of the page header. */
02871     memcpy(page, page_zip->data, FIL_PAGE_TYPE);
02872     memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data,
02873            PAGE_LEVEL - PAGE_N_DIR_SLOTS);
02874 
02875 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
02876     /* Check that the page headers match after copying. */
02877     ut_a(!memcmp(page, page_zip->data, PAGE_DATA));
02878 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
02879   }
02880 
02881 #ifdef UNIV_ZIP_DEBUG
02882   /* Clear the uncompressed page, except the header. */
02883   memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA);
02884 #endif /* UNIV_ZIP_DEBUG */
02885   UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA);
02886 
02887   /* Copy the page directory. */
02888   if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs,
02889                  recs + n_dense, n_dense))) {
02890 zlib_error:
02891     mem_heap_free(heap);
02892     return(FALSE);
02893   }
02894 
02895   /* Copy the infimum and supremum records. */
02896   memcpy(page + (PAGE_NEW_INFIMUM - REC_N_NEW_EXTRA_BYTES),
02897          infimum_extra, sizeof infimum_extra);
02898   if (UNIV_UNLIKELY(!page_get_n_recs(page))) {
02899     rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
02900               PAGE_NEW_SUPREMUM);
02901   } else {
02902     rec_set_next_offs_new(page + PAGE_NEW_INFIMUM,
02903               page_zip_dir_get(page_zip, 0)
02904               & PAGE_ZIP_DIR_SLOT_MASK);
02905   }
02906   memcpy(page + PAGE_NEW_INFIMUM, infimum_data, sizeof infimum_data);
02907   memcpy(page + (PAGE_NEW_SUPREMUM - REC_N_NEW_EXTRA_BYTES + 1),
02908          supremum_extra_data, sizeof supremum_extra_data);
02909 
02910   page_zip_set_alloc(&d_stream, heap);
02911 
02912   if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT)
02913         != Z_OK)) {
02914     ut_error;
02915   }
02916 
02917   d_stream.next_in = page_zip->data + PAGE_DATA;
02918   /* Subtract the space reserved for
02919   the page header and the end marker of the modification log. */
02920   d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1);
02921 
02922   d_stream.next_out = page + PAGE_ZIP_START;
02923   d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
02924 
02925   /* Decode the zlib header and the index information. */
02926   if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
02927 
02928     page_zip_fail(("page_zip_decompress:"
02929              " 1 inflate(Z_BLOCK)=%s\n", d_stream.msg));
02930     goto zlib_error;
02931   }
02932 
02933   if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) {
02934 
02935     page_zip_fail(("page_zip_decompress:"
02936              " 2 inflate(Z_BLOCK)=%s\n", d_stream.msg));
02937     goto zlib_error;
02938   }
02939 
02940   index = page_zip_fields_decode(
02941     page + PAGE_ZIP_START, d_stream.next_out,
02942     page_is_leaf(page) ? &trx_id_col : NULL);
02943 
02944   if (UNIV_UNLIKELY(!index)) {
02945 
02946     goto zlib_error;
02947   }
02948 
02949   /* Decompress the user records. */
02950   page_zip->n_blobs = 0;
02951   d_stream.next_out = page + PAGE_ZIP_START;
02952 
02953   {
02954     /* Pre-allocate the offsets for rec_get_offsets_reverse(). */
02955     ulint n = 1 + 1/* node ptr */ + REC_OFFS_HEADER_SIZE
02956       + dict_index_get_n_fields(index);
02957     offsets = static_cast<unsigned long *>(mem_heap_alloc(heap, n * sizeof(ulint)));
02958     *offsets = n;
02959   }
02960 
02961   /* Decompress the records in heap_no order. */
02962   if (!page_is_leaf(page)) {
02963     /* This is a node pointer page. */
02964     ulint info_bits;
02965 
02966     if (UNIV_UNLIKELY
02967         (!page_zip_decompress_node_ptrs(page_zip, &d_stream,
02968                 recs, n_dense, index,
02969                 offsets, heap))) {
02970       goto err_exit;
02971     }
02972 
02973     info_bits = mach_read_from_4(page + FIL_PAGE_PREV) == FIL_NULL
02974       ? REC_INFO_MIN_REC_FLAG : 0;
02975 
02976     if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip, page,
02977                   info_bits))) {
02978       goto err_exit;
02979     }
02980   } else if (UNIV_LIKELY(trx_id_col == ULINT_UNDEFINED)) {
02981     /* This is a leaf page in a secondary index. */
02982     if (UNIV_UNLIKELY(!page_zip_decompress_sec(page_zip, &d_stream,
02983                  recs, n_dense,
02984                  index, offsets))) {
02985       goto err_exit;
02986     }
02987 
02988     if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
02989                   page, 0))) {
02990 err_exit:
02991       page_zip_fields_free(index);
02992       mem_heap_free(heap);
02993       return(FALSE);
02994     }
02995   } else {
02996     /* This is a leaf page in a clustered index. */
02997     if (UNIV_UNLIKELY(!page_zip_decompress_clust(page_zip,
02998                    &d_stream, recs,
02999                    n_dense, index,
03000                    trx_id_col,
03001                    offsets, heap))) {
03002       goto err_exit;
03003     }
03004 
03005     if (UNIV_UNLIKELY(!page_zip_set_extra_bytes(page_zip,
03006                   page, 0))) {
03007       goto err_exit;
03008     }
03009   }
03010 
03011   ut_a(page_is_comp(page));
03012   UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
03013 
03014   page_zip_fields_free(index);
03015   mem_heap_free(heap);
03016 #ifndef UNIV_HOTBACKUP
03017   {
03018     page_zip_stat_t*  zip_stat
03019       = &page_zip_stat[page_zip->ssize - 1];
03020     zip_stat->decompressed++;
03021     zip_stat->decompressed_usec += ut_time_us(NULL) - usec;
03022   }
03023 #endif /* !UNIV_HOTBACKUP */
03024 
03025   /* Update the stat counter for LRU policy. */
03026   buf_LRU_stat_inc_unzip();
03027 
03028   return(TRUE);
03029 }
03030 
03031 #ifdef UNIV_ZIP_DEBUG
03032 /**********************************************************************/
03034 static
03035 void
03036 page_zip_hexdump_func(
03037 /*==================*/
03038   const char* name, 
03039   const void* buf,  
03040   ulint   size) 
03041 {
03042   const byte* s = buf;
03043   ulint   addr;
03044   const ulint width = 32; /* bytes per line */
03045 
03046   fprintf(stderr, "%s:\n", name);
03047 
03048   for (addr = 0; addr < size; addr += width) {
03049     ulint i;
03050 
03051     fprintf(stderr, "%04lx ", (ulong) addr);
03052 
03053     i = ut_min(width, size - addr);
03054 
03055     while (i--) {
03056       fprintf(stderr, "%02x", *s++);
03057     }
03058 
03059     putc('\n', stderr);
03060   }
03061 }
03062 
03066 #define page_zip_hexdump(buf, size) page_zip_hexdump_func(#buf, buf, size)
03067 
03069 UNIV_INTERN ibool page_zip_validate_header_only = FALSE;
03070 
03071 /**********************************************************************/
03074 UNIV_INTERN
03075 ibool
03076 page_zip_validate_low(
03077 /*==================*/
03078   const page_zip_des_t* page_zip,
03079   const page_t*   page, 
03080   ibool     sloppy) 
03082 {
03083   page_zip_des_t  temp_page_zip;
03084   byte*   temp_page_buf;
03085   page_t*   temp_page;
03086   ibool   valid;
03087 
03088   if (memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
03089        FIL_PAGE_LSN - FIL_PAGE_PREV)
03090       || memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE, 2)
03091       || memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
03092           PAGE_DATA - FIL_PAGE_DATA)) {
03093     page_zip_fail(("page_zip_validate: page header\n"));
03094     page_zip_hexdump(page_zip, sizeof *page_zip);
03095     page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
03096     page_zip_hexdump(page, UNIV_PAGE_SIZE);
03097     return(FALSE);
03098   }
03099 
03100   ut_a(page_is_comp(page));
03101 
03102   if (page_zip_validate_header_only) {
03103     return(TRUE);
03104   }
03105 
03106   /* page_zip_decompress() expects the uncompressed page to be
03107   UNIV_PAGE_SIZE aligned. */
03108   temp_page_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
03109   temp_page = ut_align(temp_page_buf, UNIV_PAGE_SIZE);
03110 
03111 #ifdef UNIV_DEBUG_VALGRIND
03112   /* Get detailed information on the valid bits in case the
03113   UNIV_MEM_ASSERT_RW() checks fail.  The v-bits of page[],
03114   page_zip->data[] or page_zip could be viewed at temp_page[] or
03115   temp_page_zip in a debugger when running valgrind --db-attach. */
03116   VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE);
03117   UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
03118 # if UNIV_WORD_SIZE == 4
03119   VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip);
03120   /* On 32-bit systems, there is no padding in page_zip_des_t.
03121   On other systems, Valgrind could complain about uninitialized
03122   pad bytes. */
03123   UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip);
03124 # endif
03125   VALGRIND_GET_VBITS(page_zip->data, temp_page,
03126          page_zip_get_size(page_zip));
03127   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03128 #endif /* UNIV_DEBUG_VALGRIND */
03129 
03130   temp_page_zip = *page_zip;
03131   valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE);
03132   if (!valid) {
03133     fputs("page_zip_validate(): failed to decompress\n", stderr);
03134     goto func_exit;
03135   }
03136   if (page_zip->n_blobs != temp_page_zip.n_blobs) {
03137     page_zip_fail(("page_zip_validate: n_blobs: %u!=%u\n",
03138              page_zip->n_blobs, temp_page_zip.n_blobs));
03139     valid = FALSE;
03140   }
03141 #ifdef UNIV_DEBUG
03142   if (page_zip->m_start != temp_page_zip.m_start) {
03143     page_zip_fail(("page_zip_validate: m_start: %u!=%u\n",
03144              page_zip->m_start, temp_page_zip.m_start));
03145     valid = FALSE;
03146   }
03147 #endif /* UNIV_DEBUG */
03148   if (page_zip->m_end != temp_page_zip.m_end) {
03149     page_zip_fail(("page_zip_validate: m_end: %u!=%u\n",
03150              page_zip->m_end, temp_page_zip.m_end));
03151     valid = FALSE;
03152   }
03153   if (page_zip->m_nonempty != temp_page_zip.m_nonempty) {
03154     page_zip_fail(("page_zip_validate(): m_nonempty: %u!=%u\n",
03155              page_zip->m_nonempty,
03156              temp_page_zip.m_nonempty));
03157     valid = FALSE;
03158   }
03159   if (memcmp(page + PAGE_HEADER, temp_page + PAGE_HEADER,
03160        UNIV_PAGE_SIZE - PAGE_HEADER - FIL_PAGE_DATA_END)) {
03161 
03162     /* In crash recovery, the "minimum record" flag may be
03163     set incorrectly until the mini-transaction is
03164     committed.  Let us tolerate that difference when we
03165     are performing a sloppy validation. */
03166 
03167     if (sloppy) {
03168       byte  info_bits_diff;
03169       ulint offset
03170         = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
03171                 TRUE);
03172       ut_a(offset >= PAGE_NEW_SUPREMUM);
03173       offset -= 5 /* REC_NEW_INFO_BITS */;
03174 
03175       info_bits_diff = page[offset] ^ temp_page[offset];
03176 
03177       if (info_bits_diff == REC_INFO_MIN_REC_FLAG) {
03178         temp_page[offset] = page[offset];
03179 
03180         if (!memcmp(page + PAGE_HEADER,
03181               temp_page + PAGE_HEADER,
03182               UNIV_PAGE_SIZE - PAGE_HEADER
03183               - FIL_PAGE_DATA_END)) {
03184 
03185           /* Only the minimum record flag
03186           differed.  Let us ignore it. */
03187           page_zip_fail(("page_zip_validate: "
03188                    "min_rec_flag "
03189                    "(ignored, "
03190                    "%lu,%lu,0x%02lx)\n",
03191                    page_get_space_id(page),
03192                    page_get_page_no(page),
03193                    (ulong) page[offset]));
03194           goto func_exit;
03195         }
03196       }
03197     }
03198     page_zip_fail(("page_zip_validate: content\n"));
03199     valid = FALSE;
03200   }
03201 
03202 func_exit:
03203   if (!valid) {
03204     page_zip_hexdump(page_zip, sizeof *page_zip);
03205     page_zip_hexdump(page_zip->data, page_zip_get_size(page_zip));
03206     page_zip_hexdump(page, UNIV_PAGE_SIZE);
03207     page_zip_hexdump(temp_page, UNIV_PAGE_SIZE);
03208   }
03209   ut_free(temp_page_buf);
03210   return(valid);
03211 }
03212 
03213 /**********************************************************************/
03216 UNIV_INTERN
03217 ibool
03218 page_zip_validate(
03219 /*==============*/
03220   const page_zip_des_t* page_zip,
03221   const page_t*   page) 
03222 {
03223   return(page_zip_validate_low(page_zip, page,
03224              recv_recovery_is_on()));
03225 }
03226 #endif /* UNIV_ZIP_DEBUG */
03227 
03228 #ifdef UNIV_DEBUG
03229 /**********************************************************************/
03232 static
03233 ibool
03234 page_zip_header_cmp(
03235 /*================*/
03236   const page_zip_des_t* page_zip,
03237   const byte*   page) 
03238 {
03239   ut_ad(!memcmp(page_zip->data + FIL_PAGE_PREV, page + FIL_PAGE_PREV,
03240           FIL_PAGE_LSN - FIL_PAGE_PREV));
03241   ut_ad(!memcmp(page_zip->data + FIL_PAGE_TYPE, page + FIL_PAGE_TYPE,
03242           2));
03243   ut_ad(!memcmp(page_zip->data + FIL_PAGE_DATA, page + FIL_PAGE_DATA,
03244           PAGE_DATA - FIL_PAGE_DATA));
03245 
03246   return(TRUE);
03247 }
03248 #endif /* UNIV_DEBUG */
03249 
03250 /**********************************************************************/
03254 static
03255 byte*
03256 page_zip_write_rec_ext(
03257 /*===================*/
03258   page_zip_des_t* page_zip, 
03259   const page_t* page,   
03260   const byte* rec,    
03261   dict_index_t* index,    
03262   const ulint*  offsets,  
03263   ulint   create,   
03264   ulint   trx_id_col, 
03265   ulint   heap_no,  
03266   byte*   storage,  
03267   byte*   data)   
03268 {
03269   const byte* start = rec;
03270   ulint   i;
03271   ulint   len;
03272   byte*   externs = storage;
03273   ulint   n_ext = rec_offs_n_extern(offsets);
03274 
03275   ut_ad(rec_offs_validate(rec, index, offsets));
03276   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
03277   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
03278          rec_offs_extra_size(offsets));
03279 
03280   externs -= (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
03281     * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW);
03282 
03283   /* Note that this will not take into account
03284   the BLOB columns of rec if create==TRUE. */
03285   ut_ad(data + rec_offs_data_size(offsets)
03286         - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
03287         - n_ext * BTR_EXTERN_FIELD_REF_SIZE
03288         < externs - BTR_EXTERN_FIELD_REF_SIZE * page_zip->n_blobs);
03289 
03290   {
03291     ulint blob_no = page_zip_get_n_prev_extern(
03292       page_zip, rec, index);
03293     byte* ext_end = externs - page_zip->n_blobs
03294       * BTR_EXTERN_FIELD_REF_SIZE;
03295     ut_ad(blob_no <= page_zip->n_blobs);
03296     externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
03297 
03298     if (create) {
03299       page_zip->n_blobs += n_ext;
03300       ASSERT_ZERO_BLOB(ext_end - n_ext
03301            * BTR_EXTERN_FIELD_REF_SIZE);
03302       memmove(ext_end - n_ext
03303         * BTR_EXTERN_FIELD_REF_SIZE,
03304         ext_end,
03305         externs - ext_end);
03306     }
03307 
03308     ut_a(blob_no + n_ext <= page_zip->n_blobs);
03309   }
03310 
03311   for (i = 0; i < rec_offs_n_fields(offsets); i++) {
03312     const byte* src;
03313 
03314     if (UNIV_UNLIKELY(i == trx_id_col)) {
03315       ut_ad(!rec_offs_nth_extern(offsets,
03316                i));
03317       ut_ad(!rec_offs_nth_extern(offsets,
03318                i + 1));
03319       /* Locate trx_id and roll_ptr. */
03320       src = rec_get_nth_field(rec, offsets,
03321             i, &len);
03322       ut_ad(len == DATA_TRX_ID_LEN);
03323       ut_ad(src + DATA_TRX_ID_LEN
03324             == rec_get_nth_field(
03325               rec, offsets,
03326               i + 1, &len));
03327       ut_ad(len == DATA_ROLL_PTR_LEN);
03328 
03329       /* Log the preceding fields. */
03330       ASSERT_ZERO(data, src - start);
03331       memcpy(data, start, src - start);
03332       data += src - start;
03333       start = src + (DATA_TRX_ID_LEN
03334                + DATA_ROLL_PTR_LEN);
03335 
03336       /* Store trx_id and roll_ptr. */
03337       memcpy(storage - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
03338              * (heap_no - 1),
03339              src, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03340       i++; /* skip also roll_ptr */
03341     } else if (rec_offs_nth_extern(offsets, i)) {
03342       src = rec_get_nth_field(rec, offsets,
03343             i, &len);
03344 
03345       ut_ad(dict_index_is_clust(index));
03346       ut_ad(len
03347             >= BTR_EXTERN_FIELD_REF_SIZE);
03348       src += len - BTR_EXTERN_FIELD_REF_SIZE;
03349 
03350       ASSERT_ZERO(data, src - start);
03351       memcpy(data, start, src - start);
03352       data += src - start;
03353       start = src + BTR_EXTERN_FIELD_REF_SIZE;
03354 
03355       /* Store the BLOB pointer. */
03356       externs -= BTR_EXTERN_FIELD_REF_SIZE;
03357       ut_ad(data < externs);
03358       memcpy(externs, src, BTR_EXTERN_FIELD_REF_SIZE);
03359     }
03360   }
03361 
03362   /* Log the last bytes of the record. */
03363   len = rec_offs_data_size(offsets) - (start - rec);
03364 
03365   ASSERT_ZERO(data, len);
03366   memcpy(data, start, len);
03367   data += len;
03368 
03369   return(data);
03370 }
03371 
03372 /**********************************************************************/
03375 UNIV_INTERN
03376 void
03377 page_zip_write_rec(
03378 /*===============*/
03379   page_zip_des_t* page_zip,
03380   const byte* rec,  
03381   dict_index_t* index,  
03382   const ulint*  offsets,
03383   ulint   create) 
03384 {
03385   const page_t* page;
03386   byte*   data;
03387   byte*   storage;
03388   ulint   heap_no;
03389   byte*   slot;
03390 
03391   ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
03392   ut_ad(page_zip_simple_validate(page_zip));
03393   ut_ad(page_zip_get_size(page_zip)
03394         > PAGE_DATA + page_zip_dir_size(page_zip));
03395   ut_ad(rec_offs_comp(offsets));
03396   ut_ad(rec_offs_validate(rec, index, offsets));
03397 
03398   ut_ad(page_zip->m_start >= PAGE_DATA);
03399 
03400   page = page_align(rec);
03401 
03402   ut_ad(page_zip_header_cmp(page_zip, page));
03403   ut_ad(page_simple_validate_new((page_t*) page));
03404 
03405   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03406   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
03407   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
03408          rec_offs_extra_size(offsets));
03409 
03410   slot = page_zip_dir_find(page_zip, page_offset(rec));
03411   ut_a(slot);
03412   /* Copy the delete mark. */
03413   if (rec_get_deleted_flag(rec, TRUE)) {
03414     *slot |= PAGE_ZIP_DIR_SLOT_DEL >> 8;
03415   } else {
03416     *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
03417   }
03418 
03419   ut_ad(rec_get_start((rec_t*) rec, offsets) >= page + PAGE_ZIP_START);
03420   ut_ad(rec_get_end((rec_t*) rec, offsets) <= page + UNIV_PAGE_SIZE
03421         - PAGE_DIR - PAGE_DIR_SLOT_SIZE
03422         * page_dir_get_n_slots(page));
03423 
03424   heap_no = rec_get_heap_no_new(rec);
03425   ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW); /* not infimum or supremum */
03426   ut_ad(heap_no < page_dir_get_n_heap(page));
03427 
03428   /* Append to the modification log. */
03429   data = page_zip->data + page_zip->m_end;
03430   ut_ad(!*data);
03431 
03432   /* Identify the record by writing its heap number - 1.
03433   0 is reserved to indicate the end of the modification log. */
03434 
03435   if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
03436     *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
03437     ut_ad(!*data);
03438   }
03439   *data++ = (byte) ((heap_no - 1) << 1);
03440   ut_ad(!*data);
03441 
03442   {
03443     const byte* start = rec - rec_offs_extra_size(offsets);
03444     const byte* b = rec - REC_N_NEW_EXTRA_BYTES;
03445 
03446     /* Write the extra bytes backwards, so that
03447     rec_offs_extra_size() can be easily computed in
03448     page_zip_apply_log() by invoking
03449     rec_get_offsets_reverse(). */
03450 
03451     while (b != start) {
03452       *data++ = *--b;
03453       ut_ad(!*data);
03454     }
03455   }
03456 
03457   /* Write the data bytes.  Store the uncompressed bytes separately. */
03458   storage = page_zip->data + page_zip_get_size(page_zip)
03459     - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
03460     * PAGE_ZIP_DIR_SLOT_SIZE;
03461 
03462   if (page_is_leaf(page)) {
03463     ulint   len;
03464 
03465     if (dict_index_is_clust(index)) {
03466       ulint   trx_id_col;
03467 
03468       trx_id_col = dict_index_get_sys_col_pos(index,
03469                 DATA_TRX_ID);
03470       ut_ad(trx_id_col != ULINT_UNDEFINED);
03471 
03472       /* Store separately trx_id, roll_ptr and
03473       the BTR_EXTERN_FIELD_REF of each BLOB column. */
03474       if (rec_offs_any_extern(offsets)) {
03475         data = page_zip_write_rec_ext(
03476           page_zip, page,
03477           rec, index, offsets, create,
03478           trx_id_col, heap_no, storage, data);
03479       } else {
03480         /* Locate trx_id and roll_ptr. */
03481         const byte* src
03482           = rec_get_nth_field(rec, offsets,
03483                   trx_id_col, &len);
03484         ut_ad(len == DATA_TRX_ID_LEN);
03485         ut_ad(src + DATA_TRX_ID_LEN
03486               == rec_get_nth_field(
03487                 rec, offsets,
03488                 trx_id_col + 1, &len));
03489         ut_ad(len == DATA_ROLL_PTR_LEN);
03490 
03491         /* Log the preceding fields. */
03492         ASSERT_ZERO(data, src - rec);
03493         memcpy(data, rec, src - rec);
03494         data += src - rec;
03495 
03496         /* Store trx_id and roll_ptr. */
03497         memcpy(storage
03498                - (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)
03499                * (heap_no - 1),
03500                src,
03501                DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03502 
03503         src += DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
03504 
03505         /* Log the last bytes of the record. */
03506         len = rec_offs_data_size(offsets)
03507           - (src - rec);
03508 
03509         ASSERT_ZERO(data, len);
03510         memcpy(data, src, len);
03511         data += len;
03512       }
03513     } else {
03514       /* Leaf page of a secondary index:
03515       no externally stored columns */
03516       ut_ad(dict_index_get_sys_col_pos(index, DATA_TRX_ID)
03517             == ULINT_UNDEFINED);
03518       ut_ad(!rec_offs_any_extern(offsets));
03519 
03520       /* Log the entire record. */
03521       len = rec_offs_data_size(offsets);
03522 
03523       ASSERT_ZERO(data, len);
03524       memcpy(data, rec, len);
03525       data += len;
03526     }
03527   } else {
03528     /* This is a node pointer page. */
03529     ulint len;
03530 
03531     /* Non-leaf nodes should not have any externally
03532     stored columns. */
03533     ut_ad(!rec_offs_any_extern(offsets));
03534 
03535     /* Copy the data bytes, except node_ptr. */
03536     len = rec_offs_data_size(offsets) - REC_NODE_PTR_SIZE;
03537     ut_ad(data + len < storage - REC_NODE_PTR_SIZE
03538           * (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW));
03539     ASSERT_ZERO(data, len);
03540     memcpy(data, rec, len);
03541     data += len;
03542 
03543     /* Copy the node pointer to the uncompressed area. */
03544     memcpy(storage - REC_NODE_PTR_SIZE
03545            * (heap_no - 1),
03546            rec + len,
03547            REC_NODE_PTR_SIZE);
03548   }
03549 
03550   ut_a(!*data);
03551   ut_ad((ulint) (data - page_zip->data) < page_zip_get_size(page_zip));
03552   page_zip->m_end = data - page_zip->data;
03553   page_zip->m_nonempty = TRUE;
03554 
03555 #ifdef UNIV_ZIP_DEBUG
03556   ut_a(page_zip_validate(page_zip, page_align(rec)));
03557 #endif /* UNIV_ZIP_DEBUG */
03558 }
03559 
03560 /***********************************************************/
03563 UNIV_INTERN
03564 byte*
03565 page_zip_parse_write_blob_ptr(
03566 /*==========================*/
03567   byte*   ptr,  
03568   byte*   end_ptr,
03569   page_t*   page, 
03570   page_zip_des_t* page_zip)
03571 {
03572   ulint offset;
03573   ulint z_offset;
03574 
03575   ut_ad(!page == !page_zip);
03576 
03577   if (UNIV_UNLIKELY
03578       (end_ptr < ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE))) {
03579 
03580     return(NULL);
03581   }
03582 
03583   offset = mach_read_from_2(ptr);
03584   z_offset = mach_read_from_2(ptr + 2);
03585 
03586   if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
03587       || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
03588       || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
03589 corrupt:
03590     recv_sys->found_corrupt_log = TRUE;
03591 
03592     return(NULL);
03593   }
03594 
03595   if (page) {
03596     if (UNIV_UNLIKELY(!page_zip)
03597         || UNIV_UNLIKELY(!page_is_leaf(page))) {
03598 
03599       goto corrupt;
03600     }
03601 
03602 #ifdef UNIV_ZIP_DEBUG
03603     ut_a(page_zip_validate(page_zip, page));
03604 #endif /* UNIV_ZIP_DEBUG */
03605 
03606     memcpy(page + offset,
03607            ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
03608     memcpy(page_zip->data + z_offset,
03609            ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
03610 
03611 #ifdef UNIV_ZIP_DEBUG
03612     ut_a(page_zip_validate(page_zip, page));
03613 #endif /* UNIV_ZIP_DEBUG */
03614   }
03615 
03616   return(ptr + (2 + 2 + BTR_EXTERN_FIELD_REF_SIZE));
03617 }
03618 
03619 /**********************************************************************/
03622 UNIV_INTERN
03623 void
03624 page_zip_write_blob_ptr(
03625 /*====================*/
03626   page_zip_des_t* page_zip,
03627   const byte* rec,  
03629   dict_index_t* index,  
03630   const ulint*  offsets,
03631   ulint   n,  
03632   mtr_t*    mtr)  
03634 {
03635   const byte* field;
03636   byte*   externs;
03637   const page_t* page  = page_align(rec);
03638   ulint   blob_no;
03639   ulint   len;
03640 
03641   ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
03642   ut_ad(page_simple_validate_new((page_t*) page));
03643   ut_ad(page_zip_simple_validate(page_zip));
03644   ut_ad(page_zip_get_size(page_zip)
03645         > PAGE_DATA + page_zip_dir_size(page_zip));
03646   ut_ad(rec_offs_comp(offsets));
03647   ut_ad(rec_offs_validate(rec, NULL, offsets));
03648   ut_ad(rec_offs_any_extern(offsets));
03649   ut_ad(rec_offs_nth_extern(offsets, n));
03650 
03651   ut_ad(page_zip->m_start >= PAGE_DATA);
03652   ut_ad(page_zip_header_cmp(page_zip, page));
03653 
03654   ut_ad(page_is_leaf(page));
03655   ut_ad(dict_index_is_clust(index));
03656 
03657   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03658   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
03659   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
03660          rec_offs_extra_size(offsets));
03661 
03662   blob_no = page_zip_get_n_prev_extern(page_zip, rec, index)
03663     + rec_get_n_extern_new(rec, index, n);
03664   ut_a(blob_no < page_zip->n_blobs);
03665 
03666   externs = page_zip->data + page_zip_get_size(page_zip)
03667     - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
03668     * (PAGE_ZIP_DIR_SLOT_SIZE
03669        + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03670 
03671   field = rec_get_nth_field(rec, offsets, n, &len);
03672 
03673   externs -= (blob_no + 1) * BTR_EXTERN_FIELD_REF_SIZE;
03674   field += len - BTR_EXTERN_FIELD_REF_SIZE;
03675 
03676   memcpy(externs, field, BTR_EXTERN_FIELD_REF_SIZE);
03677 
03678 #ifdef UNIV_ZIP_DEBUG
03679   ut_a(page_zip_validate(page_zip, page));
03680 #endif /* UNIV_ZIP_DEBUG */
03681 
03682   if (mtr) {
03683 #ifndef UNIV_HOTBACKUP
03684     byte* log_ptr = mlog_open(
03685       mtr, 11 + 2 + 2 + BTR_EXTERN_FIELD_REF_SIZE);
03686     if (UNIV_UNLIKELY(!log_ptr)) {
03687       return;
03688     }
03689 
03690     log_ptr = mlog_write_initial_log_record_fast(
03691       (byte*) field, MLOG_ZIP_WRITE_BLOB_PTR, log_ptr, mtr);
03692     mach_write_to_2(log_ptr, page_offset(field));
03693     log_ptr += 2;
03694     mach_write_to_2(log_ptr, externs - page_zip->data);
03695     log_ptr += 2;
03696     memcpy(log_ptr, externs, BTR_EXTERN_FIELD_REF_SIZE);
03697     log_ptr += BTR_EXTERN_FIELD_REF_SIZE;
03698     mlog_close(mtr, log_ptr);
03699 #endif /* !UNIV_HOTBACKUP */
03700   }
03701 }
03702 
03703 /***********************************************************/
03706 UNIV_INTERN
03707 byte*
03708 page_zip_parse_write_node_ptr(
03709 /*==========================*/
03710   byte*   ptr,  
03711   byte*   end_ptr,
03712   page_t*   page, 
03713   page_zip_des_t* page_zip)
03714 {
03715   ulint offset;
03716   ulint z_offset;
03717 
03718   ut_ad(!page == !page_zip);
03719 
03720   if (UNIV_UNLIKELY(end_ptr < ptr + (2 + 2 + REC_NODE_PTR_SIZE))) {
03721 
03722     return(NULL);
03723   }
03724 
03725   offset = mach_read_from_2(ptr);
03726   z_offset = mach_read_from_2(ptr + 2);
03727 
03728   if (UNIV_UNLIKELY(offset < PAGE_ZIP_START)
03729       || UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
03730       || UNIV_UNLIKELY(z_offset >= UNIV_PAGE_SIZE)) {
03731 corrupt:
03732     recv_sys->found_corrupt_log = TRUE;
03733 
03734     return(NULL);
03735   }
03736 
03737   if (page) {
03738     byte* storage_end;
03739     byte* field;
03740     byte* storage;
03741     ulint heap_no;
03742 
03743     if (UNIV_UNLIKELY(!page_zip)
03744         || UNIV_UNLIKELY(page_is_leaf(page))) {
03745 
03746       goto corrupt;
03747     }
03748 
03749 #ifdef UNIV_ZIP_DEBUG
03750     ut_a(page_zip_validate(page_zip, page));
03751 #endif /* UNIV_ZIP_DEBUG */
03752 
03753     field = page + offset;
03754     storage = page_zip->data + z_offset;
03755 
03756     storage_end = page_zip->data + page_zip_get_size(page_zip)
03757       - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
03758       * PAGE_ZIP_DIR_SLOT_SIZE;
03759 
03760     heap_no = 1 + (storage_end - storage) / REC_NODE_PTR_SIZE;
03761 
03762     if (UNIV_UNLIKELY((storage_end - storage) % REC_NODE_PTR_SIZE)
03763         || UNIV_UNLIKELY(heap_no < PAGE_HEAP_NO_USER_LOW)
03764         || UNIV_UNLIKELY(heap_no >= page_dir_get_n_heap(page))) {
03765 
03766       goto corrupt;
03767     }
03768 
03769     memcpy(field, ptr + 4, REC_NODE_PTR_SIZE);
03770     memcpy(storage, ptr + 4, REC_NODE_PTR_SIZE);
03771 
03772 #ifdef UNIV_ZIP_DEBUG
03773     ut_a(page_zip_validate(page_zip, page));
03774 #endif /* UNIV_ZIP_DEBUG */
03775   }
03776 
03777   return(ptr + (2 + 2 + REC_NODE_PTR_SIZE));
03778 }
03779 
03780 /**********************************************************************/
03782 UNIV_INTERN
03783 void
03784 page_zip_write_node_ptr(
03785 /*====================*/
03786   page_zip_des_t* page_zip,
03787   byte*   rec,  
03788   ulint   size, 
03789   ulint   ptr,  
03790   mtr_t*    mtr)  
03791 {
03792   byte* field;
03793   byte* storage;
03794   page_t* page  = page_align(rec);
03795 
03796   ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
03797   ut_ad(page_simple_validate_new(page));
03798   ut_ad(page_zip_simple_validate(page_zip));
03799   ut_ad(page_zip_get_size(page_zip)
03800         > PAGE_DATA + page_zip_dir_size(page_zip));
03801   ut_ad(page_rec_is_comp(rec));
03802 
03803   ut_ad(page_zip->m_start >= PAGE_DATA);
03804   ut_ad(page_zip_header_cmp(page_zip, page));
03805 
03806   ut_ad(!page_is_leaf(page));
03807 
03808   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03809   UNIV_MEM_ASSERT_RW(rec, size);
03810 
03811   storage = page_zip->data + page_zip_get_size(page_zip)
03812     - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
03813     * PAGE_ZIP_DIR_SLOT_SIZE
03814     - (rec_get_heap_no_new(rec) - 1) * REC_NODE_PTR_SIZE;
03815   field = rec + size - REC_NODE_PTR_SIZE;
03816 
03817 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
03818   ut_a(!memcmp(storage, field, REC_NODE_PTR_SIZE));
03819 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
03820 #if REC_NODE_PTR_SIZE != 4
03821 # error "REC_NODE_PTR_SIZE != 4"
03822 #endif
03823   mach_write_to_4(field, ptr);
03824   memcpy(storage, field, REC_NODE_PTR_SIZE);
03825 
03826   if (mtr) {
03827 #ifndef UNIV_HOTBACKUP
03828     byte* log_ptr = mlog_open(mtr,
03829               11 + 2 + 2 + REC_NODE_PTR_SIZE);
03830     if (UNIV_UNLIKELY(!log_ptr)) {
03831       return;
03832     }
03833 
03834     log_ptr = mlog_write_initial_log_record_fast(
03835       field, MLOG_ZIP_WRITE_NODE_PTR, log_ptr, mtr);
03836     mach_write_to_2(log_ptr, page_offset(field));
03837     log_ptr += 2;
03838     mach_write_to_2(log_ptr, storage - page_zip->data);
03839     log_ptr += 2;
03840     memcpy(log_ptr, field, REC_NODE_PTR_SIZE);
03841     log_ptr += REC_NODE_PTR_SIZE;
03842     mlog_close(mtr, log_ptr);
03843 #endif /* !UNIV_HOTBACKUP */
03844   }
03845 }
03846 
03847 /**********************************************************************/
03849 UNIV_INTERN
03850 void
03851 page_zip_write_trx_id_and_roll_ptr(
03852 /*===============================*/
03853   page_zip_des_t* page_zip,
03854   byte*   rec,  
03855   const ulint*  offsets,
03856   ulint   trx_id_col,
03857   trx_id_t  trx_id, 
03858   roll_ptr_t  roll_ptr)
03859 {
03860   byte* field;
03861   byte* storage;
03862   page_t* page  = page_align(rec);
03863   ulint len;
03864 
03865   ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
03866   ut_ad(page_simple_validate_new(page));
03867   ut_ad(page_zip_simple_validate(page_zip));
03868   ut_ad(page_zip_get_size(page_zip)
03869         > PAGE_DATA + page_zip_dir_size(page_zip));
03870   ut_ad(rec_offs_validate(rec, NULL, offsets));
03871   ut_ad(rec_offs_comp(offsets));
03872 
03873   ut_ad(page_zip->m_start >= PAGE_DATA);
03874   ut_ad(page_zip_header_cmp(page_zip, page));
03875 
03876   ut_ad(page_is_leaf(page));
03877 
03878   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03879 
03880   storage = page_zip->data + page_zip_get_size(page_zip)
03881     - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
03882     * PAGE_ZIP_DIR_SLOT_SIZE
03883     - (rec_get_heap_no_new(rec) - 1)
03884     * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03885 
03886 #if DATA_TRX_ID + 1 != DATA_ROLL_PTR
03887 # error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
03888 #endif
03889   field = rec_get_nth_field(rec, offsets, trx_id_col, &len);
03890   ut_ad(len == DATA_TRX_ID_LEN);
03891   ut_ad(field + DATA_TRX_ID_LEN
03892         == rec_get_nth_field(rec, offsets, trx_id_col + 1, &len));
03893   ut_ad(len == DATA_ROLL_PTR_LEN);
03894 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
03895   ut_a(!memcmp(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN));
03896 #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
03897 #if DATA_TRX_ID_LEN != 6
03898 # error "DATA_TRX_ID_LEN != 6"
03899 #endif
03900   mach_write_to_6(field, trx_id);
03901 #if DATA_ROLL_PTR_LEN != 7
03902 # error "DATA_ROLL_PTR_LEN != 7"
03903 #endif
03904   mach_write_to_7(field + DATA_TRX_ID_LEN, roll_ptr);
03905   memcpy(storage, field, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03906 
03907   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
03908   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
03909          rec_offs_extra_size(offsets));
03910   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03911 }
03912 
03913 #ifdef UNIV_ZIP_DEBUG
03914 
03919 UNIV_INTERN ibool page_zip_clear_rec_disable;
03920 #endif /* UNIV_ZIP_DEBUG */
03921 
03922 /**********************************************************************/
03924 static
03925 void
03926 page_zip_clear_rec(
03927 /*===============*/
03928   page_zip_des_t* page_zip,
03929   byte*   rec,  
03930   dict_index_t* index,  
03931   const ulint*  offsets)
03932 {
03933   ulint heap_no;
03934   page_t* page  = page_align(rec);
03935   /* page_zip_validate() would fail here if a record
03936   containing externally stored columns is being deleted. */
03937   ut_ad(rec_offs_validate(rec, index, offsets));
03938   ut_ad(!page_zip_dir_find(page_zip, page_offset(rec)));
03939   ut_ad(page_zip_dir_find_free(page_zip, page_offset(rec)));
03940   ut_ad(page_zip_header_cmp(page_zip, page));
03941 
03942   heap_no = rec_get_heap_no_new(rec);
03943   ut_ad(heap_no >= PAGE_HEAP_NO_USER_LOW);
03944 
03945   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
03946   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
03947   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
03948          rec_offs_extra_size(offsets));
03949 
03950   if (
03951 #ifdef UNIV_ZIP_DEBUG
03952       !page_zip_clear_rec_disable &&
03953 #endif /* UNIV_ZIP_DEBUG */
03954       page_zip->m_end
03955       + 1 + ((heap_no - 1) >= 64)/* size of the log entry */
03956       + page_zip_get_trailer_len(page_zip,
03957                dict_index_is_clust(index), NULL)
03958       < page_zip_get_size(page_zip)) {
03959     byte* data;
03960 
03961     /* Clear only the data bytes, because the allocator and
03962     the decompressor depend on the extra bytes. */
03963     memset(rec, 0, rec_offs_data_size(offsets));
03964 
03965     if (!page_is_leaf(page)) {
03966       /* Clear node_ptr on the compressed page. */
03967       byte* storage = page_zip->data
03968         + page_zip_get_size(page_zip)
03969         - (page_dir_get_n_heap(page)
03970            - PAGE_HEAP_NO_USER_LOW)
03971         * PAGE_ZIP_DIR_SLOT_SIZE;
03972 
03973       memset(storage - (heap_no - 1) * REC_NODE_PTR_SIZE,
03974              0, REC_NODE_PTR_SIZE);
03975     } else if (dict_index_is_clust(index)) {
03976       /* Clear trx_id and roll_ptr on the compressed page. */
03977       byte* storage = page_zip->data
03978         + page_zip_get_size(page_zip)
03979         - (page_dir_get_n_heap(page)
03980            - PAGE_HEAP_NO_USER_LOW)
03981         * PAGE_ZIP_DIR_SLOT_SIZE;
03982 
03983       memset(storage - (heap_no - 1)
03984              * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
03985              0, DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
03986     }
03987 
03988     /* Log that the data was zeroed out. */
03989     data = page_zip->data + page_zip->m_end;
03990     ut_ad(!*data);
03991     if (UNIV_UNLIKELY(heap_no - 1 >= 64)) {
03992       *data++ = (byte) (0x80 | (heap_no - 1) >> 7);
03993       ut_ad(!*data);
03994     }
03995     *data++ = (byte) ((heap_no - 1) << 1 | 1);
03996     ut_ad(!*data);
03997     ut_ad((ulint) (data - page_zip->data)
03998           < page_zip_get_size(page_zip));
03999     page_zip->m_end = data - page_zip->data;
04000     page_zip->m_nonempty = TRUE;
04001   } else if (page_is_leaf(page) && dict_index_is_clust(index)) {
04002     /* Do not clear the record, because there is not enough space
04003     to log the operation. */
04004 
04005     if (rec_offs_any_extern(offsets)) {
04006       ulint i;
04007 
04008       for (i = rec_offs_n_fields(offsets); i--; ) {
04009         /* Clear all BLOB pointers in order to make
04010         page_zip_validate() pass. */
04011         if (rec_offs_nth_extern(offsets, i)) {
04012           ulint len;
04013           byte* field = rec_get_nth_field(
04014             rec, offsets, i, &len);
04015           memset(field + len
04016                  - BTR_EXTERN_FIELD_REF_SIZE,
04017                  0, BTR_EXTERN_FIELD_REF_SIZE);
04018         }
04019       }
04020     }
04021   }
04022 
04023 #ifdef UNIV_ZIP_DEBUG
04024   ut_a(page_zip_validate(page_zip, page));
04025 #endif /* UNIV_ZIP_DEBUG */
04026 }
04027 
04028 /**********************************************************************/
04031 UNIV_INTERN
04032 void
04033 page_zip_rec_set_deleted(
04034 /*=====================*/
04035   page_zip_des_t* page_zip,
04036   const byte* rec,  
04037   ulint   flag) 
04038 {
04039   byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
04040   ut_a(slot);
04041   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04042   if (flag) {
04043     *slot |= (PAGE_ZIP_DIR_SLOT_DEL >> 8);
04044   } else {
04045     *slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
04046   }
04047 #ifdef UNIV_ZIP_DEBUG
04048   ut_a(page_zip_validate(page_zip, page_align(rec)));
04049 #endif /* UNIV_ZIP_DEBUG */
04050 }
04051 
04052 /**********************************************************************/
04055 UNIV_INTERN
04056 void
04057 page_zip_rec_set_owned(
04058 /*===================*/
04059   page_zip_des_t* page_zip,
04060   const byte* rec,  
04061   ulint   flag) 
04062 {
04063   byte* slot = page_zip_dir_find(page_zip, page_offset(rec));
04064   ut_a(slot);
04065   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04066   if (flag) {
04067     *slot |= (PAGE_ZIP_DIR_SLOT_OWNED >> 8);
04068   } else {
04069     *slot &= ~(PAGE_ZIP_DIR_SLOT_OWNED >> 8);
04070   }
04071 }
04072 
04073 /**********************************************************************/
04075 UNIV_INTERN
04076 void
04077 page_zip_dir_insert(
04078 /*================*/
04079   page_zip_des_t* page_zip,
04080   const byte* prev_rec,
04081   const byte* free_rec,
04083   byte*   rec)  
04084 {
04085   ulint n_dense;
04086   byte* slot_rec;
04087   byte* slot_free;
04088 
04089   ut_ad(prev_rec != rec);
04090   ut_ad(page_rec_get_next((rec_t*) prev_rec) == rec);
04091   ut_ad(page_zip_simple_validate(page_zip));
04092 
04093   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04094 
04095   if (page_rec_is_infimum(prev_rec)) {
04096     /* Use the first slot. */
04097     slot_rec = page_zip->data + page_zip_get_size(page_zip);
04098   } else {
04099     byte* end = page_zip->data + page_zip_get_size(page_zip);
04100     byte* start = end - page_zip_dir_user_size(page_zip);
04101 
04102     if (UNIV_LIKELY(!free_rec)) {
04103       /* PAGE_N_RECS was already incremented
04104       in page_cur_insert_rec_zip(), but the
04105       dense directory slot at that position
04106       contains garbage.  Skip it. */
04107       start += PAGE_ZIP_DIR_SLOT_SIZE;
04108     }
04109 
04110     slot_rec = page_zip_dir_find_low(start, end,
04111              page_offset(prev_rec));
04112     ut_a(slot_rec);
04113   }
04114 
04115   /* Read the old n_dense (n_heap may have been incremented). */
04116   n_dense = page_dir_get_n_heap(page_zip->data)
04117     - (PAGE_HEAP_NO_USER_LOW + 1);
04118 
04119   if (UNIV_LIKELY_NULL(free_rec)) {
04120     /* The record was allocated from the free list.
04121     Shift the dense directory only up to that slot.
04122     Note that in this case, n_dense is actually
04123     off by one, because page_cur_insert_rec_zip()
04124     did not increment n_heap. */
04125     ut_ad(rec_get_heap_no_new(rec) < n_dense + 1
04126           + PAGE_HEAP_NO_USER_LOW);
04127     ut_ad(rec >= free_rec);
04128     slot_free = page_zip_dir_find(page_zip, page_offset(free_rec));
04129     ut_ad(slot_free);
04130     slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
04131   } else {
04132     /* The record was allocated from the heap.
04133     Shift the entire dense directory. */
04134     ut_ad(rec_get_heap_no_new(rec) == n_dense
04135           + PAGE_HEAP_NO_USER_LOW);
04136 
04137     /* Shift to the end of the dense page directory. */
04138     slot_free = page_zip->data + page_zip_get_size(page_zip)
04139       - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
04140   }
04141 
04142   /* Shift the dense directory to allocate place for rec. */
04143   memmove(slot_free - PAGE_ZIP_DIR_SLOT_SIZE, slot_free,
04144     slot_rec - slot_free);
04145 
04146   /* Write the entry for the inserted record.
04147   The "owned" and "deleted" flags must be zero. */
04148   mach_write_to_2(slot_rec - PAGE_ZIP_DIR_SLOT_SIZE, page_offset(rec));
04149 }
04150 
04151 /**********************************************************************/
04154 UNIV_INTERN
04155 void
04156 page_zip_dir_delete(
04157 /*================*/
04158   page_zip_des_t* page_zip,
04159   byte*   rec,  
04160   dict_index_t* index,  
04161   const ulint*  offsets,
04162   const byte* free) 
04163 {
04164   byte* slot_rec;
04165   byte* slot_free;
04166   ulint n_ext;
04167   page_t* page  = page_align(rec);
04168 
04169   ut_ad(rec_offs_validate(rec, index, offsets));
04170   ut_ad(rec_offs_comp(offsets));
04171 
04172   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04173   UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
04174   UNIV_MEM_ASSERT_RW(rec - rec_offs_extra_size(offsets),
04175          rec_offs_extra_size(offsets));
04176 
04177   slot_rec = page_zip_dir_find(page_zip, page_offset(rec));
04178 
04179   ut_a(slot_rec);
04180 
04181   /* This could not be done before page_zip_dir_find(). */
04182   page_header_set_field(page, page_zip, PAGE_N_RECS,
04183             (ulint)(page_get_n_recs(page) - 1));
04184 
04185   if (UNIV_UNLIKELY(!free)) {
04186     /* Make the last slot the start of the free list. */
04187     slot_free = page_zip->data + page_zip_get_size(page_zip)
04188       - PAGE_ZIP_DIR_SLOT_SIZE
04189       * (page_dir_get_n_heap(page_zip->data)
04190          - PAGE_HEAP_NO_USER_LOW);
04191   } else {
04192     slot_free = page_zip_dir_find_free(page_zip,
04193                page_offset(free));
04194     ut_a(slot_free < slot_rec);
04195     /* Grow the free list by one slot by moving the start. */
04196     slot_free += PAGE_ZIP_DIR_SLOT_SIZE;
04197   }
04198 
04199   if (UNIV_LIKELY(slot_rec > slot_free)) {
04200     memmove(slot_free + PAGE_ZIP_DIR_SLOT_SIZE,
04201       slot_free,
04202       slot_rec - slot_free);
04203   }
04204 
04205   /* Write the entry for the deleted record.
04206   The "owned" and "deleted" flags will be cleared. */
04207   mach_write_to_2(slot_free, page_offset(rec));
04208 
04209   if (!page_is_leaf(page) || !dict_index_is_clust(index)) {
04210     ut_ad(!rec_offs_any_extern(offsets));
04211     goto skip_blobs;
04212   }
04213 
04214   n_ext = rec_offs_n_extern(offsets);
04215   if (UNIV_UNLIKELY(n_ext)) {
04216     /* Shift and zero fill the array of BLOB pointers. */
04217     ulint blob_no;
04218     byte* externs;
04219     byte* ext_end;
04220 
04221     blob_no = page_zip_get_n_prev_extern(page_zip, rec, index);
04222     ut_a(blob_no + n_ext <= page_zip->n_blobs);
04223 
04224     externs = page_zip->data + page_zip_get_size(page_zip)
04225       - (page_dir_get_n_heap(page) - PAGE_HEAP_NO_USER_LOW)
04226       * (PAGE_ZIP_DIR_SLOT_SIZE
04227          + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
04228 
04229     ext_end = externs - page_zip->n_blobs
04230       * BTR_EXTERN_FIELD_REF_SIZE;
04231     externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
04232 
04233     page_zip->n_blobs -= n_ext;
04234     /* Shift and zero fill the array. */
04235     memmove(ext_end + n_ext * BTR_EXTERN_FIELD_REF_SIZE, ext_end,
04236       (page_zip->n_blobs - blob_no)
04237       * BTR_EXTERN_FIELD_REF_SIZE);
04238     memset(ext_end, 0, n_ext * BTR_EXTERN_FIELD_REF_SIZE);
04239   }
04240 
04241 skip_blobs:
04242   /* The compression algorithm expects info_bits and n_owned
04243   to be 0 for deleted records. */
04244   rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
04245 
04246   page_zip_clear_rec(page_zip, rec, index, offsets);
04247 }
04248 
04249 /**********************************************************************/
04251 UNIV_INTERN
04252 void
04253 page_zip_dir_add_slot(
04254 /*==================*/
04255   page_zip_des_t* page_zip, 
04256   ulint   is_clustered) 
04258 {
04259   ulint n_dense;
04260   byte* dir;
04261   byte* stored;
04262 
04263   ut_ad(page_is_comp(page_zip->data));
04264   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04265 
04266   /* Read the old n_dense (n_heap has already been incremented). */
04267   n_dense = page_dir_get_n_heap(page_zip->data)
04268     - (PAGE_HEAP_NO_USER_LOW + 1);
04269 
04270   dir = page_zip->data + page_zip_get_size(page_zip)
04271     - PAGE_ZIP_DIR_SLOT_SIZE * n_dense;
04272 
04273   if (!page_is_leaf(page_zip->data)) {
04274     ut_ad(!page_zip->n_blobs);
04275     stored = dir - n_dense * REC_NODE_PTR_SIZE;
04276   } else if (UNIV_UNLIKELY(is_clustered)) {
04277     /* Move the BLOB pointer array backwards to make space for the
04278     roll_ptr and trx_id columns and the dense directory slot. */
04279     byte* externs;
04280 
04281     stored = dir - n_dense
04282       * (DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
04283     externs = stored
04284       - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
04285     ASSERT_ZERO(externs
04286           - (PAGE_ZIP_DIR_SLOT_SIZE
04287              + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
04288           PAGE_ZIP_DIR_SLOT_SIZE
04289           + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
04290     memmove(externs - (PAGE_ZIP_DIR_SLOT_SIZE
04291            + DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN),
04292       externs, stored - externs);
04293   } else {
04294     stored = dir
04295       - page_zip->n_blobs * BTR_EXTERN_FIELD_REF_SIZE;
04296     ASSERT_ZERO(stored - PAGE_ZIP_DIR_SLOT_SIZE,
04297           PAGE_ZIP_DIR_SLOT_SIZE);
04298   }
04299 
04300   /* Move the uncompressed area backwards to make space
04301   for one directory slot. */
04302   memmove(stored - PAGE_ZIP_DIR_SLOT_SIZE, stored, dir - stored);
04303 }
04304 
04305 /***********************************************************/
04308 UNIV_INTERN
04309 byte*
04310 page_zip_parse_write_header(
04311 /*========================*/
04312   byte*   ptr,  
04313   byte*   end_ptr,
04314   page_t*   page, 
04315   page_zip_des_t* page_zip)
04316 {
04317   ulint offset;
04318   ulint len;
04319 
04320   ut_ad(ptr && end_ptr);
04321   ut_ad(!page == !page_zip);
04322 
04323   if (UNIV_UNLIKELY(end_ptr < ptr + (1 + 1))) {
04324 
04325     return(NULL);
04326   }
04327 
04328   offset = (ulint) *ptr++;
04329   len = (ulint) *ptr++;
04330 
04331   if (UNIV_UNLIKELY(!len) || UNIV_UNLIKELY(offset + len >= PAGE_DATA)) {
04332 corrupt:
04333     recv_sys->found_corrupt_log = TRUE;
04334 
04335     return(NULL);
04336   }
04337 
04338   if (UNIV_UNLIKELY(end_ptr < ptr + len)) {
04339 
04340     return(NULL);
04341   }
04342 
04343   if (page) {
04344     if (UNIV_UNLIKELY(!page_zip)) {
04345 
04346       goto corrupt;
04347     }
04348 #ifdef UNIV_ZIP_DEBUG
04349     ut_a(page_zip_validate(page_zip, page));
04350 #endif /* UNIV_ZIP_DEBUG */
04351 
04352     memcpy(page + offset, ptr, len);
04353     memcpy(page_zip->data + offset, ptr, len);
04354 
04355 #ifdef UNIV_ZIP_DEBUG
04356     ut_a(page_zip_validate(page_zip, page));
04357 #endif /* UNIV_ZIP_DEBUG */
04358   }
04359 
04360   return(ptr + len);
04361 }
04362 
04363 #ifndef UNIV_HOTBACKUP
04364 /**********************************************************************/
04366 UNIV_INTERN
04367 void
04368 page_zip_write_header_log(
04369 /*======================*/
04370   const byte* data, 
04371   ulint   length, 
04372   mtr_t*    mtr)  
04373 {
04374   byte* log_ptr = mlog_open(mtr, 11 + 1 + 1);
04375   ulint offset  = page_offset(data);
04376 
04377   ut_ad(offset < PAGE_DATA);
04378   ut_ad(offset + length < PAGE_DATA);
04379 #if PAGE_DATA > 255
04380 # error "PAGE_DATA > 255"
04381 #endif
04382   ut_ad(length < 256);
04383 
04384   /* If no logging is requested, we may return now */
04385   if (UNIV_UNLIKELY(!log_ptr)) {
04386 
04387     return;
04388   }
04389 
04390   log_ptr = mlog_write_initial_log_record_fast(
04391     (byte*) data, MLOG_ZIP_WRITE_HEADER, log_ptr, mtr);
04392   *log_ptr++ = (byte) offset;
04393   *log_ptr++ = (byte) length;
04394   mlog_close(mtr, log_ptr);
04395 
04396   mlog_catenate_string(mtr, data, length);
04397 }
04398 #endif /* !UNIV_HOTBACKUP */
04399 
04400 /**********************************************************************/
04411 UNIV_INTERN
04412 ibool
04413 page_zip_reorganize(
04414 /*================*/
04415   buf_block_t*  block,  
04419   dict_index_t* index,  
04420   mtr_t*    mtr)  
04421 {
04422   buf_pool_t* buf_pool  = buf_pool_from_block(block);
04423   page_zip_des_t* page_zip  = buf_block_get_page_zip(block);
04424   page_t*   page    = buf_block_get_frame(block);
04425   buf_block_t*  temp_block;
04426   page_t*   temp_page;
04427   ulint   log_mode;
04428 
04429   ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
04430   ut_ad(page_is_comp(page));
04431   ut_ad(!dict_index_is_ibuf(index));
04432   /* Note that page_zip_validate(page_zip, page) may fail here. */
04433   UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
04434   UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
04435 
04436   /* Disable logging */
04437   log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
04438 
04439 #ifndef UNIV_HOTBACKUP
04440   temp_block = buf_block_alloc(buf_pool, 0);
04441   btr_search_drop_page_hash_index(block);
04442   block->check_index_page_at_flush = TRUE;
04443 #else /* !UNIV_HOTBACKUP */
04444   ut_ad(block == back_block1);
04445   temp_block = back_block2;
04446 #endif /* !UNIV_HOTBACKUP */
04447   temp_page = temp_block->frame;
04448 
04449   /* Copy the old page to temporary space */
04450   buf_frame_copy(temp_page, page);
04451 
04452   /* Recreate the page: note that global data on page (possible
04453   segment headers, next page-field, etc.) is preserved intact */
04454 
04455   page_create(block, mtr, TRUE);
04456 
04457   /* Copy the records from the temporary space to the recreated page;
04458   do not copy the lock bits yet */
04459 
04460   page_copy_rec_list_end_no_locks(block, temp_block,
04461           page_get_infimum_rec(temp_page),
04462           index, mtr);
04463 
04464   if (!dict_index_is_clust(index) && page_is_leaf(temp_page)) {
04465     /* Copy max trx id to recreated page */
04466     trx_id_t  max_trx_id = page_get_max_trx_id(temp_page);
04467     page_set_max_trx_id(block, NULL, max_trx_id, NULL);
04468     ut_ad(max_trx_id != 0);
04469   }
04470 
04471   /* Restore logging. */
04472   mtr_set_log_mode(mtr, log_mode);
04473 
04474   if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
04475 
04476 #ifndef UNIV_HOTBACKUP
04477     buf_block_free(temp_block);
04478 #endif /* !UNIV_HOTBACKUP */
04479     return(FALSE);
04480   }
04481 
04482   lock_move_reorganize_page(block, temp_block);
04483 
04484 #ifndef UNIV_HOTBACKUP
04485   buf_block_free(temp_block);
04486 #endif /* !UNIV_HOTBACKUP */
04487   return(TRUE);
04488 }
04489 
04490 #ifndef UNIV_HOTBACKUP
04491 /**********************************************************************/
04496 UNIV_INTERN
04497 void
04498 page_zip_copy_recs(
04499 /*===============*/
04500   page_zip_des_t*   page_zip, 
04503   page_t*     page,   
04504   const page_zip_des_t* src_zip,  
04505   const page_t*   src,    
04506   dict_index_t*   index,    
04507   mtr_t*      mtr)    
04508 {
04509   ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
04510   ut_ad(mtr_memo_contains_page(mtr, (page_t*) src, MTR_MEMO_PAGE_X_FIX));
04511   ut_ad(!dict_index_is_ibuf(index));
04512 #ifdef UNIV_ZIP_DEBUG
04513   /* The B-tree operations that call this function may set
04514   FIL_PAGE_PREV or PAGE_LEVEL, causing a temporary min_rec_flag
04515   mismatch.  A strict page_zip_validate() will be executed later
04516   during the B-tree operations. */
04517   ut_a(page_zip_validate_low(src_zip, src, TRUE));
04518 #endif /* UNIV_ZIP_DEBUG */
04519   ut_a(page_zip_get_size(page_zip) == page_zip_get_size(src_zip));
04520   if (UNIV_UNLIKELY(src_zip->n_blobs)) {
04521     ut_a(page_is_leaf(src));
04522     ut_a(dict_index_is_clust(index));
04523   }
04524 
04525   /* The PAGE_MAX_TRX_ID must be set on leaf pages of secondary
04526   indexes.  It does not matter on other pages. */
04527   ut_a(dict_index_is_clust(index) || !page_is_leaf(src)
04528        || page_get_max_trx_id(src));
04529 
04530   UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE);
04531   UNIV_MEM_ASSERT_W(page_zip->data, page_zip_get_size(page_zip));
04532   UNIV_MEM_ASSERT_RW(src, UNIV_PAGE_SIZE);
04533   UNIV_MEM_ASSERT_RW(src_zip->data, page_zip_get_size(page_zip));
04534 
04535   /* Copy those B-tree page header fields that are related to
04536   the records stored in the page.  Also copy the field
04537   PAGE_MAX_TRX_ID.  Skip the rest of the page header and
04538   trailer.  On the compressed page, there is no trailer. */
04539 #if PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END
04540 # error "PAGE_MAX_TRX_ID + 8 != PAGE_HEADER_PRIV_END"
04541 #endif
04542   memcpy(PAGE_HEADER + page, PAGE_HEADER + src,
04543          PAGE_HEADER_PRIV_END);
04544   memcpy(PAGE_DATA + page, PAGE_DATA + src,
04545          UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END);
04546   memcpy(PAGE_HEADER + page_zip->data, PAGE_HEADER + src_zip->data,
04547          PAGE_HEADER_PRIV_END);
04548   memcpy(PAGE_DATA + page_zip->data, PAGE_DATA + src_zip->data,
04549          page_zip_get_size(page_zip) - PAGE_DATA);
04550 
04551   /* Copy all fields of src_zip to page_zip, except the pointer
04552   to the compressed data page. */
04553   {
04554     page_zip_t* data = page_zip->data;
04555     memcpy(page_zip, src_zip, sizeof *page_zip);
04556     page_zip->data = data;
04557   }
04558   ut_ad(page_zip_get_trailer_len(page_zip,
04559                dict_index_is_clust(index), NULL)
04560         + page_zip->m_end < page_zip_get_size(page_zip));
04561 
04562   if (!page_is_leaf(src)
04563       && UNIV_UNLIKELY(mach_read_from_4(src + FIL_PAGE_PREV) == FIL_NULL)
04564       && UNIV_LIKELY(mach_read_from_4(page
04565               + FIL_PAGE_PREV) != FIL_NULL)) {
04566     /* Clear the REC_INFO_MIN_REC_FLAG of the first user record. */
04567     ulint offs = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
04568              TRUE);
04569     if (UNIV_LIKELY(offs != PAGE_NEW_SUPREMUM)) {
04570       rec_t*  rec = page + offs;
04571       ut_a(rec[-REC_N_NEW_EXTRA_BYTES]
04572            & REC_INFO_MIN_REC_FLAG);
04573       rec[-REC_N_NEW_EXTRA_BYTES] &= ~ REC_INFO_MIN_REC_FLAG;
04574     }
04575   }
04576 
04577 #ifdef UNIV_ZIP_DEBUG
04578   ut_a(page_zip_validate(page_zip, page));
04579 #endif /* UNIV_ZIP_DEBUG */
04580 
04581   page_zip_compress_write_log(page_zip, page, index, mtr);
04582 }
04583 #endif /* !UNIV_HOTBACKUP */
04584 
04585 /**********************************************************************/
04588 UNIV_INTERN
04589 byte*
04590 page_zip_parse_compress(
04591 /*====================*/
04592   byte*   ptr,  
04593   byte*   end_ptr,
04594   page_t*   page, 
04595   page_zip_des_t* page_zip)
04596 {
04597   ulint size;
04598   ulint trailer_size;
04599 
04600   ut_ad(ptr && end_ptr);
04601   ut_ad(!page == !page_zip);
04602 
04603   if (UNIV_UNLIKELY(ptr + (2 + 2) > end_ptr)) {
04604 
04605     return(NULL);
04606   }
04607 
04608   size = mach_read_from_2(ptr);
04609   ptr += 2;
04610   trailer_size = mach_read_from_2(ptr);
04611   ptr += 2;
04612 
04613   if (UNIV_UNLIKELY(ptr + 8 + size + trailer_size > end_ptr)) {
04614 
04615     return(NULL);
04616   }
04617 
04618   if (page) {
04619     if (UNIV_UNLIKELY(!page_zip)
04620         || UNIV_UNLIKELY(page_zip_get_size(page_zip) < size)) {
04621 corrupt:
04622       recv_sys->found_corrupt_log = TRUE;
04623 
04624       return(NULL);
04625     }
04626 
04627     memcpy(page_zip->data + FIL_PAGE_PREV, ptr, 4);
04628     memcpy(page_zip->data + FIL_PAGE_NEXT, ptr + 4, 4);
04629     memcpy(page_zip->data + FIL_PAGE_TYPE, ptr + 8, size);
04630     memset(page_zip->data + FIL_PAGE_TYPE + size, 0,
04631            page_zip_get_size(page_zip) - trailer_size
04632            - (FIL_PAGE_TYPE + size));
04633     memcpy(page_zip->data + page_zip_get_size(page_zip)
04634            - trailer_size, ptr + 8 + size, trailer_size);
04635 
04636     if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page,
04637                    TRUE))) {
04638 
04639       goto corrupt;
04640     }
04641   }
04642 
04643   return(ptr + 8 + size + trailer_size);
04644 }
04645 
04646 /**********************************************************************/
04649 UNIV_INTERN
04650 ulint
04651 page_zip_calc_checksum(
04652 /*===================*/
04653   const void* data, 
04654   ulint   size) 
04655 {
04656   /* Exclude FIL_PAGE_SPACE_OR_CHKSUM, FIL_PAGE_LSN,
04657   and FIL_PAGE_FILE_FLUSH_LSN from the checksum. */
04658 
04659   const Bytef*  s = static_cast<const Bytef *>(data);
04660   uLong   adler;
04661 
04662   ut_ad(size > FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
04663 
04664   adler = adler32(0L, s + FIL_PAGE_OFFSET,
04665       FIL_PAGE_LSN - FIL_PAGE_OFFSET);
04666   adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
04667   adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
04668       size - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
04669 
04670   return((ulint) adler);
04671 }