Drizzled Public API Documentation

buf0lru.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /**************************************************/
00026 #include <config.h>
00027 #include "buf0lru.h"
00028 
00029 #ifdef UNIV_NONINL
00030 #include "buf0lru.ic"
00031 #endif
00032 
00033 #include "ut0byte.h"
00034 #include "ut0lst.h"
00035 #include "ut0rnd.h"
00036 #include "sync0sync.h"
00037 #include "sync0rw.h"
00038 #include "hash0hash.h"
00039 #include "os0sync.h"
00040 #include "fil0fil.h"
00041 #include "btr0btr.h"
00042 #include "buf0buddy.h"
00043 #include "buf0buf.h"
00044 #include "buf0flu.h"
00045 #include "buf0rea.h"
00046 #include "btr0sea.h"
00047 #include "ibuf0ibuf.h"
00048 #include "os0file.h"
00049 #include "page0zip.h"
00050 #include "log0recv.h"
00051 #include "srv0srv.h"
00052 
00060 #define BUF_LRU_OLD_TOLERANCE 20
00061 
00065 #define BUF_LRU_NON_OLD_MIN_LEN 5
00066 #if BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN
00067 # error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN"
00068 #endif
00069 
00073 #define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024
00074 
00077 static ibool  buf_lru_switched_on_innodb_mon  = FALSE;
00078 
00079 /******************************************************************/
00088 /* @{ */
00089 
00093 #define BUF_LRU_STAT_N_INTERVAL 50
00094 
00097 #define BUF_LRU_IO_TO_UNZIP_FACTOR 50
00098 
00101 static buf_LRU_stat_t   buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
00102 
00104 static ulint      buf_LRU_stat_arr_ind;
00105 
00108 UNIV_INTERN buf_LRU_stat_t  buf_LRU_stat_cur;
00109 
00112 UNIV_INTERN buf_LRU_stat_t  buf_LRU_stat_sum;
00113 
00114 /* @} */
00115 
00119 UNIV_INTERN uint  buf_LRU_old_threshold_ms;
00120 /* @} */
00121 
00122 /******************************************************************/
00132 static
00133 enum buf_page_state
00134 buf_LRU_block_remove_hashed_page(
00135 /*=============================*/
00136   buf_page_t* bpage,  
00139   ibool   zip); 
00141 /******************************************************************/
00143 static
00144 void
00145 buf_LRU_block_free_hashed_page(
00146 /*===========================*/
00147   buf_block_t*  block); 
00150 /******************************************************************/
00154 UNIV_INLINE
00155 ibool
00156 buf_LRU_evict_from_unzip_LRU(
00157 /*=========================*/
00158   buf_pool_t* buf_pool)
00159 {
00160   ulint io_avg;
00161   ulint unzip_avg;
00162 
00163   ut_ad(buf_pool_mutex_own(buf_pool));
00164 
00165   /* If the unzip_LRU list is empty, we can only use the LRU. */
00166   if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) {
00167     return(FALSE);
00168   }
00169 
00170   /* If unzip_LRU is at most 10% of the size of the LRU list,
00171   then use the LRU.  This slack allows us to keep hot
00172   decompressed pages in the buffer pool. */
00173   if (UT_LIST_GET_LEN(buf_pool->unzip_LRU)
00174       <= UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
00175     return(FALSE);
00176   }
00177 
00178   /* If eviction hasn't started yet, we assume by default
00179   that a workload is disk bound. */
00180   if (buf_pool->freed_page_clock == 0) {
00181     return(TRUE);
00182   }
00183 
00184   /* Calculate the average over past intervals, and add the values
00185   of the current interval. */
00186   io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
00187     + buf_LRU_stat_cur.io;
00188   unzip_avg = buf_LRU_stat_sum.unzip / BUF_LRU_STAT_N_INTERVAL
00189     + buf_LRU_stat_cur.unzip;
00190 
00191   /* Decide based on our formula.  If the load is I/O bound
00192   (unzip_avg is smaller than the weighted io_avg), evict an
00193   uncompressed frame from unzip_LRU.  Otherwise we assume that
00194   the load is CPU bound and evict from the regular LRU. */
00195   return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
00196 }
00197 
00198 /******************************************************************/
00201 static
00202 void
00203 buf_LRU_drop_page_hash_batch(
00204 /*=========================*/
00205   ulint   space_id, 
00206   ulint   zip_size, 
00208   const ulint*  arr,    
00209   ulint   count)    
00210 {
00211   ulint i;
00212 
00213   ut_ad(arr != NULL);
00214   ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
00215 
00216   for (i = 0; i < count; ++i) {
00217     btr_search_drop_page_hash_when_freed(space_id, zip_size,
00218                  arr[i]);
00219   }
00220 }
00221 
00222 /******************************************************************/
00227 static
00228 void
00229 buf_LRU_drop_page_hash_for_tablespace(
00230 /*==================================*/
00231   buf_pool_t* buf_pool, 
00232   ulint   id)   
00233 {
00234   buf_page_t* bpage;
00235   ulint*    page_arr;
00236   ulint   num_entries;
00237   ulint   zip_size;
00238 
00239   zip_size = fil_space_get_zip_size(id);
00240 
00241   if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
00242     /* Somehow, the tablespace does not exist.  Nothing to drop. */
00243     ut_ad(0);
00244     return;
00245   }
00246 
00247   page_arr = static_cast<unsigned long *>(ut_malloc(
00248     sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE));
00249 
00250   buf_pool_mutex_enter(buf_pool);
00251 
00252 scan_again:
00253   num_entries = 0;
00254   bpage = UT_LIST_GET_LAST(buf_pool->LRU);
00255 
00256   while (bpage != NULL) {
00257     mutex_t*  block_mutex = buf_page_get_mutex(bpage);
00258     buf_page_t* prev_bpage;
00259 
00260     mutex_enter(block_mutex);
00261     prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
00262 
00263     ut_a(buf_page_in_file(bpage));
00264 
00265     if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE
00266         || bpage->space != id
00267         || bpage->buf_fix_count > 0
00268         || bpage->io_fix != BUF_IO_NONE) {
00269       /* We leave the fixed pages as is in this scan.
00270       To be dealt with later in the final scan. */
00271       mutex_exit(block_mutex);
00272       goto next_page;
00273     }
00274 
00275     if (((buf_block_t*) bpage)->is_hashed) {
00276 
00277       /* Store the offset(i.e.: page_no) in the array
00278       so that we can drop hash index in a batch
00279       later. */
00280       page_arr[num_entries] = bpage->offset;
00281       mutex_exit(block_mutex);
00282       ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
00283       ++num_entries;
00284 
00285       if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
00286         goto next_page;
00287       }
00288 
00289       /* Array full. We release the buf_pool->mutex to
00290       obey the latching order. */
00291       buf_pool_mutex_exit(buf_pool);
00292 
00293       buf_LRU_drop_page_hash_batch(
00294         id, zip_size, page_arr, num_entries);
00295 
00296       num_entries = 0;
00297 
00298       buf_pool_mutex_enter(buf_pool);
00299     } else {
00300       mutex_exit(block_mutex);
00301     }
00302 
00303 next_page:
00304     /* Note that we may have released the buf_pool mutex
00305     above after reading the prev_bpage during processing
00306     of a page_hash_batch (i.e.: when the array was full).
00307     This means that prev_bpage can change in LRU list.
00308     This is OK because this function is a 'best effort'
00309     to drop as many search hash entries as possible and
00310     it does not guarantee that ALL such entries will be
00311     dropped. */
00312     bpage = prev_bpage;
00313 
00314     /* If, however, bpage has been removed from LRU list
00315     to the free list then we should restart the scan.
00316     bpage->state is protected by buf_pool mutex. */
00317     if (bpage && !buf_page_in_file(bpage)) {
00318       ut_a(num_entries == 0);
00319       goto scan_again;
00320     }
00321   }
00322 
00323   buf_pool_mutex_exit(buf_pool);
00324 
00325   /* Drop any remaining batch of search hashed pages. */
00326   buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, num_entries);
00327   ut_free(page_arr);
00328 }
00329 
00330 /******************************************************************/
00334 static
00335 void
00336 buf_LRU_invalidate_tablespace_buf_pool_instance(
00337 /*============================================*/
00338   buf_pool_t* buf_pool, 
00339   ulint   id)   
00340 {
00341   buf_page_t* bpage;
00342   ibool   all_freed;
00343 
00344 scan_again:
00345   buf_pool_mutex_enter(buf_pool);
00346 
00347   all_freed = TRUE;
00348 
00349   bpage = UT_LIST_GET_LAST(buf_pool->LRU);
00350 
00351   while (bpage != NULL) {
00352     buf_page_t* prev_bpage;
00353     ibool   prev_bpage_buf_fix = FALSE;
00354 
00355     ut_a(buf_page_in_file(bpage));
00356 
00357     prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
00358 
00359     /* bpage->space and bpage->io_fix are protected by
00360     buf_pool->mutex and block_mutex.  It is safe to check
00361     them while holding buf_pool->mutex only. */
00362 
00363     if (buf_page_get_space(bpage) != id) {
00364       /* Skip this block, as it does not belong to
00365       the space that is being invalidated. */
00366     } else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
00367       /* We cannot remove this page during this scan
00368       yet; maybe the system is currently reading it
00369       in, or flushing the modifications to the file */
00370 
00371       all_freed = FALSE;
00372     } else {
00373       mutex_t* block_mutex = buf_page_get_mutex(bpage);
00374       mutex_enter(block_mutex);
00375 
00376       if (bpage->buf_fix_count > 0) {
00377 
00378         /* We cannot remove this page during
00379         this scan yet; maybe the system is
00380         currently reading it in, or flushing
00381         the modifications to the file */
00382 
00383         all_freed = FALSE;
00384 
00385         goto next_page;
00386       }
00387 
00388 #ifdef UNIV_DEBUG
00389       if (buf_debug_prints) {
00390         fprintf(stderr,
00391           "Dropping space %lu page %lu\n",
00392           (ulong) buf_page_get_space(bpage),
00393           (ulong) buf_page_get_page_no(bpage));
00394       }
00395 #endif
00396       if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
00397         /* This is a compressed-only block
00398         descriptor.  Ensure that prev_bpage
00399         cannot be relocated when bpage is freed. */
00400         if (UNIV_LIKELY(prev_bpage != NULL)) {
00401           switch (buf_page_get_state(
00402               prev_bpage)) {
00403           case BUF_BLOCK_FILE_PAGE:
00404             /* Descriptors of uncompressed
00405             blocks will not be relocated,
00406             because we are holding the
00407             buf_pool->mutex. */
00408             break;
00409           case BUF_BLOCK_ZIP_PAGE:
00410           case BUF_BLOCK_ZIP_DIRTY:
00411             /* Descriptors of compressed-
00412             only blocks can be relocated,
00413             unless they are buffer-fixed.
00414             Because both bpage and
00415             prev_bpage are protected by
00416             buf_pool_zip_mutex, it is
00417             not necessary to acquire
00418             further mutexes. */
00419             ut_ad(&buf_pool->zip_mutex
00420                   == block_mutex);
00421             ut_ad(mutex_own(block_mutex));
00422             prev_bpage_buf_fix = TRUE;
00423             prev_bpage->buf_fix_count++;
00424             break;
00425           default:
00426             ut_error;
00427           }
00428         }
00429       } else if (((buf_block_t*) bpage)->is_hashed) {
00430         ulint page_no;
00431         ulint zip_size;
00432 
00433         buf_pool_mutex_exit(buf_pool);
00434 
00435         zip_size = buf_page_get_zip_size(bpage);
00436         page_no = buf_page_get_page_no(bpage);
00437 
00438         mutex_exit(block_mutex);
00439 
00440         /* Note that the following call will acquire
00441         an S-latch on the page */
00442 
00443         btr_search_drop_page_hash_when_freed(
00444           id, zip_size, page_no);
00445         goto scan_again;
00446       }
00447 
00448       if (bpage->oldest_modification != 0) {
00449 
00450         buf_flush_remove(bpage);
00451       }
00452 
00453       /* Remove from the LRU list. */
00454 
00455       if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
00456           != BUF_BLOCK_ZIP_FREE) {
00457         buf_LRU_block_free_hashed_page((buf_block_t*)
00458                      bpage);
00459       } else {
00460         /* The block_mutex should have been
00461         released by buf_LRU_block_remove_hashed_page()
00462         when it returns BUF_BLOCK_ZIP_FREE. */
00463         ut_ad(block_mutex == &buf_pool->zip_mutex);
00464         ut_ad(!mutex_own(block_mutex));
00465 
00466         if (prev_bpage_buf_fix) {
00467           /* We temporarily buffer-fixed
00468           prev_bpage, so that
00469           buf_buddy_free() could not
00470           relocate it, in case it was a
00471           compressed-only block
00472           descriptor. */
00473 
00474           mutex_enter(block_mutex);
00475           ut_ad(prev_bpage->buf_fix_count > 0);
00476           prev_bpage->buf_fix_count--;
00477           mutex_exit(block_mutex);
00478         }
00479 
00480         goto next_page_no_mutex;
00481       }
00482 next_page:
00483       mutex_exit(block_mutex);
00484     }
00485 
00486 next_page_no_mutex:
00487     bpage = prev_bpage;
00488   }
00489 
00490   buf_pool_mutex_exit(buf_pool);
00491 
00492   if (!all_freed) {
00493     os_thread_sleep(20000);
00494 
00495     goto scan_again;
00496   }
00497 }
00498 
00499 /******************************************************************/
00502 UNIV_INTERN
00503 void
00504 buf_LRU_invalidate_tablespace(
00505 /*==========================*/
00506   ulint id) 
00507 {
00508   ulint i;
00509 
00510   /* Before we attempt to drop pages one by one we first
00511   attempt to drop page hash index entries in batches to make
00512   it more efficient. The batching attempt is a best effort
00513   attempt and does not guarantee that all pages hash entries
00514   will be dropped. We get rid of remaining page hash entries
00515   one by one below. */
00516   for (i = 0; i < srv_buf_pool_instances; i++) {
00517     buf_pool_t* buf_pool;
00518 
00519     buf_pool = buf_pool_from_array(i);
00520     buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
00521     buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id);
00522   }
00523 }
00524 
00525 /********************************************************************/
00527 UNIV_INTERN
00528 void
00529 buf_LRU_insert_zip_clean(
00530 /*=====================*/
00531   buf_page_t* bpage)  
00532 {
00533   buf_page_t* b;
00534   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
00535 
00536   ut_ad(buf_pool_mutex_own(buf_pool));
00537   ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
00538 
00539   /* Find the first successor of bpage in the LRU list
00540   that is in the zip_clean list. */
00541   b = bpage;
00542   do {
00543     b = UT_LIST_GET_NEXT(LRU, b);
00544   } while (b && buf_page_get_state(b) != BUF_BLOCK_ZIP_PAGE);
00545 
00546   /* Insert bpage before b, i.e., after the predecessor of b. */
00547   if (b) {
00548     b = UT_LIST_GET_PREV(list, b);
00549   }
00550 
00551   if (b) {
00552     UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, bpage);
00553   } else {
00554     UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, bpage);
00555   }
00556 }
00557 
00558 /******************************************************************/
00562 UNIV_INLINE
00563 ibool
00564 buf_LRU_free_from_unzip_LRU_list(
00565 /*=============================*/
00566   buf_pool_t* buf_pool, 
00567   ulint   n_iterations) 
00574 {
00575   buf_block_t*  block;
00576   ulint   distance;
00577 
00578   ut_ad(buf_pool_mutex_own(buf_pool));
00579 
00580   /* Theoratically it should be much easier to find a victim
00581   from unzip_LRU as we can choose even a dirty block (as we'll
00582   be evicting only the uncompressed frame).  In a very unlikely
00583   eventuality that we are unable to find a victim from
00584   unzip_LRU, we fall back to the regular LRU list.  We do this
00585   if we have done five iterations so far. */
00586 
00587   if (UNIV_UNLIKELY(n_iterations >= 5)
00588       || !buf_LRU_evict_from_unzip_LRU(buf_pool)) {
00589 
00590     return(FALSE);
00591   }
00592 
00593   distance = 100 + (n_iterations
00594         * UT_LIST_GET_LEN(buf_pool->unzip_LRU)) / 5;
00595 
00596   for (block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
00597        UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0);
00598        block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) {
00599 
00600     enum buf_lru_free_block_status  freed;
00601 
00602     ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
00603     ut_ad(block->in_unzip_LRU_list);
00604     ut_ad(block->page.in_LRU_list);
00605 
00606     mutex_enter(&block->mutex);
00607     freed = buf_LRU_free_block(&block->page, FALSE, NULL);
00608     mutex_exit(&block->mutex);
00609 
00610     switch (freed) {
00611     case BUF_LRU_FREED:
00612       return(TRUE);
00613 
00614     case BUF_LRU_CANNOT_RELOCATE:
00615       /* If we failed to relocate, try
00616       regular LRU eviction. */
00617       return(FALSE);
00618 
00619     case BUF_LRU_NOT_FREED:
00620       /* The block was buffer-fixed or I/O-fixed.
00621       Keep looking. */
00622       continue;
00623     }
00624 
00625     /* inappropriate return value from
00626     buf_LRU_free_block() */
00627     ut_error;
00628   }
00629 
00630   return(FALSE);
00631 }
00632 
00633 /******************************************************************/
00636 UNIV_INLINE
00637 ibool
00638 buf_LRU_free_from_common_LRU_list(
00639 /*==============================*/
00640   buf_pool_t* buf_pool,
00641   ulint   n_iterations)
00648 {
00649   buf_page_t* bpage;
00650   ulint   distance;
00651 
00652   ut_ad(buf_pool_mutex_own(buf_pool));
00653 
00654   distance = 100 + (n_iterations * buf_pool->curr_size) / 10;
00655 
00656   for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
00657        UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0);
00658        bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) {
00659 
00660     enum buf_lru_free_block_status  freed;
00661     unsigned      accessed;
00662     mutex_t*      block_mutex
00663       = buf_page_get_mutex(bpage);
00664 
00665     ut_ad(buf_page_in_file(bpage));
00666     ut_ad(bpage->in_LRU_list);
00667 
00668     mutex_enter(block_mutex);
00669     accessed = buf_page_is_accessed(bpage);
00670     freed = buf_LRU_free_block(bpage, TRUE, NULL);
00671     mutex_exit(block_mutex);
00672 
00673     switch (freed) {
00674     case BUF_LRU_FREED:
00675       /* Keep track of pages that are evicted without
00676       ever being accessed. This gives us a measure of
00677       the effectiveness of readahead */
00678       if (!accessed) {
00679         ++buf_pool->stat.n_ra_pages_evicted;
00680       }
00681       return(TRUE);
00682 
00683     case BUF_LRU_NOT_FREED:
00684       /* The block was dirty, buffer-fixed, or I/O-fixed.
00685       Keep looking. */
00686       continue;
00687 
00688     case BUF_LRU_CANNOT_RELOCATE:
00689       /* This should never occur, because we
00690       want to discard the compressed page too. */
00691       break;
00692     }
00693 
00694     /* inappropriate return value from
00695     buf_LRU_free_block() */
00696     ut_error;
00697   }
00698 
00699   return(FALSE);
00700 }
00701 
00702 /******************************************************************/
00705 UNIV_INTERN
00706 ibool
00707 buf_LRU_search_and_free_block(
00708 /*==========================*/
00709   buf_pool_t* buf_pool,
00711   ulint   n_iterations)
00720 {
00721   ibool freed = FALSE;
00722 
00723   buf_pool_mutex_enter(buf_pool);
00724 
00725   freed = buf_LRU_free_from_unzip_LRU_list(buf_pool, n_iterations);
00726 
00727   if (!freed) {
00728     freed = buf_LRU_free_from_common_LRU_list(
00729       buf_pool, n_iterations);
00730   }
00731 
00732   if (!freed) {
00733     buf_pool->LRU_flush_ended = 0;
00734   } else if (buf_pool->LRU_flush_ended > 0) {
00735     buf_pool->LRU_flush_ended--;
00736   }
00737 
00738   buf_pool_mutex_exit(buf_pool);
00739 
00740   return(freed);
00741 }
00742 
00743 /******************************************************************/
00751 UNIV_INTERN
00752 void
00753 buf_LRU_try_free_flushed_blocks(
00754 /*============================*/
00755   buf_pool_t* buf_pool)   
00756 {
00757 
00758   if (buf_pool == NULL) {
00759     ulint i;
00760 
00761     for (i = 0; i < srv_buf_pool_instances; i++) {
00762       buf_pool = buf_pool_from_array(i);
00763       buf_LRU_try_free_flushed_blocks(buf_pool);
00764     }
00765   } else {
00766     buf_pool_mutex_enter(buf_pool);
00767 
00768     while (buf_pool->LRU_flush_ended > 0) {
00769 
00770       buf_pool_mutex_exit(buf_pool);
00771 
00772       buf_LRU_search_and_free_block(buf_pool, 1);
00773 
00774       buf_pool_mutex_enter(buf_pool);
00775     }
00776 
00777     buf_pool_mutex_exit(buf_pool);
00778   }
00779 }
00780 
00781 /******************************************************************/
00786 UNIV_INTERN
00787 ibool
00788 buf_LRU_buf_pool_running_out(void)
00789 /*==============================*/
00790 {
00791   ulint i;
00792   ibool ret = FALSE;
00793 
00794   for (i = 0; i < srv_buf_pool_instances && !ret; i++) {
00795     buf_pool_t* buf_pool;
00796 
00797     buf_pool = buf_pool_from_array(i);
00798 
00799     buf_pool_mutex_enter(buf_pool);
00800 
00801     if (!recv_recovery_on
00802         && UT_LIST_GET_LEN(buf_pool->free)
00803            + UT_LIST_GET_LEN(buf_pool->LRU)
00804            < buf_pool->curr_size / 4) {
00805 
00806       ret = TRUE;
00807     }
00808 
00809     buf_pool_mutex_exit(buf_pool);
00810   }
00811 
00812   return(ret);
00813 }
00814 
00815 /******************************************************************/
00819 UNIV_INTERN
00820 buf_block_t*
00821 buf_LRU_get_free_only(
00822 /*==================*/
00823   buf_pool_t* buf_pool)
00824 {
00825   buf_block_t*  block;
00826 
00827   ut_ad(buf_pool_mutex_own(buf_pool));
00828 
00829   block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
00830 
00831   if (block) {
00832 
00833     ut_ad(block->page.in_free_list);
00834     ut_d(block->page.in_free_list = FALSE);
00835     ut_ad(!block->page.in_flush_list);
00836     ut_ad(!block->page.in_LRU_list);
00837     ut_a(!buf_page_in_file(&block->page));
00838     UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
00839 
00840     mutex_enter(&block->mutex);
00841 
00842     buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
00843     UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
00844 
00845     ut_ad(buf_pool_from_block(block) == buf_pool);
00846 
00847     mutex_exit(&block->mutex);
00848   }
00849 
00850   return(block);
00851 }
00852 
00853 /******************************************************************/
00858 UNIV_INTERN
00859 buf_block_t*
00860 buf_LRU_get_free_block(
00861 /*===================*/
00862   buf_pool_t* buf_pool, 
00863   ulint   zip_size) 
00865 {
00866   buf_block_t*  block   = NULL;
00867   ibool   freed;
00868   ulint   n_iterations  = 1;
00869   ibool   mon_value_was = FALSE;
00870   ibool   started_monitor = FALSE;
00871 loop:
00872   buf_pool_mutex_enter(buf_pool);
00873 
00874   if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
00875       + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
00876     ut_print_timestamp(stderr);
00877 
00878     fprintf(stderr,
00879       "  InnoDB: ERROR: over 95 percent of the buffer pool"
00880       " is occupied by\n"
00881       "InnoDB: lock heaps or the adaptive hash index!"
00882       " Check that your\n"
00883       "InnoDB: transactions do not set too many row locks.\n"
00884       "InnoDB: Your buffer pool size is %lu MB."
00885       " Maybe you should make\n"
00886       "InnoDB: the buffer pool bigger?\n"
00887       "InnoDB: We intentionally generate a seg fault"
00888       " to print a stack trace\n"
00889       "InnoDB: on Linux!\n",
00890       (ulong) (buf_pool->curr_size
00891          / (1024 * 1024 / UNIV_PAGE_SIZE)));
00892 
00893     ut_error;
00894 
00895   } else if (!recv_recovery_on
00896        && (UT_LIST_GET_LEN(buf_pool->free)
00897            + UT_LIST_GET_LEN(buf_pool->LRU))
00898        < buf_pool->curr_size / 3) {
00899 
00900     if (!buf_lru_switched_on_innodb_mon) {
00901 
00902       /* Over 67 % of the buffer pool is occupied by lock
00903       heaps or the adaptive hash index. This may be a memory
00904       leak! */
00905 
00906       ut_print_timestamp(stderr);
00907       fprintf(stderr,
00908         "  InnoDB: WARNING: over 67 percent of"
00909         " the buffer pool is occupied by\n"
00910         "InnoDB: lock heaps or the adaptive"
00911         " hash index! Check that your\n"
00912         "InnoDB: transactions do not set too many"
00913         " row locks.\n"
00914         "InnoDB: Your buffer pool size is %lu MB."
00915         " Maybe you should make\n"
00916         "InnoDB: the buffer pool bigger?\n"
00917         "InnoDB: Starting the InnoDB Monitor to print"
00918         " diagnostics, including\n"
00919         "InnoDB: lock heap and hash index sizes.\n",
00920         (ulong) (buf_pool->curr_size
00921            / (1024 * 1024 / UNIV_PAGE_SIZE)));
00922 
00923       buf_lru_switched_on_innodb_mon = TRUE;
00924       srv_print_innodb_monitor = TRUE;
00925       os_event_set(srv_lock_timeout_thread_event);
00926     }
00927   } else if (buf_lru_switched_on_innodb_mon) {
00928 
00929     /* Switch off the InnoDB Monitor; this is a simple way
00930     to stop the monitor if the situation becomes less urgent,
00931     but may also surprise users if the user also switched on the
00932     monitor! */
00933 
00934     buf_lru_switched_on_innodb_mon = FALSE;
00935     srv_print_innodb_monitor = FALSE;
00936   }
00937 
00938   /* If there is a block in the free list, take it */
00939   block = buf_LRU_get_free_only(buf_pool);
00940   if (block) {
00941 
00942     ut_ad(buf_pool_from_block(block) == buf_pool);
00943 
00944 #ifdef UNIV_DEBUG
00945     block->page.zip.m_start =
00946 #endif /* UNIV_DEBUG */
00947       block->page.zip.m_end =
00948       block->page.zip.m_nonempty =
00949       block->page.zip.n_blobs = 0;
00950 
00951     if (UNIV_UNLIKELY(zip_size)) {
00952       ibool lru;
00953       page_zip_set_size(&block->page.zip, zip_size);
00954 
00955       block->page.zip.data = static_cast<unsigned char *>(buf_buddy_alloc(
00956         buf_pool, zip_size, &lru));
00957 
00958       UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
00959     } else {
00960       page_zip_set_size(&block->page.zip, 0);
00961       block->page.zip.data = NULL;
00962     }
00963 
00964     buf_pool_mutex_exit(buf_pool);
00965 
00966     if (started_monitor) {
00967       srv_print_innodb_monitor = mon_value_was;
00968     }
00969 
00970     return(block);
00971   }
00972 
00973   /* If no block was in the free list, search from the end of the LRU
00974   list and try to free a block there */
00975 
00976   buf_pool_mutex_exit(buf_pool);
00977 
00978   freed = buf_LRU_search_and_free_block(buf_pool, n_iterations);
00979 
00980   if (freed > 0) {
00981     goto loop;
00982   }
00983 
00984   if (n_iterations > 30) {
00985     ut_print_timestamp(stderr);
00986     fprintf(stderr,
00987       "  InnoDB: Warning: difficult to find free blocks in\n"
00988       "InnoDB: the buffer pool (%lu search iterations)!"
00989       " Consider\n"
00990       "InnoDB: increasing the buffer pool size.\n"
00991       "InnoDB: It is also possible that"
00992       " in your Unix version\n"
00993       "InnoDB: fsync is very slow, or"
00994       " completely frozen inside\n"
00995       "InnoDB: the OS kernel. Then upgrading to"
00996       " a newer version\n"
00997       "InnoDB: of your operating system may help."
00998       " Look at the\n"
00999       "InnoDB: number of fsyncs in diagnostic info below.\n"
01000       "InnoDB: Pending flushes (fsync) log: %lu;"
01001       " buffer pool: %lu\n"
01002       "InnoDB: %lu OS file reads, %lu OS file writes,"
01003       " %lu OS fsyncs\n"
01004       "InnoDB: Starting InnoDB Monitor to print further\n"
01005       "InnoDB: diagnostics to the standard output.\n",
01006       (ulong) n_iterations,
01007       (ulong) fil_n_pending_log_flushes,
01008       (ulong) fil_n_pending_tablespace_flushes,
01009       (ulong) os_n_file_reads, (ulong) os_n_file_writes,
01010       (ulong) os_n_fsyncs);
01011 
01012     mon_value_was = srv_print_innodb_monitor;
01013     started_monitor = TRUE;
01014     srv_print_innodb_monitor = TRUE;
01015     os_event_set(srv_lock_timeout_thread_event);
01016   }
01017 
01018   /* No free block was found: try to flush the LRU list */
01019 
01020   buf_flush_free_margin(buf_pool);
01021   ++srv_buf_pool_wait_free;
01022 
01023   os_aio_simulated_wake_handler_threads();
01024 
01025   buf_pool_mutex_enter(buf_pool);
01026 
01027   if (buf_pool->LRU_flush_ended > 0) {
01028     /* We have written pages in an LRU flush. To make the insert
01029     buffer more efficient, we try to move these pages to the free
01030     list. */
01031 
01032     buf_pool_mutex_exit(buf_pool);
01033 
01034     buf_LRU_try_free_flushed_blocks(buf_pool);
01035   } else {
01036     buf_pool_mutex_exit(buf_pool);
01037   }
01038 
01039   if (n_iterations > 10) {
01040 
01041     os_thread_sleep(500000);
01042   }
01043 
01044   n_iterations++;
01045 
01046   goto loop;
01047 }
01048 
01049 /*******************************************************************/
01052 UNIV_INLINE
01053 void
01054 buf_LRU_old_adjust_len(
01055 /*===================*/
01056   buf_pool_t* buf_pool) 
01057 {
01058   ulint old_len;
01059   ulint new_len;
01060 
01061   ut_a(buf_pool->LRU_old);
01062   ut_ad(buf_pool_mutex_own(buf_pool));
01063   ut_ad(buf_pool->LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN);
01064   ut_ad(buf_pool->LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX);
01065 #if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)
01066 # error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)"
01067 #endif
01068 #ifdef UNIV_LRU_DEBUG
01069   /* buf_pool->LRU_old must be the first item in the LRU list
01070   whose "old" flag is set. */
01071   ut_a(buf_pool->LRU_old->old);
01072   ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
01073        || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
01074   ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
01075        || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
01076 #endif /* UNIV_LRU_DEBUG */
01077 
01078   old_len = buf_pool->LRU_old_len;
01079   new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU)
01080        * buf_pool->LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV,
01081        UT_LIST_GET_LEN(buf_pool->LRU)
01082        - (BUF_LRU_OLD_TOLERANCE
01083           + BUF_LRU_NON_OLD_MIN_LEN));
01084 
01085   for (;;) {
01086     buf_page_t* LRU_old = buf_pool->LRU_old;
01087 
01088     ut_a(LRU_old);
01089     ut_ad(LRU_old->in_LRU_list);
01090 #ifdef UNIV_LRU_DEBUG
01091     ut_a(LRU_old->old);
01092 #endif /* UNIV_LRU_DEBUG */
01093 
01094     /* Update the LRU_old pointer if necessary */
01095 
01096     if (old_len + BUF_LRU_OLD_TOLERANCE < new_len) {
01097 
01098       buf_pool->LRU_old = LRU_old = UT_LIST_GET_PREV(
01099         LRU, LRU_old);
01100 #ifdef UNIV_LRU_DEBUG
01101       ut_a(!LRU_old->old);
01102 #endif /* UNIV_LRU_DEBUG */
01103       old_len = ++buf_pool->LRU_old_len;
01104       buf_page_set_old(LRU_old, TRUE);
01105 
01106     } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
01107 
01108       buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU, LRU_old);
01109       old_len = --buf_pool->LRU_old_len;
01110       buf_page_set_old(LRU_old, FALSE);
01111     } else {
01112       return;
01113     }
01114   }
01115 }
01116 
01117 /*******************************************************************/
01120 static
01121 void
01122 buf_LRU_old_init(
01123 /*=============*/
01124   buf_pool_t* buf_pool)
01125 {
01126   buf_page_t* bpage;
01127 
01128   ut_ad(buf_pool_mutex_own(buf_pool));
01129   ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
01130 
01131   /* We first initialize all blocks in the LRU list as old and then use
01132   the adjust function to move the LRU_old pointer to the right
01133   position */
01134 
01135   for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); bpage != NULL;
01136        bpage = UT_LIST_GET_PREV(LRU, bpage)) {
01137     ut_ad(bpage->in_LRU_list);
01138     ut_ad(buf_page_in_file(bpage));
01139     /* This loop temporarily violates the
01140     assertions of buf_page_set_old(). */
01141     bpage->old = TRUE;
01142   }
01143 
01144   buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
01145   buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
01146 
01147   buf_LRU_old_adjust_len(buf_pool);
01148 }
01149 
01150 /******************************************************************/
01152 static
01153 void
01154 buf_unzip_LRU_remove_block_if_needed(
01155 /*=================================*/
01156   buf_page_t* bpage)  
01157 {
01158   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01159 
01160   ut_ad(buf_pool);
01161   ut_ad(bpage);
01162   ut_ad(buf_page_in_file(bpage));
01163   ut_ad(buf_pool_mutex_own(buf_pool));
01164 
01165   if (buf_page_belongs_to_unzip_LRU(bpage)) {
01166     buf_block_t*  block = (buf_block_t*) bpage;
01167 
01168     ut_ad(block->in_unzip_LRU_list);
01169     ut_d(block->in_unzip_LRU_list = FALSE);
01170 
01171     UT_LIST_REMOVE(unzip_LRU, buf_pool->unzip_LRU, block);
01172   }
01173 }
01174 
01175 /******************************************************************/
01177 UNIV_INLINE
01178 void
01179 buf_LRU_remove_block(
01180 /*=================*/
01181   buf_page_t* bpage)  
01182 {
01183   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01184 
01185   ut_ad(buf_pool);
01186   ut_ad(bpage);
01187   ut_ad(buf_pool_mutex_own(buf_pool));
01188 
01189   ut_a(buf_page_in_file(bpage));
01190 
01191   ut_ad(bpage->in_LRU_list);
01192 
01193   /* If the LRU_old pointer is defined and points to just this block,
01194   move it backward one step */
01195 
01196   if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
01197 
01198     /* Below: the previous block is guaranteed to exist,
01199     because the LRU_old pointer is only allowed to differ
01200     by BUF_LRU_OLD_TOLERANCE from strict
01201     buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU
01202     list length. */
01203     buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
01204 
01205     ut_a(prev_bpage);
01206 #ifdef UNIV_LRU_DEBUG
01207     ut_a(!prev_bpage->old);
01208 #endif /* UNIV_LRU_DEBUG */
01209     buf_pool->LRU_old = prev_bpage;
01210     buf_page_set_old(prev_bpage, TRUE);
01211 
01212     buf_pool->LRU_old_len++;
01213   }
01214 
01215   /* Remove the block from the LRU list */
01216   UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
01217   ut_d(bpage->in_LRU_list = FALSE);
01218 
01219   buf_unzip_LRU_remove_block_if_needed(bpage);
01220 
01221   /* If the LRU list is so short that LRU_old is not defined,
01222   clear the "old" flags and return */
01223   if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
01224 
01225     for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU); bpage != NULL;
01226          bpage = UT_LIST_GET_NEXT(LRU, bpage)) {
01227       /* This loop temporarily violates the
01228       assertions of buf_page_set_old(). */
01229       bpage->old = FALSE;
01230     }
01231 
01232     buf_pool->LRU_old = NULL;
01233     buf_pool->LRU_old_len = 0;
01234 
01235     return;
01236   }
01237 
01238   ut_ad(buf_pool->LRU_old);
01239 
01240   /* Update the LRU_old_len field if necessary */
01241   if (buf_page_is_old(bpage)) {
01242 
01243     buf_pool->LRU_old_len--;
01244   }
01245 
01246   /* Adjust the length of the old block list if necessary */
01247   buf_LRU_old_adjust_len(buf_pool);
01248 }
01249 
01250 /******************************************************************/
01252 UNIV_INTERN
01253 void
01254 buf_unzip_LRU_add_block(
01255 /*====================*/
01256   buf_block_t*  block,  
01257   ibool   old)  
01259 {
01260   buf_pool_t* buf_pool = buf_pool_from_block(block);
01261 
01262   ut_ad(buf_pool);
01263   ut_ad(block);
01264   ut_ad(buf_pool_mutex_own(buf_pool));
01265 
01266   ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
01267 
01268   ut_ad(!block->in_unzip_LRU_list);
01269   ut_d(block->in_unzip_LRU_list = TRUE);
01270 
01271   if (old) {
01272     UT_LIST_ADD_LAST(unzip_LRU, buf_pool->unzip_LRU, block);
01273   } else {
01274     UT_LIST_ADD_FIRST(unzip_LRU, buf_pool->unzip_LRU, block);
01275   }
01276 }
01277 
01278 /******************************************************************/
01280 UNIV_INLINE
01281 void
01282 buf_LRU_add_block_to_end_low(
01283 /*=========================*/
01284   buf_page_t* bpage)  
01285 {
01286   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01287 
01288   ut_ad(buf_pool);
01289   ut_ad(bpage);
01290   ut_ad(buf_pool_mutex_own(buf_pool));
01291 
01292   ut_a(buf_page_in_file(bpage));
01293 
01294   ut_ad(!bpage->in_LRU_list);
01295   UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage);
01296   ut_d(bpage->in_LRU_list = TRUE);
01297 
01298   if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
01299 
01300     ut_ad(buf_pool->LRU_old);
01301 
01302     /* Adjust the length of the old block list if necessary */
01303 
01304     buf_page_set_old(bpage, TRUE);
01305     buf_pool->LRU_old_len++;
01306     buf_LRU_old_adjust_len(buf_pool);
01307 
01308   } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
01309 
01310     /* The LRU list is now long enough for LRU_old to become
01311     defined: init it */
01312 
01313     buf_LRU_old_init(buf_pool);
01314   } else {
01315     buf_page_set_old(bpage, buf_pool->LRU_old != NULL);
01316   }
01317 
01318   /* If this is a zipped block with decompressed frame as well
01319   then put it on the unzip_LRU list */
01320   if (buf_page_belongs_to_unzip_LRU(bpage)) {
01321     buf_unzip_LRU_add_block((buf_block_t*) bpage, TRUE);
01322   }
01323 }
01324 
01325 /******************************************************************/
01327 UNIV_INLINE
01328 void
01329 buf_LRU_add_block_low(
01330 /*==================*/
01331   buf_page_t* bpage,  
01332   ibool   old)  
01336 {
01337   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01338 
01339   ut_ad(buf_pool);
01340   ut_ad(bpage);
01341   ut_ad(buf_pool_mutex_own(buf_pool));
01342 
01343   ut_a(buf_page_in_file(bpage));
01344   ut_ad(!bpage->in_LRU_list);
01345 
01346   if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
01347 
01348     UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
01349 
01350     bpage->freed_page_clock = buf_pool->freed_page_clock;
01351   } else {
01352 #ifdef UNIV_LRU_DEBUG
01353     /* buf_pool->LRU_old must be the first item in the LRU list
01354     whose "old" flag is set. */
01355     ut_a(buf_pool->LRU_old->old);
01356     ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
01357          || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
01358     ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
01359          || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
01360 #endif /* UNIV_LRU_DEBUG */
01361     UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
01362              bpage);
01363     buf_pool->LRU_old_len++;
01364   }
01365 
01366   ut_d(bpage->in_LRU_list = TRUE);
01367 
01368   if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
01369 
01370     ut_ad(buf_pool->LRU_old);
01371 
01372     /* Adjust the length of the old block list if necessary */
01373 
01374     buf_page_set_old(bpage, old);
01375     buf_LRU_old_adjust_len(buf_pool);
01376 
01377   } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
01378 
01379     /* The LRU list is now long enough for LRU_old to become
01380     defined: init it */
01381 
01382     buf_LRU_old_init(buf_pool);
01383   } else {
01384     buf_page_set_old(bpage, buf_pool->LRU_old != NULL);
01385   }
01386 
01387   /* If this is a zipped block with decompressed frame as well
01388   then put it on the unzip_LRU list */
01389   if (buf_page_belongs_to_unzip_LRU(bpage)) {
01390     buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
01391   }
01392 }
01393 
01394 /******************************************************************/
01396 UNIV_INTERN
01397 void
01398 buf_LRU_add_block(
01399 /*==============*/
01400   buf_page_t* bpage,  
01401   ibool   old)  
01406 {
01407   buf_LRU_add_block_low(bpage, old);
01408 }
01409 
01410 /******************************************************************/
01412 UNIV_INTERN
01413 void
01414 buf_LRU_make_block_young(
01415 /*=====================*/
01416   buf_page_t* bpage)  
01417 {
01418   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01419 
01420   ut_ad(buf_pool_mutex_own(buf_pool));
01421 
01422   if (bpage->old) {
01423     buf_pool->stat.n_pages_made_young++;
01424   }
01425 
01426   buf_LRU_remove_block(bpage);
01427   buf_LRU_add_block_low(bpage, FALSE);
01428 }
01429 
01430 /******************************************************************/
01432 UNIV_INTERN
01433 void
01434 buf_LRU_make_block_old(
01435 /*===================*/
01436   buf_page_t* bpage)  
01437 {
01438   buf_LRU_remove_block(bpage);
01439   buf_LRU_add_block_to_end_low(bpage);
01440 }
01441 
01442 /******************************************************************/
01455 UNIV_INTERN
01456 enum buf_lru_free_block_status
01457 buf_LRU_free_block(
01458 /*===============*/
01459   buf_page_t* bpage,  
01460   ibool   zip,  
01462   ibool*    buf_pool_mutex_released)
01466 {
01467   buf_page_t* b = NULL;
01468   buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
01469   mutex_t*  block_mutex = buf_page_get_mutex(bpage);
01470 
01471   ut_ad(buf_pool_mutex_own(buf_pool));
01472   ut_ad(mutex_own(block_mutex));
01473   ut_ad(buf_page_in_file(bpage));
01474   ut_ad(bpage->in_LRU_list);
01475   ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
01476 #if UNIV_WORD_SIZE == 4
01477   /* On 32-bit systems, there is no padding in buf_page_t.  On
01478   other systems, Valgrind could complain about uninitialized pad
01479   bytes. */
01480   UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
01481 #endif
01482 
01483   if (!buf_page_can_relocate(bpage)) {
01484 
01485     /* Do not free buffer-fixed or I/O-fixed blocks. */
01486     return(BUF_LRU_NOT_FREED);
01487   }
01488 
01489 #ifdef UNIV_IBUF_COUNT_DEBUG
01490   ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
01491 #endif /* UNIV_IBUF_COUNT_DEBUG */
01492 
01493   if (zip || !bpage->zip.data) {
01494     /* This would completely free the block. */
01495     /* Do not completely free dirty blocks. */
01496 
01497     if (bpage->oldest_modification) {
01498       return(BUF_LRU_NOT_FREED);
01499     }
01500   } else if (bpage->oldest_modification) {
01501     /* Do not completely free dirty blocks. */
01502 
01503     if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
01504       ut_ad(buf_page_get_state(bpage)
01505             == BUF_BLOCK_ZIP_DIRTY);
01506       return(BUF_LRU_NOT_FREED);
01507     }
01508 
01509     goto alloc;
01510   } else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
01511     /* Allocate the control block for the compressed page.
01512     If it cannot be allocated (without freeing a block
01513     from the LRU list), refuse to free bpage. */
01514 alloc:
01515     buf_pool_mutex_exit_forbid(buf_pool);
01516     b = static_cast<buf_page_t *>(buf_buddy_alloc(buf_pool, sizeof *b, NULL));
01517     buf_pool_mutex_exit_allow(buf_pool);
01518 
01519     if (UNIV_UNLIKELY(!b)) {
01520       return(BUF_LRU_CANNOT_RELOCATE);
01521     }
01522 
01523     memcpy(b, bpage, sizeof *b);
01524   }
01525 
01526 #ifdef UNIV_DEBUG
01527   if (buf_debug_prints) {
01528     fprintf(stderr, "Putting space %lu page %lu to free list\n",
01529       (ulong) buf_page_get_space(bpage),
01530       (ulong) buf_page_get_page_no(bpage));
01531   }
01532 #endif /* UNIV_DEBUG */
01533 
01534   if (buf_LRU_block_remove_hashed_page(bpage, zip)
01535       != BUF_BLOCK_ZIP_FREE) {
01536     ut_a(bpage->buf_fix_count == 0);
01537 
01538     if (b) {
01539       buf_page_t* hash_b;
01540       buf_page_t* prev_b  = UT_LIST_GET_PREV(LRU, b);
01541 
01542       const ulint fold = buf_page_address_fold(
01543         bpage->space, bpage->offset);
01544 
01545       hash_b  = buf_page_hash_get_low(
01546         buf_pool, bpage->space, bpage->offset, fold);
01547 
01548       ut_a(!hash_b);
01549 
01550       b->state = b->oldest_modification
01551         ? BUF_BLOCK_ZIP_DIRTY
01552         : BUF_BLOCK_ZIP_PAGE;
01553       UNIV_MEM_DESC(b->zip.data,
01554               page_zip_get_size(&b->zip), b);
01555 
01556       /* The fields in_page_hash and in_LRU_list of
01557       the to-be-freed block descriptor should have
01558       been cleared in
01559       buf_LRU_block_remove_hashed_page(), which
01560       invokes buf_LRU_remove_block(). */
01561       ut_ad(!bpage->in_page_hash);
01562       ut_ad(!bpage->in_LRU_list);
01563       /* bpage->state was BUF_BLOCK_FILE_PAGE because
01564       b != NULL. The type cast below is thus valid. */
01565       ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
01566 
01567       /* The fields of bpage were copied to b before
01568       buf_LRU_block_remove_hashed_page() was invoked. */
01569       ut_ad(!b->in_zip_hash);
01570       ut_ad(b->in_page_hash);
01571       ut_ad(b->in_LRU_list);
01572 
01573       HASH_INSERT(buf_page_t, hash,
01574             buf_pool->page_hash, fold, b);
01575 
01576       /* Insert b where bpage was in the LRU list. */
01577       if (UNIV_LIKELY(prev_b != NULL)) {
01578         ulint lru_len;
01579 
01580         ut_ad(prev_b->in_LRU_list);
01581         ut_ad(buf_page_in_file(prev_b));
01582 #if UNIV_WORD_SIZE == 4
01583         /* On 32-bit systems, there is no
01584         padding in buf_page_t.  On other
01585         systems, Valgrind could complain about
01586         uninitialized pad bytes. */
01587         UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
01588 #endif
01589         UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
01590                  prev_b, b);
01591 
01592         if (buf_page_is_old(b)) {
01593           buf_pool->LRU_old_len++;
01594           if (UNIV_UNLIKELY
01595               (buf_pool->LRU_old
01596                == UT_LIST_GET_NEXT(LRU, b))) {
01597 
01598             buf_pool->LRU_old = b;
01599           }
01600         }
01601 
01602         lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
01603 
01604         if (lru_len > BUF_LRU_OLD_MIN_LEN) {
01605           ut_ad(buf_pool->LRU_old);
01606           /* Adjust the length of the
01607           old block list if necessary */
01608           buf_LRU_old_adjust_len(buf_pool);
01609         } else if (lru_len == BUF_LRU_OLD_MIN_LEN) {
01610           /* The LRU list is now long
01611           enough for LRU_old to become
01612           defined: init it */
01613           buf_LRU_old_init(buf_pool);
01614         }
01615 #ifdef UNIV_LRU_DEBUG
01616         /* Check that the "old" flag is consistent
01617         in the block and its neighbours. */
01618         buf_page_set_old(b, buf_page_is_old(b));
01619 #endif /* UNIV_LRU_DEBUG */
01620       } else {
01621         ut_d(b->in_LRU_list = FALSE);
01622         buf_LRU_add_block_low(b, buf_page_is_old(b));
01623       }
01624 
01625       if (b->state == BUF_BLOCK_ZIP_PAGE) {
01626         buf_LRU_insert_zip_clean(b);
01627       } else {
01628         /* Relocate on buf_pool->flush_list. */
01629         buf_flush_relocate_on_flush_list(bpage, b);
01630       }
01631 
01632       bpage->zip.data = NULL;
01633       page_zip_set_size(&bpage->zip, 0);
01634 
01635       /* Prevent buf_page_get_gen() from
01636       decompressing the block while we release
01637       buf_pool->mutex and block_mutex. */
01638       b->buf_fix_count++;
01639       b->io_fix = BUF_IO_READ;
01640     }
01641 
01642     if (buf_pool_mutex_released) {
01643       *buf_pool_mutex_released = TRUE;
01644     }
01645 
01646     buf_pool_mutex_exit(buf_pool);
01647     mutex_exit(block_mutex);
01648 
01649     /* Remove possible adaptive hash index on the page.
01650     The page was declared uninitialized by
01651     buf_LRU_block_remove_hashed_page().  We need to flag
01652     the contents of the page valid (which it still is) in
01653     order to avoid bogus Valgrind warnings.*/
01654 
01655     UNIV_MEM_VALID(((buf_block_t*) bpage)->frame,
01656              UNIV_PAGE_SIZE);
01657     btr_search_drop_page_hash_index((buf_block_t*) bpage);
01658     UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
01659          UNIV_PAGE_SIZE);
01660 
01661     if (b) {
01662       /* Compute and stamp the compressed page
01663       checksum while not holding any mutex.  The
01664       block is already half-freed
01665       (BUF_BLOCK_REMOVE_HASH) and removed from
01666       buf_pool->page_hash, thus inaccessible by any
01667       other thread. */
01668 
01669       mach_write_to_4(
01670         b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
01671         UNIV_LIKELY(srv_use_checksums)
01672         ? page_zip_calc_checksum(
01673           b->zip.data,
01674           page_zip_get_size(&b->zip))
01675         : BUF_NO_CHECKSUM_MAGIC);
01676     }
01677 
01678     buf_pool_mutex_enter(buf_pool);
01679     mutex_enter(block_mutex);
01680 
01681     if (b) {
01682       mutex_enter(&buf_pool->zip_mutex);
01683       b->buf_fix_count--;
01684       buf_page_set_io_fix(b, BUF_IO_NONE);
01685       mutex_exit(&buf_pool->zip_mutex);
01686     }
01687 
01688     buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
01689   } else {
01690     /* The block_mutex should have been released by
01691     buf_LRU_block_remove_hashed_page() when it returns
01692     BUF_BLOCK_ZIP_FREE. */
01693     ut_ad(block_mutex == &buf_pool->zip_mutex);
01694     mutex_enter(block_mutex);
01695   }
01696 
01697   return(BUF_LRU_FREED);
01698 }
01699 
01700 /******************************************************************/
01702 UNIV_INTERN
01703 void
01704 buf_LRU_block_free_non_file_page(
01705 /*=============================*/
01706   buf_block_t*  block)  
01707 {
01708   void*   data;
01709   buf_pool_t* buf_pool = buf_pool_from_block(block);
01710 
01711   ut_ad(block);
01712   ut_ad(buf_pool_mutex_own(buf_pool));
01713   ut_ad(mutex_own(&block->mutex));
01714 
01715   switch (buf_block_get_state(block)) {
01716   case BUF_BLOCK_MEMORY:
01717   case BUF_BLOCK_READY_FOR_USE:
01718     break;
01719   default:
01720     ut_error;
01721   }
01722 
01723 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
01724   ut_a(block->n_pointers == 0);
01725 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
01726   ut_ad(!block->page.in_free_list);
01727   ut_ad(!block->page.in_flush_list);
01728   ut_ad(!block->page.in_LRU_list);
01729 
01730   buf_block_set_state(block, BUF_BLOCK_NOT_USED);
01731 
01732   UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
01733 #ifdef UNIV_DEBUG
01734   /* Wipe contents of page to reveal possible stale pointers to it */
01735   memset(block->frame, '\0', UNIV_PAGE_SIZE);
01736 #else
01737   /* Wipe page_no and space_id */
01738   memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
01739   memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
01740 #endif
01741   data = block->page.zip.data;
01742 
01743   if (data) {
01744     block->page.zip.data = NULL;
01745     mutex_exit(&block->mutex);
01746     buf_pool_mutex_exit_forbid(buf_pool);
01747 
01748     buf_buddy_free(
01749       buf_pool, data, page_zip_get_size(&block->page.zip));
01750 
01751     buf_pool_mutex_exit_allow(buf_pool);
01752     mutex_enter(&block->mutex);
01753     page_zip_set_size(&block->page.zip, 0);
01754   }
01755 
01756   UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
01757   ut_d(block->page.in_free_list = TRUE);
01758 
01759   UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
01760 }
01761 
01762 /******************************************************************/
01772 static
01773 enum buf_page_state
01774 buf_LRU_block_remove_hashed_page(
01775 /*=============================*/
01776   buf_page_t* bpage,  
01779   ibool   zip)  
01781 {
01782   ulint     fold;
01783   const buf_page_t* hashed_bpage;
01784   buf_pool_t*   buf_pool = buf_pool_from_bpage(bpage);
01785 
01786   ut_ad(bpage);
01787   ut_ad(buf_pool_mutex_own(buf_pool));
01788   ut_ad(mutex_own(buf_page_get_mutex(bpage)));
01789 
01790   ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
01791   ut_a(bpage->buf_fix_count == 0);
01792 
01793 #if UNIV_WORD_SIZE == 4
01794   /* On 32-bit systems, there is no padding in
01795   buf_page_t.  On other systems, Valgrind could complain
01796   about uninitialized pad bytes. */
01797   UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
01798 #endif
01799 
01800   buf_LRU_remove_block(bpage);
01801 
01802   buf_pool->freed_page_clock += 1;
01803 
01804   switch (buf_page_get_state(bpage)) {
01805   case BUF_BLOCK_FILE_PAGE:
01806     UNIV_MEM_ASSERT_W(bpage, sizeof(buf_block_t));
01807     UNIV_MEM_ASSERT_W(((buf_block_t*) bpage)->frame,
01808           UNIV_PAGE_SIZE);
01809     buf_block_modify_clock_inc((buf_block_t*) bpage);
01810     if (bpage->zip.data) {
01811       const page_t* page = ((buf_block_t*) bpage)->frame;
01812       const ulint zip_size
01813         = page_zip_get_size(&bpage->zip);
01814 
01815       ut_a(!zip || bpage->oldest_modification == 0);
01816 
01817       switch (UNIV_EXPECT(fil_page_get_type(page),
01818               FIL_PAGE_INDEX)) {
01819       case FIL_PAGE_TYPE_ALLOCATED:
01820       case FIL_PAGE_INODE:
01821       case FIL_PAGE_IBUF_BITMAP:
01822       case FIL_PAGE_TYPE_FSP_HDR:
01823       case FIL_PAGE_TYPE_XDES:
01824         /* These are essentially uncompressed pages. */
01825         if (!zip) {
01826           /* InnoDB writes the data to the
01827           uncompressed page frame.  Copy it
01828           to the compressed page, which will
01829           be preserved. */
01830           memcpy(bpage->zip.data, page,
01831                  zip_size);
01832         }
01833         break;
01834       case FIL_PAGE_TYPE_ZBLOB:
01835       case FIL_PAGE_TYPE_ZBLOB2:
01836         break;
01837       case FIL_PAGE_INDEX:
01838 #ifdef UNIV_ZIP_DEBUG
01839         ut_a(page_zip_validate(&bpage->zip, page));
01840 #endif /* UNIV_ZIP_DEBUG */
01841         break;
01842       default:
01843         ut_print_timestamp(stderr);
01844         fputs("  InnoDB: ERROR: The compressed page"
01845               " to be evicted seems corrupt:", stderr);
01846         ut_print_buf(stderr, page, zip_size);
01847         fputs("\nInnoDB: Possibly older version"
01848               " of the page:", stderr);
01849         ut_print_buf(stderr, bpage->zip.data,
01850                zip_size);
01851         putc('\n', stderr);
01852         ut_error;
01853       }
01854 
01855       break;
01856     }
01857     /* fall through */
01858   case BUF_BLOCK_ZIP_PAGE:
01859     ut_a(bpage->oldest_modification == 0);
01860     UNIV_MEM_ASSERT_W(bpage->zip.data,
01861           page_zip_get_size(&bpage->zip));
01862     break;
01863   case BUF_BLOCK_ZIP_FREE:
01864   case BUF_BLOCK_ZIP_DIRTY:
01865   case BUF_BLOCK_NOT_USED:
01866   case BUF_BLOCK_READY_FOR_USE:
01867   case BUF_BLOCK_MEMORY:
01868   case BUF_BLOCK_REMOVE_HASH:
01869     ut_error;
01870     break;
01871   }
01872 
01873   fold = buf_page_address_fold(bpage->space, bpage->offset);
01874   hashed_bpage = buf_page_hash_get_low(
01875     buf_pool, bpage->space, bpage->offset, fold);
01876 
01877   if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
01878     fprintf(stderr,
01879       "InnoDB: Error: page %lu %lu not found"
01880       " in the hash table\n",
01881       (ulong) bpage->space,
01882       (ulong) bpage->offset);
01883     if (hashed_bpage) {
01884       fprintf(stderr,
01885         "InnoDB: In hash table we find block"
01886         " %p of %lu %lu which is not %p\n",
01887         (const void*) hashed_bpage,
01888         (ulong) hashed_bpage->space,
01889         (ulong) hashed_bpage->offset,
01890         (const void*) bpage);
01891     }
01892 
01893 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
01894     mutex_exit(buf_page_get_mutex(bpage));
01895     buf_pool_mutex_exit(buf_pool);
01896     buf_print();
01897     buf_LRU_print();
01898     buf_validate();
01899     buf_LRU_validate();
01900 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
01901     ut_error;
01902   }
01903 
01904   ut_ad(!bpage->in_zip_hash);
01905   ut_ad(bpage->in_page_hash);
01906   ut_d(bpage->in_page_hash = FALSE);
01907   HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
01908   switch (buf_page_get_state(bpage)) {
01909   case BUF_BLOCK_ZIP_PAGE:
01910     ut_ad(!bpage->in_free_list);
01911     ut_ad(!bpage->in_flush_list);
01912     ut_ad(!bpage->in_LRU_list);
01913     ut_a(bpage->zip.data);
01914     ut_a(buf_page_get_zip_size(bpage));
01915 
01916     UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
01917 
01918     mutex_exit(&buf_pool->zip_mutex);
01919     buf_pool_mutex_exit_forbid(buf_pool);
01920 
01921     buf_buddy_free(
01922       buf_pool, bpage->zip.data,
01923       page_zip_get_size(&bpage->zip));
01924 
01925     buf_buddy_free(buf_pool, bpage, sizeof(*bpage));
01926     buf_pool_mutex_exit_allow(buf_pool);
01927 
01928     UNIV_MEM_UNDESC(bpage);
01929     return(BUF_BLOCK_ZIP_FREE);
01930 
01931   case BUF_BLOCK_FILE_PAGE:
01932     memset(((buf_block_t*) bpage)->frame
01933            + FIL_PAGE_OFFSET, 0xff, 4);
01934     memset(((buf_block_t*) bpage)->frame
01935            + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
01936     UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
01937          UNIV_PAGE_SIZE);
01938     buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
01939 
01940     if (zip && bpage->zip.data) {
01941       /* Free the compressed page. */
01942       void* data = bpage->zip.data;
01943       bpage->zip.data = NULL;
01944 
01945       ut_ad(!bpage->in_free_list);
01946       ut_ad(!bpage->in_flush_list);
01947       ut_ad(!bpage->in_LRU_list);
01948       mutex_exit(&((buf_block_t*) bpage)->mutex);
01949       buf_pool_mutex_exit_forbid(buf_pool);
01950 
01951       buf_buddy_free(
01952         buf_pool, data,
01953         page_zip_get_size(&bpage->zip));
01954 
01955       buf_pool_mutex_exit_allow(buf_pool);
01956       mutex_enter(&((buf_block_t*) bpage)->mutex);
01957       page_zip_set_size(&bpage->zip, 0);
01958     }
01959 
01960     return(BUF_BLOCK_REMOVE_HASH);
01961 
01962   case BUF_BLOCK_ZIP_FREE:
01963   case BUF_BLOCK_ZIP_DIRTY:
01964   case BUF_BLOCK_NOT_USED:
01965   case BUF_BLOCK_READY_FOR_USE:
01966   case BUF_BLOCK_MEMORY:
01967   case BUF_BLOCK_REMOVE_HASH:
01968     break;
01969   }
01970 
01971   ut_error;
01972   return(BUF_BLOCK_ZIP_FREE);
01973 }
01974 
01975 /******************************************************************/
01977 static
01978 void
01979 buf_LRU_block_free_hashed_page(
01980 /*===========================*/
01981   buf_block_t*  block)  
01983 {
01984 #ifdef UNIV_DEBUG
01985   buf_pool_t* buf_pool = buf_pool_from_block(block);
01986   ut_ad(buf_pool_mutex_own(buf_pool));
01987 #endif
01988   ut_ad(mutex_own(&block->mutex));
01989 
01990   buf_block_set_state(block, BUF_BLOCK_MEMORY);
01991 
01992   buf_LRU_block_free_non_file_page(block);
01993 }
01994 
01995 /**********************************************************************/
01998 static
01999 uint
02000 buf_LRU_old_ratio_update_instance(
02001 /*==============================*/
02002   buf_pool_t* buf_pool,
02003   uint    old_pct,
02005   ibool   adjust) 
02008 {
02009   uint  ratio;
02010 
02011   ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100;
02012   if (ratio < BUF_LRU_OLD_RATIO_MIN) {
02013     ratio = BUF_LRU_OLD_RATIO_MIN;
02014   } else if (ratio > BUF_LRU_OLD_RATIO_MAX) {
02015     ratio = BUF_LRU_OLD_RATIO_MAX;
02016   }
02017 
02018   if (adjust) {
02019     buf_pool_mutex_enter(buf_pool);
02020 
02021     if (ratio != buf_pool->LRU_old_ratio) {
02022       buf_pool->LRU_old_ratio = ratio;
02023 
02024       if (UT_LIST_GET_LEN(buf_pool->LRU)
02025          >= BUF_LRU_OLD_MIN_LEN) {
02026 
02027         buf_LRU_old_adjust_len(buf_pool);
02028       }
02029     }
02030 
02031     buf_pool_mutex_exit(buf_pool);
02032   } else {
02033     buf_pool->LRU_old_ratio = ratio;
02034   }
02035   /* the reverse of 
02036   ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */
02037   return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5));
02038 }
02039 
02040 /**********************************************************************/
02043 UNIV_INTERN
02044 ulint
02045 buf_LRU_old_ratio_update(
02046 /*=====================*/
02047   uint  old_pct,
02049   ibool adjust) 
02052 {
02053   ulint i;
02054   ulint new_ratio = 0;
02055 
02056   for (i = 0; i < srv_buf_pool_instances; i++) {
02057     buf_pool_t* buf_pool;
02058 
02059     buf_pool = buf_pool_from_array(i);
02060 
02061     new_ratio = buf_LRU_old_ratio_update_instance(
02062       buf_pool, old_pct, adjust);
02063   }
02064 
02065   return(new_ratio);
02066 }
02067 
02068 /********************************************************************/
02071 UNIV_INTERN
02072 void
02073 buf_LRU_stat_update(void)
02074 /*=====================*/
02075 {
02076   ulint   i;
02077   buf_LRU_stat_t* item;
02078   buf_pool_t* buf_pool;
02079   ibool   evict_started = FALSE;
02080 
02081   /* If we haven't started eviction yet then don't update stats. */
02082   for (i = 0; i < srv_buf_pool_instances; i++) {
02083 
02084     buf_pool = buf_pool_from_array(i);
02085 
02086     if (buf_pool->freed_page_clock != 0) {
02087       evict_started = TRUE;
02088       break;
02089     }
02090   }
02091 
02092   if (!evict_started) {
02093     goto func_exit;
02094   }
02095 
02096   /* Update the index. */
02097   item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind];
02098   buf_LRU_stat_arr_ind++;
02099   buf_LRU_stat_arr_ind %= BUF_LRU_STAT_N_INTERVAL;
02100 
02101   /* Add the current value and subtract the obsolete entry. */
02102   buf_LRU_stat_sum.io += buf_LRU_stat_cur.io - item->io;
02103   buf_LRU_stat_sum.unzip += buf_LRU_stat_cur.unzip - item->unzip;
02104 
02105   /* Put current entry in the array. */
02106   memcpy(item, &buf_LRU_stat_cur, sizeof *item);
02107 
02108 func_exit:
02109   /* Clear the current entry. */
02110   memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
02111 }
02112 
02113 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
02114 /**********************************************************************/
02116 static
02117 void
02118 buf_LRU_validate_instance(
02119 /*======================*/
02120   buf_pool_t* buf_pool)
02121 {
02122   buf_page_t* bpage;
02123   buf_block_t*  block;
02124   ulint   old_len;
02125   ulint   new_len;
02126 
02127   ut_ad(buf_pool);
02128   buf_pool_mutex_enter(buf_pool);
02129 
02130   if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
02131 
02132     ut_a(buf_pool->LRU_old);
02133     old_len = buf_pool->LRU_old_len;
02134     new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU)
02135          * buf_pool->LRU_old_ratio
02136          / BUF_LRU_OLD_RATIO_DIV,
02137          UT_LIST_GET_LEN(buf_pool->LRU)
02138          - (BUF_LRU_OLD_TOLERANCE
02139             + BUF_LRU_NON_OLD_MIN_LEN));
02140     ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
02141     ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
02142   }
02143 
02144   UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
02145        ut_ad(ut_list_node_313->in_LRU_list));
02146 
02147   bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
02148 
02149   old_len = 0;
02150 
02151   while (bpage != NULL) {
02152 
02153     switch (buf_page_get_state(bpage)) {
02154     case BUF_BLOCK_ZIP_FREE:
02155     case BUF_BLOCK_NOT_USED:
02156     case BUF_BLOCK_READY_FOR_USE:
02157     case BUF_BLOCK_MEMORY:
02158     case BUF_BLOCK_REMOVE_HASH:
02159       ut_error;
02160       break;
02161     case BUF_BLOCK_FILE_PAGE:
02162       ut_ad(((buf_block_t*) bpage)->in_unzip_LRU_list
02163             == buf_page_belongs_to_unzip_LRU(bpage));
02164     case BUF_BLOCK_ZIP_PAGE:
02165     case BUF_BLOCK_ZIP_DIRTY:
02166       break;
02167     }
02168 
02169     if (buf_page_is_old(bpage)) {
02170       const buf_page_t* prev
02171         = UT_LIST_GET_PREV(LRU, bpage);
02172       const buf_page_t* next
02173         = UT_LIST_GET_NEXT(LRU, bpage);
02174 
02175       if (!old_len++) {
02176         ut_a(buf_pool->LRU_old == bpage);
02177       } else {
02178         ut_a(!prev || buf_page_is_old(prev));
02179       }
02180 
02181       ut_a(!next || buf_page_is_old(next));
02182     }
02183 
02184     bpage = UT_LIST_GET_NEXT(LRU, bpage);
02185   }
02186 
02187   ut_a(buf_pool->LRU_old_len == old_len);
02188 
02189   UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free,
02190        ut_ad(ut_list_node_313->in_free_list));
02191 
02192   for (bpage = UT_LIST_GET_FIRST(buf_pool->free);
02193        bpage != NULL;
02194        bpage = UT_LIST_GET_NEXT(list, bpage)) {
02195 
02196     ut_a(buf_page_get_state(bpage) == BUF_BLOCK_NOT_USED);
02197   }
02198 
02199   UT_LIST_VALIDATE(unzip_LRU, buf_block_t, buf_pool->unzip_LRU,
02200        ut_ad(ut_list_node_313->in_unzip_LRU_list
02201              && ut_list_node_313->page.in_LRU_list));
02202 
02203   for (block = UT_LIST_GET_FIRST(buf_pool->unzip_LRU);
02204        block;
02205        block = UT_LIST_GET_NEXT(unzip_LRU, block)) {
02206 
02207     ut_ad(block->in_unzip_LRU_list);
02208     ut_ad(block->page.in_LRU_list);
02209     ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
02210   }
02211 
02212   buf_pool_mutex_exit(buf_pool);
02213 }
02214 
02215 /**********************************************************************/
02218 UNIV_INTERN
02219 ibool
02220 buf_LRU_validate(void)
02221 /*==================*/
02222 {
02223   ulint i;
02224 
02225   for (i = 0; i < srv_buf_pool_instances; i++) {
02226     buf_pool_t* buf_pool;
02227 
02228     buf_pool = buf_pool_from_array(i);
02229     buf_LRU_validate_instance(buf_pool);
02230   }
02231 
02232   return(TRUE);
02233 }
02234 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
02235 
02236 #if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
02237 /**********************************************************************/
02239 UNIV_INTERN
02240 void
02241 buf_LRU_print_instance(
02242 /*===================*/
02243   buf_pool_t* buf_pool)
02244 {
02245   const buf_page_t* bpage;
02246 
02247   ut_ad(buf_pool);
02248   buf_pool_mutex_enter(buf_pool);
02249 
02250   bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
02251 
02252   while (bpage != NULL) {
02253 
02254     mutex_enter(buf_page_get_mutex(bpage));
02255     fprintf(stderr, "BLOCK space %lu page %lu ",
02256       (ulong) buf_page_get_space(bpage),
02257       (ulong) buf_page_get_page_no(bpage));
02258 
02259     if (buf_page_is_old(bpage)) {
02260       fputs("old ", stderr);
02261     }
02262 
02263     if (bpage->buf_fix_count) {
02264       fprintf(stderr, "buffix count %lu ",
02265         (ulong) bpage->buf_fix_count);
02266     }
02267 
02268     if (buf_page_get_io_fix(bpage)) {
02269       fprintf(stderr, "io_fix %lu ",
02270         (ulong) buf_page_get_io_fix(bpage));
02271     }
02272 
02273     if (bpage->oldest_modification) {
02274       fputs("modif. ", stderr);
02275     }
02276 
02277     switch (buf_page_get_state(bpage)) {
02278       const byte* frame;
02279     case BUF_BLOCK_FILE_PAGE:
02280       frame = buf_block_get_frame((buf_block_t*) bpage);
02281       fprintf(stderr, "\ntype %lu"
02282         " index id %llu\n",
02283         (ulong) fil_page_get_type(frame),
02284         (ullint) btr_page_get_index_id(frame));
02285       break;
02286     case BUF_BLOCK_ZIP_PAGE:
02287       frame = bpage->zip.data;
02288       fprintf(stderr, "\ntype %lu size %lu"
02289         " index id %llu\n",
02290         (ulong) fil_page_get_type(frame),
02291         (ulong) buf_page_get_zip_size(bpage),
02292         (ullint) btr_page_get_index_id(frame));
02293       break;
02294 
02295     default:
02296       fprintf(stderr, "\n!state %lu!\n",
02297         (ulong) buf_page_get_state(bpage));
02298       break;
02299     }
02300 
02301     mutex_exit(buf_page_get_mutex(bpage));
02302     bpage = UT_LIST_GET_NEXT(LRU, bpage);
02303   }
02304 
02305   buf_pool_mutex_exit(buf_pool);
02306 }
02307 
02308 /**********************************************************************/
02310 UNIV_INTERN
02311 void
02312 buf_LRU_print(void)
02313 /*===============*/
02314 {
02315   ulint   i;
02316   buf_pool_t* buf_pool;
02317 
02318   for (i = 0; i < srv_buf_pool_instances; i++) {
02319     buf_pool = buf_pool_from_array(i);
02320     buf_LRU_print_instance(buf_pool);
02321   }
02322 }
02323 #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */