~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/buf/buf0lru.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file buf/buf0lru.c
21
 
The database buffer replacement algorithm
22
 
 
23
 
Created 11/5/1995 Heikki Tuuri
24
 
*******************************************************/
25
 
 
26
 
#include "config.h"
27
 
#include "buf0lru.h"
28
 
 
29
 
#ifdef UNIV_NONINL
30
 
#include "buf0lru.ic"
31
 
#endif
32
 
 
33
 
#include "ut0byte.h"
34
 
#include "ut0lst.h"
35
 
#include "ut0rnd.h"
36
 
#include "sync0sync.h"
37
 
#include "sync0rw.h"
38
 
#include "hash0hash.h"
39
 
#include "os0sync.h"
40
 
#include "fil0fil.h"
41
 
#include "btr0btr.h"
42
 
#include "buf0buddy.h"
43
 
#include "buf0buf.h"
44
 
#include "buf0flu.h"
45
 
#include "buf0rea.h"
46
 
#include "btr0sea.h"
47
 
#include "ibuf0ibuf.h"
48
 
#include "os0file.h"
49
 
#include "page0zip.h"
50
 
#include "log0recv.h"
51
 
#include "srv0srv.h"
52
 
 
53
 
/** The number of blocks from the LRU_old pointer onward, including
54
 
the block pointed to, must be buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV
55
 
of the whole LRU list length, except that the tolerance defined below
56
 
is allowed. Note that the tolerance must be small enough such that for
57
 
even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not
58
 
allowed to point to either end of the LRU list. */
59
 
 
60
 
#define BUF_LRU_OLD_TOLERANCE   20
61
 
 
62
 
/** The minimum amount of non-old blocks when the LRU_old list exists
63
 
(that is, when there are more than BUF_LRU_OLD_MIN_LEN blocks).
64
 
@see buf_LRU_old_adjust_len */
65
 
#define BUF_LRU_NON_OLD_MIN_LEN 5
66
 
#if BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN
67
 
# error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN"
68
 
#endif
69
 
 
70
 
/** When dropping the search hash index entries before deleting an ibd
71
 
file, we build a local array of pages belonging to that tablespace
72
 
in the buffer pool. Following is the size of that array. */
73
 
#define BUF_LRU_DROP_SEARCH_HASH_SIZE   1024
74
 
 
75
 
/** If we switch on the InnoDB monitor because there are too few available
76
 
frames in the buffer pool, we set this to TRUE */
77
 
static ibool    buf_lru_switched_on_innodb_mon  = FALSE;
78
 
 
79
 
/******************************************************************//**
80
 
These statistics are not 'of' LRU but 'for' LRU.  We keep count of I/O
81
 
and page_zip_decompress() operations.  Based on the statistics,
82
 
buf_LRU_evict_from_unzip_LRU() decides if we want to evict from
83
 
unzip_LRU or the regular LRU.  From unzip_LRU, we will only evict the
84
 
uncompressed frame (meaning we can evict dirty blocks as well).  From
85
 
the regular LRU, we will evict the entire block (i.e.: both the
86
 
uncompressed and compressed data), which must be clean. */
87
 
 
88
 
/* @{ */
89
 
 
90
 
/** Number of intervals for which we keep the history of these stats.
91
 
Each interval is 1 second, defined by the rate at which
92
 
srv_error_monitor_thread() calls buf_LRU_stat_update(). */
93
 
#define BUF_LRU_STAT_N_INTERVAL 50
94
 
 
95
 
/** Co-efficient with which we multiply I/O operations to equate them
96
 
with page_zip_decompress() operations. */
97
 
#define BUF_LRU_IO_TO_UNZIP_FACTOR 50
98
 
 
99
 
/** Sampled values buf_LRU_stat_cur.
100
 
Not protected by any mutex.  Updated by buf_LRU_stat_update(). */
101
 
static buf_LRU_stat_t           buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
102
 
 
103
 
/** Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */
104
 
static ulint                    buf_LRU_stat_arr_ind;
105
 
 
106
 
/** Current operation counters.  Not protected by any mutex.  Cleared
107
 
by buf_LRU_stat_update(). */
108
 
UNIV_INTERN buf_LRU_stat_t      buf_LRU_stat_cur;
109
 
 
110
 
/** Running sum of past values of buf_LRU_stat_cur.
111
 
Updated by buf_LRU_stat_update().  Not Protected by any mutex. */
112
 
UNIV_INTERN buf_LRU_stat_t      buf_LRU_stat_sum;
113
 
 
114
 
/* @} */
115
 
 
116
 
/** @name Heuristics for detecting index scan @{ */
117
 
/** Move blocks to "new" LRU list only if the first access was at
118
 
least this many milliseconds ago.  Not protected by any mutex or latch. */
119
 
UNIV_INTERN uint        buf_LRU_old_threshold_ms;
120
 
/* @} */
121
 
 
122
 
/******************************************************************//**
123
 
Takes a block out of the LRU list and page hash table.
124
 
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
125
 
the object will be freed and buf_pool->zip_mutex will be released.
126
 
 
127
 
If a compressed page or a compressed-only block descriptor is freed,
128
 
other compressed pages or compressed-only block descriptors may be
129
 
relocated.
130
 
@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
131
 
was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
132
 
static
133
 
enum buf_page_state
134
 
buf_LRU_block_remove_hashed_page(
135
 
/*=============================*/
136
 
        buf_page_t*     bpage,  /*!< in: block, must contain a file page and
137
 
                                be in a state where it can be freed; there
138
 
                                may or may not be a hash index to the page */
139
 
        ibool           zip);   /*!< in: TRUE if should remove also the
140
 
                                compressed page of an uncompressed page */
141
 
/******************************************************************//**
142
 
Puts a file page whose has no hash index to the free list. */
143
 
static
144
 
void
145
 
buf_LRU_block_free_hashed_page(
146
 
/*===========================*/
147
 
        buf_block_t*    block); /*!< in: block, must contain a file page and
148
 
                                be in a state where it can be freed */
149
 
 
150
 
/******************************************************************//**
151
 
Determines if the unzip_LRU list should be used for evicting a victim
152
 
instead of the general LRU list.
153
 
@return TRUE if should use unzip_LRU */
154
 
UNIV_INLINE
155
 
ibool
156
 
buf_LRU_evict_from_unzip_LRU(
157
 
/*=========================*/
158
 
        buf_pool_t*     buf_pool)
159
 
{
160
 
        ulint   io_avg;
161
 
        ulint   unzip_avg;
162
 
 
163
 
        ut_ad(buf_pool_mutex_own(buf_pool));
164
 
 
165
 
        /* If the unzip_LRU list is empty, we can only use the LRU. */
166
 
        if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) {
167
 
                return(FALSE);
168
 
        }
169
 
 
170
 
        /* If unzip_LRU is at most 10% of the size of the LRU list,
171
 
        then use the LRU.  This slack allows us to keep hot
172
 
        decompressed pages in the buffer pool. */
173
 
        if (UT_LIST_GET_LEN(buf_pool->unzip_LRU)
174
 
            <= UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
175
 
                return(FALSE);
176
 
        }
177
 
 
178
 
        /* If eviction hasn't started yet, we assume by default
179
 
        that a workload is disk bound. */
180
 
        if (buf_pool->freed_page_clock == 0) {
181
 
                return(TRUE);
182
 
        }
183
 
 
184
 
        /* Calculate the average over past intervals, and add the values
185
 
        of the current interval. */
186
 
        io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
187
 
                + buf_LRU_stat_cur.io;
188
 
        unzip_avg = buf_LRU_stat_sum.unzip / BUF_LRU_STAT_N_INTERVAL
189
 
                + buf_LRU_stat_cur.unzip;
190
 
 
191
 
        /* Decide based on our formula.  If the load is I/O bound
192
 
        (unzip_avg is smaller than the weighted io_avg), evict an
193
 
        uncompressed frame from unzip_LRU.  Otherwise we assume that
194
 
        the load is CPU bound and evict from the regular LRU. */
195
 
        return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
196
 
}
197
 
 
198
 
/******************************************************************//**
199
 
Attempts to drop page hash index on a batch of pages belonging to a
200
 
particular space id. */
201
 
static
202
 
void
203
 
buf_LRU_drop_page_hash_batch(
204
 
/*=========================*/
205
 
        ulint           space_id,       /*!< in: space id */
206
 
        ulint           zip_size,       /*!< in: compressed page size in bytes
207
 
                                        or 0 for uncompressed pages */
208
 
        const ulint*    arr,            /*!< in: array of page_no */
209
 
        ulint           count)          /*!< in: number of entries in array */
210
 
{
211
 
        ulint   i;
212
 
 
213
 
        ut_ad(arr != NULL);
214
 
        ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
215
 
 
216
 
        for (i = 0; i < count; ++i) {
217
 
                btr_search_drop_page_hash_when_freed(space_id, zip_size,
218
 
                                                     arr[i]);
219
 
        }
220
 
}
221
 
 
222
 
/******************************************************************//**
223
 
When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
224
 
hash index entries belonging to that table. This function tries to
225
 
do that in batch. Note that this is a 'best effort' attempt and does
226
 
not guarantee that ALL hash entries will be removed. */
227
 
static
228
 
void
229
 
buf_LRU_drop_page_hash_for_tablespace(
230
 
/*==================================*/
231
 
        buf_pool_t*     buf_pool,       /*!< in: buffer pool instance */
232
 
        ulint           id)             /*!< in: space id */
233
 
{
234
 
        buf_page_t*     bpage;
235
 
        ulint*          page_arr;
236
 
        ulint           num_entries;
237
 
        ulint           zip_size;
238
 
 
239
 
        zip_size = fil_space_get_zip_size(id);
240
 
 
241
 
        if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
242
 
                /* Somehow, the tablespace does not exist.  Nothing to drop. */
243
 
                ut_ad(0);
244
 
                return;
245
 
        }
246
 
 
247
 
        page_arr = ut_malloc(
248
 
                sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE);
249
 
 
250
 
        buf_pool_mutex_enter(buf_pool);
251
 
 
252
 
scan_again:
253
 
        num_entries = 0;
254
 
        bpage = UT_LIST_GET_LAST(buf_pool->LRU);
255
 
 
256
 
        while (bpage != NULL) {
257
 
                mutex_t*        block_mutex = buf_page_get_mutex(bpage);
258
 
                buf_page_t*     prev_bpage;
259
 
 
260
 
                mutex_enter(block_mutex);
261
 
                prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
262
 
 
263
 
                ut_a(buf_page_in_file(bpage));
264
 
 
265
 
                if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE
266
 
                    || bpage->space != id
267
 
                    || bpage->buf_fix_count > 0
268
 
                    || bpage->io_fix != BUF_IO_NONE) {
269
 
                        /* We leave the fixed pages as is in this scan.
270
 
                        To be dealt with later in the final scan. */
271
 
                        mutex_exit(block_mutex);
272
 
                        goto next_page;
273
 
                }
274
 
 
275
 
                if (((buf_block_t*) bpage)->is_hashed) {
276
 
 
277
 
                        /* Store the offset(i.e.: page_no) in the array
278
 
                        so that we can drop hash index in a batch
279
 
                        later. */
280
 
                        page_arr[num_entries] = bpage->offset;
281
 
                        mutex_exit(block_mutex);
282
 
                        ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
283
 
                        ++num_entries;
284
 
 
285
 
                        if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
286
 
                                goto next_page;
287
 
                        }
288
 
 
289
 
                        /* Array full. We release the buf_pool->mutex to
290
 
                        obey the latching order. */
291
 
                        buf_pool_mutex_exit(buf_pool);
292
 
 
293
 
                        buf_LRU_drop_page_hash_batch(
294
 
                                id, zip_size, page_arr, num_entries);
295
 
 
296
 
                        num_entries = 0;
297
 
 
298
 
                        buf_pool_mutex_enter(buf_pool);
299
 
                } else {
300
 
                        mutex_exit(block_mutex);
301
 
                }
302
 
 
303
 
next_page:
304
 
                /* Note that we may have released the buf_pool mutex
305
 
                above after reading the prev_bpage during processing
306
 
                of a page_hash_batch (i.e.: when the array was full).
307
 
                This means that prev_bpage can change in LRU list.
308
 
                This is OK because this function is a 'best effort'
309
 
                to drop as many search hash entries as possible and
310
 
                it does not guarantee that ALL such entries will be
311
 
                dropped. */
312
 
                bpage = prev_bpage;
313
 
 
314
 
                /* If, however, bpage has been removed from LRU list
315
 
                to the free list then we should restart the scan.
316
 
                bpage->state is protected by buf_pool mutex. */
317
 
                if (bpage && !buf_page_in_file(bpage)) {
318
 
                        ut_a(num_entries == 0);
319
 
                        goto scan_again;
320
 
                }
321
 
        }
322
 
 
323
 
        buf_pool_mutex_exit(buf_pool);
324
 
 
325
 
        /* Drop any remaining batch of search hashed pages. */
326
 
        buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, num_entries);
327
 
        ut_free(page_arr);
328
 
}
329
 
 
330
 
/******************************************************************//**
331
 
Invalidates all pages belonging to a given tablespace inside a specific
332
 
buffer pool instance when we are deleting the data file(s) of that
333
 
tablespace. */
334
 
static
335
 
void
336
 
buf_LRU_invalidate_tablespace_buf_pool_instance(
337
 
/*============================================*/
338
 
        buf_pool_t*     buf_pool,       /*!< buffer pool instance */
339
 
        ulint           id)             /*!< in: space id */
340
 
{
341
 
        buf_page_t*     bpage;
342
 
        ibool           all_freed;
343
 
 
344
 
scan_again:
345
 
        buf_pool_mutex_enter(buf_pool);
346
 
 
347
 
        all_freed = TRUE;
348
 
 
349
 
        bpage = UT_LIST_GET_LAST(buf_pool->LRU);
350
 
 
351
 
        while (bpage != NULL) {
352
 
                buf_page_t*     prev_bpage;
353
 
                ibool           prev_bpage_buf_fix = FALSE;
354
 
 
355
 
                ut_a(buf_page_in_file(bpage));
356
 
 
357
 
                prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
358
 
 
359
 
                /* bpage->space and bpage->io_fix are protected by
360
 
                buf_pool_mutex and block_mutex.  It is safe to check
361
 
                them while holding buf_pool_mutex only. */
362
 
 
363
 
                if (buf_page_get_space(bpage) != id) {
364
 
                        /* Skip this block, as it does not belong to
365
 
                        the space that is being invalidated. */
366
 
                } else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
367
 
                        /* We cannot remove this page during this scan
368
 
                        yet; maybe the system is currently reading it
369
 
                        in, or flushing the modifications to the file */
370
 
 
371
 
                        all_freed = FALSE;
372
 
                } else {
373
 
                        mutex_t* block_mutex = buf_page_get_mutex(bpage);
374
 
                        mutex_enter(block_mutex);
375
 
 
376
 
                        if (bpage->buf_fix_count > 0) {
377
 
 
378
 
                                /* We cannot remove this page during
379
 
                                this scan yet; maybe the system is
380
 
                                currently reading it in, or flushing
381
 
                                the modifications to the file */
382
 
 
383
 
                                all_freed = FALSE;
384
 
 
385
 
                                goto next_page;
386
 
                        }
387
 
 
388
 
#ifdef UNIV_DEBUG
389
 
                        if (buf_debug_prints) {
390
 
                                fprintf(stderr,
391
 
                                        "Dropping space %lu page %lu\n",
392
 
                                        (ulong) buf_page_get_space(bpage),
393
 
                                        (ulong) buf_page_get_page_no(bpage));
394
 
                        }
395
 
#endif
396
 
                        if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
397
 
                                /* This is a compressed-only block
398
 
                                descriptor.  Ensure that prev_bpage
399
 
                                cannot be relocated when bpage is freed. */
400
 
                                if (UNIV_LIKELY(prev_bpage != NULL)) {
401
 
                                        switch (buf_page_get_state(
402
 
                                                        prev_bpage)) {
403
 
                                        case BUF_BLOCK_FILE_PAGE:
404
 
                                                /* Descriptors of uncompressed
405
 
                                                blocks will not be relocated,
406
 
                                                because we are holding the
407
 
                                                buf_pool_mutex. */
408
 
                                                break;
409
 
                                        case BUF_BLOCK_ZIP_PAGE:
410
 
                                        case BUF_BLOCK_ZIP_DIRTY:
411
 
                                                /* Descriptors of compressed-
412
 
                                                only blocks can be relocated,
413
 
                                                unless they are buffer-fixed.
414
 
                                                Because both bpage and
415
 
                                                prev_bpage are protected by
416
 
                                                buf_pool_zip_mutex, it is
417
 
                                                not necessary to acquire
418
 
                                                further mutexes. */
419
 
                                                ut_ad(&buf_pool->zip_mutex
420
 
                                                      == block_mutex);
421
 
                                                ut_ad(mutex_own(block_mutex));
422
 
                                                prev_bpage_buf_fix = TRUE;
423
 
                                                prev_bpage->buf_fix_count++;
424
 
                                                break;
425
 
                                        default:
426
 
                                                ut_error;
427
 
                                        }
428
 
                                }
429
 
                        } else if (((buf_block_t*) bpage)->is_hashed) {
430
 
                                ulint   page_no;
431
 
                                ulint   zip_size;
432
 
 
433
 
                                buf_pool_mutex_exit(buf_pool);
434
 
 
435
 
                                zip_size = buf_page_get_zip_size(bpage);
436
 
                                page_no = buf_page_get_page_no(bpage);
437
 
 
438
 
                                mutex_exit(block_mutex);
439
 
 
440
 
                                /* Note that the following call will acquire
441
 
                                an S-latch on the page */
442
 
 
443
 
                                btr_search_drop_page_hash_when_freed(
444
 
                                        id, zip_size, page_no);
445
 
                                goto scan_again;
446
 
                        }
447
 
 
448
 
                        if (bpage->oldest_modification != 0) {
449
 
 
450
 
                                buf_flush_remove(bpage);
451
 
                        }
452
 
 
453
 
                        /* Remove from the LRU list. */
454
 
 
455
 
                        if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
456
 
                            != BUF_BLOCK_ZIP_FREE) {
457
 
                                buf_LRU_block_free_hashed_page((buf_block_t*)
458
 
                                                               bpage);
459
 
                        } else {
460
 
                                /* The block_mutex should have been
461
 
                                released by buf_LRU_block_remove_hashed_page()
462
 
                                when it returns BUF_BLOCK_ZIP_FREE. */
463
 
                                ut_ad(block_mutex == &buf_pool->zip_mutex);
464
 
                                ut_ad(!mutex_own(block_mutex));
465
 
 
466
 
                                if (prev_bpage_buf_fix) {
467
 
                                        /* We temporarily buffer-fixed
468
 
                                        prev_bpage, so that
469
 
                                        buf_buddy_free() could not
470
 
                                        relocate it, in case it was a
471
 
                                        compressed-only block
472
 
                                        descriptor. */
473
 
 
474
 
                                        mutex_enter(block_mutex);
475
 
                                        ut_ad(prev_bpage->buf_fix_count > 0);
476
 
                                        prev_bpage->buf_fix_count--;
477
 
                                        mutex_exit(block_mutex);
478
 
                                }
479
 
 
480
 
                                goto next_page_no_mutex;
481
 
                        }
482
 
next_page:
483
 
                        mutex_exit(block_mutex);
484
 
                }
485
 
 
486
 
next_page_no_mutex:
487
 
                bpage = prev_bpage;
488
 
        }
489
 
 
490
 
        buf_pool_mutex_exit(buf_pool);
491
 
 
492
 
        if (!all_freed) {
493
 
                os_thread_sleep(20000);
494
 
 
495
 
                goto scan_again;
496
 
        }
497
 
}
498
 
 
499
 
/******************************************************************//**
500
 
Invalidates all pages belonging to a given tablespace when we are deleting
501
 
the data file(s) of that tablespace. */
502
 
UNIV_INTERN
503
 
void
504
 
buf_LRU_invalidate_tablespace(
505
 
/*==========================*/
506
 
        ulint   id)     /*!< in: space id */
507
 
{
508
 
        ulint   i;
509
 
 
510
 
        /* Before we attempt to drop pages one by one we first
511
 
        attempt to drop page hash index entries in batches to make
512
 
        it more efficient. The batching attempt is a best effort
513
 
        attempt and does not guarantee that all pages hash entries
514
 
        will be dropped. We get rid of remaining page hash entries
515
 
        one by one below. */
516
 
        for (i = 0; i < srv_buf_pool_instances; i++) {
517
 
                buf_pool_t*     buf_pool;
518
 
 
519
 
                buf_pool = buf_pool_from_array(i);
520
 
                buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
521
 
                buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id);
522
 
        }
523
 
}
524
 
 
525
 
/********************************************************************//**
526
 
Insert a compressed block into buf_pool->zip_clean in the LRU order. */
527
 
UNIV_INTERN
528
 
void
529
 
buf_LRU_insert_zip_clean(
530
 
/*=====================*/
531
 
        buf_page_t*     bpage)  /*!< in: pointer to the block in question */
532
 
{
533
 
        buf_page_t*     b;
534
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
535
 
 
536
 
        ut_ad(buf_pool_mutex_own(buf_pool));
537
 
        ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
538
 
 
539
 
        /* Find the first successor of bpage in the LRU list
540
 
        that is in the zip_clean list. */
541
 
        b = bpage;
542
 
        do {
543
 
                b = UT_LIST_GET_NEXT(LRU, b);
544
 
        } while (b && buf_page_get_state(b) != BUF_BLOCK_ZIP_PAGE);
545
 
 
546
 
        /* Insert bpage before b, i.e., after the predecessor of b. */
547
 
        if (b) {
548
 
                b = UT_LIST_GET_PREV(list, b);
549
 
        }
550
 
 
551
 
        if (b) {
552
 
                UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, bpage);
553
 
        } else {
554
 
                UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, bpage);
555
 
        }
556
 
}
557
 
 
558
 
/******************************************************************//**
559
 
Try to free an uncompressed page of a compressed block from the unzip
560
 
LRU list.  The compressed page is preserved, and it need not be clean.
561
 
@return TRUE if freed */
562
 
UNIV_INLINE
563
 
ibool
564
 
buf_LRU_free_from_unzip_LRU_list(
565
 
/*=============================*/
566
 
        buf_pool_t*     buf_pool,       /*!< in: buffer pool instance */
567
 
        ulint           n_iterations)   /*!< in: how many times this has
568
 
                                        been called repeatedly without
569
 
                                        result: a high value means that
570
 
                                        we should search farther; we will
571
 
                                        search n_iterations / 5 of the
572
 
                                        unzip_LRU list, or nothing if
573
 
                                        n_iterations >= 5 */
574
 
{
575
 
        buf_block_t*    block;
576
 
        ulint           distance;
577
 
 
578
 
        ut_ad(buf_pool_mutex_own(buf_pool));
579
 
 
580
 
        /* Theoratically it should be much easier to find a victim
581
 
        from unzip_LRU as we can choose even a dirty block (as we'll
582
 
        be evicting only the uncompressed frame).  In a very unlikely
583
 
        eventuality that we are unable to find a victim from
584
 
        unzip_LRU, we fall back to the regular LRU list.  We do this
585
 
        if we have done five iterations so far. */
586
 
 
587
 
        if (UNIV_UNLIKELY(n_iterations >= 5)
588
 
            || !buf_LRU_evict_from_unzip_LRU(buf_pool)) {
589
 
 
590
 
                return(FALSE);
591
 
        }
592
 
 
593
 
        distance = 100 + (n_iterations
594
 
                          * UT_LIST_GET_LEN(buf_pool->unzip_LRU)) / 5;
595
 
 
596
 
        for (block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
597
 
             UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0);
598
 
             block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) {
599
 
 
600
 
                enum buf_lru_free_block_status  freed;
601
 
 
602
 
                ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
603
 
                ut_ad(block->in_unzip_LRU_list);
604
 
                ut_ad(block->page.in_LRU_list);
605
 
 
606
 
                mutex_enter(&block->mutex);
607
 
                freed = buf_LRU_free_block(&block->page, FALSE, NULL);
608
 
                mutex_exit(&block->mutex);
609
 
 
610
 
                switch (freed) {
611
 
                case BUF_LRU_FREED:
612
 
                        return(TRUE);
613
 
 
614
 
                case BUF_LRU_CANNOT_RELOCATE:
615
 
                        /* If we failed to relocate, try
616
 
                        regular LRU eviction. */
617
 
                        return(FALSE);
618
 
 
619
 
                case BUF_LRU_NOT_FREED:
620
 
                        /* The block was buffer-fixed or I/O-fixed.
621
 
                        Keep looking. */
622
 
                        continue;
623
 
                }
624
 
 
625
 
                /* inappropriate return value from
626
 
                buf_LRU_free_block() */
627
 
                ut_error;
628
 
        }
629
 
 
630
 
        return(FALSE);
631
 
}
632
 
 
633
 
/******************************************************************//**
634
 
Try to free a clean page from the common LRU list.
635
 
@return TRUE if freed */
636
 
UNIV_INLINE
637
 
ibool
638
 
buf_LRU_free_from_common_LRU_list(
639
 
/*==============================*/
640
 
        buf_pool_t*     buf_pool,
641
 
        ulint           n_iterations)
642
 
                                /*!< in: how many times this has been called
643
 
                                repeatedly without result: a high value means
644
 
                                that we should search farther; if
645
 
                                n_iterations < 10, then we search
646
 
                                n_iterations / 10 * buf_pool->curr_size
647
 
                                pages from the end of the LRU list */
648
 
{
649
 
        buf_page_t*     bpage;
650
 
        ulint           distance;
651
 
 
652
 
        ut_ad(buf_pool_mutex_own(buf_pool));
653
 
 
654
 
        distance = 100 + (n_iterations * buf_pool->curr_size) / 10;
655
 
 
656
 
        for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
657
 
             UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0);
658
 
             bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) {
659
 
 
660
 
                enum buf_lru_free_block_status  freed;
661
 
                unsigned                        accessed;
662
 
                mutex_t*                        block_mutex
663
 
                        = buf_page_get_mutex(bpage);
664
 
 
665
 
                ut_ad(buf_page_in_file(bpage));
666
 
                ut_ad(bpage->in_LRU_list);
667
 
 
668
 
                mutex_enter(block_mutex);
669
 
                accessed = buf_page_is_accessed(bpage);
670
 
                freed = buf_LRU_free_block(bpage, TRUE, NULL);
671
 
                mutex_exit(block_mutex);
672
 
 
673
 
                switch (freed) {
674
 
                case BUF_LRU_FREED:
675
 
                        /* Keep track of pages that are evicted without
676
 
                        ever being accessed. This gives us a measure of
677
 
                        the effectiveness of readahead */
678
 
                        if (!accessed) {
679
 
                                ++buf_pool->stat.n_ra_pages_evicted;
680
 
                        }
681
 
                        return(TRUE);
682
 
 
683
 
                case BUF_LRU_NOT_FREED:
684
 
                        /* The block was dirty, buffer-fixed, or I/O-fixed.
685
 
                        Keep looking. */
686
 
                        continue;
687
 
 
688
 
                case BUF_LRU_CANNOT_RELOCATE:
689
 
                        /* This should never occur, because we
690
 
                        want to discard the compressed page too. */
691
 
                        break;
692
 
                }
693
 
 
694
 
                /* inappropriate return value from
695
 
                buf_LRU_free_block() */
696
 
                ut_error;
697
 
        }
698
 
 
699
 
        return(FALSE);
700
 
}
701
 
 
702
 
/******************************************************************//**
703
 
Try to free a replaceable block.
704
 
@return TRUE if found and freed */
705
 
UNIV_INTERN
706
 
ibool
707
 
buf_LRU_search_and_free_block(
708
 
/*==========================*/
709
 
        buf_pool_t*     buf_pool,
710
 
                                /*!< in: buffer pool instance */
711
 
        ulint           n_iterations)
712
 
                                /*!< in: how many times this has been called
713
 
                                repeatedly without result: a high value means
714
 
                                that we should search farther; if
715
 
                                n_iterations < 10, then we search
716
 
                                n_iterations / 10 * buf_pool->curr_size
717
 
                                pages from the end of the LRU list; if
718
 
                                n_iterations < 5, then we will also search
719
 
                                n_iterations / 5 of the unzip_LRU list. */
720
 
{
721
 
        ibool   freed = FALSE;
722
 
 
723
 
        buf_pool_mutex_enter(buf_pool);
724
 
 
725
 
        freed = buf_LRU_free_from_unzip_LRU_list(buf_pool, n_iterations);
726
 
 
727
 
        if (!freed) {
728
 
                freed = buf_LRU_free_from_common_LRU_list(
729
 
                        buf_pool, n_iterations);
730
 
        }
731
 
 
732
 
        if (!freed) {
733
 
                buf_pool->LRU_flush_ended = 0;
734
 
        } else if (buf_pool->LRU_flush_ended > 0) {
735
 
                buf_pool->LRU_flush_ended--;
736
 
        }
737
 
 
738
 
        buf_pool_mutex_exit(buf_pool);
739
 
 
740
 
        return(freed);
741
 
}
742
 
 
743
 
/******************************************************************//**
744
 
Tries to remove LRU flushed blocks from the end of the LRU list and put them
745
 
to the free list. This is beneficial for the efficiency of the insert buffer
746
 
operation, as flushed pages from non-unique non-clustered indexes are here
747
 
taken out of the buffer pool, and their inserts redirected to the insert
748
 
buffer. Otherwise, the flushed blocks could get modified again before read
749
 
operations need new buffer blocks, and the i/o work done in flushing would be
750
 
wasted. */
751
 
UNIV_INTERN
752
 
void
753
 
buf_LRU_try_free_flushed_blocks(
754
 
/*============================*/
755
 
        buf_pool_t*     buf_pool)               /*!< in: buffer pool instance */
756
 
{
757
 
 
758
 
        if (buf_pool == NULL) {
759
 
                ulint   i;
760
 
 
761
 
                for (i = 0; i < srv_buf_pool_instances; i++) {
762
 
                        buf_pool = buf_pool_from_array(i);
763
 
                        buf_LRU_try_free_flushed_blocks(buf_pool);
764
 
                }
765
 
        } else {
766
 
                buf_pool_mutex_enter(buf_pool);
767
 
 
768
 
                while (buf_pool->LRU_flush_ended > 0) {
769
 
 
770
 
                        buf_pool_mutex_exit(buf_pool);
771
 
 
772
 
                        buf_LRU_search_and_free_block(buf_pool, 1);
773
 
 
774
 
                        buf_pool_mutex_enter(buf_pool);
775
 
                }
776
 
 
777
 
                buf_pool_mutex_exit(buf_pool);
778
 
        }
779
 
}
780
 
 
781
 
/******************************************************************//**
782
 
Returns TRUE if less than 25 % of the buffer pool in any instance is
783
 
available. This can be used in heuristics to prevent huge transactions
784
 
eating up the whole buffer pool for their locks.
785
 
@return TRUE if less than 25 % of buffer pool left */
786
 
UNIV_INTERN
787
 
ibool
788
 
buf_LRU_buf_pool_running_out(void)
789
 
/*==============================*/
790
 
{
791
 
        ulint   i;
792
 
        ibool   ret = FALSE;
793
 
 
794
 
        for (i = 0; i < srv_buf_pool_instances && !ret; i++) {
795
 
                buf_pool_t*     buf_pool;
796
 
 
797
 
                buf_pool = buf_pool_from_array(i);
798
 
 
799
 
                buf_pool_mutex_enter(buf_pool);
800
 
 
801
 
                if (!recv_recovery_on
802
 
                    && UT_LIST_GET_LEN(buf_pool->free)
803
 
                       + UT_LIST_GET_LEN(buf_pool->LRU)
804
 
                       < buf_pool->curr_size / 4) {
805
 
 
806
 
                        ret = TRUE;
807
 
                }
808
 
 
809
 
                buf_pool_mutex_exit(buf_pool);
810
 
        }
811
 
 
812
 
        return(ret);
813
 
}
814
 
 
815
 
/******************************************************************//**
816
 
Returns a free block from the buf_pool.  The block is taken off the
817
 
free list.  If it is empty, returns NULL.
818
 
@return a free control block, or NULL if the buf_block->free list is empty */
819
 
UNIV_INTERN
820
 
buf_block_t*
821
 
buf_LRU_get_free_only(
822
 
/*==================*/
823
 
        buf_pool_t*     buf_pool)
824
 
{
825
 
        buf_block_t*    block;
826
 
 
827
 
        ut_ad(buf_pool_mutex_own(buf_pool));
828
 
 
829
 
        block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
830
 
 
831
 
        if (block) {
832
 
 
833
 
                ut_ad(block->page.in_free_list);
834
 
                ut_d(block->page.in_free_list = FALSE);
835
 
                ut_ad(!block->page.in_flush_list);
836
 
                ut_ad(!block->page.in_LRU_list);
837
 
                ut_a(!buf_page_in_file(&block->page));
838
 
                UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
839
 
 
840
 
                mutex_enter(&block->mutex);
841
 
 
842
 
                buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
843
 
                UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
844
 
 
845
 
                ut_ad(buf_pool_from_block(block) == buf_pool);
846
 
 
847
 
                mutex_exit(&block->mutex);
848
 
        }
849
 
 
850
 
        return(block);
851
 
}
852
 
 
853
 
/******************************************************************//**
854
 
Returns a free block from the buf_pool. The block is taken off the
855
 
free list. If it is empty, blocks are moved from the end of the
856
 
LRU list to the free list.
857
 
@return the free control block, in state BUF_BLOCK_READY_FOR_USE */
858
 
UNIV_INTERN
859
 
buf_block_t*
860
 
buf_LRU_get_free_block(
861
 
/*===================*/
862
 
        buf_pool_t*     buf_pool,       /*!< in: buffer pool instance */
863
 
        ulint           zip_size)       /*!< in: compressed page size in bytes,
864
 
                                        or 0 if uncompressed tablespace */
865
 
{
866
 
        buf_block_t*    block           = NULL;
867
 
        ibool           freed;
868
 
        ulint           n_iterations    = 1;
869
 
        ibool           mon_value_was   = FALSE;
870
 
        ibool           started_monitor = FALSE;
871
 
loop:
872
 
        buf_pool_mutex_enter(buf_pool);
873
 
 
874
 
        if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
875
 
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
876
 
                ut_print_timestamp(stderr);
877
 
 
878
 
                fprintf(stderr,
879
 
                        "  InnoDB: ERROR: over 95 percent of the buffer pool"
880
 
                        " is occupied by\n"
881
 
                        "InnoDB: lock heaps or the adaptive hash index!"
882
 
                        " Check that your\n"
883
 
                        "InnoDB: transactions do not set too many row locks.\n"
884
 
                        "InnoDB: Your buffer pool size is %lu MB."
885
 
                        " Maybe you should make\n"
886
 
                        "InnoDB: the buffer pool bigger?\n"
887
 
                        "InnoDB: We intentionally generate a seg fault"
888
 
                        " to print a stack trace\n"
889
 
                        "InnoDB: on Linux!\n",
890
 
                        (ulong) (buf_pool->curr_size
891
 
                                 / (1024 * 1024 / UNIV_PAGE_SIZE)));
892
 
 
893
 
                ut_error;
894
 
 
895
 
        } else if (!recv_recovery_on
896
 
                   && (UT_LIST_GET_LEN(buf_pool->free)
897
 
                       + UT_LIST_GET_LEN(buf_pool->LRU))
898
 
                   < buf_pool->curr_size / 3) {
899
 
 
900
 
                if (!buf_lru_switched_on_innodb_mon) {
901
 
 
902
 
                        /* Over 67 % of the buffer pool is occupied by lock
903
 
                        heaps or the adaptive hash index. This may be a memory
904
 
                        leak! */
905
 
 
906
 
                        ut_print_timestamp(stderr);
907
 
                        fprintf(stderr,
908
 
                                "  InnoDB: WARNING: over 67 percent of"
909
 
                                " the buffer pool is occupied by\n"
910
 
                                "InnoDB: lock heaps or the adaptive"
911
 
                                " hash index! Check that your\n"
912
 
                                "InnoDB: transactions do not set too many"
913
 
                                " row locks.\n"
914
 
                                "InnoDB: Your buffer pool size is %lu MB."
915
 
                                " Maybe you should make\n"
916
 
                                "InnoDB: the buffer pool bigger?\n"
917
 
                                "InnoDB: Starting the InnoDB Monitor to print"
918
 
                                " diagnostics, including\n"
919
 
                                "InnoDB: lock heap and hash index sizes.\n",
920
 
                                (ulong) (buf_pool->curr_size
921
 
                                         / (1024 * 1024 / UNIV_PAGE_SIZE)));
922
 
 
923
 
                        buf_lru_switched_on_innodb_mon = TRUE;
924
 
                        srv_print_innodb_monitor = TRUE;
925
 
                        os_event_set(srv_lock_timeout_thread_event);
926
 
                }
927
 
        } else if (buf_lru_switched_on_innodb_mon) {
928
 
 
929
 
                /* Switch off the InnoDB Monitor; this is a simple way
930
 
                to stop the monitor if the situation becomes less urgent,
931
 
                but may also surprise users if the user also switched on the
932
 
                monitor! */
933
 
 
934
 
                buf_lru_switched_on_innodb_mon = FALSE;
935
 
                srv_print_innodb_monitor = FALSE;
936
 
        }
937
 
 
938
 
        /* If there is a block in the free list, take it */
939
 
        block = buf_LRU_get_free_only(buf_pool);
940
 
        if (block) {
941
 
 
942
 
                ut_ad(buf_pool_from_block(block) == buf_pool);
943
 
 
944
 
#ifdef UNIV_DEBUG
945
 
                block->page.zip.m_start =
946
 
#endif /* UNIV_DEBUG */
947
 
                        block->page.zip.m_end =
948
 
                        block->page.zip.m_nonempty =
949
 
                        block->page.zip.n_blobs = 0;
950
 
 
951
 
                if (UNIV_UNLIKELY(zip_size)) {
952
 
                        ibool   lru;
953
 
                        page_zip_set_size(&block->page.zip, zip_size);
954
 
 
955
 
                        block->page.zip.data = buf_buddy_alloc(
956
 
                                buf_pool, zip_size, &lru);
957
 
 
958
 
                        UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
959
 
                } else {
960
 
                        page_zip_set_size(&block->page.zip, 0);
961
 
                        block->page.zip.data = NULL;
962
 
                }
963
 
 
964
 
                buf_pool_mutex_exit(buf_pool);
965
 
 
966
 
                if (started_monitor) {
967
 
                        srv_print_innodb_monitor = mon_value_was;
968
 
                }
969
 
 
970
 
                return(block);
971
 
        }
972
 
 
973
 
        /* If no block was in the free list, search from the end of the LRU
974
 
        list and try to free a block there */
975
 
 
976
 
        buf_pool_mutex_exit(buf_pool);
977
 
 
978
 
        freed = buf_LRU_search_and_free_block(buf_pool, n_iterations);
979
 
 
980
 
        if (freed > 0) {
981
 
                goto loop;
982
 
        }
983
 
 
984
 
        if (n_iterations > 30) {
985
 
                ut_print_timestamp(stderr);
986
 
                fprintf(stderr,
987
 
                        "  InnoDB: Warning: difficult to find free blocks in\n"
988
 
                        "InnoDB: the buffer pool (%lu search iterations)!"
989
 
                        " Consider\n"
990
 
                        "InnoDB: increasing the buffer pool size.\n"
991
 
                        "InnoDB: It is also possible that"
992
 
                        " in your Unix version\n"
993
 
                        "InnoDB: fsync is very slow, or"
994
 
                        " completely frozen inside\n"
995
 
                        "InnoDB: the OS kernel. Then upgrading to"
996
 
                        " a newer version\n"
997
 
                        "InnoDB: of your operating system may help."
998
 
                        " Look at the\n"
999
 
                        "InnoDB: number of fsyncs in diagnostic info below.\n"
1000
 
                        "InnoDB: Pending flushes (fsync) log: %lu;"
1001
 
                        " buffer pool: %lu\n"
1002
 
                        "InnoDB: %lu OS file reads, %lu OS file writes,"
1003
 
                        " %lu OS fsyncs\n"
1004
 
                        "InnoDB: Starting InnoDB Monitor to print further\n"
1005
 
                        "InnoDB: diagnostics to the standard output.\n",
1006
 
                        (ulong) n_iterations,
1007
 
                        (ulong) fil_n_pending_log_flushes,
1008
 
                        (ulong) fil_n_pending_tablespace_flushes,
1009
 
                        (ulong) os_n_file_reads, (ulong) os_n_file_writes,
1010
 
                        (ulong) os_n_fsyncs);
1011
 
 
1012
 
                mon_value_was = srv_print_innodb_monitor;
1013
 
                started_monitor = TRUE;
1014
 
                srv_print_innodb_monitor = TRUE;
1015
 
                os_event_set(srv_lock_timeout_thread_event);
1016
 
        }
1017
 
 
1018
 
        /* No free block was found: try to flush the LRU list */
1019
 
 
1020
 
        buf_flush_free_margin(buf_pool);
1021
 
        ++srv_buf_pool_wait_free;
1022
 
 
1023
 
        os_aio_simulated_wake_handler_threads();
1024
 
 
1025
 
        buf_pool_mutex_enter(buf_pool);
1026
 
 
1027
 
        if (buf_pool->LRU_flush_ended > 0) {
1028
 
                /* We have written pages in an LRU flush. To make the insert
1029
 
                buffer more efficient, we try to move these pages to the free
1030
 
                list. */
1031
 
 
1032
 
                buf_pool_mutex_exit(buf_pool);
1033
 
 
1034
 
                buf_LRU_try_free_flushed_blocks(buf_pool);
1035
 
        } else {
1036
 
                buf_pool_mutex_exit(buf_pool);
1037
 
        }
1038
 
 
1039
 
        if (n_iterations > 10) {
1040
 
 
1041
 
                os_thread_sleep(500000);
1042
 
        }
1043
 
 
1044
 
        n_iterations++;
1045
 
 
1046
 
        goto loop;
1047
 
}
1048
 
 
1049
 
/*******************************************************************//**
1050
 
Moves the LRU_old pointer so that the length of the old blocks list
1051
 
is inside the allowed limits. */
1052
 
UNIV_INLINE
1053
 
void
1054
 
buf_LRU_old_adjust_len(
1055
 
/*===================*/
1056
 
        buf_pool_t*     buf_pool)       /*!< in: buffer pool instance */
1057
 
{
1058
 
        ulint   old_len;
1059
 
        ulint   new_len;
1060
 
 
1061
 
        ut_a(buf_pool->LRU_old);
1062
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1063
 
        ut_ad(buf_pool->LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN);
1064
 
        ut_ad(buf_pool->LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX);
1065
 
#if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)
1066
 
# error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)"
1067
 
#endif
1068
 
#ifdef UNIV_LRU_DEBUG
1069
 
        /* buf_pool->LRU_old must be the first item in the LRU list
1070
 
        whose "old" flag is set. */
1071
 
        ut_a(buf_pool->LRU_old->old);
1072
 
        ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
1073
 
             || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
1074
 
        ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
1075
 
             || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
1076
 
#endif /* UNIV_LRU_DEBUG */
1077
 
 
1078
 
        old_len = buf_pool->LRU_old_len;
1079
 
        new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU)
1080
 
                         * buf_pool->LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV,
1081
 
                         UT_LIST_GET_LEN(buf_pool->LRU)
1082
 
                         - (BUF_LRU_OLD_TOLERANCE
1083
 
                            + BUF_LRU_NON_OLD_MIN_LEN));
1084
 
 
1085
 
        for (;;) {
1086
 
                buf_page_t*     LRU_old = buf_pool->LRU_old;
1087
 
 
1088
 
                ut_a(LRU_old);
1089
 
                ut_ad(LRU_old->in_LRU_list);
1090
 
#ifdef UNIV_LRU_DEBUG
1091
 
                ut_a(LRU_old->old);
1092
 
#endif /* UNIV_LRU_DEBUG */
1093
 
 
1094
 
                /* Update the LRU_old pointer if necessary */
1095
 
 
1096
 
                if (old_len + BUF_LRU_OLD_TOLERANCE < new_len) {
1097
 
 
1098
 
                        buf_pool->LRU_old = LRU_old = UT_LIST_GET_PREV(
1099
 
                                LRU, LRU_old);
1100
 
#ifdef UNIV_LRU_DEBUG
1101
 
                        ut_a(!LRU_old->old);
1102
 
#endif /* UNIV_LRU_DEBUG */
1103
 
                        old_len = ++buf_pool->LRU_old_len;
1104
 
                        buf_page_set_old(LRU_old, TRUE);
1105
 
 
1106
 
                } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
1107
 
 
1108
 
                        buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU, LRU_old);
1109
 
                        old_len = --buf_pool->LRU_old_len;
1110
 
                        buf_page_set_old(LRU_old, FALSE);
1111
 
                } else {
1112
 
                        return;
1113
 
                }
1114
 
        }
1115
 
}
1116
 
 
1117
 
/*******************************************************************//**
1118
 
Initializes the old blocks pointer in the LRU list. This function should be
1119
 
called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
1120
 
static
1121
 
void
1122
 
buf_LRU_old_init(
1123
 
/*=============*/
1124
 
        buf_pool_t*     buf_pool)
1125
 
{
1126
 
        buf_page_t*     bpage;
1127
 
 
1128
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1129
 
        ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
1130
 
 
1131
 
        /* We first initialize all blocks in the LRU list as old and then use
1132
 
        the adjust function to move the LRU_old pointer to the right
1133
 
        position */
1134
 
 
1135
 
        for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); bpage != NULL;
1136
 
             bpage = UT_LIST_GET_PREV(LRU, bpage)) {
1137
 
                ut_ad(bpage->in_LRU_list);
1138
 
                ut_ad(buf_page_in_file(bpage));
1139
 
                /* This loop temporarily violates the
1140
 
                assertions of buf_page_set_old(). */
1141
 
                bpage->old = TRUE;
1142
 
        }
1143
 
 
1144
 
        buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
1145
 
        buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
1146
 
 
1147
 
        buf_LRU_old_adjust_len(buf_pool);
1148
 
}
1149
 
 
1150
 
/******************************************************************//**
1151
 
Remove a block from the unzip_LRU list if it belonged to the list. */
1152
 
static
1153
 
void
1154
 
buf_unzip_LRU_remove_block_if_needed(
1155
 
/*=================================*/
1156
 
        buf_page_t*     bpage)  /*!< in/out: control block */
1157
 
{
1158
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1159
 
 
1160
 
        ut_ad(buf_pool);
1161
 
        ut_ad(bpage);
1162
 
        ut_ad(buf_page_in_file(bpage));
1163
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1164
 
 
1165
 
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
1166
 
                buf_block_t*    block = (buf_block_t*) bpage;
1167
 
 
1168
 
                ut_ad(block->in_unzip_LRU_list);
1169
 
                ut_d(block->in_unzip_LRU_list = FALSE);
1170
 
 
1171
 
                UT_LIST_REMOVE(unzip_LRU, buf_pool->unzip_LRU, block);
1172
 
        }
1173
 
}
1174
 
 
1175
 
/******************************************************************//**
1176
 
Removes a block from the LRU list. */
1177
 
UNIV_INLINE
1178
 
void
1179
 
buf_LRU_remove_block(
1180
 
/*=================*/
1181
 
        buf_page_t*     bpage)  /*!< in: control block */
1182
 
{
1183
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1184
 
 
1185
 
        ut_ad(buf_pool);
1186
 
        ut_ad(bpage);
1187
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1188
 
 
1189
 
        ut_a(buf_page_in_file(bpage));
1190
 
 
1191
 
        ut_ad(bpage->in_LRU_list);
1192
 
 
1193
 
        /* If the LRU_old pointer is defined and points to just this block,
1194
 
        move it backward one step */
1195
 
 
1196
 
        if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
1197
 
 
1198
 
                /* Below: the previous block is guaranteed to exist,
1199
 
                because the LRU_old pointer is only allowed to differ
1200
 
                by BUF_LRU_OLD_TOLERANCE from strict
1201
 
                buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU
1202
 
                list length. */
1203
 
                buf_page_t*     prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
1204
 
 
1205
 
                ut_a(prev_bpage);
1206
 
#ifdef UNIV_LRU_DEBUG
1207
 
                ut_a(!prev_bpage->old);
1208
 
#endif /* UNIV_LRU_DEBUG */
1209
 
                buf_pool->LRU_old = prev_bpage;
1210
 
                buf_page_set_old(prev_bpage, TRUE);
1211
 
 
1212
 
                buf_pool->LRU_old_len++;
1213
 
        }
1214
 
 
1215
 
        /* Remove the block from the LRU list */
1216
 
        UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
1217
 
        ut_d(bpage->in_LRU_list = FALSE);
1218
 
 
1219
 
        buf_unzip_LRU_remove_block_if_needed(bpage);
1220
 
 
1221
 
        /* If the LRU list is so short that LRU_old is not defined,
1222
 
        clear the "old" flags and return */
1223
 
        if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
1224
 
 
1225
 
                for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU); bpage != NULL;
1226
 
                     bpage = UT_LIST_GET_NEXT(LRU, bpage)) {
1227
 
                        /* This loop temporarily violates the
1228
 
                        assertions of buf_page_set_old(). */
1229
 
                        bpage->old = FALSE;
1230
 
                }
1231
 
 
1232
 
                buf_pool->LRU_old = NULL;
1233
 
                buf_pool->LRU_old_len = 0;
1234
 
 
1235
 
                return;
1236
 
        }
1237
 
 
1238
 
        ut_ad(buf_pool->LRU_old);
1239
 
 
1240
 
        /* Update the LRU_old_len field if necessary */
1241
 
        if (buf_page_is_old(bpage)) {
1242
 
 
1243
 
                buf_pool->LRU_old_len--;
1244
 
        }
1245
 
 
1246
 
        /* Adjust the length of the old block list if necessary */
1247
 
        buf_LRU_old_adjust_len(buf_pool);
1248
 
}
1249
 
 
1250
 
/******************************************************************//**
1251
 
Adds a block to the LRU list of decompressed zip pages. */
1252
 
UNIV_INTERN
1253
 
void
1254
 
buf_unzip_LRU_add_block(
1255
 
/*====================*/
1256
 
        buf_block_t*    block,  /*!< in: control block */
1257
 
        ibool           old)    /*!< in: TRUE if should be put to the end
1258
 
                                of the list, else put to the start */
1259
 
{
1260
 
        buf_pool_t*     buf_pool = buf_pool_from_block(block);
1261
 
 
1262
 
        ut_ad(buf_pool);
1263
 
        ut_ad(block);
1264
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1265
 
 
1266
 
        ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
1267
 
 
1268
 
        ut_ad(!block->in_unzip_LRU_list);
1269
 
        ut_d(block->in_unzip_LRU_list = TRUE);
1270
 
 
1271
 
        if (old) {
1272
 
                UT_LIST_ADD_LAST(unzip_LRU, buf_pool->unzip_LRU, block);
1273
 
        } else {
1274
 
                UT_LIST_ADD_FIRST(unzip_LRU, buf_pool->unzip_LRU, block);
1275
 
        }
1276
 
}
1277
 
 
1278
 
/******************************************************************//**
1279
 
Adds a block to the LRU list end. */
1280
 
UNIV_INLINE
1281
 
void
1282
 
buf_LRU_add_block_to_end_low(
1283
 
/*=========================*/
1284
 
        buf_page_t*     bpage)  /*!< in: control block */
1285
 
{
1286
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1287
 
 
1288
 
        ut_ad(buf_pool);
1289
 
        ut_ad(bpage);
1290
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1291
 
 
1292
 
        ut_a(buf_page_in_file(bpage));
1293
 
 
1294
 
        ut_ad(!bpage->in_LRU_list);
1295
 
        UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage);
1296
 
        ut_d(bpage->in_LRU_list = TRUE);
1297
 
 
1298
 
        if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
1299
 
 
1300
 
                ut_ad(buf_pool->LRU_old);
1301
 
 
1302
 
                /* Adjust the length of the old block list if necessary */
1303
 
 
1304
 
                buf_page_set_old(bpage, TRUE);
1305
 
                buf_pool->LRU_old_len++;
1306
 
                buf_LRU_old_adjust_len(buf_pool);
1307
 
 
1308
 
        } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
1309
 
 
1310
 
                /* The LRU list is now long enough for LRU_old to become
1311
 
                defined: init it */
1312
 
 
1313
 
                buf_LRU_old_init(buf_pool);
1314
 
        } else {
1315
 
                buf_page_set_old(bpage, buf_pool->LRU_old != NULL);
1316
 
        }
1317
 
 
1318
 
        /* If this is a zipped block with decompressed frame as well
1319
 
        then put it on the unzip_LRU list */
1320
 
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
1321
 
                buf_unzip_LRU_add_block((buf_block_t*) bpage, TRUE);
1322
 
        }
1323
 
}
1324
 
 
1325
 
/******************************************************************//**
1326
 
Adds a block to the LRU list. */
1327
 
UNIV_INLINE
1328
 
void
1329
 
buf_LRU_add_block_low(
1330
 
/*==================*/
1331
 
        buf_page_t*     bpage,  /*!< in: control block */
1332
 
        ibool           old)    /*!< in: TRUE if should be put to the old blocks
1333
 
                                in the LRU list, else put to the start; if the
1334
 
                                LRU list is very short, the block is added to
1335
 
                                the start, regardless of this parameter */
1336
 
{
1337
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1338
 
 
1339
 
        ut_ad(buf_pool);
1340
 
        ut_ad(bpage);
1341
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1342
 
 
1343
 
        ut_a(buf_page_in_file(bpage));
1344
 
        ut_ad(!bpage->in_LRU_list);
1345
 
 
1346
 
        if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
1347
 
 
1348
 
                UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
1349
 
 
1350
 
                bpage->freed_page_clock = buf_pool->freed_page_clock;
1351
 
        } else {
1352
 
#ifdef UNIV_LRU_DEBUG
1353
 
                /* buf_pool->LRU_old must be the first item in the LRU list
1354
 
                whose "old" flag is set. */
1355
 
                ut_a(buf_pool->LRU_old->old);
1356
 
                ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
1357
 
                     || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
1358
 
                ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
1359
 
                     || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
1360
 
#endif /* UNIV_LRU_DEBUG */
1361
 
                UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
1362
 
                                     bpage);
1363
 
                buf_pool->LRU_old_len++;
1364
 
        }
1365
 
 
1366
 
        ut_d(bpage->in_LRU_list = TRUE);
1367
 
 
1368
 
        if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
1369
 
 
1370
 
                ut_ad(buf_pool->LRU_old);
1371
 
 
1372
 
                /* Adjust the length of the old block list if necessary */
1373
 
 
1374
 
                buf_page_set_old(bpage, old);
1375
 
                buf_LRU_old_adjust_len(buf_pool);
1376
 
 
1377
 
        } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
1378
 
 
1379
 
                /* The LRU list is now long enough for LRU_old to become
1380
 
                defined: init it */
1381
 
 
1382
 
                buf_LRU_old_init(buf_pool);
1383
 
        } else {
1384
 
                buf_page_set_old(bpage, buf_pool->LRU_old != NULL);
1385
 
        }
1386
 
 
1387
 
        /* If this is a zipped block with decompressed frame as well
1388
 
        then put it on the unzip_LRU list */
1389
 
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
1390
 
                buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
1391
 
        }
1392
 
}
1393
 
 
1394
 
/******************************************************************//**
1395
 
Adds a block to the LRU list. */
1396
 
UNIV_INTERN
1397
 
void
1398
 
buf_LRU_add_block(
1399
 
/*==============*/
1400
 
        buf_page_t*     bpage,  /*!< in: control block */
1401
 
        ibool           old)    /*!< in: TRUE if should be put to the old
1402
 
                                blocks in the LRU list, else put to the start;
1403
 
                                if the LRU list is very short, the block is
1404
 
                                added to the start, regardless of this
1405
 
                                parameter */
1406
 
{
1407
 
        buf_LRU_add_block_low(bpage, old);
1408
 
}
1409
 
 
1410
 
/******************************************************************//**
1411
 
Moves a block to the start of the LRU list. */
1412
 
UNIV_INTERN
1413
 
void
1414
 
buf_LRU_make_block_young(
1415
 
/*=====================*/
1416
 
        buf_page_t*     bpage)  /*!< in: control block */
1417
 
{
1418
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1419
 
 
1420
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1421
 
 
1422
 
        if (bpage->old) {
1423
 
                buf_pool->stat.n_pages_made_young++;
1424
 
        }
1425
 
 
1426
 
        buf_LRU_remove_block(bpage);
1427
 
        buf_LRU_add_block_low(bpage, FALSE);
1428
 
}
1429
 
 
1430
 
/******************************************************************//**
1431
 
Moves a block to the end of the LRU list. */
1432
 
UNIV_INTERN
1433
 
void
1434
 
buf_LRU_make_block_old(
1435
 
/*===================*/
1436
 
        buf_page_t*     bpage)  /*!< in: control block */
1437
 
{
1438
 
        buf_LRU_remove_block(bpage);
1439
 
        buf_LRU_add_block_to_end_low(bpage);
1440
 
}
1441
 
 
1442
 
/******************************************************************//**
1443
 
Try to free a block.  If bpage is a descriptor of a compressed-only
1444
 
page, the descriptor object will be freed as well.
1445
 
 
1446
 
NOTE: If this function returns BUF_LRU_FREED, it will temporarily
1447
 
release buf_pool_mutex.  Furthermore, the page frame will no longer be
1448
 
accessible via bpage.
1449
 
 
1450
 
The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and
1451
 
release these two mutexes after the call.  No other
1452
 
buf_page_get_mutex() may be held when calling this function.
1453
 
@return BUF_LRU_FREED if freed, BUF_LRU_CANNOT_RELOCATE or
1454
 
BUF_LRU_NOT_FREED otherwise. */
1455
 
UNIV_INTERN
1456
 
enum buf_lru_free_block_status
1457
 
buf_LRU_free_block(
1458
 
/*===============*/
1459
 
        buf_page_t*     bpage,  /*!< in: block to be freed */
1460
 
        ibool           zip,    /*!< in: TRUE if should remove also the
1461
 
                                compressed page of an uncompressed page */
1462
 
        ibool*          buf_pool_mutex_released)
1463
 
                                /*!< in: pointer to a variable that will
1464
 
                                be assigned TRUE if buf_pool_mutex
1465
 
                                was temporarily released, or NULL */
1466
 
{
1467
 
        buf_page_t*     b = NULL;
1468
 
        buf_pool_t*     buf_pool = buf_pool_from_bpage(bpage);
1469
 
        mutex_t*        block_mutex = buf_page_get_mutex(bpage);
1470
 
 
1471
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1472
 
        ut_ad(mutex_own(block_mutex));
1473
 
        ut_ad(buf_page_in_file(bpage));
1474
 
        ut_ad(bpage->in_LRU_list);
1475
 
        ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
1476
 
#if UNIV_WORD_SIZE == 4
1477
 
        /* On 32-bit systems, there is no padding in buf_page_t.  On
1478
 
        other systems, Valgrind could complain about uninitialized pad
1479
 
        bytes. */
1480
 
        UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
1481
 
#endif
1482
 
 
1483
 
        if (!buf_page_can_relocate(bpage)) {
1484
 
 
1485
 
                /* Do not free buffer-fixed or I/O-fixed blocks. */
1486
 
                return(BUF_LRU_NOT_FREED);
1487
 
        }
1488
 
 
1489
 
#ifdef UNIV_IBUF_COUNT_DEBUG
1490
 
        ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
1491
 
#endif /* UNIV_IBUF_COUNT_DEBUG */
1492
 
 
1493
 
        if (zip || !bpage->zip.data) {
1494
 
                /* This would completely free the block. */
1495
 
                /* Do not completely free dirty blocks. */
1496
 
 
1497
 
                if (bpage->oldest_modification) {
1498
 
                        return(BUF_LRU_NOT_FREED);
1499
 
                }
1500
 
        } else if (bpage->oldest_modification) {
1501
 
                /* Do not completely free dirty blocks. */
1502
 
 
1503
 
                if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
1504
 
                        ut_ad(buf_page_get_state(bpage)
1505
 
                              == BUF_BLOCK_ZIP_DIRTY);
1506
 
                        return(BUF_LRU_NOT_FREED);
1507
 
                }
1508
 
 
1509
 
                goto alloc;
1510
 
        } else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
1511
 
                /* Allocate the control block for the compressed page.
1512
 
                If it cannot be allocated (without freeing a block
1513
 
                from the LRU list), refuse to free bpage. */
1514
 
alloc:
1515
 
                buf_pool_mutex_exit_forbid(buf_pool);
1516
 
                b = buf_buddy_alloc(buf_pool, sizeof *b, NULL);
1517
 
                buf_pool_mutex_exit_allow(buf_pool);
1518
 
 
1519
 
                if (UNIV_UNLIKELY(!b)) {
1520
 
                        return(BUF_LRU_CANNOT_RELOCATE);
1521
 
                }
1522
 
 
1523
 
                memcpy(b, bpage, sizeof *b);
1524
 
        }
1525
 
 
1526
 
#ifdef UNIV_DEBUG
1527
 
        if (buf_debug_prints) {
1528
 
                fprintf(stderr, "Putting space %lu page %lu to free list\n",
1529
 
                        (ulong) buf_page_get_space(bpage),
1530
 
                        (ulong) buf_page_get_page_no(bpage));
1531
 
        }
1532
 
#endif /* UNIV_DEBUG */
1533
 
 
1534
 
        if (buf_LRU_block_remove_hashed_page(bpage, zip)
1535
 
            != BUF_BLOCK_ZIP_FREE) {
1536
 
                ut_a(bpage->buf_fix_count == 0);
1537
 
 
1538
 
                if (b) {
1539
 
                        buf_page_t*     hash_b;
1540
 
                        buf_page_t*     prev_b  = UT_LIST_GET_PREV(LRU, b);
1541
 
 
1542
 
                        const ulint     fold = buf_page_address_fold(
1543
 
                                bpage->space, bpage->offset);
1544
 
 
1545
 
                        hash_b  = buf_page_hash_get_low(
1546
 
                                buf_pool, bpage->space, bpage->offset, fold);
1547
 
 
1548
 
                        ut_a(!hash_b);
1549
 
 
1550
 
                        b->state = b->oldest_modification
1551
 
                                ? BUF_BLOCK_ZIP_DIRTY
1552
 
                                : BUF_BLOCK_ZIP_PAGE;
1553
 
                        UNIV_MEM_DESC(b->zip.data,
1554
 
                                      page_zip_get_size(&b->zip), b);
1555
 
 
1556
 
                        /* The fields in_page_hash and in_LRU_list of
1557
 
                        the to-be-freed block descriptor should have
1558
 
                        been cleared in
1559
 
                        buf_LRU_block_remove_hashed_page(), which
1560
 
                        invokes buf_LRU_remove_block(). */
1561
 
                        ut_ad(!bpage->in_page_hash);
1562
 
                        ut_ad(!bpage->in_LRU_list);
1563
 
                        /* bpage->state was BUF_BLOCK_FILE_PAGE because
1564
 
                        b != NULL. The type cast below is thus valid. */
1565
 
                        ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
1566
 
 
1567
 
                        /* The fields of bpage were copied to b before
1568
 
                        buf_LRU_block_remove_hashed_page() was invoked. */
1569
 
                        ut_ad(!b->in_zip_hash);
1570
 
                        ut_ad(b->in_page_hash);
1571
 
                        ut_ad(b->in_LRU_list);
1572
 
 
1573
 
                        HASH_INSERT(buf_page_t, hash,
1574
 
                                    buf_pool->page_hash, fold, b);
1575
 
 
1576
 
                        /* Insert b where bpage was in the LRU list. */
1577
 
                        if (UNIV_LIKELY(prev_b != NULL)) {
1578
 
                                ulint   lru_len;
1579
 
 
1580
 
                                ut_ad(prev_b->in_LRU_list);
1581
 
                                ut_ad(buf_page_in_file(prev_b));
1582
 
#if UNIV_WORD_SIZE == 4
1583
 
                                /* On 32-bit systems, there is no
1584
 
                                padding in buf_page_t.  On other
1585
 
                                systems, Valgrind could complain about
1586
 
                                uninitialized pad bytes. */
1587
 
                                UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
1588
 
#endif
1589
 
                                UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
1590
 
                                                     prev_b, b);
1591
 
 
1592
 
                                if (buf_page_is_old(b)) {
1593
 
                                        buf_pool->LRU_old_len++;
1594
 
                                        if (UNIV_UNLIKELY
1595
 
                                            (buf_pool->LRU_old
1596
 
                                             == UT_LIST_GET_NEXT(LRU, b))) {
1597
 
 
1598
 
                                                buf_pool->LRU_old = b;
1599
 
                                        }
1600
 
                                }
1601
 
 
1602
 
                                lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
1603
 
 
1604
 
                                if (lru_len > BUF_LRU_OLD_MIN_LEN) {
1605
 
                                        ut_ad(buf_pool->LRU_old);
1606
 
                                        /* Adjust the length of the
1607
 
                                        old block list if necessary */
1608
 
                                        buf_LRU_old_adjust_len(buf_pool);
1609
 
                                } else if (lru_len == BUF_LRU_OLD_MIN_LEN) {
1610
 
                                        /* The LRU list is now long
1611
 
                                        enough for LRU_old to become
1612
 
                                        defined: init it */
1613
 
                                        buf_LRU_old_init(buf_pool);
1614
 
                                }
1615
 
#ifdef UNIV_LRU_DEBUG
1616
 
                                /* Check that the "old" flag is consistent
1617
 
                                in the block and its neighbours. */
1618
 
                                buf_page_set_old(b, buf_page_is_old(b));
1619
 
#endif /* UNIV_LRU_DEBUG */
1620
 
                        } else {
1621
 
                                ut_d(b->in_LRU_list = FALSE);
1622
 
                                buf_LRU_add_block_low(b, buf_page_is_old(b));
1623
 
                        }
1624
 
 
1625
 
                        if (b->state == BUF_BLOCK_ZIP_PAGE) {
1626
 
                                buf_LRU_insert_zip_clean(b);
1627
 
                        } else {
1628
 
                                /* Relocate on buf_pool->flush_list. */
1629
 
                                buf_flush_relocate_on_flush_list(bpage, b);
1630
 
                        }
1631
 
 
1632
 
                        bpage->zip.data = NULL;
1633
 
                        page_zip_set_size(&bpage->zip, 0);
1634
 
 
1635
 
                        /* Prevent buf_page_get_gen() from
1636
 
                        decompressing the block while we release
1637
 
                        buf_pool->mutex and block_mutex. */
1638
 
                        b->buf_fix_count++;
1639
 
                        b->io_fix = BUF_IO_READ;
1640
 
                }
1641
 
 
1642
 
                if (buf_pool_mutex_released) {
1643
 
                        *buf_pool_mutex_released = TRUE;
1644
 
                }
1645
 
 
1646
 
                buf_pool_mutex_exit(buf_pool);
1647
 
                mutex_exit(block_mutex);
1648
 
 
1649
 
                /* Remove possible adaptive hash index on the page.
1650
 
                The page was declared uninitialized by
1651
 
                buf_LRU_block_remove_hashed_page().  We need to flag
1652
 
                the contents of the page valid (which it still is) in
1653
 
                order to avoid bogus Valgrind warnings.*/
1654
 
 
1655
 
                UNIV_MEM_VALID(((buf_block_t*) bpage)->frame,
1656
 
                               UNIV_PAGE_SIZE);
1657
 
                btr_search_drop_page_hash_index((buf_block_t*) bpage);
1658
 
                UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
1659
 
                                 UNIV_PAGE_SIZE);
1660
 
 
1661
 
                if (b) {
1662
 
                        /* Compute and stamp the compressed page
1663
 
                        checksum while not holding any mutex.  The
1664
 
                        block is already half-freed
1665
 
                        (BUF_BLOCK_REMOVE_HASH) and removed from
1666
 
                        buf_pool->page_hash, thus inaccessible by any
1667
 
                        other thread. */
1668
 
 
1669
 
                        mach_write_to_4(
1670
 
                                b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
1671
 
                                UNIV_LIKELY(srv_use_checksums)
1672
 
                                ? page_zip_calc_checksum(
1673
 
                                        b->zip.data,
1674
 
                                        page_zip_get_size(&b->zip))
1675
 
                                : BUF_NO_CHECKSUM_MAGIC);
1676
 
                }
1677
 
 
1678
 
                buf_pool_mutex_enter(buf_pool);
1679
 
                mutex_enter(block_mutex);
1680
 
 
1681
 
                if (b) {
1682
 
                        mutex_enter(&buf_pool->zip_mutex);
1683
 
                        b->buf_fix_count--;
1684
 
                        buf_page_set_io_fix(b, BUF_IO_NONE);
1685
 
                        mutex_exit(&buf_pool->zip_mutex);
1686
 
                }
1687
 
 
1688
 
                buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
1689
 
        } else {
1690
 
                /* The block_mutex should have been released by
1691
 
                buf_LRU_block_remove_hashed_page() when it returns
1692
 
                BUF_BLOCK_ZIP_FREE. */
1693
 
                ut_ad(block_mutex == &buf_pool->zip_mutex);
1694
 
                mutex_enter(block_mutex);
1695
 
        }
1696
 
 
1697
 
        return(BUF_LRU_FREED);
1698
 
}
1699
 
 
1700
 
/******************************************************************//**
1701
 
Puts a block back to the free list. */
1702
 
UNIV_INTERN
1703
 
void
1704
 
buf_LRU_block_free_non_file_page(
1705
 
/*=============================*/
1706
 
        buf_block_t*    block)  /*!< in: block, must not contain a file page */
1707
 
{
1708
 
        void*           data;
1709
 
        buf_pool_t*     buf_pool = buf_pool_from_block(block);
1710
 
 
1711
 
        ut_ad(block);
1712
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1713
 
        ut_ad(mutex_own(&block->mutex));
1714
 
 
1715
 
        switch (buf_block_get_state(block)) {
1716
 
        case BUF_BLOCK_MEMORY:
1717
 
        case BUF_BLOCK_READY_FOR_USE:
1718
 
                break;
1719
 
        default:
1720
 
                ut_error;
1721
 
        }
1722
 
 
1723
 
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
1724
 
        ut_a(block->n_pointers == 0);
1725
 
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
1726
 
        ut_ad(!block->page.in_free_list);
1727
 
        ut_ad(!block->page.in_flush_list);
1728
 
        ut_ad(!block->page.in_LRU_list);
1729
 
 
1730
 
        buf_block_set_state(block, BUF_BLOCK_NOT_USED);
1731
 
 
1732
 
        UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
1733
 
#ifdef UNIV_DEBUG
1734
 
        /* Wipe contents of page to reveal possible stale pointers to it */
1735
 
        memset(block->frame, '\0', UNIV_PAGE_SIZE);
1736
 
#else
1737
 
        /* Wipe page_no and space_id */
1738
 
        memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
1739
 
        memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
1740
 
#endif
1741
 
        data = block->page.zip.data;
1742
 
 
1743
 
        if (data) {
1744
 
                block->page.zip.data = NULL;
1745
 
                mutex_exit(&block->mutex);
1746
 
                buf_pool_mutex_exit_forbid(buf_pool);
1747
 
 
1748
 
                buf_buddy_free(
1749
 
                        buf_pool, data, page_zip_get_size(&block->page.zip));
1750
 
 
1751
 
                buf_pool_mutex_exit_allow(buf_pool);
1752
 
                mutex_enter(&block->mutex);
1753
 
                page_zip_set_size(&block->page.zip, 0);
1754
 
        }
1755
 
 
1756
 
        UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
1757
 
        ut_d(block->page.in_free_list = TRUE);
1758
 
 
1759
 
        UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
1760
 
}
1761
 
 
1762
 
/******************************************************************//**
1763
 
Takes a block out of the LRU list and page hash table.
1764
 
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
1765
 
the object will be freed and buf_pool->zip_mutex will be released.
1766
 
 
1767
 
If a compressed page or a compressed-only block descriptor is freed,
1768
 
other compressed pages or compressed-only block descriptors may be
1769
 
relocated.
1770
 
@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
1771
 
was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
1772
 
static
1773
 
enum buf_page_state
1774
 
buf_LRU_block_remove_hashed_page(
1775
 
/*=============================*/
1776
 
        buf_page_t*     bpage,  /*!< in: block, must contain a file page and
1777
 
                                be in a state where it can be freed; there
1778
 
                                may or may not be a hash index to the page */
1779
 
        ibool           zip)    /*!< in: TRUE if should remove also the
1780
 
                                compressed page of an uncompressed page */
1781
 
{
1782
 
        ulint                   fold;
1783
 
        const buf_page_t*       hashed_bpage;
1784
 
        buf_pool_t*             buf_pool = buf_pool_from_bpage(bpage);
1785
 
 
1786
 
        ut_ad(bpage);
1787
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1788
 
        ut_ad(mutex_own(buf_page_get_mutex(bpage)));
1789
 
 
1790
 
        ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
1791
 
        ut_a(bpage->buf_fix_count == 0);
1792
 
 
1793
 
#if UNIV_WORD_SIZE == 4
1794
 
        /* On 32-bit systems, there is no padding in
1795
 
        buf_page_t.  On other systems, Valgrind could complain
1796
 
        about uninitialized pad bytes. */
1797
 
        UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
1798
 
#endif
1799
 
 
1800
 
        buf_LRU_remove_block(bpage);
1801
 
 
1802
 
        buf_pool->freed_page_clock += 1;
1803
 
 
1804
 
        switch (buf_page_get_state(bpage)) {
1805
 
        case BUF_BLOCK_FILE_PAGE:
1806
 
                UNIV_MEM_ASSERT_W(bpage, sizeof(buf_block_t));
1807
 
                UNIV_MEM_ASSERT_W(((buf_block_t*) bpage)->frame,
1808
 
                                  UNIV_PAGE_SIZE);
1809
 
                buf_block_modify_clock_inc((buf_block_t*) bpage);
1810
 
                if (bpage->zip.data) {
1811
 
                        const page_t*   page = ((buf_block_t*) bpage)->frame;
1812
 
                        const ulint     zip_size
1813
 
                                = page_zip_get_size(&bpage->zip);
1814
 
 
1815
 
                        ut_a(!zip || bpage->oldest_modification == 0);
1816
 
 
1817
 
                        switch (UNIV_EXPECT(fil_page_get_type(page),
1818
 
                                            FIL_PAGE_INDEX)) {
1819
 
                        case FIL_PAGE_TYPE_ALLOCATED:
1820
 
                        case FIL_PAGE_INODE:
1821
 
                        case FIL_PAGE_IBUF_BITMAP:
1822
 
                        case FIL_PAGE_TYPE_FSP_HDR:
1823
 
                        case FIL_PAGE_TYPE_XDES:
1824
 
                                /* These are essentially uncompressed pages. */
1825
 
                                if (!zip) {
1826
 
                                        /* InnoDB writes the data to the
1827
 
                                        uncompressed page frame.  Copy it
1828
 
                                        to the compressed page, which will
1829
 
                                        be preserved. */
1830
 
                                        memcpy(bpage->zip.data, page,
1831
 
                                               zip_size);
1832
 
                                }
1833
 
                                break;
1834
 
                        case FIL_PAGE_TYPE_ZBLOB:
1835
 
                        case FIL_PAGE_TYPE_ZBLOB2:
1836
 
                                break;
1837
 
                        case FIL_PAGE_INDEX:
1838
 
#ifdef UNIV_ZIP_DEBUG
1839
 
                                ut_a(page_zip_validate(&bpage->zip, page));
1840
 
#endif /* UNIV_ZIP_DEBUG */
1841
 
                                break;
1842
 
                        default:
1843
 
                                ut_print_timestamp(stderr);
1844
 
                                fputs("  InnoDB: ERROR: The compressed page"
1845
 
                                      " to be evicted seems corrupt:", stderr);
1846
 
                                ut_print_buf(stderr, page, zip_size);
1847
 
                                fputs("\nInnoDB: Possibly older version"
1848
 
                                      " of the page:", stderr);
1849
 
                                ut_print_buf(stderr, bpage->zip.data,
1850
 
                                             zip_size);
1851
 
                                putc('\n', stderr);
1852
 
                                ut_error;
1853
 
                        }
1854
 
 
1855
 
                        break;
1856
 
                }
1857
 
                /* fall through */
1858
 
        case BUF_BLOCK_ZIP_PAGE:
1859
 
                ut_a(bpage->oldest_modification == 0);
1860
 
                UNIV_MEM_ASSERT_W(bpage->zip.data,
1861
 
                                  page_zip_get_size(&bpage->zip));
1862
 
                break;
1863
 
        case BUF_BLOCK_ZIP_FREE:
1864
 
        case BUF_BLOCK_ZIP_DIRTY:
1865
 
        case BUF_BLOCK_NOT_USED:
1866
 
        case BUF_BLOCK_READY_FOR_USE:
1867
 
        case BUF_BLOCK_MEMORY:
1868
 
        case BUF_BLOCK_REMOVE_HASH:
1869
 
                ut_error;
1870
 
                break;
1871
 
        }
1872
 
 
1873
 
        fold = buf_page_address_fold(bpage->space, bpage->offset);
1874
 
        hashed_bpage = buf_page_hash_get_low(
1875
 
                buf_pool, bpage->space, bpage->offset, fold);
1876
 
 
1877
 
        if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
1878
 
                fprintf(stderr,
1879
 
                        "InnoDB: Error: page %lu %lu not found"
1880
 
                        " in the hash table\n",
1881
 
                        (ulong) bpage->space,
1882
 
                        (ulong) bpage->offset);
1883
 
                if (hashed_bpage) {
1884
 
                        fprintf(stderr,
1885
 
                                "InnoDB: In hash table we find block"
1886
 
                                " %p of %lu %lu which is not %p\n",
1887
 
                                (const void*) hashed_bpage,
1888
 
                                (ulong) hashed_bpage->space,
1889
 
                                (ulong) hashed_bpage->offset,
1890
 
                                (const void*) bpage);
1891
 
                }
1892
 
 
1893
 
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
1894
 
                mutex_exit(buf_page_get_mutex(bpage));
1895
 
                buf_pool_mutex_exit(buf_pool);
1896
 
                buf_print();
1897
 
                buf_LRU_print();
1898
 
                buf_validate();
1899
 
                buf_LRU_validate();
1900
 
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
1901
 
                ut_error;
1902
 
        }
1903
 
 
1904
 
        ut_ad(!bpage->in_zip_hash);
1905
 
        ut_ad(bpage->in_page_hash);
1906
 
        ut_d(bpage->in_page_hash = FALSE);
1907
 
        HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
1908
 
        switch (buf_page_get_state(bpage)) {
1909
 
        case BUF_BLOCK_ZIP_PAGE:
1910
 
                ut_ad(!bpage->in_free_list);
1911
 
                ut_ad(!bpage->in_flush_list);
1912
 
                ut_ad(!bpage->in_LRU_list);
1913
 
                ut_a(bpage->zip.data);
1914
 
                ut_a(buf_page_get_zip_size(bpage));
1915
 
 
1916
 
                UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
1917
 
 
1918
 
                mutex_exit(&buf_pool->zip_mutex);
1919
 
                buf_pool_mutex_exit_forbid(buf_pool);
1920
 
 
1921
 
                buf_buddy_free(
1922
 
                        buf_pool, bpage->zip.data,
1923
 
                        page_zip_get_size(&bpage->zip));
1924
 
 
1925
 
                buf_buddy_free(buf_pool, bpage, sizeof(*bpage));
1926
 
                buf_pool_mutex_exit_allow(buf_pool);
1927
 
 
1928
 
                UNIV_MEM_UNDESC(bpage);
1929
 
                return(BUF_BLOCK_ZIP_FREE);
1930
 
 
1931
 
        case BUF_BLOCK_FILE_PAGE:
1932
 
                memset(((buf_block_t*) bpage)->frame
1933
 
                       + FIL_PAGE_OFFSET, 0xff, 4);
1934
 
                memset(((buf_block_t*) bpage)->frame
1935
 
                       + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
1936
 
                UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
1937
 
                                 UNIV_PAGE_SIZE);
1938
 
                buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
1939
 
 
1940
 
                if (zip && bpage->zip.data) {
1941
 
                        /* Free the compressed page. */
1942
 
                        void*   data = bpage->zip.data;
1943
 
                        bpage->zip.data = NULL;
1944
 
 
1945
 
                        ut_ad(!bpage->in_free_list);
1946
 
                        ut_ad(!bpage->in_flush_list);
1947
 
                        ut_ad(!bpage->in_LRU_list);
1948
 
                        mutex_exit(&((buf_block_t*) bpage)->mutex);
1949
 
                        buf_pool_mutex_exit_forbid(buf_pool);
1950
 
 
1951
 
                        buf_buddy_free(
1952
 
                                buf_pool, data,
1953
 
                                page_zip_get_size(&bpage->zip));
1954
 
 
1955
 
                        buf_pool_mutex_exit_allow(buf_pool);
1956
 
                        mutex_enter(&((buf_block_t*) bpage)->mutex);
1957
 
                        page_zip_set_size(&bpage->zip, 0);
1958
 
                }
1959
 
 
1960
 
                return(BUF_BLOCK_REMOVE_HASH);
1961
 
 
1962
 
        case BUF_BLOCK_ZIP_FREE:
1963
 
        case BUF_BLOCK_ZIP_DIRTY:
1964
 
        case BUF_BLOCK_NOT_USED:
1965
 
        case BUF_BLOCK_READY_FOR_USE:
1966
 
        case BUF_BLOCK_MEMORY:
1967
 
        case BUF_BLOCK_REMOVE_HASH:
1968
 
                break;
1969
 
        }
1970
 
 
1971
 
        ut_error;
1972
 
        return(BUF_BLOCK_ZIP_FREE);
1973
 
}
1974
 
 
1975
 
/******************************************************************//**
1976
 
Puts a file page whose has no hash index to the free list. */
1977
 
static
1978
 
void
1979
 
buf_LRU_block_free_hashed_page(
1980
 
/*===========================*/
1981
 
        buf_block_t*    block)  /*!< in: block, must contain a file page and
1982
 
                                be in a state where it can be freed */
1983
 
{
1984
 
#ifdef UNIV_DEBUG
1985
 
        buf_pool_t*     buf_pool = buf_pool_from_block(block);
1986
 
        ut_ad(buf_pool_mutex_own(buf_pool));
1987
 
#endif
1988
 
        ut_ad(mutex_own(&block->mutex));
1989
 
 
1990
 
        buf_block_set_state(block, BUF_BLOCK_MEMORY);
1991
 
 
1992
 
        buf_LRU_block_free_non_file_page(block);
1993
 
}
1994
 
 
1995
 
/**********************************************************************//**
1996
 
Updates buf_pool->LRU_old_ratio for one buffer pool instance.
1997
 
@return updated old_pct */
1998
 
static
1999
 
uint
2000
 
buf_LRU_old_ratio_update_instance(
2001
 
/*==============================*/
2002
 
        buf_pool_t*     buf_pool,/*!< in: buffer pool instance */
2003
 
        uint            old_pct,/*!< in: Reserve this percentage of
2004
 
                                the buffer pool for "old" blocks. */
2005
 
        ibool           adjust) /*!< in: TRUE=adjust the LRU list;
2006
 
                                FALSE=just assign buf_pool->LRU_old_ratio
2007
 
                                during the initialization of InnoDB */
2008
 
{
2009
 
        uint    ratio;
2010
 
 
2011
 
        ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100;
2012
 
        if (ratio < BUF_LRU_OLD_RATIO_MIN) {
2013
 
                ratio = BUF_LRU_OLD_RATIO_MIN;
2014
 
        } else if (ratio > BUF_LRU_OLD_RATIO_MAX) {
2015
 
                ratio = BUF_LRU_OLD_RATIO_MAX;
2016
 
        }
2017
 
 
2018
 
        if (adjust) {
2019
 
                buf_pool_mutex_enter(buf_pool);
2020
 
 
2021
 
                if (ratio != buf_pool->LRU_old_ratio) {
2022
 
                        buf_pool->LRU_old_ratio = ratio;
2023
 
 
2024
 
                        if (UT_LIST_GET_LEN(buf_pool->LRU)
2025
 
                           >= BUF_LRU_OLD_MIN_LEN) {
2026
 
 
2027
 
                                buf_LRU_old_adjust_len(buf_pool);
2028
 
                        }
2029
 
                }
2030
 
 
2031
 
                buf_pool_mutex_exit(buf_pool);
2032
 
        } else {
2033
 
                buf_pool->LRU_old_ratio = ratio;
2034
 
        }
2035
 
        /* the reverse of 
2036
 
        ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */
2037
 
        return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5));
2038
 
}
2039
 
 
2040
 
/**********************************************************************//**
2041
 
Updates buf_pool->LRU_old_ratio.
2042
 
@return updated old_pct */
2043
 
UNIV_INTERN
2044
 
ulint
2045
 
buf_LRU_old_ratio_update(
2046
 
/*=====================*/
2047
 
        uint    old_pct,/*!< in: Reserve this percentage of
2048
 
                        the buffer pool for "old" blocks. */
2049
 
        ibool   adjust) /*!< in: TRUE=adjust the LRU list;
2050
 
                        FALSE=just assign buf_pool->LRU_old_ratio
2051
 
                        during the initialization of InnoDB */
2052
 
{
2053
 
        ulint   i;
2054
 
        ulint   new_ratio = 0;
2055
 
 
2056
 
        for (i = 0; i < srv_buf_pool_instances; i++) {
2057
 
                buf_pool_t*     buf_pool;
2058
 
 
2059
 
                buf_pool = buf_pool_from_array(i);
2060
 
 
2061
 
                new_ratio = buf_LRU_old_ratio_update_instance(
2062
 
                        buf_pool, old_pct, adjust);
2063
 
        }
2064
 
 
2065
 
        return(new_ratio);
2066
 
}
2067
 
 
2068
 
/********************************************************************//**
2069
 
Update the historical stats that we are collecting for LRU eviction
2070
 
policy at the end of each interval. */
2071
 
UNIV_INTERN
2072
 
void
2073
 
buf_LRU_stat_update(void)
2074
 
/*=====================*/
2075
 
{
2076
 
        ulint           i;
2077
 
        buf_LRU_stat_t* item;
2078
 
        buf_pool_t*     buf_pool;
2079
 
        ibool           evict_started = FALSE;
2080
 
 
2081
 
        /* If we haven't started eviction yet then don't update stats. */
2082
 
        for (i = 0; i < srv_buf_pool_instances; i++) {
2083
 
 
2084
 
                buf_pool = buf_pool_from_array(i);
2085
 
 
2086
 
                if (buf_pool->freed_page_clock != 0) {
2087
 
                        evict_started = TRUE;
2088
 
                        break;
2089
 
                }
2090
 
        }
2091
 
 
2092
 
        if (!evict_started) {
2093
 
                goto func_exit;
2094
 
        }
2095
 
 
2096
 
        /* Update the index. */
2097
 
        item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind];
2098
 
        buf_LRU_stat_arr_ind++;
2099
 
        buf_LRU_stat_arr_ind %= BUF_LRU_STAT_N_INTERVAL;
2100
 
 
2101
 
        /* Add the current value and subtract the obsolete entry. */
2102
 
        buf_LRU_stat_sum.io += buf_LRU_stat_cur.io - item->io;
2103
 
        buf_LRU_stat_sum.unzip += buf_LRU_stat_cur.unzip - item->unzip;
2104
 
 
2105
 
        /* Put current entry in the array. */
2106
 
        memcpy(item, &buf_LRU_stat_cur, sizeof *item);
2107
 
 
2108
 
func_exit:
2109
 
        /* Clear the current entry. */
2110
 
        memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
2111
 
}
2112
 
 
2113
 
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
2114
 
/**********************************************************************//**
2115
 
Validates the LRU list for one buffer pool instance. */
2116
 
static
2117
 
void
2118
 
buf_LRU_validate_instance(
2119
 
/*======================*/
2120
 
        buf_pool_t*     buf_pool)
2121
 
{
2122
 
        buf_page_t*     bpage;
2123
 
        buf_block_t*    block;
2124
 
        ulint           old_len;
2125
 
        ulint           new_len;
2126
 
 
2127
 
        ut_ad(buf_pool);
2128
 
        buf_pool_mutex_enter(buf_pool);
2129
 
 
2130
 
        if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
2131
 
 
2132
 
                ut_a(buf_pool->LRU_old);
2133
 
                old_len = buf_pool->LRU_old_len;
2134
 
                new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU)
2135
 
                                 * buf_pool->LRU_old_ratio
2136
 
                                 / BUF_LRU_OLD_RATIO_DIV,
2137
 
                                 UT_LIST_GET_LEN(buf_pool->LRU)
2138
 
                                 - (BUF_LRU_OLD_TOLERANCE
2139
 
                                    + BUF_LRU_NON_OLD_MIN_LEN));
2140
 
                ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
2141
 
                ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
2142
 
        }
2143
 
 
2144
 
        UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
2145
 
                         ut_ad(ut_list_node_313->in_LRU_list));
2146
 
 
2147
 
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
2148
 
 
2149
 
        old_len = 0;
2150
 
 
2151
 
        while (bpage != NULL) {
2152
 
 
2153
 
                switch (buf_page_get_state(bpage)) {
2154
 
                case BUF_BLOCK_ZIP_FREE:
2155
 
                case BUF_BLOCK_NOT_USED:
2156
 
                case BUF_BLOCK_READY_FOR_USE:
2157
 
                case BUF_BLOCK_MEMORY:
2158
 
                case BUF_BLOCK_REMOVE_HASH:
2159
 
                        ut_error;
2160
 
                        break;
2161
 
                case BUF_BLOCK_FILE_PAGE:
2162
 
                        ut_ad(((buf_block_t*) bpage)->in_unzip_LRU_list
2163
 
                              == buf_page_belongs_to_unzip_LRU(bpage));
2164
 
                case BUF_BLOCK_ZIP_PAGE:
2165
 
                case BUF_BLOCK_ZIP_DIRTY:
2166
 
                        break;
2167
 
                }
2168
 
 
2169
 
                if (buf_page_is_old(bpage)) {
2170
 
                        const buf_page_t*       prev
2171
 
                                = UT_LIST_GET_PREV(LRU, bpage);
2172
 
                        const buf_page_t*       next
2173
 
                                = UT_LIST_GET_NEXT(LRU, bpage);
2174
 
 
2175
 
                        if (!old_len++) {
2176
 
                                ut_a(buf_pool->LRU_old == bpage);
2177
 
                        } else {
2178
 
                                ut_a(!prev || buf_page_is_old(prev));
2179
 
                        }
2180
 
 
2181
 
                        ut_a(!next || buf_page_is_old(next));
2182
 
                }
2183
 
 
2184
 
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
2185
 
        }
2186
 
 
2187
 
        ut_a(buf_pool->LRU_old_len == old_len);
2188
 
 
2189
 
        UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free,
2190
 
                         ut_ad(ut_list_node_313->in_free_list));
2191
 
 
2192
 
        for (bpage = UT_LIST_GET_FIRST(buf_pool->free);
2193
 
             bpage != NULL;
2194
 
             bpage = UT_LIST_GET_NEXT(list, bpage)) {
2195
 
 
2196
 
                ut_a(buf_page_get_state(bpage) == BUF_BLOCK_NOT_USED);
2197
 
        }
2198
 
 
2199
 
        UT_LIST_VALIDATE(unzip_LRU, buf_block_t, buf_pool->unzip_LRU,
2200
 
                         ut_ad(ut_list_node_313->in_unzip_LRU_list
2201
 
                               && ut_list_node_313->page.in_LRU_list));
2202
 
 
2203
 
        for (block = UT_LIST_GET_FIRST(buf_pool->unzip_LRU);
2204
 
             block;
2205
 
             block = UT_LIST_GET_NEXT(unzip_LRU, block)) {
2206
 
 
2207
 
                ut_ad(block->in_unzip_LRU_list);
2208
 
                ut_ad(block->page.in_LRU_list);
2209
 
                ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
2210
 
        }
2211
 
 
2212
 
        buf_pool_mutex_exit(buf_pool);
2213
 
}
2214
 
 
2215
 
/**********************************************************************//**
2216
 
Validates the LRU list.
2217
 
@return TRUE */
2218
 
UNIV_INTERN
2219
 
ibool
2220
 
buf_LRU_validate(void)
2221
 
/*==================*/
2222
 
{
2223
 
        ulint   i;
2224
 
 
2225
 
        for (i = 0; i < srv_buf_pool_instances; i++) {
2226
 
                buf_pool_t*     buf_pool;
2227
 
 
2228
 
                buf_pool = buf_pool_from_array(i);
2229
 
                buf_LRU_validate_instance(buf_pool);
2230
 
        }
2231
 
 
2232
 
        return(TRUE);
2233
 
}
2234
 
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
2235
 
 
2236
 
#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
2237
 
/**********************************************************************//**
2238
 
Prints the LRU list for one buffer pool instance. */
2239
 
UNIV_INTERN
2240
 
void
2241
 
buf_LRU_print_instance(
2242
 
/*===================*/
2243
 
        buf_pool_t*     buf_pool)
2244
 
{
2245
 
        const buf_page_t*       bpage;
2246
 
 
2247
 
        ut_ad(buf_pool);
2248
 
        buf_pool_mutex_enter(buf_pool);
2249
 
 
2250
 
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
2251
 
 
2252
 
        while (bpage != NULL) {
2253
 
 
2254
 
                mutex_enter(buf_page_get_mutex(bpage));
2255
 
                fprintf(stderr, "BLOCK space %lu page %lu ",
2256
 
                        (ulong) buf_page_get_space(bpage),
2257
 
                        (ulong) buf_page_get_page_no(bpage));
2258
 
 
2259
 
                if (buf_page_is_old(bpage)) {
2260
 
                        fputs("old ", stderr);
2261
 
                }
2262
 
 
2263
 
                if (bpage->buf_fix_count) {
2264
 
                        fprintf(stderr, "buffix count %lu ",
2265
 
                                (ulong) bpage->buf_fix_count);
2266
 
                }
2267
 
 
2268
 
                if (buf_page_get_io_fix(bpage)) {
2269
 
                        fprintf(stderr, "io_fix %lu ",
2270
 
                                (ulong) buf_page_get_io_fix(bpage));
2271
 
                }
2272
 
 
2273
 
                if (bpage->oldest_modification) {
2274
 
                        fputs("modif. ", stderr);
2275
 
                }
2276
 
 
2277
 
                switch (buf_page_get_state(bpage)) {
2278
 
                        const byte*     frame;
2279
 
                case BUF_BLOCK_FILE_PAGE:
2280
 
                        frame = buf_block_get_frame((buf_block_t*) bpage);
2281
 
                        fprintf(stderr, "\ntype %lu"
2282
 
                                " index id %llu\n",
2283
 
                                (ulong) fil_page_get_type(frame),
2284
 
                                (ullint) btr_page_get_index_id(frame));
2285
 
                        break;
2286
 
                case BUF_BLOCK_ZIP_PAGE:
2287
 
                        frame = bpage->zip.data;
2288
 
                        fprintf(stderr, "\ntype %lu size %lu"
2289
 
                                " index id %llu\n",
2290
 
                                (ulong) fil_page_get_type(frame),
2291
 
                                (ulong) buf_page_get_zip_size(bpage),
2292
 
                                (ullint) btr_page_get_index_id(frame));
2293
 
                        break;
2294
 
 
2295
 
                default:
2296
 
                        fprintf(stderr, "\n!state %lu!\n",
2297
 
                                (ulong) buf_page_get_state(bpage));
2298
 
                        break;
2299
 
                }
2300
 
 
2301
 
                mutex_exit(buf_page_get_mutex(bpage));
2302
 
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
2303
 
        }
2304
 
 
2305
 
        buf_pool_mutex_exit(buf_pool);
2306
 
}
2307
 
 
2308
 
/**********************************************************************//**
2309
 
Prints the LRU list. */
2310
 
UNIV_INTERN
2311
 
void
2312
 
buf_LRU_print(void)
2313
 
/*===============*/
2314
 
{
2315
 
        ulint           i;
2316
 
        buf_pool_t*     buf_pool;
2317
 
 
2318
 
        for (i = 0; i < srv_buf_pool_instances; i++) {
2319
 
                buf_pool = buf_pool_from_array(i);
2320
 
                buf_LRU_print_instance(buf_pool);
2321
 
        }
2322
 
}
2323
 
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */