Drizzled Public API Documentation

buf0buf.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
00004 Copyright (C) 2008, Google Inc.
00005 
00006 Portions of this file contain modifications contributed and copyrighted by
00007 Google, Inc. Those modifications are gratefully acknowledged and are described
00008 briefly in the InnoDB documentation. The contributions by Google are
00009 incorporated with their permission, and subject to the conditions contained in
00010 the file COPYING.Google.
00011 
00012 This program is free software; you can redistribute it and/or modify it under
00013 the terms of the GNU General Public License as published by the Free Software
00014 Foundation; version 2 of the License.
00015 
00016 This program is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License along with
00021 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00022 St, Fifth Floor, Boston, MA 02110-1301 USA
00023 
00024 *****************************************************************************/
00025 
00026 /**************************************************/
00033 #include "buf0buf.h"
00034 
00035 #ifdef UNIV_NONINL
00036 #include "buf0buf.ic"
00037 #endif
00038 
00039 #include "mem0mem.h"
00040 #include "btr0btr.h"
00041 #include "fil0fil.h"
00042 #ifndef UNIV_HOTBACKUP
00043 #include "buf0buddy.h"
00044 #include "lock0lock.h"
00045 #include "btr0sea.h"
00046 #include "ibuf0ibuf.h"
00047 #include "trx0undo.h"
00048 #include "log0log.h"
00049 #endif /* !UNIV_HOTBACKUP */
00050 #include "srv0srv.h"
00051 #include "dict0dict.h"
00052 #include "log0recv.h"
00053 #include "page0zip.h"
00054 
00055 #include <drizzled/errmsg_print.h>
00056 
00057 /*
00058     IMPLEMENTATION OF THE BUFFER POOL
00059     =================================
00060 
00061 Performance improvement:
00062 ------------------------
00063 Thread scheduling in NT may be so slow that the OS wait mechanism should
00064 not be used even in waiting for disk reads to complete.
00065 Rather, we should put waiting query threads to the queue of
00066 waiting jobs, and let the OS thread do something useful while the i/o
00067 is processed. In this way we could remove most OS thread switches in
00068 an i/o-intensive benchmark like TPC-C.
00069 
00070 A possibility is to put a user space thread library between the database
00071 and NT. User space thread libraries might be very fast.
00072 
00073 SQL Server 7.0 can be configured to use 'fibers' which are lightweight
00074 threads in NT. These should be studied.
00075 
00076     Buffer frames and blocks
00077     ------------------------
00078 Following the terminology of Gray and Reuter, we call the memory
00079 blocks where file pages are loaded buffer frames. For each buffer
00080 frame there is a control block, or shortly, a block, in the buffer
00081 control array. The control info which does not need to be stored
00082 in the file along with the file page, resides in the control block.
00083 
00084     Buffer pool struct
00085     ------------------
00086 The buffer buf_pool contains a single mutex which protects all the
00087 control data structures of the buf_pool. The content of a buffer frame is
00088 protected by a separate read-write lock in its control block, though.
00089 These locks can be locked and unlocked without owning the buf_pool->mutex.
00090 The OS events in the buf_pool struct can be waited for without owning the
00091 buf_pool->mutex.
00092 
00093 The buf_pool->mutex is a hot-spot in main memory, causing a lot of
00094 memory bus traffic on multiprocessor systems when processors
00095 alternately access the mutex. On our Pentium, the mutex is accessed
00096 maybe every 10 microseconds. We gave up the solution to have mutexes
00097 for each control block, for instance, because it seemed to be
00098 complicated.
00099 
00100 A solution to reduce mutex contention of the buf_pool->mutex is to
00101 create a separate mutex for the page hash table. On Pentium,
00102 accessing the hash table takes 2 microseconds, about half
00103 of the total buf_pool->mutex hold time.
00104 
00105     Control blocks
00106     --------------
00107 
00108 The control block contains, for instance, the bufferfix count
00109 which is incremented when a thread wants a file page to be fixed
00110 in a buffer frame. The bufferfix operation does not lock the
00111 contents of the frame, however. For this purpose, the control
00112 block contains a read-write lock.
00113 
00114 The buffer frames have to be aligned so that the start memory
00115 address of a frame is divisible by the universal page size, which
00116 is a power of two.
00117 
00118 We intend to make the buffer buf_pool size on-line reconfigurable,
00119 that is, the buf_pool size can be changed without closing the database.
00120 Then the database administarator may adjust it to be bigger
00121 at night, for example. The control block array must
00122 contain enough control blocks for the maximum buffer buf_pool size
00123 which is used in the particular database.
00124 If the buf_pool size is cut, we exploit the virtual memory mechanism of
00125 the OS, and just refrain from using frames at high addresses. Then the OS
00126 can swap them to disk.
00127 
00128 The control blocks containing file pages are put to a hash table
00129 according to the file address of the page.
00130 We could speed up the access to an individual page by using
00131 "pointer swizzling": we could replace the page references on
00132 non-leaf index pages by direct pointers to the page, if it exists
00133 in the buf_pool. We could make a separate hash table where we could
00134 chain all the page references in non-leaf pages residing in the buf_pool,
00135 using the page reference as the hash key,
00136 and at the time of reading of a page update the pointers accordingly.
00137 Drawbacks of this solution are added complexity and,
00138 possibly, extra space required on non-leaf pages for memory pointers.
00139 A simpler solution is just to speed up the hash table mechanism
00140 in the database, using tables whose size is a power of 2.
00141 
00142     Lists of blocks
00143     ---------------
00144 
00145 There are several lists of control blocks.
00146 
00147 The free list (buf_pool->free) contains blocks which are currently not
00148 used.
00149 
00150 The common LRU list contains all the blocks holding a file page
00151 except those for which the bufferfix count is non-zero.
00152 The pages are in the LRU list roughly in the order of the last
00153 access to the page, so that the oldest pages are at the end of the
00154 list. We also keep a pointer to near the end of the LRU list,
00155 which we can use when we want to artificially age a page in the
00156 buf_pool. This is used if we know that some page is not needed
00157 again for some time: we insert the block right after the pointer,
00158 causing it to be replaced sooner than would normally be the case.
00159 Currently this aging mechanism is used for read-ahead mechanism
00160 of pages, and it can also be used when there is a scan of a full
00161 table which cannot fit in the memory. Putting the pages near the
00162 end of the LRU list, we make sure that most of the buf_pool stays
00163 in the main memory, undisturbed.
00164 
00165 The unzip_LRU list contains a subset of the common LRU list.  The
00166 blocks on the unzip_LRU list hold a compressed file page and the
00167 corresponding uncompressed page frame.  A block is in unzip_LRU if and
00168 only if the predicate buf_page_belongs_to_unzip_LRU(&block->page)
00169 holds.  The blocks in unzip_LRU will be in same order as they are in
00170 the common LRU list.  That is, each manipulation of the common LRU
00171 list will result in the same manipulation of the unzip_LRU list.
00172 
00173 The chain of modified blocks (buf_pool->flush_list) contains the blocks
00174 holding file pages that have been modified in the memory
00175 but not written to disk yet. The block with the oldest modification
00176 which has not yet been written to disk is at the end of the chain.
00177 The access to this list is protected by buf_pool->flush_list_mutex.
00178 
00179 The chain of unmodified compressed blocks (buf_pool->zip_clean)
00180 contains the control blocks (buf_page_t) of those compressed pages
00181 that are not in buf_pool->flush_list and for which no uncompressed
00182 page has been allocated in the buffer pool.  The control blocks for
00183 uncompressed pages are accessible via buf_block_t objects that are
00184 reachable via buf_pool->chunks[].
00185 
00186 The chains of free memory blocks (buf_pool->zip_free[]) are used by
00187 the buddy allocator (buf0buddy.c) to keep track of currently unused
00188 memory blocks of size sizeof(buf_page_t)..UNIV_PAGE_SIZE / 2.  These
00189 blocks are inside the UNIV_PAGE_SIZE-sized memory blocks of type
00190 BUF_BLOCK_MEMORY that the buddy allocator requests from the buffer
00191 pool.  The buddy allocator is solely used for allocating control
00192 blocks for compressed pages (buf_page_t) and compressed page frames.
00193 
00194     Loading a file page
00195     -------------------
00196 
00197 First, a victim block for replacement has to be found in the
00198 buf_pool. It is taken from the free list or searched for from the
00199 end of the LRU-list. An exclusive lock is reserved for the frame,
00200 the io_fix field is set in the block fixing the block in buf_pool,
00201 and the io-operation for loading the page is queued. The io-handler thread
00202 releases the X-lock on the frame and resets the io_fix field
00203 when the io operation completes.
00204 
00205 A thread may request the above operation using the function
00206 buf_page_get(). It may then continue to request a lock on the frame.
00207 The lock is granted when the io-handler releases the x-lock.
00208 
00209     Read-ahead
00210     ----------
00211 
00212 The read-ahead mechanism is intended to be intelligent and
00213 isolated from the semantically higher levels of the database
00214 index management. From the higher level we only need the
00215 information if a file page has a natural successor or
00216 predecessor page. On the leaf level of a B-tree index,
00217 these are the next and previous pages in the natural
00218 order of the pages.
00219 
00220 Let us first explain the read-ahead mechanism when the leafs
00221 of a B-tree are scanned in an ascending or descending order.
00222 When a read page is the first time referenced in the buf_pool,
00223 the buffer manager checks if it is at the border of a so-called
00224 linear read-ahead area. The tablespace is divided into these
00225 areas of size 64 blocks, for example. So if the page is at the
00226 border of such an area, the read-ahead mechanism checks if
00227 all the other blocks in the area have been accessed in an
00228 ascending or descending order. If this is the case, the system
00229 looks at the natural successor or predecessor of the page,
00230 checks if that is at the border of another area, and in this case
00231 issues read-requests for all the pages in that area. Maybe
00232 we could relax the condition that all the pages in the area
00233 have to be accessed: if data is deleted from a table, there may
00234 appear holes of unused pages in the area.
00235 
00236 A different read-ahead mechanism is used when there appears
00237 to be a random access pattern to a file.
00238 If a new page is referenced in the buf_pool, and several pages
00239 of its random access area (for instance, 32 consecutive pages
00240 in a tablespace) have recently been referenced, we may predict
00241 that the whole area may be needed in the near future, and issue
00242 the read requests for the whole area.
00243 */
00244 
00245 #ifndef UNIV_HOTBACKUP
00246 
00247 static const int WAIT_FOR_READ  = 5000;
00249 static const ulint BUF_PAGE_READ_MAX_RETRIES = 100;
00250 
00252 UNIV_INTERN buf_pool_t* buf_pool_ptr;
00253 
00254 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
00255 static ulint  buf_dbg_counter = 0; 
00258 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
00259 #ifdef UNIV_DEBUG
00260 
00262 UNIV_INTERN ibool   buf_debug_prints = FALSE;
00263 #endif /* UNIV_DEBUG */
00264 
00265 #ifdef UNIV_PFS_RWLOCK
00266 /* Keys to register buffer block related rwlocks and mutexes with
00267 performance schema */
00268 UNIV_INTERN mysql_pfs_key_t buf_block_lock_key;
00269 # ifdef UNIV_SYNC_DEBUG
00270 UNIV_INTERN mysql_pfs_key_t buf_block_debug_latch_key;
00271 # endif /* UNIV_SYNC_DEBUG */
00272 #endif /* UNIV_PFS_RWLOCK */
00273 
00274 #ifdef UNIV_PFS_MUTEX
00275 UNIV_INTERN mysql_pfs_key_t buffer_block_mutex_key;
00276 UNIV_INTERN mysql_pfs_key_t buf_pool_mutex_key;
00277 UNIV_INTERN mysql_pfs_key_t buf_pool_zip_mutex_key;
00278 UNIV_INTERN mysql_pfs_key_t flush_list_mutex_key;
00279 #endif /* UNIV_PFS_MUTEX */
00280 
00281 #if defined UNIV_PFS_MUTEX || defined UNIV_PFS_RWLOCK
00282 # ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK
00283 
00284 /* Buffer block mutexes and rwlocks can be registered
00285 in one group rather than individually. If PFS_GROUP_BUFFER_SYNC
00286 is defined, register buffer block mutex and rwlock
00287 in one group after their initialization. */
00288 #  define PFS_GROUP_BUFFER_SYNC
00289 
00290 /* This define caps the number of mutexes/rwlocks can
00291 be registered with performance schema. Developers can
00292 modify this define if necessary. Please note, this would
00293 be effective only if PFS_GROUP_BUFFER_SYNC is defined. */
00294 #  define PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER  ULINT_MAX
00295 
00296 # endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */
00297 #endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */
00298 
00300 struct buf_chunk_struct{
00301   ulint   mem_size; 
00302   ulint   size;   
00303   void*   mem;    
00305   buf_block_t*  blocks;   
00306 };
00307 #endif /* !UNIV_HOTBACKUP */
00308 
00309 /********************************************************************/
00313 UNIV_INTERN
00314 ib_uint64_t
00315 buf_pool_get_oldest_modification(void)
00316 /*==================================*/
00317 {
00318   ulint   i;
00319   buf_page_t* bpage;
00320   ib_uint64_t lsn = 0;
00321   ib_uint64_t oldest_lsn = 0;
00322 
00323   /* When we traverse all the flush lists we don't want another
00324   thread to add a dirty page to any flush list. */
00325   if (srv_buf_pool_instances > 1)
00326     log_flush_order_mutex_enter();
00327 
00328   for (i = 0; i < srv_buf_pool_instances; i++) {
00329     buf_pool_t* buf_pool;
00330 
00331     buf_pool = buf_pool_from_array(i);
00332 
00333     buf_flush_list_mutex_enter(buf_pool);
00334 
00335     bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
00336 
00337     if (bpage != NULL) {
00338       ut_ad(bpage->in_flush_list);
00339       lsn = bpage->oldest_modification;
00340     }
00341 
00342     buf_flush_list_mutex_exit(buf_pool);
00343 
00344     if (!oldest_lsn || oldest_lsn > lsn) {
00345       oldest_lsn = lsn;
00346     }
00347   }
00348 
00349   log_flush_order_mutex_exit();
00350 
00351   /* The returned answer may be out of date: the flush_list can
00352   change after the mutex has been released. */
00353 
00354   return(oldest_lsn);
00355 }
00356 
00357 /********************************************************************/
00359 UNIV_INTERN
00360 void
00361 buf_get_total_list_len(
00362 /*===================*/
00363   ulint*    LRU_len,  
00364   ulint*    free_len, 
00365   ulint*    flush_list_len) 
00366 {
00367   ulint   i;
00368 
00369   *LRU_len = 0;
00370   *free_len = 0;
00371   *flush_list_len = 0;
00372 
00373   for (i = 0; i < srv_buf_pool_instances; i++) {
00374     buf_pool_t* buf_pool;
00375 
00376     buf_pool = buf_pool_from_array(i);
00377     *LRU_len += UT_LIST_GET_LEN(buf_pool->LRU);
00378     *free_len += UT_LIST_GET_LEN(buf_pool->free);
00379     *flush_list_len += UT_LIST_GET_LEN(buf_pool->flush_list);
00380   }
00381 }
00382 
00383 /********************************************************************/
00385 UNIV_INTERN
00386 void
00387 buf_get_total_stat(
00388 /*===============*/
00389   buf_pool_stat_t*  tot_stat) 
00390 {
00391   ulint     i;
00392 
00393   memset(tot_stat, 0, sizeof(*tot_stat));
00394 
00395   for (i = 0; i < srv_buf_pool_instances; i++) {
00396     buf_pool_stat_t*buf_stat;
00397     buf_pool_t* buf_pool;
00398 
00399     buf_pool = buf_pool_from_array(i);
00400 
00401     buf_stat = &buf_pool->stat;
00402     tot_stat->n_page_gets += buf_stat->n_page_gets;
00403     tot_stat->n_pages_read += buf_stat->n_pages_read;
00404     tot_stat->n_pages_written += buf_stat->n_pages_written;
00405     tot_stat->n_pages_created += buf_stat->n_pages_created;
00406     tot_stat->n_ra_pages_read += buf_stat->n_ra_pages_read;
00407     tot_stat->n_ra_pages_evicted += buf_stat->n_ra_pages_evicted;
00408     tot_stat->n_pages_made_young += buf_stat->n_pages_made_young;
00409 
00410     tot_stat->n_pages_not_made_young +=
00411       buf_stat->n_pages_not_made_young;
00412   }
00413 }
00414 
00415 /********************************************************************/
00418 UNIV_INTERN
00419 buf_block_t*
00420 buf_block_alloc(
00421 /*============*/
00422   buf_pool_t* buf_pool, 
00423   ulint   zip_size) 
00425 {
00426   buf_block_t*  block;
00427   ulint   index;
00428   static ulint  buf_pool_index;
00429 
00430   if (buf_pool == NULL) {
00431     /* We are allocating memory from any buffer pool, ensure
00432     we spread the grace on all buffer pool instances. */
00433     index = buf_pool_index++ % srv_buf_pool_instances;
00434     buf_pool = buf_pool_from_array(index);
00435   }
00436 
00437   block = buf_LRU_get_free_block(buf_pool, zip_size);
00438 
00439   buf_block_set_state(block, BUF_BLOCK_MEMORY);
00440 
00441   return(block);
00442 }
00443 
00444 /********************************************************************/
00449 UNIV_INTERN
00450 ulint
00451 buf_calc_page_new_checksum(
00452 /*=======================*/
00453   const byte* page) 
00454 {
00455   ulint checksum;
00456 
00457   /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
00458   ..._ARCH_LOG_NO, are written outside the buffer pool to the first
00459   pages of data files, we have to skip them in the page checksum
00460   calculation.
00461   We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
00462   checksum is stored, and also the last 8 bytes of page because
00463   there we store the old formula checksum. */
00464 
00465   checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
00466           FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
00467     + ut_fold_binary(page + FIL_PAGE_DATA,
00468          UNIV_PAGE_SIZE - FIL_PAGE_DATA
00469          - FIL_PAGE_END_LSN_OLD_CHKSUM);
00470   checksum = checksum & 0xFFFFFFFFUL;
00471 
00472   return(checksum);
00473 }
00474 
00475 /********************************************************************/
00483 UNIV_INTERN
00484 ulint
00485 buf_calc_page_old_checksum(
00486 /*=======================*/
00487   const byte* page) 
00488 {
00489   ulint checksum;
00490 
00491   checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
00492 
00493   checksum = checksum & 0xFFFFFFFFUL;
00494 
00495   return(checksum);
00496 }
00497 
00498 /********************************************************************/
00501 UNIV_INTERN
00502 ibool
00503 buf_page_is_corrupted(
00504 /*==================*/
00505   const byte* read_buf, 
00506   ulint   zip_size) 
00508 {
00509   ulint   checksum_field;
00510   ulint   old_checksum_field;
00511 
00512   if (UNIV_LIKELY(!zip_size)
00513       && memcmp(read_buf + FIL_PAGE_LSN + 4,
00514           read_buf + UNIV_PAGE_SIZE
00515           - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) {
00516 
00517     /* Stored log sequence numbers at the start and the end
00518     of page do not match */
00519 
00520     return(TRUE);
00521   }
00522 
00523 #ifndef UNIV_HOTBACKUP
00524   if (recv_lsn_checks_on) {
00525     ib_uint64_t current_lsn;
00526 
00527     if (log_peek_lsn(&current_lsn)
00528         && UNIV_UNLIKELY
00529         (current_lsn
00530          < mach_read_from_8(read_buf + FIL_PAGE_LSN))) {
00531       ut_print_timestamp(stderr);
00532 
00533                         drizzled::errmsg_printf(drizzled::error::INFO,
00534                                                 "InnoDB: Error: page %lu log sequence number %"PRIu64". "
00535                                                 "InnoDB: is in the future! Current system log sequence number %"PRIu64". "
00536                                                 "Your database may be corrupt or you may have copied the InnoDB tablespace but not the InnoDB log files. See "
00537                                                 " " REFMAN "forcing-recovery.html for more information. ",
00538                                                 (ulong) mach_read_from_4(read_buf
00539                                                                          + FIL_PAGE_OFFSET),
00540                                                 mach_read_from_8(read_buf + FIL_PAGE_LSN),
00541                                                 current_lsn);
00542     }
00543   }
00544 #endif
00545 
00546   /* If we use checksums validation, make additional check before
00547   returning TRUE to ensure that the checksum is not equal to
00548   BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
00549   disabled. Otherwise, skip checksum calculation and return FALSE */
00550 
00551   if (UNIV_LIKELY(srv_use_checksums)) {
00552     checksum_field = mach_read_from_4(read_buf
00553               + FIL_PAGE_SPACE_OR_CHKSUM);
00554 
00555     if (UNIV_UNLIKELY(zip_size)) {
00556       return(checksum_field != BUF_NO_CHECKSUM_MAGIC
00557              && checksum_field
00558              != page_zip_calc_checksum(read_buf, zip_size));
00559     }
00560 
00561     old_checksum_field = mach_read_from_4(
00562       read_buf + UNIV_PAGE_SIZE
00563       - FIL_PAGE_END_LSN_OLD_CHKSUM);
00564 
00565     /* There are 2 valid formulas for old_checksum_field:
00566 
00567     1. Very old versions of InnoDB only stored 8 byte lsn to the
00568     start and the end of the page.
00569 
00570     2. Newer InnoDB versions store the old formula checksum
00571     there. */
00572 
00573     if (old_checksum_field != mach_read_from_4(read_buf
00574                  + FIL_PAGE_LSN)
00575         && old_checksum_field != BUF_NO_CHECKSUM_MAGIC
00576         && old_checksum_field
00577         != buf_calc_page_old_checksum(read_buf)) {
00578 
00579       return(TRUE);
00580     }
00581 
00582     /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
00583     (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
00584 
00585     if (checksum_field != 0
00586         && checksum_field != BUF_NO_CHECKSUM_MAGIC
00587         && checksum_field
00588         != buf_calc_page_new_checksum(read_buf)) {
00589 
00590       return(TRUE);
00591     }
00592   }
00593 
00594   return(FALSE);
00595 }
00596 
00597 /********************************************************************/
00599 UNIV_INTERN
00600 void
00601 buf_page_print(
00602 /*===========*/
00603   const byte* read_buf, 
00604   ulint   zip_size) 
00606 {
00607 #ifndef UNIV_HOTBACKUP
00608   dict_index_t* index;
00609 #endif /* !UNIV_HOTBACKUP */
00610   ulint   checksum;
00611   ulint   old_checksum;
00612   ulint   size  = zip_size;
00613 
00614   if (!size) {
00615     size = UNIV_PAGE_SIZE;
00616   }
00617 
00618   ut_print_timestamp(stderr);
00619   fprintf(stderr, "  InnoDB: Page dump in ascii and hex (%lu bytes):\n",
00620     (ulong) size);
00621   ut_print_buf(stderr, read_buf, size);
00622   fputs("\nInnoDB: End of page dump\n", stderr);
00623 
00624   if (zip_size) {
00625     /* Print compressed page. */
00626 
00627     switch (fil_page_get_type(read_buf)) {
00628     case FIL_PAGE_TYPE_ZBLOB:
00629     case FIL_PAGE_TYPE_ZBLOB2:
00630       checksum = srv_use_checksums
00631         ? page_zip_calc_checksum(read_buf, zip_size)
00632         : BUF_NO_CHECKSUM_MAGIC;
00633       ut_print_timestamp(stderr);
00634       fprintf(stderr,
00635         "  InnoDB: Compressed BLOB page"
00636         " checksum %lu, stored %lu\n"
00637         "InnoDB: Page lsn %lu %lu\n"
00638         "InnoDB: Page number (if stored"
00639         " to page already) %lu,\n"
00640         "InnoDB: space id (if stored"
00641         " to page already) %lu\n",
00642         (ulong) checksum,
00643         (ulong) mach_read_from_4(
00644           read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
00645         (ulong) mach_read_from_4(
00646           read_buf + FIL_PAGE_LSN),
00647         (ulong) mach_read_from_4(
00648           read_buf + (FIL_PAGE_LSN + 4)),
00649         (ulong) mach_read_from_4(
00650           read_buf + FIL_PAGE_OFFSET),
00651         (ulong) mach_read_from_4(
00652           read_buf
00653           + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
00654       return;
00655     default:
00656       ut_print_timestamp(stderr);
00657       fprintf(stderr,
00658         "  InnoDB: unknown page type %lu,"
00659         " assuming FIL_PAGE_INDEX\n",
00660         fil_page_get_type(read_buf));
00661       /* fall through */
00662     case FIL_PAGE_INDEX:
00663       checksum = srv_use_checksums
00664         ? page_zip_calc_checksum(read_buf, zip_size)
00665         : BUF_NO_CHECKSUM_MAGIC;
00666 
00667       ut_print_timestamp(stderr);
00668       fprintf(stderr,
00669         "  InnoDB: Compressed page checksum %lu,"
00670         " stored %lu\n"
00671         "InnoDB: Page lsn %lu %lu\n"
00672         "InnoDB: Page number (if stored"
00673         " to page already) %lu,\n"
00674         "InnoDB: space id (if stored"
00675         " to page already) %lu\n",
00676         (ulong) checksum,
00677         (ulong) mach_read_from_4(
00678           read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
00679         (ulong) mach_read_from_4(
00680           read_buf + FIL_PAGE_LSN),
00681         (ulong) mach_read_from_4(
00682           read_buf + (FIL_PAGE_LSN + 4)),
00683         (ulong) mach_read_from_4(
00684           read_buf + FIL_PAGE_OFFSET),
00685         (ulong) mach_read_from_4(
00686           read_buf
00687           + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
00688       return;
00689     case FIL_PAGE_TYPE_XDES:
00690       /* This is an uncompressed page. */
00691       break;
00692     }
00693   }
00694 
00695   checksum = srv_use_checksums
00696     ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
00697   old_checksum = srv_use_checksums
00698     ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
00699 
00700   ut_print_timestamp(stderr);
00701   fprintf(stderr,
00702     "  InnoDB: Page checksum %lu, prior-to-4.0.14-form"
00703     " checksum %lu\n"
00704     "InnoDB: stored checksum %lu, prior-to-4.0.14-form"
00705     " stored checksum %lu\n"
00706     "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
00707     " at page end %lu\n"
00708     "InnoDB: Page number (if stored to page already) %lu,\n"
00709     "InnoDB: space id (if created with >= MySQL-4.1.1"
00710     " and stored already) %lu\n",
00711     (ulong) checksum, (ulong) old_checksum,
00712     (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
00713     (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
00714            - FIL_PAGE_END_LSN_OLD_CHKSUM),
00715     (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
00716     (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
00717     (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
00718            - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
00719     (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
00720     (ulong) mach_read_from_4(read_buf
00721            + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
00722 
00723 #ifndef UNIV_HOTBACKUP
00724   if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
00725       == TRX_UNDO_INSERT) {
00726     fprintf(stderr,
00727       "InnoDB: Page may be an insert undo log page\n");
00728   } else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
00729             + TRX_UNDO_PAGE_TYPE)
00730        == TRX_UNDO_UPDATE) {
00731     fprintf(stderr,
00732       "InnoDB: Page may be an update undo log page\n");
00733   }
00734 #endif /* !UNIV_HOTBACKUP */
00735 
00736   switch (fil_page_get_type(read_buf)) {
00737     index_id_t  index_id;
00738   case FIL_PAGE_INDEX:
00739     index_id = btr_page_get_index_id(read_buf);
00740     fprintf(stderr,
00741       "InnoDB: Page may be an index page where"
00742       " index id is %llu\n",
00743       (ullint) index_id);
00744 #ifndef UNIV_HOTBACKUP
00745     index = dict_index_find_on_id_low(index_id);
00746     if (index) {
00747       fputs("InnoDB: (", stderr);
00748       dict_index_name_print(stderr, NULL, index);
00749       fputs(")\n", stderr);
00750     }
00751 #endif /* !UNIV_HOTBACKUP */
00752     break;
00753   case FIL_PAGE_INODE:
00754     fputs("InnoDB: Page may be an 'inode' page\n", stderr);
00755     break;
00756   case FIL_PAGE_IBUF_FREE_LIST:
00757     fputs("InnoDB: Page may be an insert buffer free list page\n",
00758           stderr);
00759     break;
00760   case FIL_PAGE_TYPE_ALLOCATED:
00761     fputs("InnoDB: Page may be a freshly allocated page\n",
00762           stderr);
00763     break;
00764   case FIL_PAGE_IBUF_BITMAP:
00765     fputs("InnoDB: Page may be an insert buffer bitmap page\n",
00766           stderr);
00767     break;
00768   case FIL_PAGE_TYPE_SYS:
00769     fputs("InnoDB: Page may be a system page\n",
00770           stderr);
00771     break;
00772   case FIL_PAGE_TYPE_TRX_SYS:
00773     fputs("InnoDB: Page may be a transaction system page\n",
00774           stderr);
00775     break;
00776   case FIL_PAGE_TYPE_FSP_HDR:
00777     fputs("InnoDB: Page may be a file space header page\n",
00778           stderr);
00779     break;
00780   case FIL_PAGE_TYPE_XDES:
00781     fputs("InnoDB: Page may be an extent descriptor page\n",
00782           stderr);
00783     break;
00784   case FIL_PAGE_TYPE_BLOB:
00785     fputs("InnoDB: Page may be a BLOB page\n",
00786           stderr);
00787     break;
00788   case FIL_PAGE_TYPE_ZBLOB:
00789   case FIL_PAGE_TYPE_ZBLOB2:
00790     fputs("InnoDB: Page may be a compressed BLOB page\n",
00791           stderr);
00792     break;
00793   }
00794 }
00795 
00796 #ifndef UNIV_HOTBACKUP
00797 
00798 # ifdef PFS_GROUP_BUFFER_SYNC
00799 /********************************************************************/
00805 static
00806 void
00807 pfs_register_buffer_block(
00808 /*======================*/
00809   buf_chunk_t*  chunk)    
00810 {
00811   ulint   i;
00812   ulint   num_to_register;
00813   buf_block_t*    block;
00814 
00815   block = chunk->blocks;
00816 
00817   num_to_register = ut_min(chunk->size,
00818          PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER);
00819 
00820   for (i = 0; i < num_to_register; i++) {
00821     mutex_t*  mutex;
00822     rw_lock_t*  rwlock;
00823 
00824 #  ifdef UNIV_PFS_MUTEX
00825     mutex = &block->mutex;
00826     ut_a(!mutex->pfs_psi);
00827     mutex->pfs_psi = (PSI_server)
00828       ? PSI_server->init_mutex(buffer_block_mutex_key, mutex)
00829       : NULL;
00830 #  endif /* UNIV_PFS_MUTEX */
00831 
00832 #  ifdef UNIV_PFS_RWLOCK
00833     rwlock = &block->lock;
00834     ut_a(!rwlock->pfs_psi);
00835     rwlock->pfs_psi = (PSI_server)
00836       ? PSI_server->init_rwlock(buf_block_lock_key, rwlock)
00837       : NULL;
00838 #  endif /* UNIV_PFS_RWLOCK */
00839     block++;
00840   }
00841 }
00842 # endif /* PFS_GROUP_BUFFER_SYNC */
00843 
00844 /********************************************************************/
00846 static
00847 void
00848 buf_block_init(
00849 /*===========*/
00850   buf_pool_t* buf_pool, 
00851   buf_block_t*  block,    
00852   byte*   frame)    
00853 {
00854   UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block);
00855 
00856   block->frame = frame;
00857 
00858   block->page.buf_pool_index = buf_pool_index(buf_pool);
00859   block->page.state = BUF_BLOCK_NOT_USED;
00860   block->page.buf_fix_count = 0;
00861   block->page.io_fix = BUF_IO_NONE;
00862 
00863   block->modify_clock = 0;
00864 
00865 #ifdef UNIV_DEBUG_FILE_ACCESSES
00866   block->page.file_page_was_freed = FALSE;
00867 #endif /* UNIV_DEBUG_FILE_ACCESSES */
00868 
00869   block->check_index_page_at_flush = FALSE;
00870   block->index = NULL;
00871 
00872   block->is_hashed = FALSE;
00873 
00874 #ifdef UNIV_DEBUG
00875   block->page.in_page_hash = FALSE;
00876   block->page.in_zip_hash = FALSE;
00877   block->page.in_flush_list = FALSE;
00878   block->page.in_free_list = FALSE;
00879   block->page.in_LRU_list = FALSE;
00880   block->in_unzip_LRU_list = FALSE;
00881 #endif /* UNIV_DEBUG */
00882 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
00883   block->n_pointers = 0;
00884 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
00885   page_zip_des_init(&block->page.zip);
00886 
00887 #if defined PFS_SKIP_BUFFER_MUTEX_RWLOCK || defined PFS_GROUP_BUFFER_SYNC
00888   /* If PFS_SKIP_BUFFER_MUTEX_RWLOCK is defined, skip registration
00889   of buffer block mutex/rwlock with performance schema. If
00890   PFS_GROUP_BUFFER_SYNC is defined, skip the registration
00891   since buffer block mutex/rwlock will be registered later in
00892   pfs_register_buffer_block() */
00893 
00894   mutex_create(PFS_NOT_INSTRUMENTED, &block->mutex, SYNC_BUF_BLOCK);
00895   rw_lock_create(PFS_NOT_INSTRUMENTED, &block->lock, SYNC_LEVEL_VARYING);
00896 #else /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */
00897   mutex_create(buffer_block_mutex_key, &block->mutex, SYNC_BUF_BLOCK);
00898   rw_lock_create(buf_block_lock_key, &block->lock, SYNC_LEVEL_VARYING);
00899 #endif /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */
00900 
00901   ut_ad(rw_lock_validate(&(block->lock)));
00902 
00903 #ifdef UNIV_SYNC_DEBUG
00904   rw_lock_create(buf_block_debug_latch_key,
00905            &block->debug_latch, SYNC_NO_ORDER_CHECK);
00906 #endif /* UNIV_SYNC_DEBUG */
00907 }
00908 
00909 /********************************************************************/
00912 static
00913 buf_chunk_t*
00914 buf_chunk_init(
00915 /*===========*/
00916   buf_pool_t* buf_pool, 
00917   buf_chunk_t*  chunk,    
00918   ulint   mem_size) 
00919 {
00920   buf_block_t*  block;
00921   byte*   frame;
00922   ulint   i;
00923 
00924   /* Round down to a multiple of page size,
00925   although it already should be. */
00926   mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE);
00927   /* Reserve space for the block descriptors. */
00928   mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block)
00929           + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
00930 
00931   chunk->mem_size = mem_size;
00932   chunk->mem = os_mem_alloc_large(&chunk->mem_size);
00933 
00934   if (UNIV_UNLIKELY(chunk->mem == NULL)) {
00935 
00936     return(NULL);
00937   }
00938 
00939   /* Allocate the block descriptors from
00940   the start of the memory block. */
00941   chunk->blocks = static_cast<buf_block_struct *>(chunk->mem);
00942 
00943   /* Align a pointer to the first frame.  Note that when
00944   os_large_page_size is smaller than UNIV_PAGE_SIZE,
00945   we may allocate one fewer block than requested.  When
00946   it is bigger, we may allocate more blocks than requested. */
00947 
00948   frame = static_cast<unsigned char *>(ut_align(chunk->mem, UNIV_PAGE_SIZE));
00949   chunk->size = chunk->mem_size / UNIV_PAGE_SIZE
00950     - (frame != chunk->mem);
00951 
00952   /* Subtract the space needed for block descriptors. */
00953   {
00954     ulint size = chunk->size;
00955 
00956     while (frame < (byte*) (chunk->blocks + size)) {
00957       frame += UNIV_PAGE_SIZE;
00958       size--;
00959     }
00960 
00961     chunk->size = size;
00962   }
00963 
00964   /* Init block structs and assign frames for them. Then we
00965   assign the frames to the first blocks (we already mapped the
00966   memory above). */
00967 
00968   block = chunk->blocks;
00969 
00970   for (i = chunk->size; i--; ) {
00971 
00972     buf_block_init(buf_pool, block, frame);
00973 
00974 #ifdef HAVE_VALGRIND
00975     /* Wipe contents of frame to eliminate a Purify warning */
00976     memset(block->frame, '\0', UNIV_PAGE_SIZE);
00977 #endif
00978     /* Add the block to the free list */
00979     UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page));
00980 
00981     ut_d(block->page.in_free_list = TRUE);
00982     ut_ad(buf_pool_from_block(block) == buf_pool);
00983 
00984     block++;
00985     frame += UNIV_PAGE_SIZE;
00986   }
00987 
00988 #ifdef PFS_GROUP_BUFFER_SYNC
00989   pfs_register_buffer_block(chunk);
00990 #endif
00991   return(chunk);
00992 }
00993 
00994 #ifdef UNIV_DEBUG
00995 /*********************************************************************/
00999 static
01000 buf_block_t*
01001 buf_chunk_contains_zip(
01002 /*===================*/
01003   buf_chunk_t*  chunk,  
01004   const void* data) 
01005 {
01006   buf_block_t*  block;
01007   ulint   i;
01008 
01009   block = chunk->blocks;
01010 
01011   for (i = chunk->size; i--; block++) {
01012     if (block->page.zip.data == data) {
01013 
01014       return(block);
01015     }
01016   }
01017 
01018   return(NULL);
01019 }
01020 
01021 /*********************************************************************/
01025 UNIV_INTERN
01026 buf_block_t*
01027 buf_pool_contains_zip(
01028 /*==================*/
01029   buf_pool_t* buf_pool, 
01030   const void* data)   
01031 {
01032   ulint   n;
01033   buf_chunk_t*  chunk = buf_pool->chunks;
01034 
01035   ut_ad(buf_pool);
01036   ut_ad(buf_pool_mutex_own(buf_pool));
01037   for (n = buf_pool->n_chunks; n--; chunk++) {
01038 
01039     buf_block_t* block = buf_chunk_contains_zip(chunk, data);
01040 
01041     if (block) {
01042       return(block);
01043     }
01044   }
01045 
01046   return(NULL);
01047 }
01048 #endif /* UNIV_DEBUG */
01049 
01050 /*********************************************************************/
01053 static
01054 const buf_block_t*
01055 buf_chunk_not_freed(
01056 /*================*/
01057   buf_chunk_t*  chunk)  
01058 {
01059   buf_block_t*  block;
01060   ulint   i;
01061 
01062   block = chunk->blocks;
01063 
01064   for (i = chunk->size; i--; block++) {
01065     ibool ready;
01066 
01067     switch (buf_block_get_state(block)) {
01068     case BUF_BLOCK_ZIP_FREE:
01069     case BUF_BLOCK_ZIP_PAGE:
01070     case BUF_BLOCK_ZIP_DIRTY:
01071       /* The uncompressed buffer pool should never
01072       contain compressed block descriptors. */
01073       ut_error;
01074       break;
01075     case BUF_BLOCK_NOT_USED:
01076     case BUF_BLOCK_READY_FOR_USE:
01077     case BUF_BLOCK_MEMORY:
01078     case BUF_BLOCK_REMOVE_HASH:
01079       /* Skip blocks that are not being used for
01080       file pages. */
01081       break;
01082     case BUF_BLOCK_FILE_PAGE:
01083       mutex_enter(&block->mutex);
01084       ready = buf_flush_ready_for_replace(&block->page);
01085       mutex_exit(&block->mutex);
01086 
01087       if (!ready) {
01088 
01089         return(block);
01090       }
01091 
01092       break;
01093     }
01094   }
01095 
01096   return(NULL);
01097 }
01098 
01099 /*********************************************************************/
01102 static
01103 ibool
01104 buf_chunk_all_free(
01105 /*===============*/
01106   const buf_chunk_t*  chunk)  
01107 {
01108   const buf_block_t*  block;
01109   ulint     i;
01110 
01111   block = chunk->blocks;
01112 
01113   for (i = chunk->size; i--; block++) {
01114 
01115     if (buf_block_get_state(block) != BUF_BLOCK_NOT_USED) {
01116 
01117       return(FALSE);
01118     }
01119   }
01120 
01121   return(TRUE);
01122 }
01123 
01124 /********************************************************************/
01126 static
01127 void
01128 buf_chunk_free(
01129 /*===========*/
01130   buf_pool_t* buf_pool, 
01131   buf_chunk_t*  chunk)    
01132 {
01133   buf_block_t*    block;
01134   const buf_block_t*  block_end;
01135 
01136   ut_ad(buf_pool_mutex_own(buf_pool));
01137 
01138   block_end = chunk->blocks + chunk->size;
01139 
01140   for (block = chunk->blocks; block < block_end; block++) {
01141     ut_a(buf_block_get_state(block) == BUF_BLOCK_NOT_USED);
01142     ut_a(!block->page.zip.data);
01143 
01144     ut_ad(!block->page.in_LRU_list);
01145     ut_ad(!block->in_unzip_LRU_list);
01146     ut_ad(!block->page.in_flush_list);
01147     /* Remove the block from the free list. */
01148     ut_ad(block->page.in_free_list);
01149     UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
01150 
01151     /* Free the latches. */
01152     mutex_free(&block->mutex);
01153     rw_lock_free(&block->lock);
01154 #ifdef UNIV_SYNC_DEBUG
01155     rw_lock_free(&block->debug_latch);
01156 #endif /* UNIV_SYNC_DEBUG */
01157     UNIV_MEM_UNDESC(block);
01158   }
01159 
01160   os_mem_free_large(chunk->mem, chunk->mem_size);
01161 }
01162 
01163 /********************************************************************/
01165 static
01166 void
01167 buf_pool_set_sizes(void)
01168 /*====================*/
01169 {
01170   ulint i;
01171   ulint curr_size = 0;
01172 
01173   buf_pool_mutex_enter_all();
01174 
01175   for (i = 0; i < srv_buf_pool_instances; i++) {
01176     buf_pool_t* buf_pool;
01177 
01178     buf_pool = buf_pool_from_array(i);
01179     curr_size += buf_pool->curr_pool_size;
01180   }
01181 
01182   srv_buf_pool_curr_size = curr_size;
01183   srv_buf_pool_old_size = srv_buf_pool_size;
01184 
01185   buf_pool_mutex_exit_all();
01186 }
01187 
01188 /********************************************************************/
01191 static
01192 ulint
01193 buf_pool_init_instance(
01194 /*===================*/
01195   buf_pool_t* buf_pool, 
01196   ulint   buf_pool_size,  
01197   ulint   instance_no)  
01198 {
01199   ulint   i;
01200   buf_chunk_t*  chunk;
01201 
01202   /* 1. Initialize general fields
01203   ------------------------------- */
01204   mutex_create(buf_pool_mutex_key,
01205          &buf_pool->mutex, SYNC_BUF_POOL);
01206   mutex_create(buf_pool_zip_mutex_key,
01207          &buf_pool->zip_mutex, SYNC_BUF_BLOCK);
01208 
01209   buf_pool_mutex_enter(buf_pool);
01210 
01211   if (buf_pool_size > 0) {
01212     buf_pool->n_chunks = 1;
01213                 void *chunk_ptr= mem_zalloc((sizeof *chunk));
01214     buf_pool->chunks = chunk = static_cast<buf_chunk_t *>(chunk_ptr);
01215 
01216     UT_LIST_INIT(buf_pool->free);
01217 
01218     if (!buf_chunk_init(buf_pool, chunk, buf_pool_size)) {
01219       mem_free(chunk);
01220       mem_free(buf_pool);
01221 
01222       buf_pool_mutex_exit(buf_pool);
01223 
01224       return(DB_ERROR);
01225     }
01226 
01227     buf_pool->instance_no = instance_no;
01228     buf_pool->old_pool_size = buf_pool_size;
01229     buf_pool->curr_size = chunk->size;
01230     buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
01231 
01232     buf_pool->page_hash = hash_create(2 * buf_pool->curr_size);
01233     buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size);
01234     
01235     buf_pool->last_printout_time = ut_time();
01236   }
01237   /* 2. Initialize flushing fields
01238   -------------------------------- */
01239 
01240   mutex_create(flush_list_mutex_key, &buf_pool->flush_list_mutex,
01241          SYNC_BUF_FLUSH_LIST);
01242 
01243   for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
01244     buf_pool->no_flush[i] = os_event_create(NULL);
01245   }
01246 
01247   /* 3. Initialize LRU fields
01248   --------------------------- */
01249 
01250   /* All fields are initialized by mem_zalloc(). */
01251 
01252   buf_pool_mutex_exit(buf_pool);
01253 
01254   return(DB_SUCCESS);
01255 }
01256 
01257 /********************************************************************/
01259 static
01260 void
01261 buf_pool_free_instance(
01262 /*===================*/
01263   buf_pool_t* buf_pool) /* in,own: buffer pool instance
01264           to free */
01265 {
01266   buf_chunk_t*  chunk;
01267   buf_chunk_t*  chunks;
01268 
01269   chunks = buf_pool->chunks;
01270   chunk = chunks + buf_pool->n_chunks;
01271 
01272   while (--chunk >= chunks) {
01273     /* Bypass the checks of buf_chunk_free(), since they
01274     would fail at shutdown. */
01275     os_mem_free_large(chunk->mem, chunk->mem_size);
01276   }
01277 
01278   mem_free(buf_pool->chunks);
01279   hash_table_free(buf_pool->page_hash);
01280   hash_table_free(buf_pool->zip_hash);
01281 }
01282 
01283 /********************************************************************/
01286 UNIV_INTERN
01287 ulint
01288 buf_pool_init(
01289 /*==========*/
01290   ulint total_size, 
01291   ulint n_instances)  
01292 {
01293   ulint   i;
01294   const ulint size  = total_size / n_instances;
01295 
01296   ut_ad(n_instances > 0);
01297   ut_ad(n_instances <= MAX_BUFFER_POOLS);
01298   ut_ad(n_instances == srv_buf_pool_instances);
01299 
01300   /* We create an extra buffer pool instance, this instance is used
01301   for flushing the flush lists, to keep track of n_flush for all
01302   the buffer pools and also used as a waiting object during flushing. */
01303         void *buf_pool_void_ptr= mem_zalloc(n_instances * sizeof *buf_pool_ptr);
01304   buf_pool_ptr = static_cast<buf_pool_struct *>(buf_pool_void_ptr);
01305 
01306   for (i = 0; i < n_instances; i++) {
01307     buf_pool_t* ptr = &buf_pool_ptr[i];
01308 
01309     if (buf_pool_init_instance(ptr, size, i) != DB_SUCCESS) {
01310 
01311       /* Free all the instances created so far. */
01312       buf_pool_free(i);
01313 
01314       return(DB_ERROR);
01315     }
01316   }
01317 
01318   buf_pool_set_sizes();
01319   buf_LRU_old_ratio_update(100 * 3/ 8, FALSE);
01320 
01321   btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void*) / 64);
01322 
01323   return(DB_SUCCESS);
01324 }
01325 
01326 /********************************************************************/
01329 UNIV_INTERN
01330 void
01331 buf_pool_free(
01332 /*==========*/
01333   ulint n_instances)  
01334 {
01335   ulint i;
01336 
01337   for (i = 0; i < n_instances; i++) {
01338     buf_pool_free_instance(buf_pool_from_array(i));
01339   }
01340 
01341   mem_free(buf_pool_ptr);
01342   buf_pool_ptr = NULL;
01343 }
01344 
01345 /********************************************************************/
01347 static
01348 void
01349 buf_pool_drop_hash_index_instance(
01350 /*==============================*/
01351   buf_pool_t* buf_pool,   
01352   ibool*    released_search_latch)  
01355 {
01356   buf_chunk_t*  chunks  = buf_pool->chunks;
01357   buf_chunk_t*  chunk = chunks + buf_pool->n_chunks;
01358 
01359   while (--chunk >= chunks) {
01360     ulint   i;
01361     buf_block_t*  block = chunk->blocks;
01362 
01363     for (i = chunk->size; i--; block++) {
01364       /* block->is_hashed cannot be modified
01365       when we have an x-latch on btr_search_latch;
01366       see the comment in buf0buf.h */
01367       
01368       if (!block->is_hashed) {
01369         continue;
01370       }
01371       
01372       /* To follow the latching order, we
01373       have to release btr_search_latch
01374       before acquiring block->latch. */
01375       rw_lock_x_unlock(&btr_search_latch);
01376       /* When we release the search latch,
01377       we must rescan all blocks, because
01378       some may become hashed again. */
01379       *released_search_latch = TRUE;
01380       
01381       rw_lock_x_lock(&block->lock);
01382       
01383       /* This should be guaranteed by the
01384       callers, which will be holding
01385       btr_search_enabled_mutex. */
01386       ut_ad(!btr_search_enabled);
01387       
01388       /* Because we did not buffer-fix the
01389       block by calling buf_block_get_gen(),
01390       it is possible that the block has been
01391       allocated for some other use after
01392       btr_search_latch was released above.
01393       We do not care which file page the
01394       block is mapped to.  All we want to do
01395       is to drop any hash entries referring
01396       to the page. */
01397       
01398       /* It is possible that
01399       block->page.state != BUF_FILE_PAGE.
01400       Even that does not matter, because
01401       btr_search_drop_page_hash_index() will
01402       check block->is_hashed before doing
01403       anything.  block->is_hashed can only
01404       be set on uncompressed file pages. */
01405       
01406       btr_search_drop_page_hash_index(block);
01407       
01408       rw_lock_x_unlock(&block->lock);
01409       
01410       rw_lock_x_lock(&btr_search_latch);
01411       
01412       ut_ad(!btr_search_enabled);
01413     }
01414   }
01415 }
01416  
01417 /********************************************************************/
01421 UNIV_INTERN
01422 void
01423 buf_pool_drop_hash_index(void)
01424 /*==========================*/
01425 {
01426   ibool   released_search_latch;
01427 
01428 #ifdef UNIV_SYNC_DEBUG
01429   ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
01430 #endif /* UNIV_SYNC_DEBUG */
01431   ut_ad(!btr_search_enabled);
01432 
01433   do {
01434     ulint i;
01435 
01436     released_search_latch = FALSE;
01437 
01438     for (i = 0; i < srv_buf_pool_instances; i++) {
01439       buf_pool_t* buf_pool;
01440 
01441       buf_pool = buf_pool_from_array(i);
01442 
01443       buf_pool_drop_hash_index_instance(
01444         buf_pool, &released_search_latch);
01445     }
01446 
01447   } while (released_search_latch);
01448 }
01449 
01450 /********************************************************************/
01454 UNIV_INTERN
01455 void
01456 buf_relocate(
01457 /*=========*/
01458   buf_page_t* bpage,  
01461   buf_page_t* dpage)  
01462 {
01463   buf_page_t* b;
01464   ulint   fold;
01465   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01466 
01467   ut_ad(buf_pool_mutex_own(buf_pool));
01468   ut_ad(mutex_own(buf_page_get_mutex(bpage)));
01469   ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
01470   ut_a(bpage->buf_fix_count == 0);
01471   ut_ad(bpage->in_LRU_list);
01472   ut_ad(!bpage->in_zip_hash);
01473   ut_ad(bpage->in_page_hash);
01474   ut_ad(bpage == buf_page_hash_get(buf_pool,
01475                  bpage->space, bpage->offset));
01476   ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
01477 #ifdef UNIV_DEBUG
01478   switch (buf_page_get_state(bpage)) {
01479   case BUF_BLOCK_ZIP_FREE:
01480   case BUF_BLOCK_NOT_USED:
01481   case BUF_BLOCK_READY_FOR_USE:
01482   case BUF_BLOCK_FILE_PAGE:
01483   case BUF_BLOCK_MEMORY:
01484   case BUF_BLOCK_REMOVE_HASH:
01485     ut_error;
01486   case BUF_BLOCK_ZIP_DIRTY:
01487   case BUF_BLOCK_ZIP_PAGE:
01488     break;
01489   }
01490 #endif /* UNIV_DEBUG */
01491 
01492   memcpy(dpage, bpage, sizeof *dpage);
01493 
01494   ut_d(bpage->in_LRU_list = FALSE);
01495   ut_d(bpage->in_page_hash = FALSE);
01496 
01497   /* relocate buf_pool->LRU */
01498   b = UT_LIST_GET_PREV(LRU, bpage);
01499   UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
01500 
01501   if (b) {
01502     UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, b, dpage);
01503   } else {
01504     UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, dpage);
01505   }
01506 
01507   if (UNIV_UNLIKELY(buf_pool->LRU_old == bpage)) {
01508     buf_pool->LRU_old = dpage;
01509 #ifdef UNIV_LRU_DEBUG
01510     /* buf_pool->LRU_old must be the first item in the LRU list
01511     whose "old" flag is set. */
01512     ut_a(buf_pool->LRU_old->old);
01513     ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
01514          || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
01515     ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
01516          || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
01517   } else {
01518     /* Check that the "old" flag is consistent in
01519     the block and its neighbours. */
01520     buf_page_set_old(dpage, buf_page_is_old(dpage));
01521 #endif /* UNIV_LRU_DEBUG */
01522   }
01523 
01524   ut_d(UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
01525             ut_ad(ut_list_node_313->in_LRU_list)));
01526 
01527   /* relocate buf_pool->page_hash */
01528   fold = buf_page_address_fold(bpage->space, bpage->offset);
01529 
01530   HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
01531   HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage);
01532 }
01533 
01534 /********************************************************************/
01536 static
01537 void
01538 buf_pool_shrink_instance(
01539 /*=====================*/
01540   buf_pool_t* buf_pool, 
01541   ulint   chunk_size) 
01542 {
01543   buf_chunk_t*  chunks;
01544   buf_chunk_t*  chunk;
01545   ulint   max_size;
01546   ulint   max_free_size;
01547   buf_chunk_t*  max_chunk;
01548   buf_chunk_t*  max_free_chunk;
01549 
01550   ut_ad(!buf_pool_mutex_own(buf_pool));
01551 
01552 try_again:
01553   btr_search_disable(); /* Empty the adaptive hash index again */
01554   buf_pool_mutex_enter(buf_pool);
01555 
01556 shrink_again:
01557   if (buf_pool->n_chunks <= 1) {
01558 
01559     /* Cannot shrink if there is only one chunk */
01560     goto func_done;
01561   }
01562 
01563   /* Search for the largest free chunk
01564   not larger than the size difference */
01565   chunks = buf_pool->chunks;
01566   chunk = chunks + buf_pool->n_chunks;
01567   max_size = max_free_size = 0;
01568   max_chunk = max_free_chunk = NULL;
01569 
01570   while (--chunk >= chunks) {
01571     if (chunk->size <= chunk_size
01572         && chunk->size > max_free_size) {
01573       if (chunk->size > max_size) {
01574         max_size = chunk->size;
01575         max_chunk = chunk;
01576       }
01577 
01578       if (buf_chunk_all_free(chunk)) {
01579         max_free_size = chunk->size;
01580         max_free_chunk = chunk;
01581       }
01582     }
01583   }
01584 
01585   if (!max_free_size) {
01586 
01587     ulint   dirty = 0;
01588     ulint   nonfree = 0;
01589     buf_block_t*  block;
01590     buf_block_t*  bend;
01591 
01592     /* Cannot shrink: try again later
01593     (do not assign srv_buf_pool_old_size) */
01594     if (!max_chunk) {
01595 
01596       goto func_exit;
01597     }
01598 
01599     block = max_chunk->blocks;
01600     bend = block + max_chunk->size;
01601 
01602     /* Move the blocks of chunk to the end of the
01603     LRU list and try to flush them. */
01604     for (; block < bend; block++) {
01605       switch (buf_block_get_state(block)) {
01606       case BUF_BLOCK_NOT_USED:
01607         continue;
01608       case BUF_BLOCK_FILE_PAGE:
01609         break;
01610       default:
01611         nonfree++;
01612         continue;
01613       }
01614 
01615       mutex_enter(&block->mutex);
01616       /* The following calls will temporarily
01617       release block->mutex and buf_pool->mutex.
01618       Therefore, we have to always retry,
01619       even if !dirty && !nonfree. */
01620 
01621       if (!buf_flush_ready_for_replace(&block->page)) {
01622 
01623         buf_LRU_make_block_old(&block->page);
01624         dirty++;
01625       } else if (buf_LRU_free_block(&block->page, TRUE, NULL)
01626            != BUF_LRU_FREED) {
01627         nonfree++;
01628       }
01629 
01630       mutex_exit(&block->mutex);
01631     }
01632 
01633     buf_pool_mutex_exit(buf_pool);
01634 
01635     /* Request for a flush of the chunk if it helps.
01636     Do not flush if there are non-free blocks, since
01637     flushing will not make the chunk freeable. */
01638     if (nonfree) {
01639       /* Avoid busy-waiting. */
01640       os_thread_sleep(100000);
01641     } else if (dirty
01642          && buf_flush_LRU(buf_pool, dirty)
01643             == ULINT_UNDEFINED) {
01644 
01645       buf_flush_wait_batch_end(buf_pool, BUF_FLUSH_LRU);
01646     }
01647 
01648     goto try_again;
01649   }
01650 
01651   max_size = max_free_size;
01652   max_chunk = max_free_chunk;
01653 
01654   buf_pool->old_pool_size = buf_pool->curr_pool_size;
01655 
01656   /* Rewrite buf_pool->chunks.  Copy everything but max_chunk. */
01657   chunks = static_cast<buf_chunk_t *>(mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks));
01658   memcpy(chunks, buf_pool->chunks,
01659          (max_chunk - buf_pool->chunks) * sizeof *chunks);
01660   memcpy(chunks + (max_chunk - buf_pool->chunks),
01661          max_chunk + 1,
01662          buf_pool->chunks + buf_pool->n_chunks
01663          - (max_chunk + 1));
01664   ut_a(buf_pool->curr_size > max_chunk->size);
01665   buf_pool->curr_size -= max_chunk->size;
01666   buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
01667   chunk_size -= max_chunk->size;
01668   buf_chunk_free(buf_pool, max_chunk);
01669   mem_free(buf_pool->chunks);
01670   buf_pool->chunks = chunks;
01671   buf_pool->n_chunks--;
01672 
01673   /* Allow a slack of one megabyte. */
01674   if (chunk_size > 1048576 / UNIV_PAGE_SIZE) {
01675 
01676     goto shrink_again;
01677   }
01678   goto func_exit;
01679 
01680 func_done:
01681   buf_pool->old_pool_size = buf_pool->curr_pool_size;
01682 func_exit:
01683   buf_pool_mutex_exit(buf_pool);
01684   btr_search_enable();
01685 }
01686 
01687 /********************************************************************/
01689 static
01690 void
01691 buf_pool_shrink(
01692 /*============*/
01693   ulint chunk_size) 
01694 {
01695   ulint i;
01696 
01697   for (i = 0; i < srv_buf_pool_instances; i++) {
01698     buf_pool_t* buf_pool;
01699     ulint   instance_chunk_size;
01700 
01701     instance_chunk_size = chunk_size / srv_buf_pool_instances;
01702     buf_pool = buf_pool_from_array(i);
01703     buf_pool_shrink_instance(buf_pool, instance_chunk_size);
01704   }
01705 
01706   buf_pool_set_sizes();
01707 }
01708 
01709 /********************************************************************/
01711 static
01712 void
01713 buf_pool_page_hash_rebuild_instance(
01714 /*================================*/
01715   buf_pool_t* buf_pool)   
01716 {
01717   ulint   i;
01718   buf_page_t* b;
01719   buf_chunk_t*  chunk;
01720   ulint   n_chunks;
01721   hash_table_t* zip_hash;
01722   hash_table_t* page_hash;
01723 
01724   buf_pool_mutex_enter(buf_pool);
01725 
01726   /* Free, create, and populate the hash table. */
01727   hash_table_free(buf_pool->page_hash);
01728   buf_pool->page_hash = page_hash = hash_create(2 * buf_pool->curr_size);
01729   zip_hash = hash_create(2 * buf_pool->curr_size);
01730 
01731   HASH_MIGRATE(buf_pool->zip_hash, zip_hash, buf_page_t, hash,
01732          BUF_POOL_ZIP_FOLD_BPAGE);
01733 
01734   hash_table_free(buf_pool->zip_hash);
01735   buf_pool->zip_hash = zip_hash;
01736 
01737   /* Insert the uncompressed file pages to buf_pool->page_hash. */
01738 
01739   chunk = buf_pool->chunks;
01740   n_chunks = buf_pool->n_chunks;
01741 
01742   for (i = 0; i < n_chunks; i++, chunk++) {
01743     ulint   j;
01744     buf_block_t*  block = chunk->blocks;
01745 
01746     for (j = 0; j < chunk->size; j++, block++) {
01747       if (buf_block_get_state(block)
01748           == BUF_BLOCK_FILE_PAGE) {
01749         ut_ad(!block->page.in_zip_hash);
01750         ut_ad(block->page.in_page_hash);
01751 
01752         HASH_INSERT(buf_page_t, hash, page_hash,
01753               buf_page_address_fold(
01754                 block->page.space,
01755                 block->page.offset),
01756               &block->page);
01757       }
01758     }
01759   }
01760 
01761   /* Insert the compressed-only pages to buf_pool->page_hash.
01762   All such blocks are either in buf_pool->zip_clean or
01763   in buf_pool->flush_list. */
01764 
01765   for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
01766        b = UT_LIST_GET_NEXT(list, b)) {
01767     ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
01768     ut_ad(!b->in_flush_list);
01769     ut_ad(b->in_LRU_list);
01770     ut_ad(b->in_page_hash);
01771     ut_ad(!b->in_zip_hash);
01772 
01773     HASH_INSERT(buf_page_t, hash, page_hash,
01774           buf_page_address_fold(b->space, b->offset), b);
01775   }
01776 
01777   buf_flush_list_mutex_enter(buf_pool);
01778   for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
01779        b = UT_LIST_GET_NEXT(list, b)) {
01780     ut_ad(b->in_flush_list);
01781     ut_ad(b->in_LRU_list);
01782     ut_ad(b->in_page_hash);
01783     ut_ad(!b->in_zip_hash);
01784 
01785     switch (buf_page_get_state(b)) {
01786     case BUF_BLOCK_ZIP_DIRTY:
01787       HASH_INSERT(buf_page_t, hash, page_hash,
01788             buf_page_address_fold(b->space,
01789                 b->offset), b);
01790       break;
01791     case BUF_BLOCK_FILE_PAGE:
01792       /* uncompressed page */
01793       break;
01794     case BUF_BLOCK_ZIP_FREE:
01795     case BUF_BLOCK_ZIP_PAGE:
01796     case BUF_BLOCK_NOT_USED:
01797     case BUF_BLOCK_READY_FOR_USE:
01798     case BUF_BLOCK_MEMORY:
01799     case BUF_BLOCK_REMOVE_HASH:
01800       ut_error;
01801       break;
01802     }
01803   }
01804 
01805   buf_flush_list_mutex_exit(buf_pool);
01806   buf_pool_mutex_exit(buf_pool);
01807 }
01808 
01809 /********************************************************************
01810 Determine if a block is a sentinel for a buffer pool watch.
01811 @return TRUE if a sentinel for a buffer pool watch, FALSE if not */
01812 UNIV_INTERN
01813 ibool
01814 buf_pool_watch_is_sentinel(
01815 /*=======================*/
01816   buf_pool_t*   buf_pool, 
01817   const buf_page_t* bpage)    
01818 {
01819   ut_ad(buf_page_in_file(bpage));
01820 
01821   if (bpage < &buf_pool->watch[0]
01822       || bpage >= &buf_pool->watch[BUF_POOL_WATCH_SIZE]) {
01823 
01824     ut_ad(buf_page_get_state(bpage) != BUF_BLOCK_ZIP_PAGE
01825           || bpage->zip.data != NULL);
01826 
01827     return(FALSE);
01828   }
01829 
01830   ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
01831   ut_ad(!bpage->in_zip_hash);
01832   ut_ad(bpage->in_page_hash);
01833   ut_ad(bpage->zip.data == NULL);
01834   ut_ad(bpage->buf_fix_count > 0);
01835   return(TRUE);
01836 }
01837 
01838 /****************************************************************/
01842 UNIV_INTERN
01843 buf_page_t*
01844 buf_pool_watch_set(
01845 /*===============*/
01846   ulint space,  
01847   ulint offset, 
01848   ulint fold) 
01849 {
01850   buf_page_t* bpage;
01851   ulint   i;
01852   buf_pool_t* buf_pool = buf_pool_get(space, offset);
01853 
01854   ut_ad(buf_pool_mutex_own(buf_pool));
01855 
01856   bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
01857 
01858   if (UNIV_LIKELY_NULL(bpage)) {
01859     if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) {
01860       /* The page was loaded meanwhile. */
01861       return(bpage);
01862     }
01863     /* Add to an existing watch. */
01864     bpage->buf_fix_count++;
01865     return(NULL);
01866   }
01867 
01868   for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
01869     bpage = &buf_pool->watch[i];
01870 
01871     ut_ad(bpage->access_time == 0);
01872     ut_ad(bpage->newest_modification == 0);
01873     ut_ad(bpage->oldest_modification == 0);
01874     ut_ad(bpage->zip.data == NULL);
01875     ut_ad(!bpage->in_zip_hash);
01876 
01877     switch (bpage->state) {
01878     case BUF_BLOCK_POOL_WATCH:
01879       ut_ad(!bpage->in_page_hash);
01880       ut_ad(bpage->buf_fix_count == 0);
01881 
01882       /* bpage is pointing to buf_pool->watch[],
01883       which is protected by buf_pool->mutex.
01884       Normally, buf_page_t objects are protected by
01885       buf_block_t::mutex or buf_pool->zip_mutex or both. */
01886 
01887       bpage->state = BUF_BLOCK_ZIP_PAGE;
01888       bpage->space = space;
01889       bpage->offset = offset;
01890       bpage->buf_fix_count = 1;
01891 
01892       ut_d(bpage->in_page_hash = TRUE);
01893       HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
01894             fold, bpage);
01895       return(NULL);
01896     case BUF_BLOCK_ZIP_PAGE:
01897       ut_ad(bpage->in_page_hash);
01898       ut_ad(bpage->buf_fix_count > 0);
01899       break;
01900     default:
01901       ut_error;
01902     }
01903   }
01904 
01905   /* Allocation failed.  Either the maximum number of purge
01906   threads should never exceed BUF_POOL_WATCH_SIZE, or this code
01907   should be modified to return a special non-NULL value and the
01908   caller should purge the record directly. */
01909   ut_error;
01910 
01911   /* Fix compiler warning */
01912   return(NULL);
01913 }
01914 
01915 /********************************************************************/
01917 static
01918 void
01919 buf_pool_page_hash_rebuild(void)
01920 /*============================*/
01921 {
01922   ulint   i;
01923 
01924   for (i = 0; i < srv_buf_pool_instances; i++) {
01925     buf_pool_page_hash_rebuild_instance(buf_pool_from_array(i));
01926   }
01927 }
01928 
01929 /********************************************************************/
01931 static
01932 void
01933 buf_pool_increase_instance(
01934 /*=======================*/
01935   buf_pool_t* buf_pool, 
01936   ulint   change_size)  
01937 {
01938   buf_chunk_t*  chunks;
01939   buf_chunk_t*  chunk;
01940 
01941   buf_pool_mutex_enter(buf_pool);
01942   chunks = static_cast<buf_chunk_t *>(mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks));
01943 
01944   memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks * sizeof *chunks);
01945 
01946   chunk = &chunks[buf_pool->n_chunks];
01947 
01948   if (!buf_chunk_init(buf_pool, chunk, change_size)) {
01949     mem_free(chunks);
01950   } else {
01951     buf_pool->old_pool_size = buf_pool->curr_pool_size;
01952     buf_pool->curr_size += chunk->size;
01953     buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
01954     mem_free(buf_pool->chunks);
01955     buf_pool->chunks = chunks;
01956     buf_pool->n_chunks++;
01957   }
01958 
01959   buf_pool_mutex_exit(buf_pool);
01960 }
01961 
01962 /********************************************************************/
01964 static
01965 void
01966 buf_pool_increase(
01967 /*==============*/
01968   ulint   change_size)
01969 {
01970   ulint   i;
01971 
01972   for (i = 0; i < srv_buf_pool_instances; i++) {
01973     buf_pool_increase_instance(
01974       buf_pool_from_array(i),
01975       change_size / srv_buf_pool_instances);
01976   }
01977 
01978   buf_pool_set_sizes();
01979 }
01980 
01981 /********************************************************************/
01983 UNIV_INTERN
01984 void
01985 buf_pool_resize(void)
01986 /*=================*/
01987 {
01988   ulint change_size;
01989   ulint min_change_size = 1048576 * srv_buf_pool_instances;
01990 
01991   buf_pool_mutex_enter_all();
01992   
01993     if (srv_buf_pool_old_size == srv_buf_pool_size) {
01994   
01995     buf_pool_mutex_exit_all();
01996 
01997       return;
01998 
01999     } else if (srv_buf_pool_curr_size + min_change_size
02000        > srv_buf_pool_size) {
02001   
02002     change_size = (srv_buf_pool_curr_size - srv_buf_pool_size)
02003           / UNIV_PAGE_SIZE;
02004 
02005     buf_pool_mutex_exit_all();
02006   
02007       /* Disable adaptive hash indexes and empty the index
02008       in order to free up memory in the buffer pool chunks. */
02009     buf_pool_shrink(change_size);
02010 
02011   } else if (srv_buf_pool_curr_size + min_change_size
02012        < srv_buf_pool_size) {
02013  
02014       /* Enlarge the buffer pool by at least one megabyte */
02015   
02016     change_size = srv_buf_pool_size - srv_buf_pool_curr_size;
02017 
02018     buf_pool_mutex_exit_all();
02019 
02020     buf_pool_increase(change_size);
02021   } else {
02022     srv_buf_pool_size = srv_buf_pool_old_size;
02023 
02024     buf_pool_mutex_exit_all();
02025 
02026     return;
02027   }
02028   
02029     buf_pool_page_hash_rebuild();
02030 }
02031  
02032 /****************************************************************/
02037 static
02038 void
02039 buf_pool_watch_remove(
02040 /*==================*/
02041   buf_pool_t* buf_pool, 
02042   ulint   fold,   
02044   buf_page_t* watch)    
02045 {
02046   ut_ad(buf_pool_mutex_own(buf_pool));
02047 
02048   HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, watch);
02049   ut_d(watch->in_page_hash = FALSE);
02050   watch->buf_fix_count = 0;
02051   watch->state = BUF_BLOCK_POOL_WATCH;
02052 }
02053 
02054 /****************************************************************/
02057 UNIV_INTERN
02058 void
02059 buf_pool_watch_unset(
02060 /*=================*/
02061   ulint space,  
02062   ulint offset) 
02063 {
02064   buf_page_t* bpage;
02065   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02066   ulint   fold = buf_page_address_fold(space, offset);
02067 
02068   buf_pool_mutex_enter(buf_pool);
02069   bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
02070   /* The page must exist because buf_pool_watch_set()
02071   increments buf_fix_count. */
02072   ut_a(bpage);
02073 
02074   if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) {
02075     mutex_t* mutex = buf_page_get_mutex(bpage);
02076 
02077     mutex_enter(mutex);
02078     ut_a(bpage->buf_fix_count > 0);
02079     bpage->buf_fix_count--;
02080     mutex_exit(mutex);
02081   } else {
02082     ut_a(bpage->buf_fix_count > 0);
02083 
02084     if (UNIV_LIKELY(!--bpage->buf_fix_count)) {
02085       buf_pool_watch_remove(buf_pool, fold, bpage);
02086     }
02087   }
02088 
02089   buf_pool_mutex_exit(buf_pool);
02090 }
02091 
02092 /****************************************************************/
02097 UNIV_INTERN
02098 ibool
02099 buf_pool_watch_occurred(
02100 /*====================*/
02101   ulint space,  
02102   ulint offset) 
02103 {
02104   ibool   ret;
02105   buf_page_t* bpage;
02106   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02107   ulint   fold  = buf_page_address_fold(space, offset);
02108 
02109   buf_pool_mutex_enter(buf_pool);
02110 
02111   bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
02112   /* The page must exist because buf_pool_watch_set()
02113   increments buf_fix_count. */
02114   ut_a(bpage);
02115   ret = !buf_pool_watch_is_sentinel(buf_pool, bpage);
02116   buf_pool_mutex_exit(buf_pool);
02117 
02118   return(ret);
02119 }
02120 
02121 /********************************************************************/
02125 UNIV_INTERN
02126 void
02127 buf_page_make_young(
02128 /*================*/
02129   buf_page_t* bpage)  
02130 {
02131   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
02132 
02133   buf_pool_mutex_enter(buf_pool);
02134 
02135   ut_a(buf_page_in_file(bpage));
02136 
02137   buf_LRU_make_block_young(bpage);
02138 
02139   buf_pool_mutex_exit(buf_pool);
02140 }
02141 
02142 /********************************************************************/
02147 static
02148 void
02149 buf_page_set_accessed_make_young(
02150 /*=============================*/
02151   buf_page_t* bpage,    
02153   unsigned  access_time)  
02156 {
02157   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
02158 
02159   ut_ad(!buf_pool_mutex_own(buf_pool));
02160   ut_a(buf_page_in_file(bpage));
02161 
02162   if (buf_page_peek_if_too_old(bpage)) {
02163     buf_pool_mutex_enter(buf_pool);
02164     buf_LRU_make_block_young(bpage);
02165     buf_pool_mutex_exit(buf_pool);
02166   } else if (!access_time) {
02167     ulint time_ms = ut_time_ms();
02168     buf_pool_mutex_enter(buf_pool);
02169     buf_page_set_accessed(bpage, time_ms);
02170     buf_pool_mutex_exit(buf_pool);
02171   }
02172 }
02173 
02174 /********************************************************************/
02177 UNIV_INTERN
02178 void
02179 buf_reset_check_index_page_at_flush(
02180 /*================================*/
02181   ulint space,  
02182   ulint offset) 
02183 {
02184   buf_block_t*  block;
02185   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02186 
02187   buf_pool_mutex_enter(buf_pool);
02188 
02189   block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset);
02190 
02191   if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) {
02192     ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
02193     block->check_index_page_at_flush = FALSE;
02194   }
02195 
02196   buf_pool_mutex_exit(buf_pool);
02197 }
02198 
02199 /********************************************************************/
02204 UNIV_INTERN
02205 ibool
02206 buf_page_peek_if_search_hashed(
02207 /*===========================*/
02208   ulint space,  
02209   ulint offset) 
02210 {
02211   buf_block_t*  block;
02212   ibool   is_hashed;
02213   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02214 
02215   buf_pool_mutex_enter(buf_pool);
02216 
02217   block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset);
02218 
02219   if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
02220     is_hashed = FALSE;
02221   } else {
02222     ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
02223     is_hashed = block->is_hashed;
02224   }
02225 
02226   buf_pool_mutex_exit(buf_pool);
02227 
02228   return(is_hashed);
02229 }
02230 
02231 #ifdef UNIV_DEBUG_FILE_ACCESSES
02232 /********************************************************************/
02238 UNIV_INTERN
02239 buf_page_t*
02240 buf_page_set_file_page_was_freed(
02241 /*=============================*/
02242   ulint space,  
02243   ulint offset) 
02244 {
02245   buf_page_t* bpage;
02246   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02247 
02248   buf_pool_mutex_enter(buf_pool);
02249 
02250   bpage = buf_page_hash_get(buf_pool, space, offset);
02251 
02252   if (bpage) {
02253     ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
02254     bpage->file_page_was_freed = TRUE;
02255   }
02256 
02257   buf_pool_mutex_exit(buf_pool);
02258 
02259   return(bpage);
02260 }
02261 
02262 /********************************************************************/
02268 UNIV_INTERN
02269 buf_page_t*
02270 buf_page_reset_file_page_was_freed(
02271 /*===============================*/
02272   ulint space,  
02273   ulint offset) 
02274 {
02275   buf_page_t* bpage;
02276   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02277 
02278   buf_pool_mutex_enter(buf_pool);
02279 
02280   bpage = buf_page_hash_get(buf_pool, space, offset);
02281 
02282   if (bpage) {
02283     ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
02284     bpage->file_page_was_freed = FALSE;
02285   }
02286 
02287   buf_pool_mutex_exit(buf_pool);
02288 
02289   return(bpage);
02290 }
02291 #endif /* UNIV_DEBUG_FILE_ACCESSES */
02292 
02293 /********************************************************************/
02302 UNIV_INTERN
02303 buf_page_t*
02304 buf_page_get_zip(
02305 /*=============*/
02306   ulint   space,  
02307   ulint   zip_size,
02308   ulint   offset) 
02309 {
02310   buf_page_t* bpage;
02311   mutex_t*  block_mutex;
02312   ibool   must_read;
02313   unsigned  access_time;
02314   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02315 
02316 #ifndef UNIV_LOG_DEBUG
02317   ut_ad(!ibuf_inside());
02318 #endif
02319   buf_pool->stat.n_page_gets++;
02320 
02321   for (;;) {
02322     buf_pool_mutex_enter(buf_pool);
02323 lookup:
02324     bpage = buf_page_hash_get(buf_pool, space, offset);
02325     if (bpage) {
02326       ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
02327       break;
02328     }
02329 
02330     /* Page not in buf_pool: needs to be read from file */
02331 
02332     buf_pool_mutex_exit(buf_pool);
02333 
02334     buf_read_page(space, zip_size, offset);
02335 
02336 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
02337     ut_a(++buf_dbg_counter % 37 || buf_validate());
02338 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
02339   }
02340 
02341   if (UNIV_UNLIKELY(!bpage->zip.data)) {
02342     /* There is no compressed page. */
02343 err_exit:
02344     buf_pool_mutex_exit(buf_pool);
02345     return(NULL);
02346   }
02347 
02348   ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
02349 
02350   switch (buf_page_get_state(bpage)) {
02351   case BUF_BLOCK_NOT_USED:
02352   case BUF_BLOCK_READY_FOR_USE:
02353   case BUF_BLOCK_MEMORY:
02354   case BUF_BLOCK_REMOVE_HASH:
02355   case BUF_BLOCK_ZIP_FREE:
02356     break;
02357   case BUF_BLOCK_ZIP_PAGE:
02358   case BUF_BLOCK_ZIP_DIRTY:
02359     block_mutex = &buf_pool->zip_mutex;
02360     mutex_enter(block_mutex);
02361     bpage->buf_fix_count++;
02362     goto got_block;
02363   case BUF_BLOCK_FILE_PAGE:
02364     block_mutex = &((buf_block_t*) bpage)->mutex;
02365     mutex_enter(block_mutex);
02366 
02367     /* Discard the uncompressed page frame if possible. */
02368     if (buf_LRU_free_block(bpage, FALSE, NULL)
02369         == BUF_LRU_FREED) {
02370 
02371       mutex_exit(block_mutex);
02372       goto lookup;
02373     }
02374 
02375     buf_block_buf_fix_inc((buf_block_t*) bpage,
02376               __FILE__, __LINE__);
02377     goto got_block;
02378   }
02379 
02380   ut_error;
02381   goto err_exit;
02382 
02383 got_block:
02384   must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
02385   access_time = buf_page_is_accessed(bpage);
02386 
02387   buf_pool_mutex_exit(buf_pool);
02388 
02389   mutex_exit(block_mutex);
02390 
02391   buf_page_set_accessed_make_young(bpage, access_time);
02392 
02393 #ifdef UNIV_DEBUG_FILE_ACCESSES
02394   ut_a(!bpage->file_page_was_freed);
02395 #endif
02396 
02397 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
02398   ut_a(++buf_dbg_counter % 5771 || buf_validate());
02399   ut_a(bpage->buf_fix_count > 0);
02400   ut_a(buf_page_in_file(bpage));
02401 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
02402 
02403   if (must_read) {
02404     /* Let us wait until the read operation
02405     completes */
02406 
02407     for (;;) {
02408       enum buf_io_fix io_fix;
02409 
02410       mutex_enter(block_mutex);
02411       io_fix = buf_page_get_io_fix(bpage);
02412       mutex_exit(block_mutex);
02413 
02414       if (io_fix == BUF_IO_READ) {
02415 
02416         os_thread_sleep(WAIT_FOR_READ);
02417       } else {
02418         break;
02419       }
02420     }
02421   }
02422 
02423 #ifdef UNIV_IBUF_COUNT_DEBUG
02424   ut_a(ibuf_count_get(buf_page_get_space(bpage),
02425           buf_page_get_page_no(bpage)) == 0);
02426 #endif
02427   return(bpage);
02428 }
02429 
02430 /********************************************************************/
02432 UNIV_INLINE
02433 void
02434 buf_block_init_low(
02435 /*===============*/
02436   buf_block_t*  block)  
02437 {
02438   block->check_index_page_at_flush = FALSE;
02439   block->index    = NULL;
02440 
02441   block->n_hash_helps = 0;
02442   block->is_hashed  = FALSE;
02443   block->n_fields   = 1;
02444   block->n_bytes    = 0;
02445   block->left_side  = TRUE;
02446 }
02447 #endif /* !UNIV_HOTBACKUP */
02448 
02449 /********************************************************************/
02452 UNIV_INTERN
02453 ibool
02454 buf_zip_decompress(
02455 /*===============*/
02456   buf_block_t*  block,  
02457   ibool   check)  
02458 {
02459   const byte* frame   = block->page.zip.data;
02460   ulint   stamp_checksum  = mach_read_from_4(
02461     frame + FIL_PAGE_SPACE_OR_CHKSUM);
02462 
02463   ut_ad(buf_block_get_zip_size(block));
02464   ut_a(buf_block_get_space(block) != 0);
02465 
02466   if (UNIV_LIKELY(check && stamp_checksum != BUF_NO_CHECKSUM_MAGIC)) {
02467     ulint calc_checksum = page_zip_calc_checksum(
02468       frame, page_zip_get_size(&block->page.zip));
02469 
02470     if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) {
02471       ut_print_timestamp(stderr);
02472       fprintf(stderr,
02473         "  InnoDB: compressed page checksum mismatch"
02474         " (space %u page %u): %lu != %lu\n",
02475         block->page.space, block->page.offset,
02476         stamp_checksum, calc_checksum);
02477       return(FALSE);
02478     }
02479   }
02480 
02481   switch (fil_page_get_type(frame)) {
02482   case FIL_PAGE_INDEX:
02483     if (page_zip_decompress(&block->page.zip,
02484           block->frame, TRUE)) {
02485       return(TRUE);
02486     }
02487 
02488     fprintf(stderr,
02489       "InnoDB: unable to decompress space %lu page %lu\n",
02490       (ulong) block->page.space,
02491       (ulong) block->page.offset);
02492     return(FALSE);
02493 
02494   case FIL_PAGE_TYPE_ALLOCATED:
02495   case FIL_PAGE_INODE:
02496   case FIL_PAGE_IBUF_BITMAP:
02497   case FIL_PAGE_TYPE_FSP_HDR:
02498   case FIL_PAGE_TYPE_XDES:
02499   case FIL_PAGE_TYPE_ZBLOB:
02500   case FIL_PAGE_TYPE_ZBLOB2:
02501     /* Copy to uncompressed storage. */
02502     memcpy(block->frame, frame,
02503            buf_block_get_zip_size(block));
02504     return(TRUE);
02505   }
02506 
02507   ut_print_timestamp(stderr);
02508   fprintf(stderr,
02509     "  InnoDB: unknown compressed page"
02510     " type %lu\n",
02511     fil_page_get_type(frame));
02512   return(FALSE);
02513 }
02514 
02515 #ifndef UNIV_HOTBACKUP
02516 /*******************************************************************/
02520 static
02521 buf_block_t*
02522 buf_block_align_instance(
02523 /*=====================*/
02524   buf_pool_t* buf_pool, 
02526   const byte* ptr)    
02527 {
02528   buf_chunk_t*  chunk;
02529   ulint   i;
02530 
02531   /* TODO: protect buf_pool->chunks with a mutex (it will
02532   currently remain constant after buf_pool_init()) */
02533   for (chunk = buf_pool->chunks, i = buf_pool->n_chunks; i--; chunk++) {
02534     lint  offs = ptr - chunk->blocks->frame;
02535 
02536     if (UNIV_UNLIKELY(offs < 0)) {
02537 
02538       continue;
02539     }
02540 
02541     offs >>= UNIV_PAGE_SIZE_SHIFT;
02542 
02543     if (UNIV_LIKELY((ulint) offs < chunk->size)) {
02544       buf_block_t*  block = &chunk->blocks[offs];
02545 
02546       /* The function buf_chunk_init() invokes
02547       buf_block_init() so that block[n].frame ==
02548       block->frame + n * UNIV_PAGE_SIZE.  Check it. */
02549       ut_ad(block->frame == page_align(ptr));
02550 #ifdef UNIV_DEBUG
02551       /* A thread that updates these fields must
02552       hold buf_pool->mutex and block->mutex.  Acquire
02553       only the latter. */
02554       mutex_enter(&block->mutex);
02555 
02556       switch (buf_block_get_state(block)) {
02557       case BUF_BLOCK_ZIP_FREE:
02558       case BUF_BLOCK_ZIP_PAGE:
02559       case BUF_BLOCK_ZIP_DIRTY:
02560         /* These types should only be used in
02561         the compressed buffer pool, whose
02562         memory is allocated from
02563         buf_pool->chunks, in UNIV_PAGE_SIZE
02564         blocks flagged as BUF_BLOCK_MEMORY. */
02565         ut_error;
02566         break;
02567       case BUF_BLOCK_NOT_USED:
02568       case BUF_BLOCK_READY_FOR_USE:
02569       case BUF_BLOCK_MEMORY:
02570         /* Some data structures contain
02571         "guess" pointers to file pages.  The
02572         file pages may have been freed and
02573         reused.  Do not complain. */
02574         break;
02575       case BUF_BLOCK_REMOVE_HASH:
02576         /* buf_LRU_block_remove_hashed_page()
02577         will overwrite the FIL_PAGE_OFFSET and
02578         FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
02579         0xff and set the state to
02580         BUF_BLOCK_REMOVE_HASH. */
02581         ut_ad(page_get_space_id(page_align(ptr))
02582               == 0xffffffff);
02583         ut_ad(page_get_page_no(page_align(ptr))
02584               == 0xffffffff);
02585         break;
02586       case BUF_BLOCK_FILE_PAGE:
02587         ut_ad(block->page.space
02588               == page_get_space_id(page_align(ptr)));
02589         ut_ad(block->page.offset
02590               == page_get_page_no(page_align(ptr)));
02591         break;
02592       }
02593 
02594       mutex_exit(&block->mutex);
02595 #endif /* UNIV_DEBUG */
02596 
02597       return(block);
02598     }
02599   }
02600 
02601   return(NULL);
02602 }
02603 
02604 /*******************************************************************/
02607 UNIV_INTERN
02608 buf_block_t*
02609 buf_block_align(
02610 /*============*/
02611   const byte* ptr)  
02612 {
02613   ulint   i;
02614 
02615   for (i = 0; i < srv_buf_pool_instances; i++) {
02616     buf_block_t*  block;
02617 
02618     block = buf_block_align_instance(
02619       buf_pool_from_array(i), ptr);
02620     if (block) {
02621       return(block);
02622     }
02623   }
02624 
02625   /* The block should always be found. */
02626   ut_error;
02627   return(NULL);
02628 }
02629 
02630 /********************************************************************/
02635 static
02636 ibool
02637 buf_pointer_is_block_field_instance(
02638 /*================================*/
02639   buf_pool_t* buf_pool, 
02640   const void* ptr)    
02641 {
02642   const buf_chunk_t*    chunk = buf_pool->chunks;
02643   const buf_chunk_t* const  echunk  = chunk + buf_pool->n_chunks;
02644 
02645   /* TODO: protect buf_pool->chunks with a mutex (it will
02646   currently remain constant after buf_pool_init()) */
02647   while (chunk < echunk) {
02648     if (ptr >= (void *)chunk->blocks
02649         && ptr < (void *)(chunk->blocks + chunk->size)) {
02650 
02651       return(TRUE);
02652     }
02653 
02654     chunk++;
02655   }
02656 
02657   return(FALSE);
02658 }
02659 
02660 /********************************************************************/
02664 UNIV_INTERN
02665 ibool
02666 buf_pointer_is_block_field(
02667 /*=======================*/
02668   const void* ptr)  
02669 {
02670   ulint i;
02671 
02672   for (i = 0; i < srv_buf_pool_instances; i++) {
02673     ibool found;
02674 
02675     found = buf_pointer_is_block_field_instance(
02676       buf_pool_from_array(i), ptr);
02677     if (found) {
02678       return(TRUE);
02679     }
02680   }
02681 
02682   return(FALSE);
02683 }
02684 
02685 /********************************************************************/
02688 static
02689 ibool
02690 buf_block_is_uncompressed(
02691 /*======================*/
02692   buf_pool_t*   buf_pool, 
02693   const buf_block_t*  block)    
02695 {
02696   ut_ad(buf_pool_mutex_own(buf_pool));
02697 
02698   if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) {
02699     /* The pointer should be aligned. */
02700     return(FALSE);
02701   }
02702 
02703   return(buf_pointer_is_block_field_instance(buf_pool, (void *)block));
02704 }
02705 
02706 /********************************************************************/
02709 UNIV_INTERN
02710 buf_block_t*
02711 buf_page_get_gen(
02712 /*=============*/
02713   ulint   space,  
02714   ulint   zip_size,
02716   ulint   offset, 
02717   ulint   rw_latch,
02718   buf_block_t*  guess,  
02719   ulint   mode, 
02722   const char* file, 
02723   ulint   line, 
02724   mtr_t*    mtr)  
02725 {
02726   buf_block_t*  block;
02727   ulint   fold;
02728   unsigned  access_time;
02729   ulint   fix_type;
02730   ibool   must_read;
02731   ulint   retries = 0;
02732   buf_pool_t* buf_pool = buf_pool_get(space, offset);
02733 
02734   ut_ad(mtr);
02735   ut_ad(mtr->state == MTR_ACTIVE);
02736   ut_ad((rw_latch == RW_S_LATCH)
02737         || (rw_latch == RW_X_LATCH)
02738         || (rw_latch == RW_NO_LATCH));
02739   ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
02740   ut_ad(mode == BUF_GET
02741         || mode == BUF_GET_IF_IN_POOL
02742         || mode == BUF_GET_NO_LATCH
02743         || mode == BUF_GET_IF_IN_POOL_OR_WATCH);
02744   ut_ad(zip_size == fil_space_get_zip_size(space));
02745   ut_ad(ut_is_2pow(zip_size));
02746 #ifndef UNIV_LOG_DEBUG
02747   ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL));
02748 #endif
02749   buf_pool->stat.n_page_gets++;
02750   fold = buf_page_address_fold(space, offset);
02751 loop:
02752   block = guess;
02753   buf_pool_mutex_enter(buf_pool);
02754 
02755   if (block) {
02756     /* If the guess is a compressed page descriptor that
02757     has been allocated by buf_buddy_alloc(), it may have
02758     been invalidated by buf_buddy_relocate().  In that
02759     case, block could point to something that happens to
02760     contain the expected bits in block->page.  Similarly,
02761     the guess may be pointing to a buffer pool chunk that
02762     has been released when resizing the buffer pool. */
02763 
02764     if (!buf_block_is_uncompressed(buf_pool, block)
02765         || offset != block->page.offset
02766         || space != block->page.space
02767         || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
02768 
02769       block = guess = NULL;
02770     } else {
02771       ut_ad(!block->page.in_zip_hash);
02772       ut_ad(block->page.in_page_hash);
02773     }
02774   }
02775 
02776   if (block == NULL) {
02777     block = (buf_block_t*) buf_page_hash_get_low(
02778       buf_pool, space, offset, fold);
02779   }
02780 
02781 loop2:
02782   if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
02783     block = NULL;
02784   }
02785 
02786   if (block == NULL) {
02787     /* Page not in buf_pool: needs to be read from file */
02788 
02789     if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
02790       block = (buf_block_t*) buf_pool_watch_set(
02791         space, offset, fold);
02792 
02793       if (UNIV_LIKELY_NULL(block)) {
02794 
02795         goto got_block;
02796       }
02797     }
02798 
02799     buf_pool_mutex_exit(buf_pool);
02800 
02801     if (mode == BUF_GET_IF_IN_POOL
02802         || mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
02803 
02804       return(NULL);
02805     }
02806 
02807     if (buf_read_page(space, zip_size, offset)) {
02808       retries = 0;
02809     } else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
02810       ++retries;
02811     } else {
02812       fprintf(stderr, "InnoDB: Error: Unable"
02813         " to read tablespace %lu page no"
02814         " %lu into the buffer pool after"
02815         " %lu attempts\n"
02816         "InnoDB: The most probable cause"
02817         " of this error may be that the"
02818         " table has been corrupted.\n"
02819         "InnoDB: You can try to fix this"
02820         " problem by using"
02821         " innodb_force_recovery.\n"
02822         "InnoDB: Please see reference manual"
02823         " for more details.\n"
02824         "InnoDB: Aborting...\n",
02825         space, offset,
02826         BUF_PAGE_READ_MAX_RETRIES);
02827 
02828       ut_error;
02829     }
02830 
02831 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
02832     ut_a(++buf_dbg_counter % 37 || buf_validate());
02833 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
02834     goto loop;
02835   }
02836 
02837 got_block:
02838   ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
02839 
02840   must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
02841 
02842   if (must_read && mode == BUF_GET_IF_IN_POOL) {
02843 
02844     /* The page is being read to buffer pool,
02845     but we cannot wait around for the read to
02846     complete. */
02847     buf_pool_mutex_exit(buf_pool);
02848 
02849     return(NULL);
02850   }
02851 
02852   switch (buf_block_get_state(block)) {
02853     buf_page_t* bpage;
02854     ibool   success;
02855 
02856   case BUF_BLOCK_FILE_PAGE:
02857     break;
02858 
02859   case BUF_BLOCK_ZIP_PAGE:
02860   case BUF_BLOCK_ZIP_DIRTY:
02861     bpage = &block->page;
02862     /* Protect bpage->buf_fix_count. */
02863     mutex_enter(&buf_pool->zip_mutex);
02864 
02865     if (bpage->buf_fix_count
02866         || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
02867       /* This condition often occurs when the buffer
02868       is not buffer-fixed, but I/O-fixed by
02869       buf_page_init_for_read(). */
02870       mutex_exit(&buf_pool->zip_mutex);
02871 wait_until_unfixed:
02872       /* The block is buffer-fixed or I/O-fixed.
02873       Try again later. */
02874       buf_pool_mutex_exit(buf_pool);
02875       os_thread_sleep(WAIT_FOR_READ);
02876   
02877       goto loop;
02878     }
02879 
02880     /* Allocate an uncompressed page. */
02881     buf_pool_mutex_exit(buf_pool);
02882     mutex_exit(&buf_pool->zip_mutex);
02883 
02884     block = buf_LRU_get_free_block(buf_pool, 0);
02885     ut_a(block);
02886 
02887     buf_pool_mutex_enter(buf_pool);
02888     mutex_enter(&block->mutex);
02889 
02890     {
02891       buf_page_t* hash_bpage;
02892 
02893       hash_bpage = buf_page_hash_get_low(
02894         buf_pool, space, offset, fold);
02895 
02896       if (UNIV_UNLIKELY(bpage != hash_bpage)) {
02897         /* The buf_pool->page_hash was modified
02898         while buf_pool->mutex was released.
02899         Free the block that was allocated. */
02900 
02901         buf_LRU_block_free_non_file_page(block);
02902         mutex_exit(&block->mutex);
02903 
02904         block = (buf_block_t*) hash_bpage;
02905         goto loop2;
02906       }
02907     }
02908 
02909     if (UNIV_UNLIKELY
02910         (bpage->buf_fix_count
02911          || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
02912 
02913       /* The block was buffer-fixed or I/O-fixed
02914       while buf_pool->mutex was not held by this thread.
02915       Free the block that was allocated and try again.
02916       This should be extremely unlikely. */
02917 
02918       buf_LRU_block_free_non_file_page(block);
02919       mutex_exit(&block->mutex);
02920 
02921       goto wait_until_unfixed;
02922     }
02923 
02924     /* Move the compressed page from bpage to block,
02925     and uncompress it. */
02926 
02927     mutex_enter(&buf_pool->zip_mutex);
02928 
02929     buf_relocate(bpage, &block->page);
02930     buf_block_init_low(block);
02931     block->lock_hash_val = lock_rec_hash(space, offset);
02932 
02933     UNIV_MEM_DESC(&block->page.zip.data,
02934             page_zip_get_size(&block->page.zip), block);
02935 
02936     if (buf_page_get_state(&block->page)
02937         == BUF_BLOCK_ZIP_PAGE) {
02938       UT_LIST_REMOVE(list, buf_pool->zip_clean,
02939                &block->page);
02940       ut_ad(!block->page.in_flush_list);
02941     } else {
02942       /* Relocate buf_pool->flush_list. */
02943       buf_flush_relocate_on_flush_list(bpage,
02944                &block->page);
02945     }
02946 
02947     /* Buffer-fix, I/O-fix, and X-latch the block
02948     for the duration of the decompression.
02949     Also add the block to the unzip_LRU list. */
02950     block->page.state = BUF_BLOCK_FILE_PAGE;
02951 
02952     /* Insert at the front of unzip_LRU list */
02953     buf_unzip_LRU_add_block(block, FALSE);
02954 
02955     block->page.buf_fix_count = 1;
02956     buf_block_set_io_fix(block, BUF_IO_READ);
02957     rw_lock_x_lock_func(&block->lock, 0, file, line);
02958 
02959     UNIV_MEM_INVALID(bpage, sizeof *bpage);
02960 
02961     mutex_exit(&block->mutex);
02962     mutex_exit(&buf_pool->zip_mutex);
02963     buf_pool->n_pend_unzip++;
02964 
02965     buf_buddy_free(buf_pool, bpage, sizeof *bpage);
02966 
02967     buf_pool_mutex_exit(buf_pool);
02968 
02969     /* Decompress the page and apply buffered operations
02970     while not holding buf_pool->mutex or block->mutex. */
02971     success = buf_zip_decompress(block, srv_use_checksums);
02972     ut_a(success);
02973 
02974     if (UNIV_LIKELY(!recv_no_ibuf_operations)) {
02975       ibuf_merge_or_delete_for_page(block, space, offset,
02976                   zip_size, TRUE);
02977     }
02978 
02979     /* Unfix and unlatch the block. */
02980     buf_pool_mutex_enter(buf_pool);
02981     mutex_enter(&block->mutex);
02982     block->page.buf_fix_count--;
02983     buf_block_set_io_fix(block, BUF_IO_NONE);
02984     mutex_exit(&block->mutex);
02985     buf_pool->n_pend_unzip--;
02986     rw_lock_x_unlock(&block->lock);
02987 
02988     break;
02989 
02990   case BUF_BLOCK_ZIP_FREE:
02991   case BUF_BLOCK_NOT_USED:
02992   case BUF_BLOCK_READY_FOR_USE:
02993   case BUF_BLOCK_MEMORY:
02994   case BUF_BLOCK_REMOVE_HASH:
02995     ut_error;
02996     break;
02997   }
02998 
02999   ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03000 
03001   mutex_enter(&block->mutex);
03002 #if UNIV_WORD_SIZE == 4
03003   /* On 32-bit systems, there is no padding in buf_page_t.  On
03004   other systems, Valgrind could complain about uninitialized pad
03005   bytes. */
03006   UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page);
03007 #endif
03008 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
03009   if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH)
03010       && ibuf_debug) {
03011     /* Try to evict the block from the buffer pool, to use the
03012     insert buffer (change buffer) as much as possible. */
03013 
03014     if (buf_LRU_free_block(&block->page, TRUE, NULL)
03015         == BUF_LRU_FREED) {
03016       mutex_exit(&block->mutex);
03017       if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
03018         /* Set the watch, as it would have
03019         been set if the page were not in the
03020         buffer pool in the first place. */
03021         block = (buf_block_t*) buf_pool_watch_set(
03022           space, offset, fold);
03023 
03024         if (UNIV_LIKELY_NULL(block)) {
03025 
03026           /* The page entered the buffer
03027           pool for some reason. Try to
03028           evict it again. */
03029           goto got_block;
03030         }
03031       }
03032       buf_pool_mutex_exit(buf_pool);
03033       fprintf(stderr,
03034         "innodb_change_buffering_debug evict %u %u\n",
03035         (unsigned) space, (unsigned) offset);
03036       return(NULL);
03037     } else if (buf_flush_page_try(buf_pool, block)) {
03038       fprintf(stderr,
03039         "innodb_change_buffering_debug flush %u %u\n",
03040         (unsigned) space, (unsigned) offset);
03041       guess = block;
03042       goto loop;
03043     }
03044 
03045     /* Failed to evict the page; change it directly */
03046   }
03047 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
03048 
03049   buf_block_buf_fix_inc(block, file, line);
03050 
03051   mutex_exit(&block->mutex);
03052 
03053   /* Check if this is the first access to the page */
03054 
03055   access_time = buf_page_is_accessed(&block->page);
03056 
03057   buf_pool_mutex_exit(buf_pool);
03058 
03059   buf_page_set_accessed_make_young(&block->page, access_time);
03060 
03061 #ifdef UNIV_DEBUG_FILE_ACCESSES
03062   ut_a(!block->page.file_page_was_freed);
03063 #endif
03064 
03065 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03066   ut_a(++buf_dbg_counter % 5771 || buf_validate());
03067   ut_a(block->page.buf_fix_count > 0);
03068   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03069 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03070 
03071   switch (rw_latch) {
03072   case RW_NO_LATCH:
03073     if (must_read) {
03074       /* Let us wait until the read operation
03075       completes */
03076 
03077       for (;;) {
03078         enum buf_io_fix io_fix;
03079 
03080         mutex_enter(&block->mutex);
03081         io_fix = buf_block_get_io_fix(block);
03082         mutex_exit(&block->mutex);
03083 
03084         if (io_fix == BUF_IO_READ) {
03085 
03086           os_thread_sleep(WAIT_FOR_READ);
03087         } else {
03088           break;
03089         }
03090       }
03091     }
03092 
03093     fix_type = MTR_MEMO_BUF_FIX;
03094     break;
03095 
03096   case RW_S_LATCH:
03097     rw_lock_s_lock_func(&(block->lock), 0, file, line);
03098 
03099     fix_type = MTR_MEMO_PAGE_S_FIX;
03100     break;
03101 
03102   default:
03103     ut_ad(rw_latch == RW_X_LATCH);
03104     rw_lock_x_lock_func(&(block->lock), 0, file, line);
03105 
03106     fix_type = MTR_MEMO_PAGE_X_FIX;
03107     break;
03108   }
03109 
03110   mtr_memo_push(mtr, block, fix_type);
03111 
03112   if (!access_time) {
03113     /* In the case of a first access, try to apply linear
03114     read-ahead */
03115 
03116     buf_read_ahead_linear(space, zip_size, offset);
03117   }
03118 
03119 #ifdef UNIV_IBUF_COUNT_DEBUG
03120   ut_a(ibuf_count_get(buf_block_get_space(block),
03121           buf_block_get_page_no(block)) == 0);
03122 #endif
03123   return(block);
03124 }
03125 
03126 /********************************************************************/
03130 UNIV_INTERN
03131 ibool
03132 buf_page_optimistic_get(
03133 /*====================*/
03134   ulint   rw_latch,
03135   buf_block_t*  block,  
03136   ib_uint64_t modify_clock,
03138   const char* file, 
03139   ulint   line, 
03140   mtr_t*    mtr)  
03141 {
03142   buf_pool_t* buf_pool;
03143   unsigned  access_time;
03144   ibool   success;
03145   ulint   fix_type;
03146 
03147   ut_ad(block);
03148   ut_ad(mtr);
03149   ut_ad(mtr->state == MTR_ACTIVE);
03150   ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
03151 
03152   mutex_enter(&block->mutex);
03153 
03154   if (UNIV_UNLIKELY(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE)) {
03155 
03156     mutex_exit(&block->mutex);
03157 
03158     return(FALSE);
03159   }
03160 
03161   buf_block_buf_fix_inc(block, file, line);
03162 
03163   mutex_exit(&block->mutex);
03164 
03165   /* Check if this is the first access to the page.
03166   We do a dirty read on purpose, to avoid mutex contention.
03167   This field is only used for heuristic purposes; it does not
03168   affect correctness. */
03169 
03170   access_time = buf_page_is_accessed(&block->page);
03171   buf_page_set_accessed_make_young(&block->page, access_time);
03172 
03173   ut_ad(!ibuf_inside()
03174         || ibuf_page(buf_block_get_space(block),
03175          buf_block_get_zip_size(block),
03176          buf_block_get_page_no(block), NULL));
03177 
03178   if (rw_latch == RW_S_LATCH) {
03179     success = rw_lock_s_lock_nowait(&(block->lock),
03180             file, line);
03181     fix_type = MTR_MEMO_PAGE_S_FIX;
03182   } else {
03183     success = rw_lock_x_lock_func_nowait(&(block->lock),
03184                  file, line);
03185     fix_type = MTR_MEMO_PAGE_X_FIX;
03186   }
03187 
03188   if (UNIV_UNLIKELY(!success)) {
03189     mutex_enter(&block->mutex);
03190     buf_block_buf_fix_dec(block);
03191     mutex_exit(&block->mutex);
03192 
03193     return(FALSE);
03194   }
03195 
03196   if (UNIV_UNLIKELY(modify_clock != block->modify_clock)) {
03197     buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
03198 
03199     if (rw_latch == RW_S_LATCH) {
03200       rw_lock_s_unlock(&(block->lock));
03201     } else {
03202       rw_lock_x_unlock(&(block->lock));
03203     }
03204 
03205     mutex_enter(&block->mutex);
03206     buf_block_buf_fix_dec(block);
03207     mutex_exit(&block->mutex);
03208 
03209     return(FALSE);
03210   }
03211 
03212   mtr_memo_push(mtr, block, fix_type);
03213 
03214 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03215   ut_a(++buf_dbg_counter % 5771 || buf_validate());
03216   ut_a(block->page.buf_fix_count > 0);
03217   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03218 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03219 
03220 #ifdef UNIV_DEBUG_FILE_ACCESSES
03221   ut_a(block->page.file_page_was_freed == FALSE);
03222 #endif
03223   if (UNIV_UNLIKELY(!access_time)) {
03224     /* In the case of a first access, try to apply linear
03225     read-ahead */
03226 
03227     buf_read_ahead_linear(buf_block_get_space(block),
03228               buf_block_get_zip_size(block),
03229               buf_block_get_page_no(block));
03230   }
03231 
03232 #ifdef UNIV_IBUF_COUNT_DEBUG
03233   ut_a(ibuf_count_get(buf_block_get_space(block),
03234           buf_block_get_page_no(block)) == 0);
03235 #endif
03236   buf_pool = buf_pool_from_block(block);
03237   buf_pool->stat.n_page_gets++;
03238 
03239   return(TRUE);
03240 }
03241 
03242 /********************************************************************/
03247 UNIV_INTERN
03248 ibool
03249 buf_page_get_known_nowait(
03250 /*======================*/
03251   ulint   rw_latch,
03252   buf_block_t*  block,  
03253   ulint   mode, 
03254   const char* file, 
03255   ulint   line, 
03256   mtr_t*    mtr)  
03257 {
03258   buf_pool_t* buf_pool;
03259   ibool   success;
03260   ulint   fix_type;
03261 
03262   ut_ad(mtr);
03263   ut_ad(mtr->state == MTR_ACTIVE);
03264   ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
03265 
03266   mutex_enter(&block->mutex);
03267 
03268   if (buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH) {
03269     /* Another thread is just freeing the block from the LRU list
03270     of the buffer pool: do not try to access this page; this
03271     attempt to access the page can only come through the hash
03272     index because when the buffer block state is ..._REMOVE_HASH,
03273     we have already removed it from the page address hash table
03274     of the buffer pool. */
03275 
03276     mutex_exit(&block->mutex);
03277 
03278     return(FALSE);
03279   }
03280 
03281   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03282 
03283   buf_block_buf_fix_inc(block, file, line);
03284 
03285   mutex_exit(&block->mutex);
03286 
03287   buf_pool = buf_pool_from_block(block);
03288 
03289   if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) {
03290     buf_pool_mutex_enter(buf_pool);
03291     buf_LRU_make_block_young(&block->page);
03292     buf_pool_mutex_exit(buf_pool);
03293   } else if (!buf_page_is_accessed(&block->page)) {
03294     /* Above, we do a dirty read on purpose, to avoid
03295     mutex contention.  The field buf_page_t::access_time
03296     is only used for heuristic purposes.  Writes to the
03297     field must be protected by mutex, however. */
03298     ulint time_ms = ut_time_ms();
03299 
03300     buf_pool_mutex_enter(buf_pool);
03301     buf_page_set_accessed(&block->page, time_ms);
03302     buf_pool_mutex_exit(buf_pool);
03303   }
03304 
03305   ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
03306 
03307   if (rw_latch == RW_S_LATCH) {
03308     success = rw_lock_s_lock_nowait(&(block->lock),
03309             file, line);
03310     fix_type = MTR_MEMO_PAGE_S_FIX;
03311   } else {
03312     success = rw_lock_x_lock_func_nowait(&(block->lock),
03313                  file, line);
03314     fix_type = MTR_MEMO_PAGE_X_FIX;
03315   }
03316 
03317   if (!success) {
03318     mutex_enter(&block->mutex);
03319     buf_block_buf_fix_dec(block);
03320     mutex_exit(&block->mutex);
03321 
03322     return(FALSE);
03323   }
03324 
03325   mtr_memo_push(mtr, block, fix_type);
03326 
03327 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03328   ut_a(++buf_dbg_counter % 5771 || buf_validate());
03329   ut_a(block->page.buf_fix_count > 0);
03330   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03331 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03332 #ifdef UNIV_DEBUG_FILE_ACCESSES
03333   ut_a(block->page.file_page_was_freed == FALSE);
03334 #endif
03335 
03336 #ifdef UNIV_IBUF_COUNT_DEBUG
03337   ut_a((mode == BUF_KEEP_OLD)
03338        || (ibuf_count_get(buf_block_get_space(block),
03339         buf_block_get_page_no(block)) == 0));
03340 #endif
03341   buf_pool->stat.n_page_gets++;
03342 
03343   return(TRUE);
03344 }
03345 
03346 /*******************************************************************/
03351 UNIV_INTERN
03352 const buf_block_t*
03353 buf_page_try_get_func(
03354 /*==================*/
03355   ulint   space_id,
03356   ulint   page_no,
03357   const char* file, 
03358   ulint   line, 
03359   mtr_t*    mtr)  
03360 {
03361   buf_block_t*  block;
03362   ibool   success;
03363   ulint   fix_type;
03364   buf_pool_t* buf_pool = buf_pool_get(space_id, page_no);
03365 
03366   ut_ad(mtr);
03367   ut_ad(mtr->state == MTR_ACTIVE);
03368 
03369   buf_pool_mutex_enter(buf_pool);
03370   block = buf_block_hash_get(buf_pool, space_id, page_no);
03371 
03372   if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
03373     buf_pool_mutex_exit(buf_pool);
03374     return(NULL);
03375   }
03376 
03377   ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
03378 
03379   mutex_enter(&block->mutex);
03380   buf_pool_mutex_exit(buf_pool);
03381 
03382 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03383   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03384   ut_a(buf_block_get_space(block) == space_id);
03385   ut_a(buf_block_get_page_no(block) == page_no);
03386 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03387 
03388   buf_block_buf_fix_inc(block, file, line);
03389   mutex_exit(&block->mutex);
03390 
03391   fix_type = MTR_MEMO_PAGE_S_FIX;
03392   success = rw_lock_s_lock_nowait(&block->lock, file, line);
03393 
03394   if (!success) {
03395     /* Let us try to get an X-latch. If the current thread
03396     is holding an X-latch on the page, we cannot get an
03397     S-latch. */
03398 
03399     fix_type = MTR_MEMO_PAGE_X_FIX;
03400     success = rw_lock_x_lock_func_nowait(&block->lock,
03401                  file, line);
03402   }
03403 
03404   if (!success) {
03405     mutex_enter(&block->mutex);
03406     buf_block_buf_fix_dec(block);
03407     mutex_exit(&block->mutex);
03408 
03409     return(NULL);
03410   }
03411 
03412   mtr_memo_push(mtr, block, fix_type);
03413 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03414   ut_a(++buf_dbg_counter % 5771 || buf_validate());
03415   ut_a(block->page.buf_fix_count > 0);
03416   ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
03417 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03418 #ifdef UNIV_DEBUG_FILE_ACCESSES
03419   ut_a(block->page.file_page_was_freed == FALSE);
03420 #endif /* UNIV_DEBUG_FILE_ACCESSES */
03421   buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
03422 
03423   buf_pool->stat.n_page_gets++;
03424 
03425 #ifdef UNIV_IBUF_COUNT_DEBUG
03426   ut_a(ibuf_count_get(buf_block_get_space(block),
03427           buf_block_get_page_no(block)) == 0);
03428 #endif
03429 
03430   return(block);
03431 }
03432 
03433 /********************************************************************/
03435 UNIV_INLINE
03436 void
03437 buf_page_init_low(
03438 /*==============*/
03439   buf_page_t* bpage)  
03440 {
03441   bpage->flush_type = BUF_FLUSH_LRU;
03442   bpage->io_fix = BUF_IO_NONE;
03443   bpage->buf_fix_count = 0;
03444   bpage->freed_page_clock = 0;
03445   bpage->access_time = 0;
03446   bpage->newest_modification = 0;
03447   bpage->oldest_modification = 0;
03448   HASH_INVALIDATE(bpage, hash);
03449 #ifdef UNIV_DEBUG_FILE_ACCESSES
03450   bpage->file_page_was_freed = FALSE;
03451 #endif /* UNIV_DEBUG_FILE_ACCESSES */
03452 }
03453 
03454 /********************************************************************/
03456 static
03457 void
03458 buf_page_init(
03459 /*==========*/
03460   ulint   space,  
03461   ulint   offset, 
03463   ulint   fold, 
03464   buf_block_t*  block)  
03465 {
03466   buf_page_t* hash_page;
03467   buf_pool_t* buf_pool = buf_pool_get(space, offset);
03468 
03469   ut_ad(buf_pool_mutex_own(buf_pool));
03470   ut_ad(mutex_own(&(block->mutex)));
03471   ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
03472 
03473   /* Set the state of the block */
03474   buf_block_set_file_page(block, space, offset);
03475 
03476 #ifdef UNIV_DEBUG_VALGRIND
03477   if (!space) {
03478     /* Silence valid Valgrind warnings about uninitialized
03479     data being written to data files.  There are some unused
03480     bytes on some pages that InnoDB does not initialize. */
03481     UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
03482   }
03483 #endif /* UNIV_DEBUG_VALGRIND */
03484 
03485   buf_block_init_low(block);
03486 
03487   block->lock_hash_val = lock_rec_hash(space, offset);
03488 
03489   buf_page_init_low(&block->page);
03490 
03491   /* Insert into the hash table of file pages */
03492 
03493   hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
03494 
03495   if (UNIV_LIKELY(!hash_page)) {
03496   } else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) {
03497     /* Preserve the reference count. */
03498     ulint buf_fix_count = hash_page->buf_fix_count;
03499 
03500     ut_a(buf_fix_count > 0);
03501     block->page.buf_fix_count += buf_fix_count;
03502     buf_pool_watch_remove(buf_pool, fold, hash_page);
03503   } else {
03504     fprintf(stderr,
03505       "InnoDB: Error: page %lu %lu already found"
03506       " in the hash table: %p, %p\n",
03507       (ulong) space,
03508       (ulong) offset,
03509       (const void*) hash_page, (const void*) block);
03510 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03511     mutex_exit(&block->mutex);
03512     buf_pool_mutex_exit(buf_pool);
03513     buf_print();
03514     buf_LRU_print();
03515     buf_validate();
03516     buf_LRU_validate();
03517 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03518     ut_error;
03519   }
03520 
03521   ut_ad(!block->page.in_zip_hash);
03522   ut_ad(!block->page.in_page_hash);
03523   ut_d(block->page.in_page_hash = TRUE);
03524   HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
03525         fold, &block->page);
03526 }
03527 
03528 /********************************************************************/
03538 UNIV_INTERN
03539 buf_page_t*
03540 buf_page_init_for_read(
03541 /*===================*/
03542   ulint*    err,  
03543   ulint   mode, 
03544   ulint   space,  
03545   ulint   zip_size,
03546   ibool   unzip,  
03547   ib_int64_t  tablespace_version,
03551   ulint   offset) 
03552 {
03553   buf_block_t*  block;
03554   buf_page_t* bpage = NULL;
03555   buf_page_t* watch_page;
03556   mtr_t   mtr;
03557   ulint   fold;
03558   ibool   lru = FALSE;
03559   void*   data;
03560   buf_pool_t* buf_pool = buf_pool_get(space, offset);
03561 
03562   ut_ad(buf_pool);
03563 
03564   *err = DB_SUCCESS;
03565 
03566   if (mode == BUF_READ_IBUF_PAGES_ONLY) {
03567     /* It is a read-ahead within an ibuf routine */
03568 
03569     ut_ad(!ibuf_bitmap_page(zip_size, offset));
03570     ut_ad(ibuf_inside());
03571 
03572     mtr_start(&mtr);
03573 
03574     if (!recv_no_ibuf_operations
03575         && !ibuf_page(space, zip_size, offset, &mtr)) {
03576 
03577       mtr_commit(&mtr);
03578 
03579       return(NULL);
03580     }
03581   } else {
03582     ut_ad(mode == BUF_READ_ANY_PAGE);
03583   }
03584 
03585   if (zip_size && UNIV_LIKELY(!unzip)
03586       && UNIV_LIKELY(!recv_recovery_is_on())) {
03587     block = NULL;
03588   } else {
03589     block = buf_LRU_get_free_block(buf_pool, 0);
03590     ut_ad(block);
03591     ut_ad(buf_pool_from_block(block) == buf_pool);
03592   }
03593 
03594   fold = buf_page_address_fold(space, offset);
03595 
03596   buf_pool_mutex_enter(buf_pool);
03597 
03598   watch_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
03599   if (watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page)) {
03600     /* The page is already in the buffer pool. */
03601     watch_page = NULL;
03602 err_exit:
03603     if (block) {
03604       mutex_enter(&block->mutex);
03605       buf_LRU_block_free_non_file_page(block);
03606       mutex_exit(&block->mutex);
03607     }
03608 
03609     bpage = NULL;
03610     goto func_exit;
03611   }
03612 
03613   if (fil_tablespace_deleted_or_being_deleted_in_mem(
03614         space, tablespace_version)) {
03615     /* The page belongs to a space which has been
03616     deleted or is being deleted. */
03617     *err = DB_TABLESPACE_DELETED;
03618 
03619     goto err_exit;
03620   }
03621 
03622   if (block) {
03623     bpage = &block->page;
03624     mutex_enter(&block->mutex);
03625 
03626     ut_ad(buf_pool_from_bpage(bpage) == buf_pool);
03627 
03628     buf_page_init(space, offset, fold, block);
03629 
03630     /* The block must be put to the LRU list, to the old blocks */
03631     buf_LRU_add_block(bpage, TRUE/* to old blocks */);
03632 
03633     /* We set a pass-type x-lock on the frame because then
03634     the same thread which called for the read operation
03635     (and is running now at this point of code) can wait
03636     for the read to complete by waiting for the x-lock on
03637     the frame; if the x-lock were recursive, the same
03638     thread would illegally get the x-lock before the page
03639     read is completed.  The x-lock is cleared by the
03640     io-handler thread. */
03641 
03642     rw_lock_x_lock_gen(&block->lock, BUF_IO_READ);
03643     buf_page_set_io_fix(bpage, BUF_IO_READ);
03644 
03645     if (UNIV_UNLIKELY(zip_size)) {
03646       page_zip_set_size(&block->page.zip, zip_size);
03647 
03648       /* buf_pool->mutex may be released and
03649       reacquired by buf_buddy_alloc().  Thus, we
03650       must release block->mutex in order not to
03651       break the latching order in the reacquisition
03652       of buf_pool->mutex.  We also must defer this
03653       operation until after the block descriptor has
03654       been added to buf_pool->LRU and
03655       buf_pool->page_hash. */
03656       mutex_exit(&block->mutex);
03657       data = buf_buddy_alloc(buf_pool, zip_size, &lru);
03658       mutex_enter(&block->mutex);
03659       block->page.zip.data = static_cast<unsigned char *>(data);
03660 
03661       /* To maintain the invariant
03662       block->in_unzip_LRU_list
03663       == buf_page_belongs_to_unzip_LRU(&block->page)
03664       we have to add this block to unzip_LRU
03665       after block->page.zip.data is set. */
03666       ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
03667       buf_unzip_LRU_add_block(block, TRUE);
03668     }
03669 
03670     mutex_exit(&block->mutex);
03671   } else {
03672     /* Defer buf_buddy_alloc() until after the block has
03673     been found not to exist.  The buf_buddy_alloc() and
03674     buf_buddy_free() calls may be expensive because of
03675     buf_buddy_relocate(). */
03676 
03677     /* The compressed page must be allocated before the
03678     control block (bpage), in order to avoid the
03679     invocation of buf_buddy_relocate_block() on
03680     uninitialized data. */
03681     data = buf_buddy_alloc(buf_pool, zip_size, &lru);
03682     bpage = static_cast<buf_page_struct *>(buf_buddy_alloc(buf_pool, sizeof *bpage, &lru));
03683 
03684     /* Initialize the buf_pool pointer. */
03685     bpage->buf_pool_index = buf_pool_index(buf_pool);
03686 
03687     /* If buf_buddy_alloc() allocated storage from the LRU list,
03688     it released and reacquired buf_pool->mutex.  Thus, we must
03689     check the page_hash again, as it may have been modified. */
03690     if (UNIV_UNLIKELY(lru)) {
03691 
03692       watch_page = buf_page_hash_get_low(
03693         buf_pool, space, offset, fold);
03694 
03695       if (watch_page
03696           && !buf_pool_watch_is_sentinel(buf_pool,
03697                    watch_page)) {
03698 
03699         /* The block was added by some other thread. */
03700         watch_page = NULL;
03701         buf_buddy_free(buf_pool, bpage, sizeof *bpage);
03702         buf_buddy_free(buf_pool, data, zip_size);
03703 
03704         bpage = NULL;
03705         goto func_exit;
03706       }
03707     }
03708 
03709     page_zip_des_init(&bpage->zip);
03710     page_zip_set_size(&bpage->zip, zip_size);
03711     bpage->zip.data = static_cast<unsigned char *>(data);
03712 
03713     mutex_enter(&buf_pool->zip_mutex);
03714     UNIV_MEM_DESC(bpage->zip.data,
03715             page_zip_get_size(&bpage->zip), bpage);
03716 
03717     buf_page_init_low(bpage);
03718 
03719     bpage->state  = BUF_BLOCK_ZIP_PAGE;
03720     bpage->space  = space;
03721     bpage->offset = offset;
03722 
03723 
03724 #ifdef UNIV_DEBUG
03725     bpage->in_page_hash = FALSE;
03726     bpage->in_zip_hash = FALSE;
03727     bpage->in_flush_list = FALSE;
03728     bpage->in_free_list = FALSE;
03729     bpage->in_LRU_list = FALSE;
03730 #endif /* UNIV_DEBUG */
03731 
03732     ut_d(bpage->in_page_hash = TRUE);
03733 
03734     if (UNIV_LIKELY_NULL(watch_page)) {
03735       /* Preserve the reference count. */
03736       ulint buf_fix_count = watch_page->buf_fix_count;
03737       ut_a(buf_fix_count > 0);
03738       bpage->buf_fix_count += buf_fix_count;
03739       ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page));
03740       buf_pool_watch_remove(buf_pool, fold, watch_page);
03741     }
03742 
03743     HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold,
03744           bpage);
03745 
03746     /* The block must be put to the LRU list, to the old blocks */
03747     buf_LRU_add_block(bpage, TRUE/* to old blocks */);
03748     buf_LRU_insert_zip_clean(bpage);
03749 
03750     buf_page_set_io_fix(bpage, BUF_IO_READ);
03751 
03752     mutex_exit(&buf_pool->zip_mutex);
03753   }
03754 
03755   buf_pool->n_pend_reads++;
03756 func_exit:
03757   buf_pool_mutex_exit(buf_pool);
03758 
03759   if (mode == BUF_READ_IBUF_PAGES_ONLY) {
03760 
03761     mtr_commit(&mtr);
03762   }
03763 
03764   ut_ad(!bpage || buf_page_in_file(bpage));
03765   return(bpage);
03766 }
03767 
03768 /********************************************************************/
03774 UNIV_INTERN
03775 buf_block_t*
03776 buf_page_create(
03777 /*============*/
03778   ulint space,  
03779   ulint offset, 
03781   ulint zip_size,
03782   mtr_t*  mtr)  
03783 {
03784   buf_frame_t*  frame;
03785   buf_block_t*  block;
03786   ulint   fold;
03787   buf_block_t*  free_block  = NULL;
03788   ulint   time_ms   = ut_time_ms();
03789   buf_pool_t* buf_pool  = buf_pool_get(space, offset);
03790 
03791   ut_ad(mtr);
03792   ut_ad(mtr->state == MTR_ACTIVE);
03793   ut_ad(space || !zip_size);
03794 
03795   free_block = buf_LRU_get_free_block(buf_pool, 0);
03796 
03797   fold = buf_page_address_fold(space, offset);
03798 
03799   buf_pool_mutex_enter(buf_pool);
03800 
03801   block = (buf_block_t*) buf_page_hash_get_low(
03802     buf_pool, space, offset, fold);
03803 
03804   if (block
03805       && buf_page_in_file(&block->page)
03806       && !buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
03807 #ifdef UNIV_IBUF_COUNT_DEBUG
03808     ut_a(ibuf_count_get(space, offset) == 0);
03809 #endif
03810 #ifdef UNIV_DEBUG_FILE_ACCESSES
03811     block->page.file_page_was_freed = FALSE;
03812 #endif /* UNIV_DEBUG_FILE_ACCESSES */
03813 
03814     /* Page can be found in buf_pool */
03815     buf_pool_mutex_exit(buf_pool);
03816 
03817     buf_block_free(free_block);
03818 
03819     return(buf_page_get_with_no_latch(space, zip_size,
03820               offset, mtr));
03821   }
03822 
03823   /* If we get here, the page was not in buf_pool: init it there */
03824 
03825 #ifdef UNIV_DEBUG
03826   if (buf_debug_prints) {
03827     fprintf(stderr, "Creating space %lu page %lu to buffer\n",
03828       (ulong) space, (ulong) offset);
03829   }
03830 #endif /* UNIV_DEBUG */
03831 
03832   block = free_block;
03833 
03834   mutex_enter(&block->mutex);
03835 
03836   buf_page_init(space, offset, fold, block);
03837 
03838   /* The block must be put to the LRU list */
03839   buf_LRU_add_block(&block->page, FALSE);
03840 
03841   buf_block_buf_fix_inc(block, __FILE__, __LINE__);
03842   buf_pool->stat.n_pages_created++;
03843 
03844   if (zip_size) {
03845     void* data;
03846     ibool lru;
03847 
03848     /* Prevent race conditions during buf_buddy_alloc(),
03849     which may release and reacquire buf_pool->mutex,
03850     by IO-fixing and X-latching the block. */
03851 
03852     buf_page_set_io_fix(&block->page, BUF_IO_READ);
03853     rw_lock_x_lock(&block->lock);
03854 
03855     page_zip_set_size(&block->page.zip, zip_size);
03856     mutex_exit(&block->mutex);
03857     /* buf_pool->mutex may be released and reacquired by
03858     buf_buddy_alloc().  Thus, we must release block->mutex
03859     in order not to break the latching order in
03860     the reacquisition of buf_pool->mutex.  We also must
03861     defer this operation until after the block descriptor
03862     has been added to buf_pool->LRU and buf_pool->page_hash. */
03863     data = buf_buddy_alloc(buf_pool, zip_size, &lru);
03864     mutex_enter(&block->mutex);
03865     block->page.zip.data = static_cast<unsigned char *>(data);
03866 
03867     /* To maintain the invariant
03868     block->in_unzip_LRU_list
03869     == buf_page_belongs_to_unzip_LRU(&block->page)
03870     we have to add this block to unzip_LRU after
03871     block->page.zip.data is set. */
03872     ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
03873     buf_unzip_LRU_add_block(block, FALSE);
03874 
03875     buf_page_set_io_fix(&block->page, BUF_IO_NONE);
03876     rw_lock_x_unlock(&block->lock);
03877   }
03878 
03879   buf_page_set_accessed(&block->page, time_ms);
03880 
03881   buf_pool_mutex_exit(buf_pool);
03882 
03883   mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
03884 
03885   mutex_exit(&block->mutex);
03886 
03887   /* Delete possible entries for the page from the insert buffer:
03888   such can exist if the page belonged to an index which was dropped */
03889 
03890   ibuf_merge_or_delete_for_page(NULL, space, offset, zip_size, TRUE);
03891 
03892   /* Flush pages from the end of the LRU list if necessary */
03893   buf_flush_free_margin(buf_pool);
03894 
03895   frame = block->frame;
03896 
03897   memset(frame + FIL_PAGE_PREV, 0xff, 4);
03898   memset(frame + FIL_PAGE_NEXT, 0xff, 4);
03899   mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
03900 
03901   /* Reset to zero the file flush lsn field in the page; if the first
03902   page of an ibdata file is 'created' in this function into the buffer
03903   pool then we lose the original contents of the file flush lsn stamp.
03904   Then InnoDB could in a crash recovery print a big, false, corruption
03905   warning if the stamp contains an lsn bigger than the ib_logfile lsn. */
03906 
03907   memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
03908 
03909 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
03910   ut_a(++buf_dbg_counter % 357 || buf_validate());
03911 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
03912 #ifdef UNIV_IBUF_COUNT_DEBUG
03913   ut_a(ibuf_count_get(buf_block_get_space(block),
03914           buf_block_get_page_no(block)) == 0);
03915 #endif
03916   return(block);
03917 }
03918 
03919 /********************************************************************/
03922 UNIV_INTERN
03923 void
03924 buf_page_io_complete(
03925 /*=================*/
03926   buf_page_t* bpage)  
03927 {
03928   enum buf_io_fix io_type;
03929   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
03930   const ibool uncompressed = (buf_page_get_state(bpage)
03931           == BUF_BLOCK_FILE_PAGE);
03932 
03933   ut_a(buf_page_in_file(bpage));
03934 
03935   /* We do not need protect io_fix here by mutex to read
03936   it because this is the only function where we can change the value
03937   from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code
03938   ensures that this is the only thread that handles the i/o for this
03939   block. */
03940 
03941   io_type = buf_page_get_io_fix(bpage);
03942   ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
03943 
03944   if (io_type == BUF_IO_READ) {
03945     ulint read_page_no;
03946     ulint read_space_id;
03947     byte* frame;
03948 
03949     if (buf_page_get_zip_size(bpage)) {
03950       frame = bpage->zip.data;
03951       buf_pool->n_pend_unzip++;
03952       if (uncompressed
03953           && !buf_zip_decompress((buf_block_t*) bpage,
03954                FALSE)) {
03955 
03956         buf_pool->n_pend_unzip--;
03957         goto corrupt;
03958       }
03959       buf_pool->n_pend_unzip--;
03960     } else {
03961       ut_a(uncompressed);
03962       frame = ((buf_block_t*) bpage)->frame;
03963     }
03964 
03965     /* If this page is not uninitialized and not in the
03966     doublewrite buffer, then the page number and space id
03967     should be the same as in block. */
03968     read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
03969     read_space_id = mach_read_from_4(
03970       frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
03971 
03972     if (bpage->space == TRX_SYS_SPACE
03973         && trx_doublewrite_page_inside(bpage->offset)) {
03974 
03975       ut_print_timestamp(stderr);
03976       fprintf(stderr,
03977         "  InnoDB: Error: reading page %lu\n"
03978         "InnoDB: which is in the"
03979         " doublewrite buffer!\n",
03980         (ulong) bpage->offset);
03981     } else if (!read_space_id && !read_page_no) {
03982       /* This is likely an uninitialized page. */
03983     } else if ((bpage->space
03984           && bpage->space != read_space_id)
03985          || bpage->offset != read_page_no) {
03986       /* We did not compare space_id to read_space_id
03987       if bpage->space == 0, because the field on the
03988       page may contain garbage in MySQL < 4.1.1,
03989       which only supported bpage->space == 0. */
03990 
03991       ut_print_timestamp(stderr);
03992       fprintf(stderr,
03993         "  InnoDB: Error: space id and page n:o"
03994         " stored in the page\n"
03995         "InnoDB: read in are %lu:%lu,"
03996         " should be %lu:%lu!\n",
03997         (ulong) read_space_id, (ulong) read_page_no,
03998         (ulong) bpage->space,
03999         (ulong) bpage->offset);
04000     }
04001 
04002     /* From version 3.23.38 up we store the page checksum
04003     to the 4 first bytes of the page end lsn field */
04004 
04005     if (buf_page_is_corrupted(frame,
04006             buf_page_get_zip_size(bpage))) {
04007 corrupt:
04008       fprintf(stderr,
04009         "InnoDB: Database page corruption on disk"
04010         " or a failed\n"
04011         "InnoDB: file read of page %lu.\n"
04012         "InnoDB: You may have to recover"
04013         " from a backup.\n",
04014         (ulong) bpage->offset);
04015       buf_page_print(frame, buf_page_get_zip_size(bpage));
04016       fprintf(stderr,
04017         "InnoDB: Database page corruption on disk"
04018         " or a failed\n"
04019         "InnoDB: file read of page %lu.\n"
04020         "InnoDB: You may have to recover"
04021         " from a backup.\n",
04022         (ulong) bpage->offset);
04023       fputs("InnoDB: It is also possible that"
04024             " your operating\n"
04025             "InnoDB: system has corrupted its"
04026             " own file cache\n"
04027             "InnoDB: and rebooting your computer"
04028             " removes the\n"
04029             "InnoDB: error.\n"
04030             "InnoDB: If the corrupt page is an index page\n"
04031             "InnoDB: you can also try to"
04032             " fix the corruption\n"
04033             "InnoDB: by dumping, dropping,"
04034             " and reimporting\n"
04035             "InnoDB: the corrupt table."
04036             " You can use CHECK\n"
04037             "InnoDB: TABLE to scan your"
04038             " table for corruption.\n"
04039             "InnoDB: See also "
04040             REFMAN "forcing-recovery.html\n"
04041             "InnoDB: about forcing recovery.\n", stderr);
04042 
04043       if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
04044         fputs("InnoDB: Ending processing because of"
04045               " a corrupt database page.\n",
04046               stderr);
04047         exit(1);
04048       }
04049     }
04050 
04051     if (recv_recovery_is_on()) {
04052       /* Pages must be uncompressed for crash recovery. */
04053       ut_a(uncompressed);
04054       recv_recover_page(TRUE, (buf_block_t*) bpage);
04055     }
04056 
04057     if (uncompressed && !recv_no_ibuf_operations && !srv_fake_write) {
04058       ibuf_merge_or_delete_for_page(
04059         (buf_block_t*) bpage, bpage->space,
04060         bpage->offset, buf_page_get_zip_size(bpage),
04061         TRUE);
04062     }
04063   }
04064 
04065   buf_pool_mutex_enter(buf_pool);
04066   mutex_enter(buf_page_get_mutex(bpage));
04067 
04068 #ifdef UNIV_IBUF_COUNT_DEBUG
04069   if (io_type == BUF_IO_WRITE || uncompressed) {
04070     /* For BUF_IO_READ of compressed-only blocks, the
04071     buffered operations will be merged by buf_page_get_gen()
04072     after the block has been uncompressed. */
04073     ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
04074   }
04075 #endif
04076   /* Because this thread which does the unlocking is not the same that
04077   did the locking, we use a pass value != 0 in unlock, which simply
04078   removes the newest lock debug record, without checking the thread
04079   id. */
04080 
04081   buf_page_set_io_fix(bpage, BUF_IO_NONE);
04082 
04083   switch (io_type) {
04084   case BUF_IO_READ:
04085     /* NOTE that the call to ibuf may have moved the ownership of
04086     the x-latch to this OS thread: do not let this confuse you in
04087     debugging! */
04088 
04089     ut_ad(buf_pool->n_pend_reads > 0);
04090     buf_pool->n_pend_reads--;
04091     buf_pool->stat.n_pages_read++;
04092 
04093     if (uncompressed) {
04094       rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
04095                BUF_IO_READ);
04096     }
04097 
04098     break;
04099 
04100   case BUF_IO_WRITE:
04101     /* Write means a flush operation: call the completion
04102     routine in the flush system */
04103 
04104     buf_flush_write_complete(bpage);
04105 
04106     if (uncompressed) {
04107       rw_lock_s_unlock_gen(&((buf_block_t*) bpage)->lock,
04108                BUF_IO_WRITE);
04109     }
04110 
04111     buf_pool->stat.n_pages_written++;
04112 
04113     break;
04114 
04115   default:
04116     ut_error;
04117   }
04118 
04119 #ifdef UNIV_DEBUG
04120   if (buf_debug_prints) {
04121     fprintf(stderr, "Has %s page space %lu page no %lu\n",
04122       io_type == BUF_IO_READ ? "read" : "written",
04123       (ulong) buf_page_get_space(bpage),
04124       (ulong) buf_page_get_page_no(bpage));
04125   }
04126 #endif /* UNIV_DEBUG */
04127 
04128   mutex_exit(buf_page_get_mutex(bpage));
04129   buf_pool_mutex_exit(buf_pool);
04130 }
04131 
04132 /*********************************************************************/
04135 static
04136 ibool
04137 buf_all_freed_instance(
04138 /*===================*/
04139   buf_pool_t* buf_pool) 
04140 {
04141   ulint   i;
04142   buf_chunk_t*  chunk;
04143 
04144   ut_ad(buf_pool);
04145 
04146   buf_pool_mutex_enter(buf_pool);
04147 
04148   chunk = buf_pool->chunks;
04149 
04150   for (i = buf_pool->n_chunks; i--; chunk++) {
04151 
04152     const buf_block_t* block = buf_chunk_not_freed(chunk);
04153 
04154     if (UNIV_LIKELY_NULL(block)) {
04155       fprintf(stderr,
04156         "Page %lu %lu still fixed or dirty\n",
04157         (ulong) block->page.space,
04158         (ulong) block->page.offset);
04159       ut_error;
04160     }
04161   }
04162 
04163   buf_pool_mutex_exit(buf_pool);
04164 
04165   return(TRUE);
04166 }
04167 
04168 /*********************************************************************/
04170 static
04171 void
04172 buf_pool_invalidate_instance(
04173 /*=========================*/
04174   buf_pool_t* buf_pool) 
04175 {
04176   ibool   freed;
04177   int i;
04178 
04179   buf_pool_mutex_enter(buf_pool);
04180 
04181   for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
04182 
04183     /* As this function is called during startup and
04184     during redo application phase during recovery, InnoDB
04185     is single threaded (apart from IO helper threads) at
04186     this stage. No new write batch can be in intialization
04187     stage at this point. */
04188     ut_ad(buf_pool->init_flush[i] == FALSE);
04189 
04190     /* However, it is possible that a write batch that has
04191     been posted earlier is still not complete. For buffer
04192     pool invalidation to proceed we must ensure there is NO
04193     write activity happening. */
04194     if (buf_pool->n_flush[i] > 0) {
04195       buf_pool_mutex_exit(buf_pool);
04196       buf_flush_wait_batch_end(buf_pool, static_cast<buf_flush>(i));
04197       buf_pool_mutex_enter(buf_pool);
04198     }
04199   }
04200 
04201   buf_pool_mutex_exit(buf_pool);
04202 
04203   ut_ad(buf_all_freed_instance(buf_pool));
04204 
04205   freed = TRUE;
04206 
04207   while (freed) {
04208     freed = buf_LRU_search_and_free_block(buf_pool, 100);
04209   }
04210 
04211   buf_pool_mutex_enter(buf_pool);
04212 
04213   ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
04214   ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0);
04215 
04216   buf_pool->freed_page_clock = 0;
04217   buf_pool->LRU_old = NULL;
04218   buf_pool->LRU_old_len = 0;
04219   buf_pool->LRU_flush_ended = 0;
04220 
04221   memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat));
04222   buf_refresh_io_stats(buf_pool);
04223 
04224   buf_pool_mutex_exit(buf_pool);
04225 }
04226 
04227 /*********************************************************************/
04231 UNIV_INTERN
04232 void
04233 buf_pool_invalidate(void)
04234 /*=====================*/
04235 {
04236   ulint   i;
04237 
04238   for (i = 0; i < srv_buf_pool_instances; i++) {
04239     buf_pool_invalidate_instance(buf_pool_from_array(i));
04240   }
04241 }
04242 
04243 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
04244 /*********************************************************************/
04247 static
04248 ibool
04249 buf_pool_validate_instance(
04250 /*=======================*/
04251   buf_pool_t* buf_pool) 
04252 {
04253   buf_page_t* b;
04254   buf_chunk_t*  chunk;
04255   ulint   i;
04256   ulint   n_single_flush  = 0;
04257   ulint   n_lru_flush = 0;
04258   ulint   n_list_flush  = 0;
04259   ulint   n_lru   = 0;
04260   ulint   n_flush   = 0;
04261   ulint   n_free    = 0;
04262   ulint   n_zip   = 0;
04263 
04264   ut_ad(buf_pool);
04265 
04266   buf_pool_mutex_enter(buf_pool);
04267 
04268   chunk = buf_pool->chunks;
04269 
04270   /* Check the uncompressed blocks. */
04271 
04272   for (i = buf_pool->n_chunks; i--; chunk++) {
04273 
04274     ulint   j;
04275     buf_block_t*  block = chunk->blocks;
04276 
04277     for (j = chunk->size; j--; block++) {
04278 
04279       mutex_enter(&block->mutex);
04280 
04281       switch (buf_block_get_state(block)) {
04282       case BUF_BLOCK_ZIP_FREE:
04283       case BUF_BLOCK_ZIP_PAGE:
04284       case BUF_BLOCK_ZIP_DIRTY:
04285         /* These should only occur on
04286         zip_clean, zip_free[], or flush_list. */
04287         ut_error;
04288         break;
04289 
04290       case BUF_BLOCK_FILE_PAGE:
04291         ut_a(buf_page_hash_get(buf_pool,
04292                    buf_block_get_space(
04293                      block),
04294                    buf_block_get_page_no(
04295                      block))
04296              == &block->page);
04297 
04298 #ifdef UNIV_IBUF_COUNT_DEBUG
04299         ut_a(buf_page_get_io_fix(&block->page)
04300              == BUF_IO_READ
04301              || !ibuf_count_get(buf_block_get_space(
04302                 block),
04303               buf_block_get_page_no(
04304                 block)));
04305 #endif
04306         switch (buf_page_get_io_fix(&block->page)) {
04307         case BUF_IO_NONE:
04308           break;
04309 
04310         case BUF_IO_WRITE:
04311           switch (buf_page_get_flush_type(
04312               &block->page)) {
04313           case BUF_FLUSH_LRU:
04314             n_lru_flush++;
04315             ut_a(rw_lock_is_locked(
04316                    &block->lock,
04317                    RW_LOCK_SHARED));
04318             break;
04319           case BUF_FLUSH_LIST:
04320             n_list_flush++;
04321             break;
04322           case BUF_FLUSH_SINGLE_PAGE:
04323             n_single_flush++;
04324             break;
04325           default:
04326             ut_error;
04327           }
04328 
04329           break;
04330 
04331         case BUF_IO_READ:
04332 
04333           ut_a(rw_lock_is_locked(&block->lock,
04334                      RW_LOCK_EX));
04335           break;
04336         }
04337 
04338         n_lru++;
04339         break;
04340 
04341       case BUF_BLOCK_NOT_USED:
04342         n_free++;
04343         break;
04344 
04345       case BUF_BLOCK_READY_FOR_USE:
04346       case BUF_BLOCK_MEMORY:
04347       case BUF_BLOCK_REMOVE_HASH:
04348         /* do nothing */
04349         break;
04350       }
04351 
04352       mutex_exit(&block->mutex);
04353     }
04354   }
04355 
04356   mutex_enter(&buf_pool->zip_mutex);
04357 
04358   /* Check clean compressed-only blocks. */
04359 
04360   for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
04361        b = UT_LIST_GET_NEXT(list, b)) {
04362     ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
04363     switch (buf_page_get_io_fix(b)) {
04364     case BUF_IO_NONE:
04365       /* All clean blocks should be I/O-unfixed. */
04366       break;
04367     case BUF_IO_READ:
04368       /* In buf_LRU_free_block(), we temporarily set
04369       b->io_fix = BUF_IO_READ for a newly allocated
04370       control block in order to prevent
04371       buf_page_get_gen() from decompressing the block. */
04372       break;
04373     default:
04374       ut_error;
04375       break;
04376     }
04377 
04378     /* It is OK to read oldest_modification here because
04379     we have acquired buf_pool->zip_mutex above which acts
04380     as the 'block->mutex' for these bpages. */
04381     ut_a(!b->oldest_modification);
04382     ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b);
04383 
04384     n_lru++;
04385     n_zip++;
04386   }
04387 
04388   /* Check dirty blocks. */
04389 
04390   buf_flush_list_mutex_enter(buf_pool);
04391   for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
04392        b = UT_LIST_GET_NEXT(list, b)) {
04393     ut_ad(b->in_flush_list);
04394     ut_a(b->oldest_modification);
04395     n_flush++;
04396 
04397     switch (buf_page_get_state(b)) {
04398     case BUF_BLOCK_ZIP_DIRTY:
04399       n_lru++;
04400       n_zip++;
04401       switch (buf_page_get_io_fix(b)) {
04402       case BUF_IO_NONE:
04403       case BUF_IO_READ:
04404         break;
04405       case BUF_IO_WRITE:
04406         switch (buf_page_get_flush_type(b)) {
04407         case BUF_FLUSH_LRU:
04408           n_lru_flush++;
04409           break;
04410         case BUF_FLUSH_LIST:
04411           n_list_flush++;
04412           break;
04413         case BUF_FLUSH_SINGLE_PAGE:
04414           n_single_flush++;
04415           break;
04416         default:
04417           ut_error;
04418         }
04419         break;
04420       }
04421       break;
04422     case BUF_BLOCK_FILE_PAGE:
04423       /* uncompressed page */
04424       break;
04425     case BUF_BLOCK_ZIP_FREE:
04426     case BUF_BLOCK_ZIP_PAGE:
04427     case BUF_BLOCK_NOT_USED:
04428     case BUF_BLOCK_READY_FOR_USE:
04429     case BUF_BLOCK_MEMORY:
04430     case BUF_BLOCK_REMOVE_HASH:
04431       ut_error;
04432       break;
04433     }
04434     ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b);
04435   }
04436 
04437   ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
04438 
04439   buf_flush_list_mutex_exit(buf_pool);
04440 
04441   mutex_exit(&buf_pool->zip_mutex);
04442 
04443   if (n_lru + n_free > buf_pool->curr_size + n_zip) {
04444     fprintf(stderr, "n LRU %lu, n free %lu, pool %lu zip %lu\n",
04445       (ulong) n_lru, (ulong) n_free,
04446       (ulong) buf_pool->curr_size, (ulong) n_zip);
04447     ut_error;
04448   }
04449 
04450   ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
04451   if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
04452     fprintf(stderr, "Free list len %lu, free blocks %lu\n",
04453       (ulong) UT_LIST_GET_LEN(buf_pool->free),
04454       (ulong) n_free);
04455     ut_error;
04456   }
04457 
04458   ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
04459   ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
04460   ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
04461 
04462   buf_pool_mutex_exit(buf_pool);
04463 
04464   ut_a(buf_LRU_validate());
04465   ut_a(buf_flush_validate(buf_pool));
04466 
04467   return(TRUE);
04468 }
04469 
04470 /*********************************************************************/
04473 UNIV_INTERN
04474 ibool
04475 buf_validate(void)
04476 /*==============*/
04477 {
04478   ulint i;
04479 
04480   for (i = 0; i < srv_buf_pool_instances; i++) {
04481     buf_pool_t* buf_pool;
04482 
04483     buf_pool = buf_pool_from_array(i);
04484 
04485     buf_pool_validate_instance(buf_pool);
04486   }
04487   return(TRUE);
04488 }
04489 
04490 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
04491 
04492 #if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
04493 /*********************************************************************/
04495 static
04496 void
04497 buf_print_instance(
04498 /*===============*/
04499   buf_pool_t* buf_pool)
04500 {
04501   index_id_t* index_ids;
04502   ulint*    counts;
04503   ulint   size;
04504   ulint   i;
04505   ulint   j;
04506   index_id_t  id;
04507   ulint   n_found;
04508   buf_chunk_t*  chunk;
04509   dict_index_t* index;
04510 
04511   ut_ad(buf_pool);
04512 
04513   size = buf_pool->curr_size;
04514 
04515   index_ids = mem_alloc(size * sizeof *index_ids);
04516   counts = mem_alloc(sizeof(ulint) * size);
04517 
04518   buf_pool_mutex_enter(buf_pool);
04519   buf_flush_list_mutex_enter(buf_pool);
04520 
04521   fprintf(stderr,
04522     "buf_pool size %lu\n"
04523     "database pages %lu\n"
04524     "free pages %lu\n"
04525     "modified database pages %lu\n"
04526     "n pending decompressions %lu\n"
04527     "n pending reads %lu\n"
04528     "n pending flush LRU %lu list %lu single page %lu\n"
04529     "pages made young %lu, not young %lu\n"
04530     "pages read %lu, created %lu, written %lu\n",
04531     (ulong) size,
04532     (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
04533     (ulong) UT_LIST_GET_LEN(buf_pool->free),
04534     (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
04535     (ulong) buf_pool->n_pend_unzip,
04536     (ulong) buf_pool->n_pend_reads,
04537     (ulong) buf_pool->n_flush[BUF_FLUSH_LRU],
04538     (ulong) buf_pool->n_flush[BUF_FLUSH_LIST],
04539     (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE],
04540     (ulong) buf_pool->stat.n_pages_made_young,
04541     (ulong) buf_pool->stat.n_pages_not_made_young,
04542     (ulong) buf_pool->stat.n_pages_read,
04543     (ulong) buf_pool->stat.n_pages_created,
04544     (ulong) buf_pool->stat.n_pages_written);
04545 
04546   buf_flush_list_mutex_exit(buf_pool);
04547 
04548   /* Count the number of blocks belonging to each index in the buffer */
04549 
04550   n_found = 0;
04551 
04552   chunk = buf_pool->chunks;
04553 
04554   for (i = buf_pool->n_chunks; i--; chunk++) {
04555     buf_block_t*  block   = chunk->blocks;
04556     ulint   n_blocks  = chunk->size;
04557 
04558     for (; n_blocks--; block++) {
04559       const buf_frame_t* frame = block->frame;
04560 
04561       if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
04562 
04563         id = btr_page_get_index_id(frame);
04564 
04565         /* Look for the id in the index_ids array */
04566         j = 0;
04567 
04568         while (j < n_found) {
04569 
04570           if (index_ids[j] == id) {
04571             counts[j]++;
04572 
04573             break;
04574           }
04575           j++;
04576         }
04577 
04578         if (j == n_found) {
04579           n_found++;
04580           index_ids[j] = id;
04581           counts[j] = 1;
04582         }
04583       }
04584     }
04585   }
04586 
04587   buf_pool_mutex_exit(buf_pool);
04588 
04589   for (i = 0; i < n_found; i++) {
04590     index = dict_index_get_if_in_cache(index_ids[i]);
04591 
04592     fprintf(stderr,
04593       "Block count for index %llu in buffer is about %lu",
04594       (ullint) index_ids[i],
04595       (ulong) counts[i]);
04596 
04597     if (index) {
04598       putc(' ', stderr);
04599       dict_index_name_print(stderr, NULL, index);
04600     }
04601 
04602     putc('\n', stderr);
04603   }
04604 
04605   mem_free(index_ids);
04606   mem_free(counts);
04607 
04608   ut_a(buf_pool_validate_instance(buf_pool));
04609 }
04610 
04611 /*********************************************************************/
04613 UNIV_INTERN
04614 void
04615 buf_print(void)
04616 /*===========*/
04617 {
04618   ulint   i;
04619 
04620   for (i = 0; i < srv_buf_pool_instances; i++) {
04621     buf_pool_t* buf_pool;
04622 
04623     buf_pool = buf_pool_from_array(i);
04624     buf_print_instance(buf_pool);
04625   }
04626 }
04627 #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
04628 
04629 #ifdef UNIV_DEBUG
04630 /*********************************************************************/
04633 UNIV_INTERN
04634 ulint
04635 buf_get_latched_pages_number_instance(
04636 /*==================================*/
04637   buf_pool_t* buf_pool) 
04638 {
04639   buf_page_t* b;
04640   ulint   i;
04641   buf_chunk_t*  chunk;
04642   ulint   fixed_pages_number = 0;
04643 
04644   buf_pool_mutex_enter(buf_pool);
04645 
04646   chunk = buf_pool->chunks;
04647 
04648   for (i = buf_pool->n_chunks; i--; chunk++) {
04649     buf_block_t*  block;
04650     ulint   j;
04651 
04652     block = chunk->blocks;
04653 
04654     for (j = chunk->size; j--; block++) {
04655       if (buf_block_get_state(block)
04656           != BUF_BLOCK_FILE_PAGE) {
04657 
04658         continue;
04659       }
04660 
04661       mutex_enter(&block->mutex);
04662 
04663       if (block->page.buf_fix_count != 0
04664           || buf_page_get_io_fix(&block->page)
04665           != BUF_IO_NONE) {
04666         fixed_pages_number++;
04667       }
04668 
04669       mutex_exit(&block->mutex);
04670     }
04671   }
04672 
04673   mutex_enter(&buf_pool->zip_mutex);
04674 
04675   /* Traverse the lists of clean and dirty compressed-only blocks. */
04676 
04677   for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
04678        b = UT_LIST_GET_NEXT(list, b)) {
04679     ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
04680     ut_a(buf_page_get_io_fix(b) != BUF_IO_WRITE);
04681 
04682     if (b->buf_fix_count != 0
04683         || buf_page_get_io_fix(b) != BUF_IO_NONE) {
04684       fixed_pages_number++;
04685     }
04686   }
04687 
04688   buf_flush_list_mutex_enter(buf_pool);
04689   for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
04690        b = UT_LIST_GET_NEXT(list, b)) {
04691     ut_ad(b->in_flush_list);
04692 
04693     switch (buf_page_get_state(b)) {
04694     case BUF_BLOCK_ZIP_DIRTY:
04695       if (b->buf_fix_count != 0
04696           || buf_page_get_io_fix(b) != BUF_IO_NONE) {
04697         fixed_pages_number++;
04698       }
04699       break;
04700     case BUF_BLOCK_FILE_PAGE:
04701       /* uncompressed page */
04702       break;
04703     case BUF_BLOCK_ZIP_FREE:
04704     case BUF_BLOCK_ZIP_PAGE:
04705     case BUF_BLOCK_NOT_USED:
04706     case BUF_BLOCK_READY_FOR_USE:
04707     case BUF_BLOCK_MEMORY:
04708     case BUF_BLOCK_REMOVE_HASH:
04709       ut_error;
04710       break;
04711     }
04712   }
04713 
04714   buf_flush_list_mutex_exit(buf_pool);
04715   mutex_exit(&buf_pool->zip_mutex);
04716   buf_pool_mutex_exit(buf_pool);
04717 
04718   return(fixed_pages_number);
04719 }
04720 
04721 /*********************************************************************/
04724 UNIV_INTERN
04725 ulint
04726 buf_get_latched_pages_number(void)
04727 /*==============================*/
04728 {
04729   ulint i;
04730   ulint total_latched_pages = 0;
04731 
04732   for (i = 0; i < srv_buf_pool_instances; i++) {
04733     buf_pool_t* buf_pool;
04734 
04735     buf_pool = buf_pool_from_array(i);
04736 
04737     total_latched_pages += buf_get_latched_pages_number_instance(
04738       buf_pool);
04739   }
04740 
04741   return(total_latched_pages);
04742 }
04743 
04744 #endif /* UNIV_DEBUG */
04745 
04746 /*********************************************************************/
04749 UNIV_INTERN
04750 ulint
04751 buf_get_n_pending_ios(void)
04752 /*=======================*/
04753 {
04754   ulint i;
04755   ulint pend_ios = 0;
04756 
04757   for (i = 0; i < srv_buf_pool_instances; i++) {
04758     buf_pool_t* buf_pool;
04759 
04760     buf_pool = buf_pool_from_array(i);
04761 
04762     pend_ios +=
04763       buf_pool->n_pend_reads
04764       + buf_pool->n_flush[BUF_FLUSH_LRU]
04765       + buf_pool->n_flush[BUF_FLUSH_LIST]
04766       + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
04767   }
04768 
04769   return(pend_ios);
04770 }
04771 
04772 /*********************************************************************/
04776 UNIV_INTERN
04777 ulint
04778 buf_get_modified_ratio_pct(void)
04779 /*============================*/
04780 {
04781   ulint   ratio;
04782   ulint   lru_len = 0;
04783   ulint   free_len = 0;
04784   ulint   flush_list_len = 0;
04785 
04786   buf_get_total_list_len(&lru_len, &free_len, &flush_list_len);
04787 
04788   ratio = (100 * flush_list_len) / (1 + lru_len + free_len);
04789   
04790   /* 1 + is there to avoid division by zero */
04791 
04792   return(ratio);
04793 }
04794 
04795 /*********************************************************************/
04797 static
04798 void
04799 buf_print_io_instance(
04800 /*==================*/
04801   buf_pool_t* buf_pool, 
04802   FILE*   file)   
04803 {
04804   time_t  current_time;
04805   double  time_elapsed;
04806   ulint n_gets_diff;
04807 
04808   ut_ad(buf_pool);
04809 
04810   buf_pool_mutex_enter(buf_pool);
04811   buf_flush_list_mutex_enter(buf_pool);
04812 
04813   fprintf(file,
04814     "Buffer pool size   %lu\n"
04815     "Free buffers       %lu\n"
04816     "Database pages     %lu\n"
04817     "Old database pages %lu\n"
04818     "Modified db pages  %lu\n"
04819     "Pending reads %lu\n"
04820     "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
04821     (ulong) buf_pool->curr_size,
04822     (ulong) UT_LIST_GET_LEN(buf_pool->free),
04823     (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
04824     (ulong) buf_pool->LRU_old_len,
04825     (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
04826     (ulong) buf_pool->n_pend_reads,
04827     (ulong) buf_pool->n_flush[BUF_FLUSH_LRU]
04828     + buf_pool->init_flush[BUF_FLUSH_LRU],
04829     (ulong) buf_pool->n_flush[BUF_FLUSH_LIST]
04830     + buf_pool->init_flush[BUF_FLUSH_LIST],
04831     (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
04832 
04833   buf_flush_list_mutex_exit(buf_pool);
04834 
04835   current_time = time(NULL);
04836   time_elapsed = 0.001 + difftime(current_time,
04837           buf_pool->last_printout_time);
04838 
04839   fprintf(file,
04840     "Pages made young %lu, not young %lu\n"
04841     "%.2f youngs/s, %.2f non-youngs/s\n"
04842     "Pages read %lu, created %lu, written %lu\n"
04843     "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
04844     (ulong) buf_pool->stat.n_pages_made_young,
04845     (ulong) buf_pool->stat.n_pages_not_made_young,
04846     (buf_pool->stat.n_pages_made_young
04847      - buf_pool->old_stat.n_pages_made_young)
04848     / time_elapsed,
04849     (buf_pool->stat.n_pages_not_made_young
04850      - buf_pool->old_stat.n_pages_not_made_young)
04851     / time_elapsed,
04852     (ulong) buf_pool->stat.n_pages_read,
04853     (ulong) buf_pool->stat.n_pages_created,
04854     (ulong) buf_pool->stat.n_pages_written,
04855     (buf_pool->stat.n_pages_read
04856      - buf_pool->old_stat.n_pages_read)
04857     / time_elapsed,
04858     (buf_pool->stat.n_pages_created
04859      - buf_pool->old_stat.n_pages_created)
04860     / time_elapsed,
04861     (buf_pool->stat.n_pages_written
04862      - buf_pool->old_stat.n_pages_written)
04863     / time_elapsed);
04864 
04865   n_gets_diff = buf_pool->stat.n_page_gets
04866         - buf_pool->old_stat.n_page_gets;
04867 
04868   if (n_gets_diff) {
04869     fprintf(file,
04870       "Buffer pool hit rate %lu / 1000,"
04871       " young-making rate %lu / 1000 not %lu / 1000\n",
04872       (ulong)
04873       (1000 - ((1000 * (buf_pool->stat.n_pages_read
04874             - buf_pool->old_stat.n_pages_read))
04875          / (buf_pool->stat.n_page_gets
04876             - buf_pool->old_stat.n_page_gets))),
04877       (ulong)
04878       (1000 * (buf_pool->stat.n_pages_made_young
04879          - buf_pool->old_stat.n_pages_made_young)
04880        / n_gets_diff),
04881       (ulong)
04882       (1000 * (buf_pool->stat.n_pages_not_made_young
04883          - buf_pool->old_stat.n_pages_not_made_young)
04884        / n_gets_diff));
04885   } else {
04886     fputs("No buffer pool page gets since the last printout\n",
04887           file);
04888   }
04889 
04890   /* Statistics about read ahead algorithm */
04891   fprintf(file, "Pages read ahead %.2f/s,"
04892     " evicted without access %.2f/s\n",
04893     (buf_pool->stat.n_ra_pages_read
04894     - buf_pool->old_stat.n_ra_pages_read)
04895     / time_elapsed,
04896     (buf_pool->stat.n_ra_pages_evicted
04897     - buf_pool->old_stat.n_ra_pages_evicted)
04898     / time_elapsed);
04899 
04900   /* Print some values to help us with visualizing what is
04901   happening with LRU eviction. */
04902   fprintf(file,
04903     "LRU len: %lu, unzip_LRU len: %lu\n"
04904     "I/O sum[%lu]:cur[%lu], unzip sum[%lu]:cur[%lu]\n",
04905     static_cast<ulint>(UT_LIST_GET_LEN(buf_pool->LRU)),
04906     static_cast<ulint>(UT_LIST_GET_LEN(buf_pool->unzip_LRU)),
04907     buf_LRU_stat_sum.io, buf_LRU_stat_cur.io,
04908     buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip);
04909 
04910   buf_refresh_io_stats(buf_pool);
04911   buf_pool_mutex_exit(buf_pool);
04912 }
04913 
04914 /*********************************************************************/
04916 UNIV_INTERN
04917 void
04918 buf_print_io(
04919 /*=========*/
04920   FILE* file) 
04921 {
04922   ulint   i;
04923 
04924   for (i = 0; i < srv_buf_pool_instances; i++) {
04925     buf_pool_t* buf_pool;
04926 
04927     buf_pool = buf_pool_from_array(i);
04928     buf_print_io_instance(buf_pool, file);
04929   }
04930 }
04931 
04932 /**********************************************************************/
04934 UNIV_INTERN
04935 void
04936 buf_refresh_io_stats(
04937 /*=================*/
04938   buf_pool_t* buf_pool) 
04939 {
04940   buf_pool->last_printout_time = ut_time();
04941   buf_pool->old_stat = buf_pool->stat;
04942 }
04943 
04944 /**********************************************************************/
04946 UNIV_INTERN
04947 void
04948 buf_refresh_io_stats_all(void)
04949 /*==========================*/
04950 {
04951   ulint   i;
04952 
04953   for (i = 0; i < srv_buf_pool_instances; i++) {
04954     buf_pool_t* buf_pool;
04955 
04956     buf_pool = buf_pool_from_array(i);
04957 
04958     buf_refresh_io_stats(buf_pool);
04959   }
04960 }
04961 
04962 /**********************************************************************/
04965 UNIV_INTERN
04966 ibool
04967 buf_all_freed(void)
04968 /*===============*/
04969 {
04970   ulint i;
04971 
04972   for (i = 0; i < srv_buf_pool_instances; i++) {
04973     buf_pool_t* buf_pool;
04974 
04975     buf_pool = buf_pool_from_array(i);
04976 
04977     if (!buf_all_freed_instance(buf_pool)) {
04978       return(FALSE);
04979     }
04980   }
04981 
04982   return(TRUE);
04983 }
04984   
04985 /*********************************************************************/
04989 UNIV_INTERN
04990 ibool
04991 buf_pool_check_no_pending_io(void)
04992 /*==============================*/
04993 {
04994   ulint   i;
04995   ibool   ret = TRUE;
04996 
04997   buf_pool_mutex_enter_all();
04998 
04999   for (i = 0; i < srv_buf_pool_instances && ret; i++) {
05000     const buf_pool_t* buf_pool;
05001 
05002     buf_pool = buf_pool_from_array(i);
05003 
05004     if (buf_pool->n_pend_reads
05005         + buf_pool->n_flush[BUF_FLUSH_LRU]
05006         + buf_pool->n_flush[BUF_FLUSH_LIST]
05007         + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
05008 
05009       ret = FALSE;
05010     }
05011   }
05012 
05013   buf_pool_mutex_exit_all();
05014 
05015   return(ret);
05016 }
05017 
05018 #if 0
05019 Code currently not used
05020 /*********************************************************************/
05023 UNIV_INTERN
05024 ulint
05025 buf_get_free_list_len(void)
05026 /*=======================*/
05027 {
05028   ulint len;
05029 
05030   buf_pool_mutex_enter(buf_pool);
05031 
05032   len = UT_LIST_GET_LEN(buf_pool->free);
05033 
05034   buf_pool_mutex_exit(buf_pool);
05035 
05036   return(len);
05037 }
05038 #endif
05039 
05040 #else /* !UNIV_HOTBACKUP */
05041 /********************************************************************/
05043 UNIV_INTERN
05044 void
05045 buf_page_init_for_backup_restore(
05046 /*=============================*/
05047   ulint   space,  
05048   ulint   offset, 
05050   ulint   zip_size,
05052   buf_block_t*  block)  
05053 {
05054   block->page.state = BUF_BLOCK_FILE_PAGE;
05055   block->page.space = space;
05056   block->page.offset  = offset;
05057 
05058   page_zip_des_init(&block->page.zip);
05059 
05060   /* We assume that block->page.data has been allocated
05061   with zip_size == UNIV_PAGE_SIZE. */
05062   ut_ad(zip_size <= UNIV_PAGE_SIZE);
05063   ut_ad(ut_is_2pow(zip_size));
05064   page_zip_set_size(&block->page.zip, zip_size);
05065   if (zip_size) {
05066     block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
05067   }
05068 }
05069 #endif /* !UNIV_HOTBACKUP */