1
/******************************************************
2
The database buffer replacement algorithm
6
Created 11/5/1995 Heikki Tuuri
7
*******************************************************/
18
#include "sync0sync.h"
20
#include "hash0hash.h"
24
#include "buf0buddy.h"
34
/* The number of blocks from the LRU_old pointer onward, including the block
35
pointed to, must be 3/8 of the whole LRU list length, except that the
36
tolerance defined below is allowed. Note that the tolerance must be small
37
enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the
38
LRU_old pointer is not allowed to point to either end of the LRU list. */
40
#define BUF_LRU_OLD_TOLERANCE 20
42
/* The whole LRU list length is divided by this number to determine an
43
initial segment in buf_LRU_get_recent_limit */
45
#define BUF_LRU_INITIAL_RATIO 8
47
/* If we switch on the InnoDB monitor because there are too few available
48
frames in the buffer pool, we set this to TRUE */
49
UNIV_INTERN ibool buf_lru_switched_on_innodb_mon = FALSE;
51
/**********************************************************************
52
These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O
53
and page_zip_decompress() operations. Based on the statistics,
54
buf_LRU_evict_from_unzip_LRU() decides if we want to evict from
55
unzip_LRU or the regular LRU. From unzip_LRU, we will only evict the
56
uncompressed frame (meaning we can evict dirty blocks as well). From
57
the regular LRU, we will evict the entire block (i.e.: both the
58
uncompressed and compressed data), which must be clean. */
60
/* Number of intervals for which we keep the history of these stats.
61
Each interval is 1 second, defined by the rate at which
62
srv_error_monitor_thread() calls buf_LRU_stat_update(). */
63
#define BUF_LRU_STAT_N_INTERVAL 50
65
/* Co-efficient with which we multiply I/O operations to equate them
66
with page_zip_decompress() operations. */
67
#define BUF_LRU_IO_TO_UNZIP_FACTOR 50
69
/* Sampled values buf_LRU_stat_cur.
70
Protected by buf_pool_mutex. Updated by buf_LRU_stat_update(). */
71
static buf_LRU_stat_t buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
72
/* Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */
73
static ulint buf_LRU_stat_arr_ind;
75
/* Current operation counters. Not protected by any mutex. Cleared
76
by buf_LRU_stat_update(). */
77
UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_cur;
79
/* Running sum of past values of buf_LRU_stat_cur.
80
Updated by buf_LRU_stat_update(). Protected by buf_pool_mutex. */
81
UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum;
83
/**********************************************************************
84
Takes a block out of the LRU list and page hash table.
85
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
86
the object will be freed and buf_pool_zip_mutex will be released.
88
If a compressed page or a compressed-only block descriptor is freed,
89
other compressed pages or compressed-only block descriptors may be
93
buf_LRU_block_remove_hashed_page(
94
/*=============================*/
95
/* out: the new state of the block
96
(BUF_BLOCK_ZIP_FREE if the state was
97
BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH
99
buf_page_t* bpage, /* in: block, must contain a file page and
100
be in a state where it can be freed; there
101
may or may not be a hash index to the page */
102
ibool zip); /* in: TRUE if should remove also the
103
compressed page of an uncompressed page */
104
/**********************************************************************
105
Puts a file page whose has no hash index to the free list. */
108
buf_LRU_block_free_hashed_page(
109
/*===========================*/
110
buf_block_t* block); /* in: block, must contain a file page and
111
be in a state where it can be freed */
113
/**********************************************************************
114
Determines if the unzip_LRU list should be used for evicting a victim
115
instead of the general LRU list. */
118
buf_LRU_evict_from_unzip_LRU(void)
119
/*==============================*/
120
/* out: TRUE if should use unzip_LRU */
125
ut_ad(buf_pool_mutex_own());
127
/* If the unzip_LRU list is empty, we can only use the LRU. */
128
if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) {
132
/* If unzip_LRU is at most 10% of the size of the LRU list,
133
then use the LRU. This slack allows us to keep hot
134
decompressed pages in the buffer pool. */
135
if (UT_LIST_GET_LEN(buf_pool->unzip_LRU)
136
<= UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
140
/* If eviction hasn't started yet, we assume by default
141
that a workload is disk bound. */
142
if (buf_pool->freed_page_clock == 0) {
146
/* Calculate the average over past intervals, and add the values
147
of the current interval. */
148
io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
149
+ buf_LRU_stat_cur.io;
150
unzip_avg = buf_LRU_stat_sum.unzip / BUF_LRU_STAT_N_INTERVAL
151
+ buf_LRU_stat_cur.unzip;
153
/* Decide based on our formula. If the load is I/O bound
154
(unzip_avg is smaller than the weighted io_avg), evict an
155
uncompressed frame from unzip_LRU. Otherwise we assume that
156
the load is CPU bound and evict from the regular LRU. */
157
return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
160
/**********************************************************************
161
Invalidates all pages belonging to a given tablespace when we are deleting
162
the data file(s) of that tablespace. */
165
buf_LRU_invalidate_tablespace(
166
/*==========================*/
167
ulint id) /* in: space id */
174
buf_pool_mutex_enter();
178
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
180
while (bpage != NULL) {
181
mutex_t* block_mutex = buf_page_get_mutex(bpage);
182
buf_page_t* prev_bpage;
184
ut_a(buf_page_in_file(bpage));
186
mutex_enter(block_mutex);
187
prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
189
if (buf_page_get_space(bpage) == id) {
190
if (bpage->buf_fix_count > 0
191
|| buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
193
/* We cannot remove this page during
194
this scan yet; maybe the system is
195
currently reading it in, or flushing
196
the modifications to the file */
204
if (buf_debug_prints) {
206
"Dropping space %lu page %lu\n",
207
(ulong) buf_page_get_space(bpage),
208
(ulong) buf_page_get_page_no(bpage));
211
if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE
212
&& ((buf_block_t*) bpage)->is_hashed) {
213
page_no = buf_page_get_page_no(bpage);
215
buf_pool_mutex_exit();
216
mutex_exit(block_mutex);
218
/* Note that the following call will acquire
219
an S-latch on the page */
221
btr_search_drop_page_hash_when_freed(
223
buf_page_get_zip_size(bpage),
228
if (bpage->oldest_modification != 0) {
230
buf_flush_remove(bpage);
233
/* Remove from the LRU list */
234
if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
235
!= BUF_BLOCK_ZIP_FREE) {
236
buf_LRU_block_free_hashed_page((buf_block_t*)
239
/* The compressed block descriptor
240
(bpage) has been deallocated and
241
block_mutex released. Also,
242
buf_buddy_free() may have relocated
243
prev_bpage. Rescan the LRU list. */
245
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
250
mutex_exit(block_mutex);
254
buf_pool_mutex_exit();
257
os_thread_sleep(20000);
263
/**********************************************************************
264
Gets the minimum LRU_position field for the blocks in an initial segment
265
(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
266
guaranteed to be precise, because the ulint_clock may wrap around. */
269
buf_LRU_get_recent_limit(void)
270
/*==========================*/
271
/* out: the limit; zero if could not determine it */
273
const buf_page_t* bpage;
277
buf_pool_mutex_enter();
279
len = UT_LIST_GET_LEN(buf_pool->LRU);
281
if (len < BUF_LRU_OLD_MIN_LEN) {
282
/* The LRU list is too short to do read-ahead */
284
buf_pool_mutex_exit();
289
bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
291
limit = buf_page_get_LRU_position(bpage) - len / BUF_LRU_INITIAL_RATIO;
293
buf_pool_mutex_exit();
298
/************************************************************************
299
Insert a compressed block into buf_pool->zip_clean in the LRU order. */
302
buf_LRU_insert_zip_clean(
303
/*=====================*/
304
buf_page_t* bpage) /* in: pointer to the block in question */
308
ut_ad(buf_pool_mutex_own());
309
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
311
/* Find the first successor of bpage in the LRU list
312
that is in the zip_clean list. */
315
b = UT_LIST_GET_NEXT(LRU, b);
316
} while (b && buf_page_get_state(b) != BUF_BLOCK_ZIP_PAGE);
318
/* Insert bpage before b, i.e., after the predecessor of b. */
320
b = UT_LIST_GET_PREV(list, b);
324
UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, bpage);
326
UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, bpage);
330
/**********************************************************************
331
Try to free an uncompressed page of a compressed block from the unzip
332
LRU list. The compressed page is preserved, and it need not be clean. */
335
buf_LRU_free_from_unzip_LRU_list(
336
/*=============================*/
337
/* out: TRUE if freed */
338
ulint n_iterations) /* in: how many times this has been called
339
repeatedly without result: a high value means
340
that we should search farther; we will search
341
n_iterations / 5 of the unzip_LRU list,
342
or nothing if n_iterations >= 5 */
347
ut_ad(buf_pool_mutex_own());
349
/* Theoratically it should be much easier to find a victim
350
from unzip_LRU as we can choose even a dirty block (as we'll
351
be evicting only the uncompressed frame). In a very unlikely
352
eventuality that we are unable to find a victim from
353
unzip_LRU, we fall back to the regular LRU list. We do this
354
if we have done five iterations so far. */
356
if (UNIV_UNLIKELY(n_iterations >= 5)
357
|| !buf_LRU_evict_from_unzip_LRU()) {
362
distance = 100 + (n_iterations
363
* UT_LIST_GET_LEN(buf_pool->unzip_LRU)) / 5;
365
for (block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
366
UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0);
367
block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) {
369
enum buf_lru_free_block_status freed;
371
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
372
ut_ad(block->in_unzip_LRU_list);
373
ut_ad(block->page.in_LRU_list);
375
mutex_enter(&block->mutex);
376
freed = buf_LRU_free_block(&block->page, FALSE, NULL);
377
mutex_exit(&block->mutex);
383
case BUF_LRU_CANNOT_RELOCATE:
384
/* If we failed to relocate, try
385
regular LRU eviction. */
388
case BUF_LRU_NOT_FREED:
389
/* The block was buffer-fixed or I/O-fixed.
394
/* inappropriate return value from
395
buf_LRU_free_block() */
402
/**********************************************************************
403
Try to free a clean page from the common LRU list. */
406
buf_LRU_free_from_common_LRU_list(
407
/*==============================*/
408
/* out: TRUE if freed */
409
ulint n_iterations) /* in: how many times this has been called
410
repeatedly without result: a high value means
411
that we should search farther; if
412
n_iterations < 10, then we search
413
n_iterations / 10 * buf_pool->curr_size
414
pages from the end of the LRU list */
419
ut_ad(buf_pool_mutex_own());
421
distance = 100 + (n_iterations * buf_pool->curr_size) / 10;
423
for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
424
UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0);
425
bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) {
427
enum buf_lru_free_block_status freed;
429
= buf_page_get_mutex(bpage);
431
ut_ad(buf_page_in_file(bpage));
432
ut_ad(bpage->in_LRU_list);
434
mutex_enter(block_mutex);
435
freed = buf_LRU_free_block(bpage, TRUE, NULL);
436
mutex_exit(block_mutex);
442
case BUF_LRU_NOT_FREED:
443
/* The block was dirty, buffer-fixed, or I/O-fixed.
447
case BUF_LRU_CANNOT_RELOCATE:
448
/* This should never occur, because we
449
want to discard the compressed page too. */
453
/* inappropriate return value from
454
buf_LRU_free_block() */
461
/**********************************************************************
462
Try to free a replaceable block. */
465
buf_LRU_search_and_free_block(
466
/*==========================*/
467
/* out: TRUE if found and freed */
468
ulint n_iterations) /* in: how many times this has been called
469
repeatedly without result: a high value means
470
that we should search farther; if
471
n_iterations < 10, then we search
472
n_iterations / 10 * buf_pool->curr_size
473
pages from the end of the LRU list; if
474
n_iterations < 5, then we will also search
475
n_iterations / 5 of the unzip_LRU list. */
479
buf_pool_mutex_enter();
481
freed = buf_LRU_free_from_unzip_LRU_list(n_iterations);
484
freed = buf_LRU_free_from_common_LRU_list(n_iterations);
488
buf_pool->LRU_flush_ended = 0;
489
} else if (buf_pool->LRU_flush_ended > 0) {
490
buf_pool->LRU_flush_ended--;
493
buf_pool_mutex_exit();
498
/**********************************************************************
499
Tries to remove LRU flushed blocks from the end of the LRU list and put them
500
to the free list. This is beneficial for the efficiency of the insert buffer
501
operation, as flushed pages from non-unique non-clustered indexes are here
502
taken out of the buffer pool, and their inserts redirected to the insert
503
buffer. Otherwise, the flushed blocks could get modified again before read
504
operations need new buffer blocks, and the i/o work done in flushing would be
508
buf_LRU_try_free_flushed_blocks(void)
509
/*=================================*/
511
buf_pool_mutex_enter();
513
while (buf_pool->LRU_flush_ended > 0) {
515
buf_pool_mutex_exit();
517
buf_LRU_search_and_free_block(1);
519
buf_pool_mutex_enter();
522
buf_pool_mutex_exit();
525
/**********************************************************************
526
Returns TRUE if less than 25 % of the buffer pool is available. This can be
527
used in heuristics to prevent huge transactions eating up the whole buffer
528
pool for their locks. */
531
buf_LRU_buf_pool_running_out(void)
532
/*==============================*/
533
/* out: TRUE if less than 25 % of buffer pool
538
buf_pool_mutex_enter();
540
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
541
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 4) {
546
buf_pool_mutex_exit();
551
/**********************************************************************
552
Returns a free block from the buf_pool. The block is taken off the
553
free list. If it is empty, returns NULL. */
556
buf_LRU_get_free_only(void)
557
/*=======================*/
558
/* out: a free control block, or NULL
559
if the buf_block->free list is empty */
563
ut_ad(buf_pool_mutex_own());
565
block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
568
ut_ad(block->page.in_free_list);
569
ut_d(block->page.in_free_list = FALSE);
570
ut_ad(!block->page.in_flush_list);
571
ut_ad(!block->page.in_LRU_list);
572
ut_a(!buf_page_in_file(&block->page));
573
UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
575
mutex_enter(&block->mutex);
577
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
578
UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
580
mutex_exit(&block->mutex);
586
/**********************************************************************
587
Returns a free block from the buf_pool. The block is taken off the
588
free list. If it is empty, blocks are moved from the end of the
589
LRU list to the free list. */
592
buf_LRU_get_free_block(
593
/*===================*/
594
/* out: the free control block,
595
in state BUF_BLOCK_READY_FOR_USE */
596
ulint zip_size) /* in: compressed page size in bytes,
597
or 0 if uncompressed tablespace */
599
buf_block_t* block = NULL;
601
ulint n_iterations = 1;
602
ibool mon_value_was = FALSE;
603
ibool started_monitor = FALSE;
605
buf_pool_mutex_enter();
607
if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
608
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
609
ut_print_timestamp(stderr);
612
" InnoDB: ERROR: over 95 percent of the buffer pool"
614
"InnoDB: lock heaps or the adaptive hash index!"
616
"InnoDB: transactions do not set too many row locks.\n"
617
"InnoDB: Your buffer pool size is %lu MB."
618
" Maybe you should make\n"
619
"InnoDB: the buffer pool bigger?\n"
620
"InnoDB: We intentionally generate a seg fault"
621
" to print a stack trace\n"
622
"InnoDB: on Linux!\n",
623
(ulong) (buf_pool->curr_size
624
/ (1024 * 1024 / UNIV_PAGE_SIZE)));
628
} else if (!recv_recovery_on
629
&& (UT_LIST_GET_LEN(buf_pool->free)
630
+ UT_LIST_GET_LEN(buf_pool->LRU))
631
< buf_pool->curr_size / 3) {
633
if (!buf_lru_switched_on_innodb_mon) {
635
/* Over 67 % of the buffer pool is occupied by lock
636
heaps or the adaptive hash index. This may be a memory
639
ut_print_timestamp(stderr);
641
" InnoDB: WARNING: over 67 percent of"
642
" the buffer pool is occupied by\n"
643
"InnoDB: lock heaps or the adaptive"
644
" hash index! Check that your\n"
645
"InnoDB: transactions do not set too many"
647
"InnoDB: Your buffer pool size is %lu MB."
648
" Maybe you should make\n"
649
"InnoDB: the buffer pool bigger?\n"
650
"InnoDB: Starting the InnoDB Monitor to print"
651
" diagnostics, including\n"
652
"InnoDB: lock heap and hash index sizes.\n",
653
(ulong) (buf_pool->curr_size
654
/ (1024 * 1024 / UNIV_PAGE_SIZE)));
656
buf_lru_switched_on_innodb_mon = TRUE;
657
srv_print_innodb_monitor = TRUE;
658
os_event_set(srv_lock_timeout_thread_event);
660
} else if (buf_lru_switched_on_innodb_mon) {
662
/* Switch off the InnoDB Monitor; this is a simple way
663
to stop the monitor if the situation becomes less urgent,
664
but may also surprise users if the user also switched on the
667
buf_lru_switched_on_innodb_mon = FALSE;
668
srv_print_innodb_monitor = FALSE;
671
/* If there is a block in the free list, take it */
672
block = buf_LRU_get_free_only();
676
block->page.zip.m_start =
677
#endif /* UNIV_DEBUG */
678
block->page.zip.m_end =
679
block->page.zip.m_nonempty =
680
block->page.zip.n_blobs = 0;
682
if (UNIV_UNLIKELY(zip_size)) {
684
page_zip_set_size(&block->page.zip, zip_size);
685
block->page.zip.data = buf_buddy_alloc(zip_size, &lru);
686
UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
688
page_zip_set_size(&block->page.zip, 0);
689
block->page.zip.data = NULL;
692
buf_pool_mutex_exit();
694
if (started_monitor) {
695
srv_print_innodb_monitor = mon_value_was;
701
/* If no block was in the free list, search from the end of the LRU
702
list and try to free a block there */
704
buf_pool_mutex_exit();
706
freed = buf_LRU_search_and_free_block(n_iterations);
712
if (n_iterations > 30) {
713
ut_print_timestamp(stderr);
715
"InnoDB: Warning: difficult to find free blocks from\n"
716
"InnoDB: the buffer pool (%lu search iterations)!"
718
"InnoDB: increasing the buffer pool size.\n"
719
"InnoDB: It is also possible that"
720
" in your Unix version\n"
721
"InnoDB: fsync is very slow, or"
722
" completely frozen inside\n"
723
"InnoDB: the OS kernel. Then upgrading to"
725
"InnoDB: of your operating system may help."
727
"InnoDB: number of fsyncs in diagnostic info below.\n"
728
"InnoDB: Pending flushes (fsync) log: %lu;"
729
" buffer pool: %lu\n"
730
"InnoDB: %lu OS file reads, %lu OS file writes,"
732
"InnoDB: Starting InnoDB Monitor to print further\n"
733
"InnoDB: diagnostics to the standard output.\n",
734
(ulong) n_iterations,
735
(ulong) fil_n_pending_log_flushes,
736
(ulong) fil_n_pending_tablespace_flushes,
737
(ulong) os_n_file_reads, (ulong) os_n_file_writes,
738
(ulong) os_n_fsyncs);
740
mon_value_was = srv_print_innodb_monitor;
741
started_monitor = TRUE;
742
srv_print_innodb_monitor = TRUE;
743
os_event_set(srv_lock_timeout_thread_event);
746
/* No free block was found: try to flush the LRU list */
748
buf_flush_free_margin();
749
++srv_buf_pool_wait_free;
751
os_aio_simulated_wake_handler_threads();
753
buf_pool_mutex_enter();
755
if (buf_pool->LRU_flush_ended > 0) {
756
/* We have written pages in an LRU flush. To make the insert
757
buffer more efficient, we try to move these pages to the free
760
buf_pool_mutex_exit();
762
buf_LRU_try_free_flushed_blocks();
764
buf_pool_mutex_exit();
767
if (n_iterations > 10) {
769
os_thread_sleep(500000);
777
/***********************************************************************
778
Moves the LRU_old pointer so that the length of the old blocks list
779
is inside the allowed limits. */
782
buf_LRU_old_adjust_len(void)
783
/*========================*/
788
ut_a(buf_pool->LRU_old);
789
ut_ad(buf_pool_mutex_own());
790
#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5
791
# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5"
795
old_len = buf_pool->LRU_old_len;
796
new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
798
ut_ad(buf_pool->LRU_old->in_LRU_list);
800
/* Update the LRU_old pointer if necessary */
802
if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
804
buf_pool->LRU_old = UT_LIST_GET_PREV(
805
LRU, buf_pool->LRU_old);
806
buf_page_set_old(buf_pool->LRU_old, TRUE);
807
buf_pool->LRU_old_len++;
809
} else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
811
buf_page_set_old(buf_pool->LRU_old, FALSE);
812
buf_pool->LRU_old = UT_LIST_GET_NEXT(
813
LRU, buf_pool->LRU_old);
814
buf_pool->LRU_old_len--;
816
ut_a(buf_pool->LRU_old); /* Check that we did not
817
fall out of the LRU list */
823
/***********************************************************************
824
Initializes the old blocks pointer in the LRU list. This function should be
825
called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
828
buf_LRU_old_init(void)
829
/*==================*/
833
ut_ad(buf_pool_mutex_own());
834
ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
836
/* We first initialize all blocks in the LRU list as old and then use
837
the adjust function to move the LRU_old pointer to the right
840
bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
842
while (bpage != NULL) {
843
ut_ad(bpage->in_LRU_list);
844
buf_page_set_old(bpage, TRUE);
845
bpage = UT_LIST_GET_NEXT(LRU, bpage);
848
buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
849
buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
851
buf_LRU_old_adjust_len();
854
/**********************************************************************
855
Remove a block from the unzip_LRU list if it belonged to the list. */
858
buf_unzip_LRU_remove_block_if_needed(
859
/*=================================*/
860
buf_page_t* bpage) /* in/out: control block */
864
ut_ad(buf_page_in_file(bpage));
865
ut_ad(buf_pool_mutex_own());
867
if (buf_page_belongs_to_unzip_LRU(bpage)) {
868
buf_block_t* block = (buf_block_t*) bpage;
870
ut_ad(block->in_unzip_LRU_list);
871
ut_d(block->in_unzip_LRU_list = FALSE);
873
UT_LIST_REMOVE(unzip_LRU, buf_pool->unzip_LRU, block);
877
/**********************************************************************
878
Removes a block from the LRU list. */
881
buf_LRU_remove_block(
882
/*=================*/
883
buf_page_t* bpage) /* in: control block */
887
ut_ad(buf_pool_mutex_own());
889
ut_a(buf_page_in_file(bpage));
891
ut_ad(bpage->in_LRU_list);
893
/* If the LRU_old pointer is defined and points to just this block,
894
move it backward one step */
896
if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
898
/* Below: the previous block is guaranteed to exist, because
899
the LRU_old pointer is only allowed to differ by the
900
tolerance value from strict 3/8 of the LRU list length. */
902
buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage);
903
ut_a(buf_pool->LRU_old);
904
buf_page_set_old(buf_pool->LRU_old, TRUE);
906
buf_pool->LRU_old_len++;
909
/* Remove the block from the LRU list */
910
UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
911
ut_d(bpage->in_LRU_list = FALSE);
913
buf_unzip_LRU_remove_block_if_needed(bpage);
915
/* If the LRU list is so short that LRU_old not defined, return */
916
if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
918
buf_pool->LRU_old = NULL;
923
ut_ad(buf_pool->LRU_old);
925
/* Update the LRU_old_len field if necessary */
926
if (buf_page_is_old(bpage)) {
928
buf_pool->LRU_old_len--;
931
/* Adjust the length of the old block list if necessary */
932
buf_LRU_old_adjust_len();
935
/**********************************************************************
936
Adds a block to the LRU list of decompressed zip pages. */
939
buf_unzip_LRU_add_block(
940
/*====================*/
941
buf_block_t* block, /* in: control block */
942
ibool old) /* in: TRUE if should be put to the end
943
of the list, else put to the start */
947
ut_ad(buf_pool_mutex_own());
949
ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
951
ut_ad(!block->in_unzip_LRU_list);
952
ut_d(block->in_unzip_LRU_list = TRUE);
955
UT_LIST_ADD_LAST(unzip_LRU, buf_pool->unzip_LRU, block);
957
UT_LIST_ADD_FIRST(unzip_LRU, buf_pool->unzip_LRU, block);
961
/**********************************************************************
962
Adds a block to the LRU list end. */
965
buf_LRU_add_block_to_end_low(
966
/*=========================*/
967
buf_page_t* bpage) /* in: control block */
969
buf_page_t* last_bpage;
973
ut_ad(buf_pool_mutex_own());
975
ut_a(buf_page_in_file(bpage));
977
buf_page_set_old(bpage, TRUE);
979
last_bpage = UT_LIST_GET_LAST(buf_pool->LRU);
982
bpage->LRU_position = last_bpage->LRU_position;
984
bpage->LRU_position = buf_pool_clock_tic();
987
ut_ad(!bpage->in_LRU_list);
988
UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage);
989
ut_d(bpage->in_LRU_list = TRUE);
991
if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
993
buf_pool->LRU_old_len++;
996
if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
998
ut_ad(buf_pool->LRU_old);
1000
/* Adjust the length of the old block list if necessary */
1002
buf_LRU_old_adjust_len();
1004
} else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
1006
/* The LRU list is now long enough for LRU_old to become
1012
/* If this is a zipped block with decompressed frame as well
1013
then put it on the unzip_LRU list */
1014
if (buf_page_belongs_to_unzip_LRU(bpage)) {
1015
buf_unzip_LRU_add_block((buf_block_t*) bpage, TRUE);
1019
/**********************************************************************
1020
Adds a block to the LRU list. */
1023
buf_LRU_add_block_low(
1024
/*==================*/
1025
buf_page_t* bpage, /* in: control block */
1026
ibool old) /* in: TRUE if should be put to the old blocks
1027
in the LRU list, else put to the start; if the
1028
LRU list is very short, the block is added to
1029
the start, regardless of this parameter */
1033
ut_ad(buf_pool_mutex_own());
1035
ut_a(buf_page_in_file(bpage));
1036
ut_ad(!bpage->in_LRU_list);
1038
buf_page_set_old(bpage, old);
1040
if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
1042
UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
1044
bpage->LRU_position = buf_pool_clock_tic();
1045
bpage->freed_page_clock = buf_pool->freed_page_clock;
1047
UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
1049
buf_pool->LRU_old_len++;
1051
/* We copy the LRU position field of the previous block
1054
bpage->LRU_position = (buf_pool->LRU_old)->LRU_position;
1057
ut_d(bpage->in_LRU_list = TRUE);
1059
if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
1061
ut_ad(buf_pool->LRU_old);
1063
/* Adjust the length of the old block list if necessary */
1065
buf_LRU_old_adjust_len();
1067
} else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
1069
/* The LRU list is now long enough for LRU_old to become
1075
/* If this is a zipped block with decompressed frame as well
1076
then put it on the unzip_LRU list */
1077
if (buf_page_belongs_to_unzip_LRU(bpage)) {
1078
buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
1082
/**********************************************************************
1083
Adds a block to the LRU list. */
1088
buf_page_t* bpage, /* in: control block */
1089
ibool old) /* in: TRUE if should be put to the old
1090
blocks in the LRU list, else put to the start;
1091
if the LRU list is very short, the block is
1092
added to the start, regardless of this
1095
buf_LRU_add_block_low(bpage, old);
1098
/**********************************************************************
1099
Moves a block to the start of the LRU list. */
1102
buf_LRU_make_block_young(
1103
/*=====================*/
1104
buf_page_t* bpage) /* in: control block */
1106
buf_LRU_remove_block(bpage);
1107
buf_LRU_add_block_low(bpage, FALSE);
1110
/**********************************************************************
1111
Moves a block to the end of the LRU list. */
1114
buf_LRU_make_block_old(
1115
/*===================*/
1116
buf_page_t* bpage) /* in: control block */
1118
buf_LRU_remove_block(bpage);
1119
buf_LRU_add_block_to_end_low(bpage);
1122
/**********************************************************************
1123
Try to free a block. If bpage is a descriptor of a compressed-only
1124
page, the descriptor object will be freed as well. If this function
1125
returns BUF_LRU_FREED, it will not temporarily release
1128
enum buf_lru_free_block_status
1131
/* out: BUF_LRU_FREED if freed,
1132
BUF_LRU_CANNOT_RELOCATE or
1133
BUF_LRU_NOT_FREED otherwise. */
1134
buf_page_t* bpage, /* in: block to be freed */
1135
ibool zip, /* in: TRUE if should remove also the
1136
compressed page of an uncompressed page */
1137
ibool* buf_pool_mutex_released)
1138
/* in: pointer to a variable that will
1139
be assigned TRUE if buf_pool_mutex
1140
was temporarily released, or NULL */
1142
buf_page_t* b = NULL;
1143
mutex_t* block_mutex = buf_page_get_mutex(bpage);
1145
ut_ad(buf_pool_mutex_own());
1146
ut_ad(mutex_own(block_mutex));
1147
ut_ad(buf_page_in_file(bpage));
1148
ut_ad(bpage->in_LRU_list);
1149
ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
1150
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
1152
if (!buf_page_can_relocate(bpage)) {
1154
/* Do not free buffer-fixed or I/O-fixed blocks. */
1155
return(BUF_LRU_NOT_FREED);
1158
if (zip || !bpage->zip.data) {
1159
/* This would completely free the block. */
1160
/* Do not completely free dirty blocks. */
1162
if (bpage->oldest_modification) {
1163
return(BUF_LRU_NOT_FREED);
1165
} else if (bpage->oldest_modification) {
1166
/* Do not completely free dirty blocks. */
1168
if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
1169
ut_ad(buf_page_get_state(bpage)
1170
== BUF_BLOCK_ZIP_DIRTY);
1171
return(BUF_LRU_NOT_FREED);
1175
} else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
1176
/* Allocate the control block for the compressed page.
1177
If it cannot be allocated (without freeing a block
1178
from the LRU list), refuse to free bpage. */
1180
buf_pool_mutex_exit_forbid();
1181
b = buf_buddy_alloc(sizeof *b, NULL);
1182
buf_pool_mutex_exit_allow();
1184
if (UNIV_UNLIKELY(!b)) {
1185
return(BUF_LRU_CANNOT_RELOCATE);
1188
memcpy(b, bpage, sizeof *b);
1192
if (buf_debug_prints) {
1193
fprintf(stderr, "Putting space %lu page %lu to free list\n",
1194
(ulong) buf_page_get_space(bpage),
1195
(ulong) buf_page_get_page_no(bpage));
1197
#endif /* UNIV_DEBUG */
1199
if (buf_LRU_block_remove_hashed_page(bpage, zip)
1200
!= BUF_BLOCK_ZIP_FREE) {
1201
ut_a(bpage->buf_fix_count == 0);
1204
buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b);
1205
const ulint fold = buf_page_address_fold(
1206
bpage->space, bpage->offset);
1208
ut_a(!buf_page_hash_get(bpage->space, bpage->offset));
1210
b->state = b->oldest_modification
1211
? BUF_BLOCK_ZIP_DIRTY
1212
: BUF_BLOCK_ZIP_PAGE;
1213
UNIV_MEM_DESC(b->zip.data,
1214
page_zip_get_size(&b->zip), b);
1216
/* The fields in_page_hash and in_LRU_list of
1217
the to-be-freed block descriptor should have
1219
buf_LRU_block_remove_hashed_page(), which
1220
invokes buf_LRU_remove_block(). */
1221
ut_ad(!bpage->in_page_hash);
1222
ut_ad(!bpage->in_LRU_list);
1223
/* bpage->state was BUF_BLOCK_FILE_PAGE because
1224
b != NULL. The type cast below is thus valid. */
1225
ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
1227
/* The fields of bpage were copied to b before
1228
buf_LRU_block_remove_hashed_page() was invoked. */
1229
ut_ad(!b->in_zip_hash);
1230
ut_ad(b->in_page_hash);
1231
ut_ad(b->in_LRU_list);
1233
HASH_INSERT(buf_page_t, hash,
1234
buf_pool->page_hash, fold, b);
1236
/* Insert b where bpage was in the LRU list. */
1237
if (UNIV_LIKELY(prev_b != NULL)) {
1240
ut_ad(prev_b->in_LRU_list);
1241
ut_ad(buf_page_in_file(prev_b));
1242
UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
1244
UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
1247
if (buf_page_is_old(b)) {
1248
buf_pool->LRU_old_len++;
1251
lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
1253
if (lru_len > BUF_LRU_OLD_MIN_LEN) {
1254
ut_ad(buf_pool->LRU_old);
1255
/* Adjust the length of the
1256
old block list if necessary */
1257
buf_LRU_old_adjust_len();
1258
} else if (lru_len == BUF_LRU_OLD_MIN_LEN) {
1259
/* The LRU list is now long
1260
enough for LRU_old to become
1265
ut_d(b->in_LRU_list = FALSE);
1266
buf_LRU_add_block_low(b, buf_page_is_old(b));
1269
if (b->state == BUF_BLOCK_ZIP_PAGE) {
1270
buf_LRU_insert_zip_clean(b);
1274
ut_ad(b->in_flush_list);
1275
ut_d(bpage->in_flush_list = FALSE);
1277
prev = UT_LIST_GET_PREV(list, b);
1278
UT_LIST_REMOVE(list, buf_pool->flush_list, b);
1281
ut_ad(prev->in_flush_list);
1282
UT_LIST_INSERT_AFTER(
1284
buf_pool->flush_list,
1289
buf_pool->flush_list,
1294
bpage->zip.data = NULL;
1295
page_zip_set_size(&bpage->zip, 0);
1297
/* Prevent buf_page_get_gen() from
1298
decompressing the block while we release
1299
buf_pool_mutex and block_mutex. */
1301
b->io_fix = BUF_IO_READ;
1304
if (buf_pool_mutex_released) {
1305
*buf_pool_mutex_released = TRUE;
1308
buf_pool_mutex_exit();
1309
mutex_exit(block_mutex);
1311
/* Remove possible adaptive hash index on the page.
1312
The page was declared uninitialized by
1313
buf_LRU_block_remove_hashed_page(). We need to flag
1314
the contents of the page valid (which it still is) in
1315
order to avoid bogus Valgrind warnings.*/
1317
UNIV_MEM_VALID(((buf_block_t*) bpage)->frame,
1319
btr_search_drop_page_hash_index((buf_block_t*) bpage);
1320
UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
1324
/* Compute and stamp the compressed page
1325
checksum while not holding any mutex. The
1326
block is already half-freed
1327
(BUF_BLOCK_REMOVE_HASH) and removed from
1328
buf_pool->page_hash, thus inaccessible by any
1332
b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
1333
UNIV_LIKELY(srv_use_checksums)
1334
? page_zip_calc_checksum(
1336
page_zip_get_size(&b->zip))
1337
: BUF_NO_CHECKSUM_MAGIC);
1340
buf_pool_mutex_enter();
1341
mutex_enter(block_mutex);
1344
mutex_enter(&buf_pool_zip_mutex);
1346
buf_page_set_io_fix(b, BUF_IO_NONE);
1347
mutex_exit(&buf_pool_zip_mutex);
1350
buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
1352
mutex_enter(block_mutex);
1355
return(BUF_LRU_FREED);
1358
/**********************************************************************
1359
Puts a block back to the free list. */
1362
buf_LRU_block_free_non_file_page(
1363
/*=============================*/
1364
buf_block_t* block) /* in: block, must not contain a file page */
1368
ut_ad(buf_pool_mutex_own());
1369
ut_ad(mutex_own(&block->mutex));
1372
switch (buf_block_get_state(block)) {
1373
case BUF_BLOCK_MEMORY:
1374
case BUF_BLOCK_READY_FOR_USE:
1380
ut_ad(block->n_pointers == 0);
1381
ut_ad(!block->page.in_free_list);
1382
ut_ad(!block->page.in_flush_list);
1383
ut_ad(!block->page.in_LRU_list);
1385
buf_block_set_state(block, BUF_BLOCK_NOT_USED);
1387
UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
1389
/* Wipe contents of page to reveal possible stale pointers to it */
1390
memset(block->frame, '\0', UNIV_PAGE_SIZE);
1392
/* Wipe page_no and space_id */
1393
memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
1394
memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
1396
data = block->page.zip.data;
1399
block->page.zip.data = NULL;
1400
mutex_exit(&block->mutex);
1401
buf_pool_mutex_exit_forbid();
1402
buf_buddy_free(data, page_zip_get_size(&block->page.zip));
1403
buf_pool_mutex_exit_allow();
1404
mutex_enter(&block->mutex);
1405
page_zip_set_size(&block->page.zip, 0);
1408
UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
1409
ut_d(block->page.in_free_list = TRUE);
1411
UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
1414
/**********************************************************************
1415
Takes a block out of the LRU list and page hash table.
1416
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
1417
the object will be freed and buf_pool_zip_mutex will be released.
1419
If a compressed page or a compressed-only block descriptor is freed,
1420
other compressed pages or compressed-only block descriptors may be
1424
buf_LRU_block_remove_hashed_page(
1425
/*=============================*/
1426
/* out: the new state of the block
1427
(BUF_BLOCK_ZIP_FREE if the state was
1428
BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH
1430
buf_page_t* bpage, /* in: block, must contain a file page and
1431
be in a state where it can be freed; there
1432
may or may not be a hash index to the page */
1433
ibool zip) /* in: TRUE if should remove also the
1434
compressed page of an uncompressed page */
1436
const buf_page_t* hashed_bpage;
1438
ut_ad(buf_pool_mutex_own());
1439
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
1441
ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
1442
ut_a(bpage->buf_fix_count == 0);
1444
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
1446
buf_LRU_remove_block(bpage);
1448
buf_pool->freed_page_clock += 1;
1450
switch (buf_page_get_state(bpage)) {
1451
case BUF_BLOCK_FILE_PAGE:
1452
UNIV_MEM_ASSERT_W(bpage, sizeof(buf_block_t));
1453
UNIV_MEM_ASSERT_W(((buf_block_t*) bpage)->frame,
1455
buf_block_modify_clock_inc((buf_block_t*) bpage);
1456
if (bpage->zip.data) {
1457
const page_t* page = ((buf_block_t*) bpage)->frame;
1459
ut_a(!zip || bpage->oldest_modification == 0);
1461
switch (UNIV_EXPECT(fil_page_get_type(page),
1463
case FIL_PAGE_TYPE_ALLOCATED:
1464
case FIL_PAGE_INODE:
1465
case FIL_PAGE_IBUF_BITMAP:
1466
case FIL_PAGE_TYPE_FSP_HDR:
1467
case FIL_PAGE_TYPE_XDES:
1468
/* These are essentially uncompressed pages. */
1470
/* InnoDB writes the data to the
1471
uncompressed page frame. Copy it
1472
to the compressed page, which will
1474
memcpy(bpage->zip.data, page,
1475
page_zip_get_size(&bpage->zip));
1478
case FIL_PAGE_TYPE_ZBLOB:
1479
case FIL_PAGE_TYPE_ZBLOB2:
1481
case FIL_PAGE_INDEX:
1482
#ifdef UNIV_ZIP_DEBUG
1483
ut_a(page_zip_validate(&bpage->zip, page));
1484
#endif /* UNIV_ZIP_DEBUG */
1493
case BUF_BLOCK_ZIP_PAGE:
1494
ut_a(bpage->oldest_modification == 0);
1495
UNIV_MEM_ASSERT_W(bpage->zip.data,
1496
page_zip_get_size(&bpage->zip));
1498
case BUF_BLOCK_ZIP_FREE:
1499
case BUF_BLOCK_ZIP_DIRTY:
1500
case BUF_BLOCK_NOT_USED:
1501
case BUF_BLOCK_READY_FOR_USE:
1502
case BUF_BLOCK_MEMORY:
1503
case BUF_BLOCK_REMOVE_HASH:
1508
hashed_bpage = buf_page_hash_get(bpage->space, bpage->offset);
1510
if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
1512
"InnoDB: Error: page %lu %lu not found"
1513
" in the hash table\n",
1514
(ulong) bpage->space,
1515
(ulong) bpage->offset);
1518
"InnoDB: In hash table we find block"
1519
" %p of %lu %lu which is not %p\n",
1520
(const void*) hashed_bpage,
1521
(ulong) hashed_bpage->space,
1522
(ulong) hashed_bpage->offset,
1523
(const void*) bpage);
1526
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
1527
mutex_exit(buf_page_get_mutex(bpage));
1528
buf_pool_mutex_exit();
1533
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
1537
ut_ad(!bpage->in_zip_hash);
1538
ut_ad(bpage->in_page_hash);
1539
ut_d(bpage->in_page_hash = FALSE);
1540
HASH_DELETE(buf_page_t, hash, buf_pool->page_hash,
1541
buf_page_address_fold(bpage->space, bpage->offset),
1543
switch (buf_page_get_state(bpage)) {
1544
case BUF_BLOCK_ZIP_PAGE:
1545
ut_ad(!bpage->in_free_list);
1546
ut_ad(!bpage->in_flush_list);
1547
ut_ad(!bpage->in_LRU_list);
1548
ut_a(bpage->zip.data);
1549
ut_a(buf_page_get_zip_size(bpage));
1551
UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
1553
mutex_exit(&buf_pool_zip_mutex);
1554
buf_pool_mutex_exit_forbid();
1555
buf_buddy_free(bpage->zip.data,
1556
page_zip_get_size(&bpage->zip));
1557
buf_buddy_free(bpage, sizeof(*bpage));
1558
buf_pool_mutex_exit_allow();
1559
UNIV_MEM_UNDESC(bpage);
1560
return(BUF_BLOCK_ZIP_FREE);
1562
case BUF_BLOCK_FILE_PAGE:
1563
memset(((buf_block_t*) bpage)->frame
1564
+ FIL_PAGE_OFFSET, 0xff, 4);
1565
memset(((buf_block_t*) bpage)->frame
1566
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
1567
UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
1569
buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
1571
if (zip && bpage->zip.data) {
1572
/* Free the compressed page. */
1573
void* data = bpage->zip.data;
1574
bpage->zip.data = NULL;
1576
mutex_exit(&((buf_block_t*) bpage)->mutex);
1577
buf_buddy_free(data, page_zip_get_size(&bpage->zip));
1578
mutex_enter(&((buf_block_t*) bpage)->mutex);
1579
page_zip_set_size(&bpage->zip, 0);
1582
return(BUF_BLOCK_REMOVE_HASH);
1584
case BUF_BLOCK_ZIP_FREE:
1585
case BUF_BLOCK_ZIP_DIRTY:
1586
case BUF_BLOCK_NOT_USED:
1587
case BUF_BLOCK_READY_FOR_USE:
1588
case BUF_BLOCK_MEMORY:
1589
case BUF_BLOCK_REMOVE_HASH:
1594
return(BUF_BLOCK_ZIP_FREE);
1597
/**********************************************************************
1598
Puts a file page whose has no hash index to the free list. */
1601
buf_LRU_block_free_hashed_page(
1602
/*===========================*/
1603
buf_block_t* block) /* in: block, must contain a file page and
1604
be in a state where it can be freed */
1606
ut_ad(buf_pool_mutex_own());
1607
ut_ad(mutex_own(&block->mutex));
1609
buf_block_set_state(block, BUF_BLOCK_MEMORY);
1611
buf_LRU_block_free_non_file_page(block);
1614
/************************************************************************
1615
Update the historical stats that we are collecting for LRU eviction
1616
policy at the end of each interval. */
1619
buf_LRU_stat_update(void)
1620
/*=====================*/
1622
buf_LRU_stat_t* item;
1624
/* If we haven't started eviction yet then don't update stats. */
1625
if (buf_pool->freed_page_clock == 0) {
1629
buf_pool_mutex_enter();
1631
/* Update the index. */
1632
item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind];
1633
buf_LRU_stat_arr_ind++;
1634
buf_LRU_stat_arr_ind %= BUF_LRU_STAT_N_INTERVAL;
1636
/* Add the current value and subtract the obsolete entry. */
1637
buf_LRU_stat_sum.io += buf_LRU_stat_cur.io - item->io;
1638
buf_LRU_stat_sum.unzip += buf_LRU_stat_cur.unzip - item->unzip;
1640
/* Put current entry in the array. */
1641
memcpy(item, &buf_LRU_stat_cur, sizeof *item);
1643
buf_pool_mutex_exit();
1646
/* Clear the current entry. */
1647
memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
1650
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
1651
/**************************************************************************
1652
Validates the LRU list. */
1655
buf_LRU_validate(void)
1656
/*==================*/
1665
buf_pool_mutex_enter();
1667
if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
1669
ut_a(buf_pool->LRU_old);
1670
old_len = buf_pool->LRU_old_len;
1671
new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
1672
ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
1673
ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
1676
UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU);
1678
bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
1682
while (bpage != NULL) {
1684
switch (buf_page_get_state(bpage)) {
1685
case BUF_BLOCK_ZIP_FREE:
1686
case BUF_BLOCK_NOT_USED:
1687
case BUF_BLOCK_READY_FOR_USE:
1688
case BUF_BLOCK_MEMORY:
1689
case BUF_BLOCK_REMOVE_HASH:
1692
case BUF_BLOCK_FILE_PAGE:
1693
ut_ad(((buf_block_t*) bpage)->in_unzip_LRU_list
1694
== buf_page_belongs_to_unzip_LRU(bpage));
1695
case BUF_BLOCK_ZIP_PAGE:
1696
case BUF_BLOCK_ZIP_DIRTY:
1700
if (buf_page_is_old(bpage)) {
1704
if (buf_pool->LRU_old && (old_len == 1)) {
1705
ut_a(buf_pool->LRU_old == bpage);
1708
LRU_pos = buf_page_get_LRU_position(bpage);
1710
bpage = UT_LIST_GET_NEXT(LRU, bpage);
1713
/* If the following assert fails, it may
1714
not be an error: just the buf_pool clock
1715
has wrapped around */
1716
ut_a(LRU_pos >= buf_page_get_LRU_position(bpage));
1720
if (buf_pool->LRU_old) {
1721
ut_a(buf_pool->LRU_old_len == old_len);
1724
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free);
1726
for (bpage = UT_LIST_GET_FIRST(buf_pool->free);
1728
bpage = UT_LIST_GET_NEXT(list, bpage)) {
1730
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_NOT_USED);
1733
UT_LIST_VALIDATE(unzip_LRU, buf_block_t, buf_pool->unzip_LRU);
1735
for (block = UT_LIST_GET_FIRST(buf_pool->unzip_LRU);
1737
block = UT_LIST_GET_NEXT(unzip_LRU, block)) {
1739
ut_ad(block->in_unzip_LRU_list);
1740
ut_ad(block->page.in_LRU_list);
1741
ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
1744
buf_pool_mutex_exit();
1747
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
1749
#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
1750
/**************************************************************************
1751
Prints the LRU list. */
1757
const buf_page_t* bpage;
1760
buf_pool_mutex_enter();
1762
fprintf(stderr, "Pool ulint clock %lu\n",
1763
(ulong) buf_pool->ulint_clock);
1765
bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
1767
while (bpage != NULL) {
1769
fprintf(stderr, "BLOCK space %lu page %lu ",
1770
(ulong) buf_page_get_space(bpage),
1771
(ulong) buf_page_get_page_no(bpage));
1773
if (buf_page_is_old(bpage)) {
1774
fputs("old ", stderr);
1777
if (bpage->buf_fix_count) {
1778
fprintf(stderr, "buffix count %lu ",
1779
(ulong) bpage->buf_fix_count);
1782
if (buf_page_get_io_fix(bpage)) {
1783
fprintf(stderr, "io_fix %lu ",
1784
(ulong) buf_page_get_io_fix(bpage));
1787
if (bpage->oldest_modification) {
1788
fputs("modif. ", stderr);
1791
switch (buf_page_get_state(bpage)) {
1793
case BUF_BLOCK_FILE_PAGE:
1794
frame = buf_block_get_frame((buf_block_t*) bpage);
1795
fprintf(stderr, "\nLRU pos %lu type %lu"
1797
(ulong) buf_page_get_LRU_position(bpage),
1798
(ulong) fil_page_get_type(frame),
1799
(ulong) ut_dulint_get_low(
1800
btr_page_get_index_id(frame)));
1802
case BUF_BLOCK_ZIP_PAGE:
1803
frame = bpage->zip.data;
1804
fprintf(stderr, "\nLRU pos %lu type %lu size %lu"
1806
(ulong) buf_page_get_LRU_position(bpage),
1807
(ulong) fil_page_get_type(frame),
1808
(ulong) buf_page_get_zip_size(bpage),
1809
(ulong) ut_dulint_get_low(
1810
btr_page_get_index_id(frame)));
1814
fprintf(stderr, "\nLRU pos %lu !state %lu!\n",
1815
(ulong) buf_page_get_LRU_position(bpage),
1816
(ulong) buf_page_get_state(bpage));
1820
bpage = UT_LIST_GET_NEXT(LRU, bpage);
1823
buf_pool_mutex_exit();
1825
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */