~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-11-16 06:29:53 UTC
  • mto: (584.1.9 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116062953-ivdltjmfe009b5fr
Moved stuff into item/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The database buffer replacement algorithm
 
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
 
6
Created 11/5/1995 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "buf0lru.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "buf0lru.ic"
 
13
#endif
 
14
 
 
15
#include "ut0byte.h"
 
16
#include "ut0lst.h"
 
17
#include "ut0rnd.h"
 
18
#include "sync0sync.h"
 
19
#include "sync0rw.h"
 
20
#include "hash0hash.h"
 
21
#include "os0sync.h"
 
22
#include "fil0fil.h"
 
23
#include "btr0btr.h"
 
24
#include "buf0buddy.h"
 
25
#include "buf0buf.h"
 
26
#include "buf0flu.h"
 
27
#include "buf0rea.h"
 
28
#include "btr0sea.h"
 
29
#include "os0file.h"
 
30
#include "page0zip.h"
 
31
#include "log0recv.h"
 
32
#include "srv0srv.h"
 
33
 
 
34
/* The number of blocks from the LRU_old pointer onward, including the block
 
35
pointed to, must be 3/8 of the whole LRU list length, except that the
 
36
tolerance defined below is allowed. Note that the tolerance must be small
 
37
enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the
 
38
LRU_old pointer is not allowed to point to either end of the LRU list. */
 
39
 
 
40
#define BUF_LRU_OLD_TOLERANCE   20
 
41
 
 
42
/* The whole LRU list length is divided by this number to determine an
 
43
initial segment in buf_LRU_get_recent_limit */
 
44
 
 
45
#define BUF_LRU_INITIAL_RATIO   8
 
46
 
 
47
/* If we switch on the InnoDB monitor because there are too few available
 
48
frames in the buffer pool, we set this to TRUE */
 
49
UNIV_INTERN ibool       buf_lru_switched_on_innodb_mon  = FALSE;
 
50
 
 
51
/**********************************************************************
 
52
These statistics are not 'of' LRU but 'for' LRU.  We keep count of I/O
 
53
and page_zip_decompress() operations.  Based on the statistics,
 
54
buf_LRU_evict_from_unzip_LRU() decides if we want to evict from
 
55
unzip_LRU or the regular LRU.  From unzip_LRU, we will only evict the
 
56
uncompressed frame (meaning we can evict dirty blocks as well).  From
 
57
the regular LRU, we will evict the entire block (i.e.: both the
 
58
uncompressed and compressed data), which must be clean. */
 
59
 
 
60
/* Number of intervals for which we keep the history of these stats.
 
61
Each interval is 1 second, defined by the rate at which
 
62
srv_error_monitor_thread() calls buf_LRU_stat_update(). */
 
63
#define BUF_LRU_STAT_N_INTERVAL 50
 
64
 
 
65
/* Co-efficient with which we multiply I/O operations to equate them
 
66
with page_zip_decompress() operations. */
 
67
#define BUF_LRU_IO_TO_UNZIP_FACTOR 50
 
68
 
 
69
/* Sampled values buf_LRU_stat_cur.
 
70
Protected by buf_pool_mutex.  Updated by buf_LRU_stat_update(). */
 
71
static buf_LRU_stat_t           buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
 
72
/* Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */
 
73
static ulint                    buf_LRU_stat_arr_ind;
 
74
 
 
75
/* Current operation counters.  Not protected by any mutex.  Cleared
 
76
by buf_LRU_stat_update(). */
 
77
UNIV_INTERN buf_LRU_stat_t      buf_LRU_stat_cur;
 
78
 
 
79
/* Running sum of past values of buf_LRU_stat_cur.
 
80
Updated by buf_LRU_stat_update().  Protected by buf_pool_mutex. */
 
81
UNIV_INTERN buf_LRU_stat_t      buf_LRU_stat_sum;
 
82
 
 
83
/**********************************************************************
 
84
Takes a block out of the LRU list and page hash table.
 
85
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
 
86
the object will be freed and buf_pool_zip_mutex will be released.
 
87
 
 
88
If a compressed page or a compressed-only block descriptor is freed,
 
89
other compressed pages or compressed-only block descriptors may be
 
90
relocated. */
 
91
static
 
92
enum buf_page_state
 
93
buf_LRU_block_remove_hashed_page(
 
94
/*=============================*/
 
95
                                /* out: the new state of the block
 
96
                                (BUF_BLOCK_ZIP_FREE if the state was
 
97
                                BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH
 
98
                                otherwise) */
 
99
        buf_page_t*     bpage,  /* in: block, must contain a file page and
 
100
                                be in a state where it can be freed; there
 
101
                                may or may not be a hash index to the page */
 
102
        ibool           zip);   /* in: TRUE if should remove also the
 
103
                                compressed page of an uncompressed page */
 
104
/**********************************************************************
 
105
Puts a file page whose has no hash index to the free list. */
 
106
static
 
107
void
 
108
buf_LRU_block_free_hashed_page(
 
109
/*===========================*/
 
110
        buf_block_t*    block); /* in: block, must contain a file page and
 
111
                                be in a state where it can be freed */
 
112
 
 
113
/**********************************************************************
 
114
Determines if the unzip_LRU list should be used for evicting a victim
 
115
instead of the general LRU list. */
 
116
UNIV_INLINE
 
117
ibool
 
118
buf_LRU_evict_from_unzip_LRU(void)
 
119
/*==============================*/
 
120
                                /* out: TRUE if should use unzip_LRU */
 
121
{
 
122
        ulint   io_avg;
 
123
        ulint   unzip_avg;
 
124
 
 
125
        ut_ad(buf_pool_mutex_own());
 
126
 
 
127
        /* If the unzip_LRU list is empty, we can only use the LRU. */
 
128
        if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) {
 
129
                return(FALSE);
 
130
        }
 
131
 
 
132
        /* If unzip_LRU is at most 10% of the size of the LRU list,
 
133
        then use the LRU.  This slack allows us to keep hot
 
134
        decompressed pages in the buffer pool. */
 
135
        if (UT_LIST_GET_LEN(buf_pool->unzip_LRU)
 
136
            <= UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
 
137
                return(FALSE);
 
138
        }
 
139
 
 
140
        /* If eviction hasn't started yet, we assume by default
 
141
        that a workload is disk bound. */
 
142
        if (buf_pool->freed_page_clock == 0) {
 
143
                return(TRUE);
 
144
        }
 
145
 
 
146
        /* Calculate the average over past intervals, and add the values
 
147
        of the current interval. */
 
148
        io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
 
149
                + buf_LRU_stat_cur.io;
 
150
        unzip_avg = buf_LRU_stat_sum.unzip / BUF_LRU_STAT_N_INTERVAL
 
151
                + buf_LRU_stat_cur.unzip;
 
152
 
 
153
        /* Decide based on our formula.  If the load is I/O bound
 
154
        (unzip_avg is smaller than the weighted io_avg), evict an
 
155
        uncompressed frame from unzip_LRU.  Otherwise we assume that
 
156
        the load is CPU bound and evict from the regular LRU. */
 
157
        return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
 
158
}
 
159
 
 
160
/**********************************************************************
 
161
Invalidates all pages belonging to a given tablespace when we are deleting
 
162
the data file(s) of that tablespace. */
 
163
UNIV_INTERN
 
164
void
 
165
buf_LRU_invalidate_tablespace(
 
166
/*==========================*/
 
167
        ulint   id)     /* in: space id */
 
168
{
 
169
        buf_page_t*     bpage;
 
170
        ulint           page_no;
 
171
        ibool           all_freed;
 
172
 
 
173
scan_again:
 
174
        buf_pool_mutex_enter();
 
175
 
 
176
        all_freed = TRUE;
 
177
 
 
178
        bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
179
 
 
180
        while (bpage != NULL) {
 
181
                mutex_t*        block_mutex = buf_page_get_mutex(bpage);
 
182
                buf_page_t*     prev_bpage;
 
183
 
 
184
                ut_a(buf_page_in_file(bpage));
 
185
 
 
186
                mutex_enter(block_mutex);
 
187
                prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
 
188
 
 
189
                if (buf_page_get_space(bpage) == id) {
 
190
                        if (bpage->buf_fix_count > 0
 
191
                            || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
 
192
 
 
193
                                /* We cannot remove this page during
 
194
                                this scan yet; maybe the system is
 
195
                                currently reading it in, or flushing
 
196
                                the modifications to the file */
 
197
 
 
198
                                all_freed = FALSE;
 
199
 
 
200
                                goto next_page;
 
201
                        }
 
202
 
 
203
#ifdef UNIV_DEBUG
 
204
                        if (buf_debug_prints) {
 
205
                                fprintf(stderr,
 
206
                                        "Dropping space %lu page %lu\n",
 
207
                                        (ulong) buf_page_get_space(bpage),
 
208
                                        (ulong) buf_page_get_page_no(bpage));
 
209
                        }
 
210
#endif
 
211
                        if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE
 
212
                            && ((buf_block_t*) bpage)->is_hashed) {
 
213
                                page_no = buf_page_get_page_no(bpage);
 
214
 
 
215
                                buf_pool_mutex_exit();
 
216
                                mutex_exit(block_mutex);
 
217
 
 
218
                                /* Note that the following call will acquire
 
219
                                an S-latch on the page */
 
220
 
 
221
                                btr_search_drop_page_hash_when_freed(
 
222
                                        id,
 
223
                                        buf_page_get_zip_size(bpage),
 
224
                                        page_no);
 
225
                                goto scan_again;
 
226
                        }
 
227
 
 
228
                        if (bpage->oldest_modification != 0) {
 
229
 
 
230
                                buf_flush_remove(bpage);
 
231
                        }
 
232
 
 
233
                        /* Remove from the LRU list */
 
234
                        if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
 
235
                            != BUF_BLOCK_ZIP_FREE) {
 
236
                                buf_LRU_block_free_hashed_page((buf_block_t*)
 
237
                                                               bpage);
 
238
                        } else {
 
239
                                /* The compressed block descriptor
 
240
                                (bpage) has been deallocated and
 
241
                                block_mutex released.  Also,
 
242
                                buf_buddy_free() may have relocated
 
243
                                prev_bpage.  Rescan the LRU list. */
 
244
 
 
245
                                bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
246
                                continue;
 
247
                        }
 
248
                }
 
249
next_page:
 
250
                mutex_exit(block_mutex);
 
251
                bpage = prev_bpage;
 
252
        }
 
253
 
 
254
        buf_pool_mutex_exit();
 
255
 
 
256
        if (!all_freed) {
 
257
                os_thread_sleep(20000);
 
258
 
 
259
                goto scan_again;
 
260
        }
 
261
}
 
262
 
 
263
/**********************************************************************
 
264
Gets the minimum LRU_position field for the blocks in an initial segment
 
265
(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
 
266
guaranteed to be precise, because the ulint_clock may wrap around. */
 
267
UNIV_INTERN
 
268
ulint
 
269
buf_LRU_get_recent_limit(void)
 
270
/*==========================*/
 
271
                        /* out: the limit; zero if could not determine it */
 
272
{
 
273
        const buf_page_t*       bpage;
 
274
        ulint                   len;
 
275
        ulint                   limit;
 
276
 
 
277
        buf_pool_mutex_enter();
 
278
 
 
279
        len = UT_LIST_GET_LEN(buf_pool->LRU);
 
280
 
 
281
        if (len < BUF_LRU_OLD_MIN_LEN) {
 
282
                /* The LRU list is too short to do read-ahead */
 
283
 
 
284
                buf_pool_mutex_exit();
 
285
 
 
286
                return(0);
 
287
        }
 
288
 
 
289
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
 
290
 
 
291
        limit = buf_page_get_LRU_position(bpage) - len / BUF_LRU_INITIAL_RATIO;
 
292
 
 
293
        buf_pool_mutex_exit();
 
294
 
 
295
        return(limit);
 
296
}
 
297
 
 
298
/************************************************************************
 
299
Insert a compressed block into buf_pool->zip_clean in the LRU order. */
 
300
UNIV_INTERN
 
301
void
 
302
buf_LRU_insert_zip_clean(
 
303
/*=====================*/
 
304
        buf_page_t*     bpage)  /* in: pointer to the block in question */
 
305
{
 
306
        buf_page_t*     b;
 
307
 
 
308
        ut_ad(buf_pool_mutex_own());
 
309
        ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
 
310
 
 
311
        /* Find the first successor of bpage in the LRU list
 
312
        that is in the zip_clean list. */
 
313
        b = bpage;
 
314
        do {
 
315
                b = UT_LIST_GET_NEXT(LRU, b);
 
316
        } while (b && buf_page_get_state(b) != BUF_BLOCK_ZIP_PAGE);
 
317
 
 
318
        /* Insert bpage before b, i.e., after the predecessor of b. */
 
319
        if (b) {
 
320
                b = UT_LIST_GET_PREV(list, b);
 
321
        }
 
322
 
 
323
        if (b) {
 
324
                UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, bpage);
 
325
        } else {
 
326
                UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, bpage);
 
327
        }
 
328
}
 
329
 
 
330
/**********************************************************************
 
331
Try to free an uncompressed page of a compressed block from the unzip
 
332
LRU list.  The compressed page is preserved, and it need not be clean. */
 
333
UNIV_INLINE
 
334
ibool
 
335
buf_LRU_free_from_unzip_LRU_list(
 
336
/*=============================*/
 
337
                                /* out: TRUE if freed */
 
338
        ulint   n_iterations)   /* in: how many times this has been called
 
339
                                repeatedly without result: a high value means
 
340
                                that we should search farther; we will search
 
341
                                n_iterations / 5 of the unzip_LRU list,
 
342
                                or nothing if n_iterations >= 5 */
 
343
{
 
344
        buf_block_t*    block;
 
345
        ulint           distance;
 
346
 
 
347
        ut_ad(buf_pool_mutex_own());
 
348
 
 
349
        /* Theoratically it should be much easier to find a victim
 
350
        from unzip_LRU as we can choose even a dirty block (as we'll
 
351
        be evicting only the uncompressed frame).  In a very unlikely
 
352
        eventuality that we are unable to find a victim from
 
353
        unzip_LRU, we fall back to the regular LRU list.  We do this
 
354
        if we have done five iterations so far. */
 
355
 
 
356
        if (UNIV_UNLIKELY(n_iterations >= 5)
 
357
            || !buf_LRU_evict_from_unzip_LRU()) {
 
358
 
 
359
                return(FALSE);
 
360
        }
 
361
 
 
362
        distance = 100 + (n_iterations
 
363
                          * UT_LIST_GET_LEN(buf_pool->unzip_LRU)) / 5;
 
364
 
 
365
        for (block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
 
366
             UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0);
 
367
             block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) {
 
368
 
 
369
                enum buf_lru_free_block_status  freed;
 
370
 
 
371
                ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
 
372
                ut_ad(block->in_unzip_LRU_list);
 
373
                ut_ad(block->page.in_LRU_list);
 
374
 
 
375
                mutex_enter(&block->mutex);
 
376
                freed = buf_LRU_free_block(&block->page, FALSE, NULL);
 
377
                mutex_exit(&block->mutex);
 
378
 
 
379
                switch (freed) {
 
380
                case BUF_LRU_FREED:
 
381
                        return(TRUE);
 
382
 
 
383
                case BUF_LRU_CANNOT_RELOCATE:
 
384
                        /* If we failed to relocate, try
 
385
                        regular LRU eviction. */
 
386
                        return(FALSE);
 
387
 
 
388
                case BUF_LRU_NOT_FREED:
 
389
                        /* The block was buffer-fixed or I/O-fixed.
 
390
                        Keep looking. */
 
391
                        continue;
 
392
                }
 
393
 
 
394
                /* inappropriate return value from
 
395
                buf_LRU_free_block() */
 
396
                ut_error;
 
397
        }
 
398
 
 
399
        return(FALSE);
 
400
}
 
401
 
 
402
/**********************************************************************
 
403
Try to free a clean page from the common LRU list. */
 
404
UNIV_INLINE
 
405
ibool
 
406
buf_LRU_free_from_common_LRU_list(
 
407
/*==============================*/
 
408
                                /* out: TRUE if freed */
 
409
        ulint   n_iterations)   /* in: how many times this has been called
 
410
                                repeatedly without result: a high value means
 
411
                                that we should search farther; if
 
412
                                n_iterations < 10, then we search
 
413
                                n_iterations / 10 * buf_pool->curr_size
 
414
                                pages from the end of the LRU list */
 
415
{
 
416
        buf_page_t*     bpage;
 
417
        ulint           distance;
 
418
 
 
419
        ut_ad(buf_pool_mutex_own());
 
420
 
 
421
        distance = 100 + (n_iterations * buf_pool->curr_size) / 10;
 
422
 
 
423
        for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
424
             UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0);
 
425
             bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) {
 
426
 
 
427
                enum buf_lru_free_block_status  freed;
 
428
                mutex_t*                        block_mutex
 
429
                        = buf_page_get_mutex(bpage);
 
430
 
 
431
                ut_ad(buf_page_in_file(bpage));
 
432
                ut_ad(bpage->in_LRU_list);
 
433
 
 
434
                mutex_enter(block_mutex);
 
435
                freed = buf_LRU_free_block(bpage, TRUE, NULL);
 
436
                mutex_exit(block_mutex);
 
437
 
 
438
                switch (freed) {
 
439
                case BUF_LRU_FREED:
 
440
                        return(TRUE);
 
441
 
 
442
                case BUF_LRU_NOT_FREED:
 
443
                        /* The block was dirty, buffer-fixed, or I/O-fixed.
 
444
                        Keep looking. */
 
445
                        continue;
 
446
 
 
447
                case BUF_LRU_CANNOT_RELOCATE:
 
448
                        /* This should never occur, because we
 
449
                        want to discard the compressed page too. */
 
450
                        break;
 
451
                }
 
452
 
 
453
                /* inappropriate return value from
 
454
                buf_LRU_free_block() */
 
455
                ut_error;
 
456
        }
 
457
 
 
458
        return(FALSE);
 
459
}
 
460
 
 
461
/**********************************************************************
 
462
Try to free a replaceable block. */
 
463
UNIV_INTERN
 
464
ibool
 
465
buf_LRU_search_and_free_block(
 
466
/*==========================*/
 
467
                                /* out: TRUE if found and freed */
 
468
        ulint   n_iterations)   /* in: how many times this has been called
 
469
                                repeatedly without result: a high value means
 
470
                                that we should search farther; if
 
471
                                n_iterations < 10, then we search
 
472
                                n_iterations / 10 * buf_pool->curr_size
 
473
                                pages from the end of the LRU list; if
 
474
                                n_iterations < 5, then we will also search
 
475
                                n_iterations / 5 of the unzip_LRU list. */
 
476
{
 
477
        ibool   freed = FALSE;
 
478
 
 
479
        buf_pool_mutex_enter();
 
480
 
 
481
        freed = buf_LRU_free_from_unzip_LRU_list(n_iterations);
 
482
 
 
483
        if (!freed) {
 
484
                freed = buf_LRU_free_from_common_LRU_list(n_iterations);
 
485
        }
 
486
 
 
487
        if (!freed) {
 
488
                buf_pool->LRU_flush_ended = 0;
 
489
        } else if (buf_pool->LRU_flush_ended > 0) {
 
490
                buf_pool->LRU_flush_ended--;
 
491
        }
 
492
 
 
493
        buf_pool_mutex_exit();
 
494
 
 
495
        return(freed);
 
496
}
 
497
 
 
498
/**********************************************************************
 
499
Tries to remove LRU flushed blocks from the end of the LRU list and put them
 
500
to the free list. This is beneficial for the efficiency of the insert buffer
 
501
operation, as flushed pages from non-unique non-clustered indexes are here
 
502
taken out of the buffer pool, and their inserts redirected to the insert
 
503
buffer. Otherwise, the flushed blocks could get modified again before read
 
504
operations need new buffer blocks, and the i/o work done in flushing would be
 
505
wasted. */
 
506
UNIV_INTERN
 
507
void
 
508
buf_LRU_try_free_flushed_blocks(void)
 
509
/*=================================*/
 
510
{
 
511
        buf_pool_mutex_enter();
 
512
 
 
513
        while (buf_pool->LRU_flush_ended > 0) {
 
514
 
 
515
                buf_pool_mutex_exit();
 
516
 
 
517
                buf_LRU_search_and_free_block(1);
 
518
 
 
519
                buf_pool_mutex_enter();
 
520
        }
 
521
 
 
522
        buf_pool_mutex_exit();
 
523
}
 
524
 
 
525
/**********************************************************************
 
526
Returns TRUE if less than 25 % of the buffer pool is available. This can be
 
527
used in heuristics to prevent huge transactions eating up the whole buffer
 
528
pool for their locks. */
 
529
UNIV_INTERN
 
530
ibool
 
531
buf_LRU_buf_pool_running_out(void)
 
532
/*==============================*/
 
533
                                /* out: TRUE if less than 25 % of buffer pool
 
534
                                left */
 
535
{
 
536
        ibool   ret     = FALSE;
 
537
 
 
538
        buf_pool_mutex_enter();
 
539
 
 
540
        if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
 
541
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 4) {
 
542
 
 
543
                ret = TRUE;
 
544
        }
 
545
 
 
546
        buf_pool_mutex_exit();
 
547
 
 
548
        return(ret);
 
549
}
 
550
 
 
551
/**********************************************************************
 
552
Returns a free block from the buf_pool.  The block is taken off the
 
553
free list.  If it is empty, returns NULL. */
 
554
UNIV_INTERN
 
555
buf_block_t*
 
556
buf_LRU_get_free_only(void)
 
557
/*=======================*/
 
558
                                /* out: a free control block, or NULL
 
559
                                if the buf_block->free list is empty */
 
560
{
 
561
        buf_block_t*    block;
 
562
 
 
563
        ut_ad(buf_pool_mutex_own());
 
564
 
 
565
        block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
 
566
 
 
567
        if (block) {
 
568
                ut_ad(block->page.in_free_list);
 
569
                ut_d(block->page.in_free_list = FALSE);
 
570
                ut_ad(!block->page.in_flush_list);
 
571
                ut_ad(!block->page.in_LRU_list);
 
572
                ut_a(!buf_page_in_file(&block->page));
 
573
                UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
 
574
 
 
575
                mutex_enter(&block->mutex);
 
576
 
 
577
                buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
 
578
                UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
 
579
 
 
580
                mutex_exit(&block->mutex);
 
581
        }
 
582
 
 
583
        return(block);
 
584
}
 
585
 
 
586
/**********************************************************************
 
587
Returns a free block from the buf_pool. The block is taken off the
 
588
free list. If it is empty, blocks are moved from the end of the
 
589
LRU list to the free list. */
 
590
UNIV_INTERN
 
591
buf_block_t*
 
592
buf_LRU_get_free_block(
 
593
/*===================*/
 
594
                                /* out: the free control block,
 
595
                                in state BUF_BLOCK_READY_FOR_USE */
 
596
        ulint   zip_size)       /* in: compressed page size in bytes,
 
597
                                or 0 if uncompressed tablespace */
 
598
{
 
599
        buf_block_t*    block           = NULL;
 
600
        ibool           freed;
 
601
        ulint           n_iterations    = 1;
 
602
        ibool           mon_value_was   = FALSE;
 
603
        ibool           started_monitor = FALSE;
 
604
loop:
 
605
        buf_pool_mutex_enter();
 
606
 
 
607
        if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
 
608
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
 
609
                ut_print_timestamp(stderr);
 
610
 
 
611
                fprintf(stderr,
 
612
                        "  InnoDB: ERROR: over 95 percent of the buffer pool"
 
613
                        " is occupied by\n"
 
614
                        "InnoDB: lock heaps or the adaptive hash index!"
 
615
                        " Check that your\n"
 
616
                        "InnoDB: transactions do not set too many row locks.\n"
 
617
                        "InnoDB: Your buffer pool size is %lu MB."
 
618
                        " Maybe you should make\n"
 
619
                        "InnoDB: the buffer pool bigger?\n"
 
620
                        "InnoDB: We intentionally generate a seg fault"
 
621
                        " to print a stack trace\n"
 
622
                        "InnoDB: on Linux!\n",
 
623
                        (ulong) (buf_pool->curr_size
 
624
                                 / (1024 * 1024 / UNIV_PAGE_SIZE)));
 
625
 
 
626
                ut_error;
 
627
 
 
628
        } else if (!recv_recovery_on
 
629
                   && (UT_LIST_GET_LEN(buf_pool->free)
 
630
                       + UT_LIST_GET_LEN(buf_pool->LRU))
 
631
                   < buf_pool->curr_size / 3) {
 
632
 
 
633
                if (!buf_lru_switched_on_innodb_mon) {
 
634
 
 
635
                        /* Over 67 % of the buffer pool is occupied by lock
 
636
                        heaps or the adaptive hash index. This may be a memory
 
637
                        leak! */
 
638
 
 
639
                        ut_print_timestamp(stderr);
 
640
                        fprintf(stderr,
 
641
                                "  InnoDB: WARNING: over 67 percent of"
 
642
                                " the buffer pool is occupied by\n"
 
643
                                "InnoDB: lock heaps or the adaptive"
 
644
                                " hash index! Check that your\n"
 
645
                                "InnoDB: transactions do not set too many"
 
646
                                " row locks.\n"
 
647
                                "InnoDB: Your buffer pool size is %lu MB."
 
648
                                " Maybe you should make\n"
 
649
                                "InnoDB: the buffer pool bigger?\n"
 
650
                                "InnoDB: Starting the InnoDB Monitor to print"
 
651
                                " diagnostics, including\n"
 
652
                                "InnoDB: lock heap and hash index sizes.\n",
 
653
                                (ulong) (buf_pool->curr_size
 
654
                                         / (1024 * 1024 / UNIV_PAGE_SIZE)));
 
655
 
 
656
                        buf_lru_switched_on_innodb_mon = TRUE;
 
657
                        srv_print_innodb_monitor = TRUE;
 
658
                        os_event_set(srv_lock_timeout_thread_event);
 
659
                }
 
660
        } else if (buf_lru_switched_on_innodb_mon) {
 
661
 
 
662
                /* Switch off the InnoDB Monitor; this is a simple way
 
663
                to stop the monitor if the situation becomes less urgent,
 
664
                but may also surprise users if the user also switched on the
 
665
                monitor! */
 
666
 
 
667
                buf_lru_switched_on_innodb_mon = FALSE;
 
668
                srv_print_innodb_monitor = FALSE;
 
669
        }
 
670
 
 
671
        /* If there is a block in the free list, take it */
 
672
        block = buf_LRU_get_free_only();
 
673
        if (block) {
 
674
 
 
675
#ifdef UNIV_DEBUG
 
676
                block->page.zip.m_start =
 
677
#endif /* UNIV_DEBUG */
 
678
                        block->page.zip.m_end =
 
679
                        block->page.zip.m_nonempty =
 
680
                        block->page.zip.n_blobs = 0;
 
681
 
 
682
                if (UNIV_UNLIKELY(zip_size)) {
 
683
                        ibool   lru;
 
684
                        page_zip_set_size(&block->page.zip, zip_size);
 
685
                        block->page.zip.data = buf_buddy_alloc(zip_size, &lru);
 
686
                        UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
 
687
                } else {
 
688
                        page_zip_set_size(&block->page.zip, 0);
 
689
                        block->page.zip.data = NULL;
 
690
                }
 
691
 
 
692
                buf_pool_mutex_exit();
 
693
 
 
694
                if (started_monitor) {
 
695
                        srv_print_innodb_monitor = mon_value_was;
 
696
                }
 
697
 
 
698
                return(block);
 
699
        }
 
700
 
 
701
        /* If no block was in the free list, search from the end of the LRU
 
702
        list and try to free a block there */
 
703
 
 
704
        buf_pool_mutex_exit();
 
705
 
 
706
        freed = buf_LRU_search_and_free_block(n_iterations);
 
707
 
 
708
        if (freed > 0) {
 
709
                goto loop;
 
710
        }
 
711
 
 
712
        if (n_iterations > 30) {
 
713
                ut_print_timestamp(stderr);
 
714
                fprintf(stderr,
 
715
                        "InnoDB: Warning: difficult to find free blocks from\n"
 
716
                        "InnoDB: the buffer pool (%lu search iterations)!"
 
717
                        " Consider\n"
 
718
                        "InnoDB: increasing the buffer pool size.\n"
 
719
                        "InnoDB: It is also possible that"
 
720
                        " in your Unix version\n"
 
721
                        "InnoDB: fsync is very slow, or"
 
722
                        " completely frozen inside\n"
 
723
                        "InnoDB: the OS kernel. Then upgrading to"
 
724
                        " a newer version\n"
 
725
                        "InnoDB: of your operating system may help."
 
726
                        " Look at the\n"
 
727
                        "InnoDB: number of fsyncs in diagnostic info below.\n"
 
728
                        "InnoDB: Pending flushes (fsync) log: %lu;"
 
729
                        " buffer pool: %lu\n"
 
730
                        "InnoDB: %lu OS file reads, %lu OS file writes,"
 
731
                        " %lu OS fsyncs\n"
 
732
                        "InnoDB: Starting InnoDB Monitor to print further\n"
 
733
                        "InnoDB: diagnostics to the standard output.\n",
 
734
                        (ulong) n_iterations,
 
735
                        (ulong) fil_n_pending_log_flushes,
 
736
                        (ulong) fil_n_pending_tablespace_flushes,
 
737
                        (ulong) os_n_file_reads, (ulong) os_n_file_writes,
 
738
                        (ulong) os_n_fsyncs);
 
739
 
 
740
                mon_value_was = srv_print_innodb_monitor;
 
741
                started_monitor = TRUE;
 
742
                srv_print_innodb_monitor = TRUE;
 
743
                os_event_set(srv_lock_timeout_thread_event);
 
744
        }
 
745
 
 
746
        /* No free block was found: try to flush the LRU list */
 
747
 
 
748
        buf_flush_free_margin();
 
749
        ++srv_buf_pool_wait_free;
 
750
 
 
751
        os_aio_simulated_wake_handler_threads();
 
752
 
 
753
        buf_pool_mutex_enter();
 
754
 
 
755
        if (buf_pool->LRU_flush_ended > 0) {
 
756
                /* We have written pages in an LRU flush. To make the insert
 
757
                buffer more efficient, we try to move these pages to the free
 
758
                list. */
 
759
 
 
760
                buf_pool_mutex_exit();
 
761
 
 
762
                buf_LRU_try_free_flushed_blocks();
 
763
        } else {
 
764
                buf_pool_mutex_exit();
 
765
        }
 
766
 
 
767
        if (n_iterations > 10) {
 
768
 
 
769
                os_thread_sleep(500000);
 
770
        }
 
771
 
 
772
        n_iterations++;
 
773
 
 
774
        goto loop;
 
775
}
 
776
 
 
777
/***********************************************************************
 
778
Moves the LRU_old pointer so that the length of the old blocks list
 
779
is inside the allowed limits. */
 
780
UNIV_INLINE
 
781
void
 
782
buf_LRU_old_adjust_len(void)
 
783
/*========================*/
 
784
{
 
785
        ulint   old_len;
 
786
        ulint   new_len;
 
787
 
 
788
        ut_a(buf_pool->LRU_old);
 
789
        ut_ad(buf_pool_mutex_own());
 
790
#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5
 
791
# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5"
 
792
#endif
 
793
 
 
794
        for (;;) {
 
795
                old_len = buf_pool->LRU_old_len;
 
796
                new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
 
797
 
 
798
                ut_ad(buf_pool->LRU_old->in_LRU_list);
 
799
 
 
800
                /* Update the LRU_old pointer if necessary */
 
801
 
 
802
                if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
 
803
 
 
804
                        buf_pool->LRU_old = UT_LIST_GET_PREV(
 
805
                                LRU, buf_pool->LRU_old);
 
806
                        buf_page_set_old(buf_pool->LRU_old, TRUE);
 
807
                        buf_pool->LRU_old_len++;
 
808
 
 
809
                } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
 
810
 
 
811
                        buf_page_set_old(buf_pool->LRU_old, FALSE);
 
812
                        buf_pool->LRU_old = UT_LIST_GET_NEXT(
 
813
                                LRU, buf_pool->LRU_old);
 
814
                        buf_pool->LRU_old_len--;
 
815
                } else {
 
816
                        ut_a(buf_pool->LRU_old); /* Check that we did not
 
817
                                                 fall out of the LRU list */
 
818
                        return;
 
819
                }
 
820
        }
 
821
}
 
822
 
 
823
/***********************************************************************
 
824
Initializes the old blocks pointer in the LRU list. This function should be
 
825
called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
 
826
static
 
827
void
 
828
buf_LRU_old_init(void)
 
829
/*==================*/
 
830
{
 
831
        buf_page_t*     bpage;
 
832
 
 
833
        ut_ad(buf_pool_mutex_own());
 
834
        ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
 
835
 
 
836
        /* We first initialize all blocks in the LRU list as old and then use
 
837
        the adjust function to move the LRU_old pointer to the right
 
838
        position */
 
839
 
 
840
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
 
841
 
 
842
        while (bpage != NULL) {
 
843
                ut_ad(bpage->in_LRU_list);
 
844
                buf_page_set_old(bpage, TRUE);
 
845
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
 
846
        }
 
847
 
 
848
        buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
 
849
        buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
 
850
 
 
851
        buf_LRU_old_adjust_len();
 
852
}
 
853
 
 
854
/**********************************************************************
 
855
Remove a block from the unzip_LRU list if it belonged to the list. */
 
856
static
 
857
void
 
858
buf_unzip_LRU_remove_block_if_needed(
 
859
/*=================================*/
 
860
        buf_page_t*     bpage)  /* in/out: control block */
 
861
{
 
862
        ut_ad(buf_pool);
 
863
        ut_ad(bpage);
 
864
        ut_ad(buf_page_in_file(bpage));
 
865
        ut_ad(buf_pool_mutex_own());
 
866
 
 
867
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
 
868
                buf_block_t*    block = (buf_block_t*) bpage;
 
869
 
 
870
                ut_ad(block->in_unzip_LRU_list);
 
871
                ut_d(block->in_unzip_LRU_list = FALSE);
 
872
 
 
873
                UT_LIST_REMOVE(unzip_LRU, buf_pool->unzip_LRU, block);
 
874
        }
 
875
}
 
876
 
 
877
/**********************************************************************
 
878
Removes a block from the LRU list. */
 
879
UNIV_INLINE
 
880
void
 
881
buf_LRU_remove_block(
 
882
/*=================*/
 
883
        buf_page_t*     bpage)  /* in: control block */
 
884
{
 
885
        ut_ad(buf_pool);
 
886
        ut_ad(bpage);
 
887
        ut_ad(buf_pool_mutex_own());
 
888
 
 
889
        ut_a(buf_page_in_file(bpage));
 
890
 
 
891
        ut_ad(bpage->in_LRU_list);
 
892
 
 
893
        /* If the LRU_old pointer is defined and points to just this block,
 
894
        move it backward one step */
 
895
 
 
896
        if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
 
897
 
 
898
                /* Below: the previous block is guaranteed to exist, because
 
899
                the LRU_old pointer is only allowed to differ by the
 
900
                tolerance value from strict 3/8 of the LRU list length. */
 
901
 
 
902
                buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage);
 
903
                ut_a(buf_pool->LRU_old);
 
904
                buf_page_set_old(buf_pool->LRU_old, TRUE);
 
905
 
 
906
                buf_pool->LRU_old_len++;
 
907
        }
 
908
 
 
909
        /* Remove the block from the LRU list */
 
910
        UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
 
911
        ut_d(bpage->in_LRU_list = FALSE);
 
912
 
 
913
        buf_unzip_LRU_remove_block_if_needed(bpage);
 
914
 
 
915
        /* If the LRU list is so short that LRU_old not defined, return */
 
916
        if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
 
917
 
 
918
                buf_pool->LRU_old = NULL;
 
919
 
 
920
                return;
 
921
        }
 
922
 
 
923
        ut_ad(buf_pool->LRU_old);
 
924
 
 
925
        /* Update the LRU_old_len field if necessary */
 
926
        if (buf_page_is_old(bpage)) {
 
927
 
 
928
                buf_pool->LRU_old_len--;
 
929
        }
 
930
 
 
931
        /* Adjust the length of the old block list if necessary */
 
932
        buf_LRU_old_adjust_len();
 
933
}
 
934
 
 
935
/**********************************************************************
 
936
Adds a block to the LRU list of decompressed zip pages. */
 
937
UNIV_INTERN
 
938
void
 
939
buf_unzip_LRU_add_block(
 
940
/*====================*/
 
941
        buf_block_t*    block,  /* in: control block */
 
942
        ibool           old)    /* in: TRUE if should be put to the end
 
943
                                of the list, else put to the start */
 
944
{
 
945
        ut_ad(buf_pool);
 
946
        ut_ad(block);
 
947
        ut_ad(buf_pool_mutex_own());
 
948
 
 
949
        ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
 
950
 
 
951
        ut_ad(!block->in_unzip_LRU_list);
 
952
        ut_d(block->in_unzip_LRU_list = TRUE);
 
953
 
 
954
        if (old) {
 
955
                UT_LIST_ADD_LAST(unzip_LRU, buf_pool->unzip_LRU, block);
 
956
        } else {
 
957
                UT_LIST_ADD_FIRST(unzip_LRU, buf_pool->unzip_LRU, block);
 
958
        }
 
959
}
 
960
 
 
961
/**********************************************************************
 
962
Adds a block to the LRU list end. */
 
963
UNIV_INLINE
 
964
void
 
965
buf_LRU_add_block_to_end_low(
 
966
/*=========================*/
 
967
        buf_page_t*     bpage)  /* in: control block */
 
968
{
 
969
        buf_page_t*     last_bpage;
 
970
 
 
971
        ut_ad(buf_pool);
 
972
        ut_ad(bpage);
 
973
        ut_ad(buf_pool_mutex_own());
 
974
 
 
975
        ut_a(buf_page_in_file(bpage));
 
976
 
 
977
        buf_page_set_old(bpage, TRUE);
 
978
 
 
979
        last_bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
980
 
 
981
        if (last_bpage) {
 
982
                bpage->LRU_position = last_bpage->LRU_position;
 
983
        } else {
 
984
                bpage->LRU_position = buf_pool_clock_tic();
 
985
        }
 
986
 
 
987
        ut_ad(!bpage->in_LRU_list);
 
988
        UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage);
 
989
        ut_d(bpage->in_LRU_list = TRUE);
 
990
 
 
991
        if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
 
992
 
 
993
                buf_pool->LRU_old_len++;
 
994
        }
 
995
 
 
996
        if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
 
997
 
 
998
                ut_ad(buf_pool->LRU_old);
 
999
 
 
1000
                /* Adjust the length of the old block list if necessary */
 
1001
 
 
1002
                buf_LRU_old_adjust_len();
 
1003
 
 
1004
        } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
 
1005
 
 
1006
                /* The LRU list is now long enough for LRU_old to become
 
1007
                defined: init it */
 
1008
 
 
1009
                buf_LRU_old_init();
 
1010
        }
 
1011
 
 
1012
        /* If this is a zipped block with decompressed frame as well
 
1013
        then put it on the unzip_LRU list */
 
1014
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
 
1015
                buf_unzip_LRU_add_block((buf_block_t*) bpage, TRUE);
 
1016
        }
 
1017
}
 
1018
 
 
1019
/**********************************************************************
 
1020
Adds a block to the LRU list. */
 
1021
UNIV_INLINE
 
1022
void
 
1023
buf_LRU_add_block_low(
 
1024
/*==================*/
 
1025
        buf_page_t*     bpage,  /* in: control block */
 
1026
        ibool           old)    /* in: TRUE if should be put to the old blocks
 
1027
                                in the LRU list, else put to the start; if the
 
1028
                                LRU list is very short, the block is added to
 
1029
                                the start, regardless of this parameter */
 
1030
{
 
1031
        ut_ad(buf_pool);
 
1032
        ut_ad(bpage);
 
1033
        ut_ad(buf_pool_mutex_own());
 
1034
 
 
1035
        ut_a(buf_page_in_file(bpage));
 
1036
        ut_ad(!bpage->in_LRU_list);
 
1037
 
 
1038
        buf_page_set_old(bpage, old);
 
1039
 
 
1040
        if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
 
1041
 
 
1042
                UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
 
1043
 
 
1044
                bpage->LRU_position = buf_pool_clock_tic();
 
1045
                bpage->freed_page_clock = buf_pool->freed_page_clock;
 
1046
        } else {
 
1047
                UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
 
1048
                                     bpage);
 
1049
                buf_pool->LRU_old_len++;
 
1050
 
 
1051
                /* We copy the LRU position field of the previous block
 
1052
                to the new block */
 
1053
 
 
1054
                bpage->LRU_position = (buf_pool->LRU_old)->LRU_position;
 
1055
        }
 
1056
 
 
1057
        ut_d(bpage->in_LRU_list = TRUE);
 
1058
 
 
1059
        if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
 
1060
 
 
1061
                ut_ad(buf_pool->LRU_old);
 
1062
 
 
1063
                /* Adjust the length of the old block list if necessary */
 
1064
 
 
1065
                buf_LRU_old_adjust_len();
 
1066
 
 
1067
        } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
 
1068
 
 
1069
                /* The LRU list is now long enough for LRU_old to become
 
1070
                defined: init it */
 
1071
 
 
1072
                buf_LRU_old_init();
 
1073
        }
 
1074
 
 
1075
        /* If this is a zipped block with decompressed frame as well
 
1076
        then put it on the unzip_LRU list */
 
1077
        if (buf_page_belongs_to_unzip_LRU(bpage)) {
 
1078
                buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
 
1079
        }
 
1080
}
 
1081
 
 
1082
/**********************************************************************
 
1083
Adds a block to the LRU list. */
 
1084
UNIV_INTERN
 
1085
void
 
1086
buf_LRU_add_block(
 
1087
/*==============*/
 
1088
        buf_page_t*     bpage,  /* in: control block */
 
1089
        ibool           old)    /* in: TRUE if should be put to the old
 
1090
                                blocks in the LRU list, else put to the start;
 
1091
                                if the LRU list is very short, the block is
 
1092
                                added to the start, regardless of this
 
1093
                                parameter */
 
1094
{
 
1095
        buf_LRU_add_block_low(bpage, old);
 
1096
}
 
1097
 
 
1098
/**********************************************************************
 
1099
Moves a block to the start of the LRU list. */
 
1100
UNIV_INTERN
 
1101
void
 
1102
buf_LRU_make_block_young(
 
1103
/*=====================*/
 
1104
        buf_page_t*     bpage)  /* in: control block */
 
1105
{
 
1106
        buf_LRU_remove_block(bpage);
 
1107
        buf_LRU_add_block_low(bpage, FALSE);
 
1108
}
 
1109
 
 
1110
/**********************************************************************
 
1111
Moves a block to the end of the LRU list. */
 
1112
UNIV_INTERN
 
1113
void
 
1114
buf_LRU_make_block_old(
 
1115
/*===================*/
 
1116
        buf_page_t*     bpage)  /* in: control block */
 
1117
{
 
1118
        buf_LRU_remove_block(bpage);
 
1119
        buf_LRU_add_block_to_end_low(bpage);
 
1120
}
 
1121
 
 
1122
/**********************************************************************
 
1123
Try to free a block.  If bpage is a descriptor of a compressed-only
 
1124
page, the descriptor object will be freed as well.  If this function
 
1125
returns BUF_LRU_FREED, it will not temporarily release
 
1126
buf_pool_mutex. */
 
1127
UNIV_INTERN
 
1128
enum buf_lru_free_block_status
 
1129
buf_LRU_free_block(
 
1130
/*===============*/
 
1131
                                /* out: BUF_LRU_FREED if freed,
 
1132
                                BUF_LRU_CANNOT_RELOCATE or
 
1133
                                BUF_LRU_NOT_FREED otherwise. */
 
1134
        buf_page_t*     bpage,  /* in: block to be freed */
 
1135
        ibool           zip,    /* in: TRUE if should remove also the
 
1136
                                compressed page of an uncompressed page */
 
1137
        ibool*          buf_pool_mutex_released)
 
1138
                                /* in: pointer to a variable that will
 
1139
                                be assigned TRUE if buf_pool_mutex
 
1140
                                was temporarily released, or NULL */
 
1141
{
 
1142
        buf_page_t*     b = NULL;
 
1143
        mutex_t*        block_mutex = buf_page_get_mutex(bpage);
 
1144
 
 
1145
        ut_ad(buf_pool_mutex_own());
 
1146
        ut_ad(mutex_own(block_mutex));
 
1147
        ut_ad(buf_page_in_file(bpage));
 
1148
        ut_ad(bpage->in_LRU_list);
 
1149
        ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
 
1150
        UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
 
1151
 
 
1152
        if (!buf_page_can_relocate(bpage)) {
 
1153
 
 
1154
                /* Do not free buffer-fixed or I/O-fixed blocks. */
 
1155
                return(BUF_LRU_NOT_FREED);
 
1156
        }
 
1157
 
 
1158
        if (zip || !bpage->zip.data) {
 
1159
                /* This would completely free the block. */
 
1160
                /* Do not completely free dirty blocks. */
 
1161
 
 
1162
                if (bpage->oldest_modification) {
 
1163
                        return(BUF_LRU_NOT_FREED);
 
1164
                }
 
1165
        } else if (bpage->oldest_modification) {
 
1166
                /* Do not completely free dirty blocks. */
 
1167
 
 
1168
                if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
 
1169
                        ut_ad(buf_page_get_state(bpage)
 
1170
                              == BUF_BLOCK_ZIP_DIRTY);
 
1171
                        return(BUF_LRU_NOT_FREED);
 
1172
                }
 
1173
 
 
1174
                goto alloc;
 
1175
        } else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
 
1176
                /* Allocate the control block for the compressed page.
 
1177
                If it cannot be allocated (without freeing a block
 
1178
                from the LRU list), refuse to free bpage. */
 
1179
alloc:
 
1180
                buf_pool_mutex_exit_forbid();
 
1181
                b = buf_buddy_alloc(sizeof *b, NULL);
 
1182
                buf_pool_mutex_exit_allow();
 
1183
 
 
1184
                if (UNIV_UNLIKELY(!b)) {
 
1185
                        return(BUF_LRU_CANNOT_RELOCATE);
 
1186
                }
 
1187
 
 
1188
                memcpy(b, bpage, sizeof *b);
 
1189
        }
 
1190
 
 
1191
#ifdef UNIV_DEBUG
 
1192
        if (buf_debug_prints) {
 
1193
                fprintf(stderr, "Putting space %lu page %lu to free list\n",
 
1194
                        (ulong) buf_page_get_space(bpage),
 
1195
                        (ulong) buf_page_get_page_no(bpage));
 
1196
        }
 
1197
#endif /* UNIV_DEBUG */
 
1198
 
 
1199
        if (buf_LRU_block_remove_hashed_page(bpage, zip)
 
1200
            != BUF_BLOCK_ZIP_FREE) {
 
1201
                ut_a(bpage->buf_fix_count == 0);
 
1202
 
 
1203
                if (b) {
 
1204
                        buf_page_t*     prev_b  = UT_LIST_GET_PREV(LRU, b);
 
1205
                        const ulint     fold    = buf_page_address_fold(
 
1206
                                bpage->space, bpage->offset);
 
1207
 
 
1208
                        ut_a(!buf_page_hash_get(bpage->space, bpage->offset));
 
1209
 
 
1210
                        b->state = b->oldest_modification
 
1211
                                ? BUF_BLOCK_ZIP_DIRTY
 
1212
                                : BUF_BLOCK_ZIP_PAGE;
 
1213
                        UNIV_MEM_DESC(b->zip.data,
 
1214
                                      page_zip_get_size(&b->zip), b);
 
1215
 
 
1216
                        /* The fields in_page_hash and in_LRU_list of
 
1217
                        the to-be-freed block descriptor should have
 
1218
                        been cleared in
 
1219
                        buf_LRU_block_remove_hashed_page(), which
 
1220
                        invokes buf_LRU_remove_block(). */
 
1221
                        ut_ad(!bpage->in_page_hash);
 
1222
                        ut_ad(!bpage->in_LRU_list);
 
1223
                        /* bpage->state was BUF_BLOCK_FILE_PAGE because
 
1224
                        b != NULL. The type cast below is thus valid. */
 
1225
                        ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
 
1226
 
 
1227
                        /* The fields of bpage were copied to b before
 
1228
                        buf_LRU_block_remove_hashed_page() was invoked. */
 
1229
                        ut_ad(!b->in_zip_hash);
 
1230
                        ut_ad(b->in_page_hash);
 
1231
                        ut_ad(b->in_LRU_list);
 
1232
 
 
1233
                        HASH_INSERT(buf_page_t, hash,
 
1234
                                    buf_pool->page_hash, fold, b);
 
1235
 
 
1236
                        /* Insert b where bpage was in the LRU list. */
 
1237
                        if (UNIV_LIKELY(prev_b != NULL)) {
 
1238
                                ulint   lru_len;
 
1239
 
 
1240
                                ut_ad(prev_b->in_LRU_list);
 
1241
                                ut_ad(buf_page_in_file(prev_b));
 
1242
                                UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
 
1243
 
 
1244
                                UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
 
1245
                                                     prev_b, b);
 
1246
 
 
1247
                                if (buf_page_is_old(b)) {
 
1248
                                        buf_pool->LRU_old_len++;
 
1249
                                }
 
1250
 
 
1251
                                lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
 
1252
 
 
1253
                                if (lru_len > BUF_LRU_OLD_MIN_LEN) {
 
1254
                                        ut_ad(buf_pool->LRU_old);
 
1255
                                        /* Adjust the length of the
 
1256
                                        old block list if necessary */
 
1257
                                        buf_LRU_old_adjust_len();
 
1258
                                } else if (lru_len == BUF_LRU_OLD_MIN_LEN) {
 
1259
                                        /* The LRU list is now long
 
1260
                                        enough for LRU_old to become
 
1261
                                        defined: init it */
 
1262
                                        buf_LRU_old_init();
 
1263
                                }
 
1264
                        } else {
 
1265
                                ut_d(b->in_LRU_list = FALSE);
 
1266
                                buf_LRU_add_block_low(b, buf_page_is_old(b));
 
1267
                        }
 
1268
 
 
1269
                        if (b->state == BUF_BLOCK_ZIP_PAGE) {
 
1270
                                buf_LRU_insert_zip_clean(b);
 
1271
                        } else {
 
1272
                                buf_page_t* prev;
 
1273
 
 
1274
                                ut_ad(b->in_flush_list);
 
1275
                                ut_d(bpage->in_flush_list = FALSE);
 
1276
 
 
1277
                                prev = UT_LIST_GET_PREV(list, b);
 
1278
                                UT_LIST_REMOVE(list, buf_pool->flush_list, b);
 
1279
 
 
1280
                                if (prev) {
 
1281
                                        ut_ad(prev->in_flush_list);
 
1282
                                        UT_LIST_INSERT_AFTER(
 
1283
                                                list,
 
1284
                                                buf_pool->flush_list,
 
1285
                                                prev, b);
 
1286
                                } else {
 
1287
                                        UT_LIST_ADD_FIRST(
 
1288
                                                list,
 
1289
                                                buf_pool->flush_list,
 
1290
                                                b);
 
1291
                                }
 
1292
                        }
 
1293
 
 
1294
                        bpage->zip.data = NULL;
 
1295
                        page_zip_set_size(&bpage->zip, 0);
 
1296
 
 
1297
                        /* Prevent buf_page_get_gen() from
 
1298
                        decompressing the block while we release
 
1299
                        buf_pool_mutex and block_mutex. */
 
1300
                        b->buf_fix_count++;
 
1301
                        b->io_fix = BUF_IO_READ;
 
1302
                }
 
1303
 
 
1304
                if (buf_pool_mutex_released) {
 
1305
                        *buf_pool_mutex_released = TRUE;
 
1306
                }
 
1307
 
 
1308
                buf_pool_mutex_exit();
 
1309
                mutex_exit(block_mutex);
 
1310
 
 
1311
                /* Remove possible adaptive hash index on the page.
 
1312
                The page was declared uninitialized by
 
1313
                buf_LRU_block_remove_hashed_page().  We need to flag
 
1314
                the contents of the page valid (which it still is) in
 
1315
                order to avoid bogus Valgrind warnings.*/
 
1316
 
 
1317
                UNIV_MEM_VALID(((buf_block_t*) bpage)->frame,
 
1318
                               UNIV_PAGE_SIZE);
 
1319
                btr_search_drop_page_hash_index((buf_block_t*) bpage);
 
1320
                UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
 
1321
                                 UNIV_PAGE_SIZE);
 
1322
 
 
1323
                if (b) {
 
1324
                        /* Compute and stamp the compressed page
 
1325
                        checksum while not holding any mutex.  The
 
1326
                        block is already half-freed
 
1327
                        (BUF_BLOCK_REMOVE_HASH) and removed from
 
1328
                        buf_pool->page_hash, thus inaccessible by any
 
1329
                        other thread. */
 
1330
 
 
1331
                        mach_write_to_4(
 
1332
                                b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
 
1333
                                UNIV_LIKELY(srv_use_checksums)
 
1334
                                ? page_zip_calc_checksum(
 
1335
                                        b->zip.data,
 
1336
                                        page_zip_get_size(&b->zip))
 
1337
                                : BUF_NO_CHECKSUM_MAGIC);
 
1338
                }
 
1339
 
 
1340
                buf_pool_mutex_enter();
 
1341
                mutex_enter(block_mutex);
 
1342
 
 
1343
                if (b) {
 
1344
                        mutex_enter(&buf_pool_zip_mutex);
 
1345
                        b->buf_fix_count--;
 
1346
                        buf_page_set_io_fix(b, BUF_IO_NONE);
 
1347
                        mutex_exit(&buf_pool_zip_mutex);
 
1348
                }
 
1349
 
 
1350
                buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
 
1351
        } else {
 
1352
                mutex_enter(block_mutex);
 
1353
        }
 
1354
 
 
1355
        return(BUF_LRU_FREED);
 
1356
}
 
1357
 
 
1358
/**********************************************************************
 
1359
Puts a block back to the free list. */
 
1360
UNIV_INTERN
 
1361
void
 
1362
buf_LRU_block_free_non_file_page(
 
1363
/*=============================*/
 
1364
        buf_block_t*    block)  /* in: block, must not contain a file page */
 
1365
{
 
1366
        void*   data;
 
1367
 
 
1368
        ut_ad(buf_pool_mutex_own());
 
1369
        ut_ad(mutex_own(&block->mutex));
 
1370
        ut_ad(block);
 
1371
 
 
1372
        switch (buf_block_get_state(block)) {
 
1373
        case BUF_BLOCK_MEMORY:
 
1374
        case BUF_BLOCK_READY_FOR_USE:
 
1375
                break;
 
1376
        default:
 
1377
                ut_error;
 
1378
        }
 
1379
 
 
1380
        ut_ad(block->n_pointers == 0);
 
1381
        ut_ad(!block->page.in_free_list);
 
1382
        ut_ad(!block->page.in_flush_list);
 
1383
        ut_ad(!block->page.in_LRU_list);
 
1384
 
 
1385
        buf_block_set_state(block, BUF_BLOCK_NOT_USED);
 
1386
 
 
1387
        UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
 
1388
#ifdef UNIV_DEBUG
 
1389
        /* Wipe contents of page to reveal possible stale pointers to it */
 
1390
        memset(block->frame, '\0', UNIV_PAGE_SIZE);
 
1391
#else
 
1392
        /* Wipe page_no and space_id */
 
1393
        memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
 
1394
        memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
 
1395
#endif
 
1396
        data = block->page.zip.data;
 
1397
 
 
1398
        if (data) {
 
1399
                block->page.zip.data = NULL;
 
1400
                mutex_exit(&block->mutex);
 
1401
                buf_pool_mutex_exit_forbid();
 
1402
                buf_buddy_free(data, page_zip_get_size(&block->page.zip));
 
1403
                buf_pool_mutex_exit_allow();
 
1404
                mutex_enter(&block->mutex);
 
1405
                page_zip_set_size(&block->page.zip, 0);
 
1406
        }
 
1407
 
 
1408
        UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
 
1409
        ut_d(block->page.in_free_list = TRUE);
 
1410
 
 
1411
        UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
 
1412
}
 
1413
 
 
1414
/**********************************************************************
 
1415
Takes a block out of the LRU list and page hash table.
 
1416
If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
 
1417
the object will be freed and buf_pool_zip_mutex will be released.
 
1418
 
 
1419
If a compressed page or a compressed-only block descriptor is freed,
 
1420
other compressed pages or compressed-only block descriptors may be
 
1421
relocated. */
 
1422
static
 
1423
enum buf_page_state
 
1424
buf_LRU_block_remove_hashed_page(
 
1425
/*=============================*/
 
1426
                                /* out: the new state of the block
 
1427
                                (BUF_BLOCK_ZIP_FREE if the state was
 
1428
                                BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH
 
1429
                                otherwise) */
 
1430
        buf_page_t*     bpage,  /* in: block, must contain a file page and
 
1431
                                be in a state where it can be freed; there
 
1432
                                may or may not be a hash index to the page */
 
1433
        ibool           zip)    /* in: TRUE if should remove also the
 
1434
                                compressed page of an uncompressed page */
 
1435
{
 
1436
        const buf_page_t*       hashed_bpage;
 
1437
        ut_ad(bpage);
 
1438
        ut_ad(buf_pool_mutex_own());
 
1439
        ut_ad(mutex_own(buf_page_get_mutex(bpage)));
 
1440
 
 
1441
        ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
 
1442
        ut_a(bpage->buf_fix_count == 0);
 
1443
 
 
1444
        UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
 
1445
 
 
1446
        buf_LRU_remove_block(bpage);
 
1447
 
 
1448
        buf_pool->freed_page_clock += 1;
 
1449
 
 
1450
        switch (buf_page_get_state(bpage)) {
 
1451
        case BUF_BLOCK_FILE_PAGE:
 
1452
                UNIV_MEM_ASSERT_W(bpage, sizeof(buf_block_t));
 
1453
                UNIV_MEM_ASSERT_W(((buf_block_t*) bpage)->frame,
 
1454
                                  UNIV_PAGE_SIZE);
 
1455
                buf_block_modify_clock_inc((buf_block_t*) bpage);
 
1456
                if (bpage->zip.data) {
 
1457
                        const page_t*   page = ((buf_block_t*) bpage)->frame;
 
1458
 
 
1459
                        ut_a(!zip || bpage->oldest_modification == 0);
 
1460
 
 
1461
                        switch (UNIV_EXPECT(fil_page_get_type(page),
 
1462
                                            FIL_PAGE_INDEX)) {
 
1463
                        case FIL_PAGE_TYPE_ALLOCATED:
 
1464
                        case FIL_PAGE_INODE:
 
1465
                        case FIL_PAGE_IBUF_BITMAP:
 
1466
                        case FIL_PAGE_TYPE_FSP_HDR:
 
1467
                        case FIL_PAGE_TYPE_XDES:
 
1468
                                /* These are essentially uncompressed pages. */
 
1469
                                if (!zip) {
 
1470
                                        /* InnoDB writes the data to the
 
1471
                                        uncompressed page frame.  Copy it
 
1472
                                        to the compressed page, which will
 
1473
                                        be preserved. */
 
1474
                                        memcpy(bpage->zip.data, page,
 
1475
                                               page_zip_get_size(&bpage->zip));
 
1476
                                }
 
1477
                                break;
 
1478
                        case FIL_PAGE_TYPE_ZBLOB:
 
1479
                        case FIL_PAGE_TYPE_ZBLOB2:
 
1480
                                break;
 
1481
                        case FIL_PAGE_INDEX:
 
1482
#ifdef UNIV_ZIP_DEBUG
 
1483
                                ut_a(page_zip_validate(&bpage->zip, page));
 
1484
#endif /* UNIV_ZIP_DEBUG */
 
1485
                                break;
 
1486
                        default:
 
1487
                                ut_error;
 
1488
                        }
 
1489
 
 
1490
                        break;
 
1491
                }
 
1492
                /* fall through */
 
1493
        case BUF_BLOCK_ZIP_PAGE:
 
1494
                ut_a(bpage->oldest_modification == 0);
 
1495
                UNIV_MEM_ASSERT_W(bpage->zip.data,
 
1496
                                  page_zip_get_size(&bpage->zip));
 
1497
                break;
 
1498
        case BUF_BLOCK_ZIP_FREE:
 
1499
        case BUF_BLOCK_ZIP_DIRTY:
 
1500
        case BUF_BLOCK_NOT_USED:
 
1501
        case BUF_BLOCK_READY_FOR_USE:
 
1502
        case BUF_BLOCK_MEMORY:
 
1503
        case BUF_BLOCK_REMOVE_HASH:
 
1504
                ut_error;
 
1505
                break;
 
1506
        }
 
1507
 
 
1508
        hashed_bpage = buf_page_hash_get(bpage->space, bpage->offset);
 
1509
 
 
1510
        if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
 
1511
                fprintf(stderr,
 
1512
                        "InnoDB: Error: page %lu %lu not found"
 
1513
                        " in the hash table\n",
 
1514
                        (ulong) bpage->space,
 
1515
                        (ulong) bpage->offset);
 
1516
                if (hashed_bpage) {
 
1517
                        fprintf(stderr,
 
1518
                                "InnoDB: In hash table we find block"
 
1519
                                " %p of %lu %lu which is not %p\n",
 
1520
                                (const void*) hashed_bpage,
 
1521
                                (ulong) hashed_bpage->space,
 
1522
                                (ulong) hashed_bpage->offset,
 
1523
                                (const void*) bpage);
 
1524
                }
 
1525
 
 
1526
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 
1527
                mutex_exit(buf_page_get_mutex(bpage));
 
1528
                buf_pool_mutex_exit();
 
1529
                buf_print();
 
1530
                buf_LRU_print();
 
1531
                buf_validate();
 
1532
                buf_LRU_validate();
 
1533
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
 
1534
                ut_error;
 
1535
        }
 
1536
 
 
1537
        ut_ad(!bpage->in_zip_hash);
 
1538
        ut_ad(bpage->in_page_hash);
 
1539
        ut_d(bpage->in_page_hash = FALSE);
 
1540
        HASH_DELETE(buf_page_t, hash, buf_pool->page_hash,
 
1541
                    buf_page_address_fold(bpage->space, bpage->offset),
 
1542
                    bpage);
 
1543
        switch (buf_page_get_state(bpage)) {
 
1544
        case BUF_BLOCK_ZIP_PAGE:
 
1545
                ut_ad(!bpage->in_free_list);
 
1546
                ut_ad(!bpage->in_flush_list);
 
1547
                ut_ad(!bpage->in_LRU_list);
 
1548
                ut_a(bpage->zip.data);
 
1549
                ut_a(buf_page_get_zip_size(bpage));
 
1550
 
 
1551
                UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
 
1552
 
 
1553
                mutex_exit(&buf_pool_zip_mutex);
 
1554
                buf_pool_mutex_exit_forbid();
 
1555
                buf_buddy_free(bpage->zip.data,
 
1556
                               page_zip_get_size(&bpage->zip));
 
1557
                buf_buddy_free(bpage, sizeof(*bpage));
 
1558
                buf_pool_mutex_exit_allow();
 
1559
                UNIV_MEM_UNDESC(bpage);
 
1560
                return(BUF_BLOCK_ZIP_FREE);
 
1561
 
 
1562
        case BUF_BLOCK_FILE_PAGE:
 
1563
                memset(((buf_block_t*) bpage)->frame
 
1564
                       + FIL_PAGE_OFFSET, 0xff, 4);
 
1565
                memset(((buf_block_t*) bpage)->frame
 
1566
                       + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
 
1567
                UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
 
1568
                                 UNIV_PAGE_SIZE);
 
1569
                buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
 
1570
 
 
1571
                if (zip && bpage->zip.data) {
 
1572
                        /* Free the compressed page. */
 
1573
                        void*   data = bpage->zip.data;
 
1574
                        bpage->zip.data = NULL;
 
1575
 
 
1576
                        mutex_exit(&((buf_block_t*) bpage)->mutex);
 
1577
                        buf_buddy_free(data, page_zip_get_size(&bpage->zip));
 
1578
                        mutex_enter(&((buf_block_t*) bpage)->mutex);
 
1579
                        page_zip_set_size(&bpage->zip, 0);
 
1580
                }
 
1581
 
 
1582
                return(BUF_BLOCK_REMOVE_HASH);
 
1583
 
 
1584
        case BUF_BLOCK_ZIP_FREE:
 
1585
        case BUF_BLOCK_ZIP_DIRTY:
 
1586
        case BUF_BLOCK_NOT_USED:
 
1587
        case BUF_BLOCK_READY_FOR_USE:
 
1588
        case BUF_BLOCK_MEMORY:
 
1589
        case BUF_BLOCK_REMOVE_HASH:
 
1590
                break;
 
1591
        }
 
1592
 
 
1593
        ut_error;
 
1594
        return(BUF_BLOCK_ZIP_FREE);
 
1595
}
 
1596
 
 
1597
/**********************************************************************
 
1598
Puts a file page whose has no hash index to the free list. */
 
1599
static
 
1600
void
 
1601
buf_LRU_block_free_hashed_page(
 
1602
/*===========================*/
 
1603
        buf_block_t*    block)  /* in: block, must contain a file page and
 
1604
                                be in a state where it can be freed */
 
1605
{
 
1606
        ut_ad(buf_pool_mutex_own());
 
1607
        ut_ad(mutex_own(&block->mutex));
 
1608
 
 
1609
        buf_block_set_state(block, BUF_BLOCK_MEMORY);
 
1610
 
 
1611
        buf_LRU_block_free_non_file_page(block);
 
1612
}
 
1613
 
 
1614
/************************************************************************
 
1615
Update the historical stats that we are collecting for LRU eviction
 
1616
policy at the end of each interval. */
 
1617
UNIV_INTERN
 
1618
void
 
1619
buf_LRU_stat_update(void)
 
1620
/*=====================*/
 
1621
{
 
1622
        buf_LRU_stat_t* item;
 
1623
 
 
1624
        /* If we haven't started eviction yet then don't update stats. */
 
1625
        if (buf_pool->freed_page_clock == 0) {
 
1626
                goto func_exit;
 
1627
        }
 
1628
 
 
1629
        buf_pool_mutex_enter();
 
1630
 
 
1631
        /* Update the index. */
 
1632
        item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind];
 
1633
        buf_LRU_stat_arr_ind++;
 
1634
        buf_LRU_stat_arr_ind %= BUF_LRU_STAT_N_INTERVAL;
 
1635
 
 
1636
        /* Add the current value and subtract the obsolete entry. */
 
1637
        buf_LRU_stat_sum.io += buf_LRU_stat_cur.io - item->io;
 
1638
        buf_LRU_stat_sum.unzip += buf_LRU_stat_cur.unzip - item->unzip;
 
1639
 
 
1640
        /* Put current entry in the array. */
 
1641
        memcpy(item, &buf_LRU_stat_cur, sizeof *item);
 
1642
 
 
1643
        buf_pool_mutex_exit();
 
1644
 
 
1645
func_exit:
 
1646
        /* Clear the current entry. */
 
1647
        memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
 
1648
}
 
1649
 
 
1650
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 
1651
/**************************************************************************
 
1652
Validates the LRU list. */
 
1653
UNIV_INTERN
 
1654
ibool
 
1655
buf_LRU_validate(void)
 
1656
/*==================*/
 
1657
{
 
1658
        buf_page_t*     bpage;
 
1659
        buf_block_t*    block;
 
1660
        ulint           old_len;
 
1661
        ulint           new_len;
 
1662
        ulint           LRU_pos;
 
1663
 
 
1664
        ut_ad(buf_pool);
 
1665
        buf_pool_mutex_enter();
 
1666
 
 
1667
        if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
 
1668
 
 
1669
                ut_a(buf_pool->LRU_old);
 
1670
                old_len = buf_pool->LRU_old_len;
 
1671
                new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
 
1672
                ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
 
1673
                ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
 
1674
        }
 
1675
 
 
1676
        UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU);
 
1677
 
 
1678
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
 
1679
 
 
1680
        old_len = 0;
 
1681
 
 
1682
        while (bpage != NULL) {
 
1683
 
 
1684
                switch (buf_page_get_state(bpage)) {
 
1685
                case BUF_BLOCK_ZIP_FREE:
 
1686
                case BUF_BLOCK_NOT_USED:
 
1687
                case BUF_BLOCK_READY_FOR_USE:
 
1688
                case BUF_BLOCK_MEMORY:
 
1689
                case BUF_BLOCK_REMOVE_HASH:
 
1690
                        ut_error;
 
1691
                        break;
 
1692
                case BUF_BLOCK_FILE_PAGE:
 
1693
                        ut_ad(((buf_block_t*) bpage)->in_unzip_LRU_list
 
1694
                              == buf_page_belongs_to_unzip_LRU(bpage));
 
1695
                case BUF_BLOCK_ZIP_PAGE:
 
1696
                case BUF_BLOCK_ZIP_DIRTY:
 
1697
                        break;
 
1698
                }
 
1699
 
 
1700
                if (buf_page_is_old(bpage)) {
 
1701
                        old_len++;
 
1702
                }
 
1703
 
 
1704
                if (buf_pool->LRU_old && (old_len == 1)) {
 
1705
                        ut_a(buf_pool->LRU_old == bpage);
 
1706
                }
 
1707
 
 
1708
                LRU_pos = buf_page_get_LRU_position(bpage);
 
1709
 
 
1710
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
 
1711
 
 
1712
                if (bpage) {
 
1713
                        /* If the following assert fails, it may
 
1714
                        not be an error: just the buf_pool clock
 
1715
                        has wrapped around */
 
1716
                        ut_a(LRU_pos >= buf_page_get_LRU_position(bpage));
 
1717
                }
 
1718
        }
 
1719
 
 
1720
        if (buf_pool->LRU_old) {
 
1721
                ut_a(buf_pool->LRU_old_len == old_len);
 
1722
        }
 
1723
 
 
1724
        UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free);
 
1725
 
 
1726
        for (bpage = UT_LIST_GET_FIRST(buf_pool->free);
 
1727
             bpage != NULL;
 
1728
             bpage = UT_LIST_GET_NEXT(list, bpage)) {
 
1729
 
 
1730
                ut_a(buf_page_get_state(bpage) == BUF_BLOCK_NOT_USED);
 
1731
        }
 
1732
 
 
1733
        UT_LIST_VALIDATE(unzip_LRU, buf_block_t, buf_pool->unzip_LRU);
 
1734
 
 
1735
        for (block = UT_LIST_GET_FIRST(buf_pool->unzip_LRU);
 
1736
             block;
 
1737
             block = UT_LIST_GET_NEXT(unzip_LRU, block)) {
 
1738
 
 
1739
                ut_ad(block->in_unzip_LRU_list);
 
1740
                ut_ad(block->page.in_LRU_list);
 
1741
                ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
 
1742
        }
 
1743
 
 
1744
        buf_pool_mutex_exit();
 
1745
        return(TRUE);
 
1746
}
 
1747
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
 
1748
 
 
1749
#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 
1750
/**************************************************************************
 
1751
Prints the LRU list. */
 
1752
UNIV_INTERN
 
1753
void
 
1754
buf_LRU_print(void)
 
1755
/*===============*/
 
1756
{
 
1757
        const buf_page_t*       bpage;
 
1758
 
 
1759
        ut_ad(buf_pool);
 
1760
        buf_pool_mutex_enter();
 
1761
 
 
1762
        fprintf(stderr, "Pool ulint clock %lu\n",
 
1763
                (ulong) buf_pool->ulint_clock);
 
1764
 
 
1765
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
 
1766
 
 
1767
        while (bpage != NULL) {
 
1768
 
 
1769
                fprintf(stderr, "BLOCK space %lu page %lu ",
 
1770
                        (ulong) buf_page_get_space(bpage),
 
1771
                        (ulong) buf_page_get_page_no(bpage));
 
1772
 
 
1773
                if (buf_page_is_old(bpage)) {
 
1774
                        fputs("old ", stderr);
 
1775
                }
 
1776
 
 
1777
                if (bpage->buf_fix_count) {
 
1778
                        fprintf(stderr, "buffix count %lu ",
 
1779
                                (ulong) bpage->buf_fix_count);
 
1780
                }
 
1781
 
 
1782
                if (buf_page_get_io_fix(bpage)) {
 
1783
                        fprintf(stderr, "io_fix %lu ",
 
1784
                                (ulong) buf_page_get_io_fix(bpage));
 
1785
                }
 
1786
 
 
1787
                if (bpage->oldest_modification) {
 
1788
                        fputs("modif. ", stderr);
 
1789
                }
 
1790
 
 
1791
                switch (buf_page_get_state(bpage)) {
 
1792
                        const byte*     frame;
 
1793
                case BUF_BLOCK_FILE_PAGE:
 
1794
                        frame = buf_block_get_frame((buf_block_t*) bpage);
 
1795
                        fprintf(stderr, "\nLRU pos %lu type %lu"
 
1796
                                " index id %lu\n",
 
1797
                                (ulong) buf_page_get_LRU_position(bpage),
 
1798
                                (ulong) fil_page_get_type(frame),
 
1799
                                (ulong) ut_dulint_get_low(
 
1800
                                        btr_page_get_index_id(frame)));
 
1801
                        break;
 
1802
                case BUF_BLOCK_ZIP_PAGE:
 
1803
                        frame = bpage->zip.data;
 
1804
                        fprintf(stderr, "\nLRU pos %lu type %lu size %lu"
 
1805
                                " index id %lu\n",
 
1806
                                (ulong) buf_page_get_LRU_position(bpage),
 
1807
                                (ulong) fil_page_get_type(frame),
 
1808
                                (ulong) buf_page_get_zip_size(bpage),
 
1809
                                (ulong) ut_dulint_get_low(
 
1810
                                        btr_page_get_index_id(frame)));
 
1811
                        break;
 
1812
 
 
1813
                default:
 
1814
                        fprintf(stderr, "\nLRU pos %lu !state %lu!\n",
 
1815
                                (ulong) buf_page_get_LRU_position(bpage),
 
1816
                                (ulong) buf_page_get_state(bpage));
 
1817
                        break;
 
1818
                }
 
1819
 
 
1820
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
 
1821
        }
 
1822
 
 
1823
        buf_pool_mutex_exit();
 
1824
}
 
1825
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */