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