~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2010-12-24 02:13:05 UTC
  • mto: This revision was merged to the branch mainline in revision 2038.
  • Revision ID: mordred@inaugust.com-20101224021305-e3slv1cyjczqorij
Changed the bzrignore file.

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 */