~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-11-04 15:39:09 UTC
  • mfrom: (575.1.2 devel)
  • Revision ID: brian@tangent.org-20081104153909-c72hn65udxs1ccal
Merge of Monty's work

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
 
11
11
#ifdef UNIV_NONINL
12
12
#include "buf0lru.ic"
13
 
#include "srv0srv.h"    /* Needed to getsrv_print_innodb_monitor */
14
13
#endif
15
14
 
16
15
#include "ut0byte.h"
22
21
#include "os0sync.h"
23
22
#include "fil0fil.h"
24
23
#include "btr0btr.h"
 
24
#include "buf0buddy.h"
25
25
#include "buf0buf.h"
26
26
#include "buf0flu.h"
27
27
#include "buf0rea.h"
28
28
#include "btr0sea.h"
29
29
#include "os0file.h"
 
30
#include "page0zip.h"
30
31
#include "log0recv.h"
 
32
#include "srv0srv.h"
31
33
 
32
34
/* The number of blocks from the LRU_old pointer onward, including the block
33
35
pointed to, must be 3/8 of the whole LRU list length, except that the
44
46
 
45
47
/* If we switch on the InnoDB monitor because there are too few available
46
48
frames in the buffer pool, we set this to TRUE */
47
 
ibool   buf_lru_switched_on_innodb_mon  = FALSE;
48
 
 
49
 
/**********************************************************************
50
 
Takes a block out of the LRU list and page hash table and sets the block
51
 
state to BUF_BLOCK_REMOVE_HASH. */
 
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. */
52
91
static
53
 
void
 
92
enum buf_page_state
54
93
buf_LRU_block_remove_hashed_page(
55
94
/*=============================*/
56
 
        buf_block_t*    block); /* in: block, must contain a file page and
 
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
57
100
                                be in a state where it can be freed; there
58
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 */
59
104
/**********************************************************************
60
105
Puts a file page whose has no hash index to the free list. */
61
106
static
66
111
                                be in a state where it can be freed */
67
112
 
68
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
/**********************************************************************
69
161
Invalidates all pages belonging to a given tablespace when we are deleting
70
162
the data file(s) of that tablespace. */
71
 
 
 
163
UNIV_INTERN
72
164
void
73
165
buf_LRU_invalidate_tablespace(
74
166
/*==========================*/
75
167
        ulint   id)     /* in: space id */
76
168
{
77
 
        buf_block_t*    block;
 
169
        buf_page_t*     bpage;
78
170
        ulint           page_no;
79
171
        ibool           all_freed;
80
172
 
81
173
scan_again:
82
 
        mutex_enter(&(buf_pool->mutex));
 
174
        buf_pool_mutex_enter();
83
175
 
84
176
        all_freed = TRUE;
85
177
 
86
 
        block = UT_LIST_GET_LAST(buf_pool->LRU);
87
 
 
88
 
        while (block != NULL) {
89
 
                buf_block_t*    prev_block;
90
 
 
91
 
                mutex_enter(&block->mutex);
92
 
                prev_block = UT_LIST_GET_PREV(LRU, block);
93
 
 
94
 
                ut_a(block->state == BUF_BLOCK_FILE_PAGE);
95
 
 
96
 
                if (block->space == id
97
 
                    && (block->buf_fix_count > 0 || block->io_fix != 0)) {
98
 
 
99
 
                        /* We cannot remove this page during this scan yet;
100
 
                        maybe the system is currently reading it in, or
101
 
                        flushing the modifications to the file */
102
 
 
103
 
                        all_freed = FALSE;
104
 
 
105
 
                        goto next_page;
106
 
                }
107
 
 
108
 
                if (block->space == id) {
 
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
 
109
203
#ifdef UNIV_DEBUG
110
204
                        if (buf_debug_prints) {
111
205
                                fprintf(stderr,
112
206
                                        "Dropping space %lu page %lu\n",
113
 
                                        (ulong) block->space,
114
 
                                        (ulong) block->offset);
 
207
                                        (ulong) buf_page_get_space(bpage),
 
208
                                        (ulong) buf_page_get_page_no(bpage));
115
209
                        }
116
210
#endif
117
 
                        if (block->is_hashed) {
118
 
                                page_no = block->offset;
119
 
 
120
 
                                mutex_exit(&block->mutex);
121
 
 
122
 
                                mutex_exit(&(buf_pool->mutex));
 
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);
123
217
 
124
218
                                /* Note that the following call will acquire
125
219
                                an S-latch on the page */
126
220
 
127
 
                                btr_search_drop_page_hash_when_freed(id,
128
 
                                                                     page_no);
 
221
                                btr_search_drop_page_hash_when_freed(
 
222
                                        id,
 
223
                                        buf_page_get_zip_size(bpage),
 
224
                                        page_no);
129
225
                                goto scan_again;
130
226
                        }
131
227
 
132
 
                        if (0 != ut_dulint_cmp(block->oldest_modification,
133
 
                                               ut_dulint_zero)) {
134
 
 
135
 
                                /* Remove from the flush list of modified
136
 
                                blocks */
137
 
                                block->oldest_modification = ut_dulint_zero;
138
 
 
139
 
                                UT_LIST_REMOVE(flush_list,
140
 
                                               buf_pool->flush_list, block);
 
228
                        if (bpage->oldest_modification != 0) {
 
229
 
 
230
                                buf_flush_remove(bpage);
141
231
                        }
142
232
 
143
233
                        /* Remove from the LRU list */
144
 
                        buf_LRU_block_remove_hashed_page(block);
145
 
                        buf_LRU_block_free_hashed_page(block);
 
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
                        }
146
248
                }
147
249
next_page:
148
 
                mutex_exit(&block->mutex);
149
 
                block = prev_block;
 
250
                mutex_exit(block_mutex);
 
251
                bpage = prev_bpage;
150
252
        }
151
253
 
152
 
        mutex_exit(&(buf_pool->mutex));
 
254
        buf_pool_mutex_exit();
153
255
 
154
256
        if (!all_freed) {
155
257
                os_thread_sleep(20000);
162
264
Gets the minimum LRU_position field for the blocks in an initial segment
163
265
(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
164
266
guaranteed to be precise, because the ulint_clock may wrap around. */
165
 
 
 
267
UNIV_INTERN
166
268
ulint
167
269
buf_LRU_get_recent_limit(void)
168
270
/*==========================*/
169
271
                        /* out: the limit; zero if could not determine it */
170
272
{
171
 
        buf_block_t*    block;
172
 
        ulint           len;
173
 
        ulint           limit;
 
273
        const buf_page_t*       bpage;
 
274
        ulint                   len;
 
275
        ulint                   limit;
174
276
 
175
 
        mutex_enter(&(buf_pool->mutex));
 
277
        buf_pool_mutex_enter();
176
278
 
177
279
        len = UT_LIST_GET_LEN(buf_pool->LRU);
178
280
 
179
281
        if (len < BUF_LRU_OLD_MIN_LEN) {
180
282
                /* The LRU list is too short to do read-ahead */
181
283
 
182
 
                mutex_exit(&(buf_pool->mutex));
 
284
                buf_pool_mutex_exit();
183
285
 
184
286
                return(0);
185
287
        }
186
288
 
187
 
        block = UT_LIST_GET_FIRST(buf_pool->LRU);
188
 
 
189
 
        limit = block->LRU_position - len / BUF_LRU_INITIAL_RATIO;
190
 
 
191
 
        mutex_exit(&(buf_pool->mutex));
 
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();
192
294
 
193
295
        return(limit);
194
296
}
195
297
 
196
 
/**********************************************************************
197
 
Look for a replaceable block from the end of the LRU list and put it to
198
 
the free list if found. */
199
 
 
 
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
200
464
ibool
201
465
buf_LRU_search_and_free_block(
202
466
/*==========================*/
203
 
                                /* out: TRUE if freed */
 
467
                                /* out: TRUE if found and freed */
204
468
        ulint   n_iterations)   /* in: how many times this has been called
205
469
                                repeatedly without result: a high value means
206
 
                                that we should search farther; if value is
207
 
                                k < 10, then we only search k/10 * [number
208
 
                                of pages in the buffer pool] from the end
209
 
                                of the LRU list */
 
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. */
210
476
{
211
 
        buf_block_t*    block;
212
 
        ulint           distance = 0;
213
 
        ibool           freed;
214
 
 
215
 
        mutex_enter(&(buf_pool->mutex));
216
 
 
217
 
        freed = FALSE;
218
 
        block = UT_LIST_GET_LAST(buf_pool->LRU);
219
 
 
220
 
        while (block != NULL) {
221
 
                ut_a(block->in_LRU_list);
222
 
 
223
 
                mutex_enter(&block->mutex);
224
 
 
225
 
                if (buf_flush_ready_for_replace(block)) {
226
 
 
227
 
#ifdef UNIV_DEBUG
228
 
                        if (buf_debug_prints) {
229
 
                                fprintf(stderr,
230
 
                                        "Putting space %lu page %lu"
231
 
                                        " to free list\n",
232
 
                                        (ulong) block->space,
233
 
                                        (ulong) block->offset);
234
 
                        }
235
 
#endif /* UNIV_DEBUG */
236
 
 
237
 
                        buf_LRU_block_remove_hashed_page(block);
238
 
 
239
 
                        mutex_exit(&(buf_pool->mutex));
240
 
                        mutex_exit(&block->mutex);
241
 
 
242
 
                        /* Remove possible adaptive hash index built on the
243
 
                        page; in the case of AWE the block may not have a
244
 
                        frame at all */
245
 
 
246
 
                        if (block->frame) {
247
 
                                /* The page was declared uninitialized
248
 
                                by buf_LRU_block_remove_hashed_page().
249
 
                                We need to flag the contents of the
250
 
                                page valid (which it still is) in
251
 
                                order to avoid bogus Valgrind
252
 
                                warnings. */
253
 
                                UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
254
 
                                btr_search_drop_page_hash_index(block->frame);
255
 
                                UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
256
 
                        }
257
 
 
258
 
                        ut_a(block->buf_fix_count == 0);
259
 
 
260
 
                        mutex_enter(&(buf_pool->mutex));
261
 
                        mutex_enter(&block->mutex);
262
 
 
263
 
                        buf_LRU_block_free_hashed_page(block);
264
 
                        freed = TRUE;
265
 
                        mutex_exit(&block->mutex);
266
 
 
267
 
                        break;
268
 
                }
269
 
 
270
 
                mutex_exit(&block->mutex);
271
 
 
272
 
                block = UT_LIST_GET_PREV(LRU, block);
273
 
                distance++;
274
 
 
275
 
                if (!freed && n_iterations <= 10
276
 
                    && distance > 100 + (n_iterations * buf_pool->curr_size)
277
 
                    / 10) {
278
 
                        buf_pool->LRU_flush_ended = 0;
279
 
 
280
 
                        mutex_exit(&(buf_pool->mutex));
281
 
 
282
 
                        return(FALSE);
283
 
                }
 
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);
284
485
        }
285
 
        if (buf_pool->LRU_flush_ended > 0) {
 
486
 
 
487
        if (!freed) {
 
488
                buf_pool->LRU_flush_ended = 0;
 
489
        } else if (buf_pool->LRU_flush_ended > 0) {
286
490
                buf_pool->LRU_flush_ended--;
287
491
        }
288
 
        if (!freed) {
289
 
                buf_pool->LRU_flush_ended = 0;
290
 
        }
291
 
        mutex_exit(&(buf_pool->mutex));
 
492
 
 
493
        buf_pool_mutex_exit();
292
494
 
293
495
        return(freed);
294
496
}
301
503
buffer. Otherwise, the flushed blocks could get modified again before read
302
504
operations need new buffer blocks, and the i/o work done in flushing would be
303
505
wasted. */
304
 
 
 
506
UNIV_INTERN
305
507
void
306
508
buf_LRU_try_free_flushed_blocks(void)
307
509
/*=================================*/
308
510
{
309
 
        mutex_enter(&(buf_pool->mutex));
 
511
        buf_pool_mutex_enter();
310
512
 
311
513
        while (buf_pool->LRU_flush_ended > 0) {
312
514
 
313
 
                mutex_exit(&(buf_pool->mutex));
 
515
                buf_pool_mutex_exit();
314
516
 
315
517
                buf_LRU_search_and_free_block(1);
316
518
 
317
 
                mutex_enter(&(buf_pool->mutex));
 
519
                buf_pool_mutex_enter();
318
520
        }
319
521
 
320
 
        mutex_exit(&(buf_pool->mutex));
 
522
        buf_pool_mutex_exit();
321
523
}
322
524
 
323
525
/**********************************************************************
324
526
Returns TRUE if less than 25 % of the buffer pool is available. This can be
325
527
used in heuristics to prevent huge transactions eating up the whole buffer
326
528
pool for their locks. */
327
 
 
 
529
UNIV_INTERN
328
530
ibool
329
531
buf_LRU_buf_pool_running_out(void)
330
532
/*==============================*/
333
535
{
334
536
        ibool   ret     = FALSE;
335
537
 
336
 
        mutex_enter(&(buf_pool->mutex));
 
538
        buf_pool_mutex_enter();
337
539
 
338
540
        if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
339
 
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) {
 
541
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 4) {
340
542
 
341
543
                ret = TRUE;
342
544
        }
343
545
 
344
 
        mutex_exit(&(buf_pool->mutex));
 
546
        buf_pool_mutex_exit();
345
547
 
346
548
        return(ret);
347
549
}
348
550
 
349
551
/**********************************************************************
350
 
Returns a free block from buf_pool. The block is taken off the free list.
351
 
If it is empty, blocks are moved from the end of the LRU list to the free
352
 
list. */
353
 
 
354
 
buf_block_t*
355
 
buf_LRU_get_free_block(void)
356
 
/*========================*/
357
 
                                /* out: the free control block; also if AWE is
358
 
                                used, it is guaranteed that the block has its
359
 
                                page mapped to a frame when we return */
 
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 */
360
598
{
361
599
        buf_block_t*    block           = NULL;
362
600
        ibool           freed;
364
602
        ibool           mon_value_was   = FALSE;
365
603
        ibool           started_monitor = FALSE;
366
604
loop:
367
 
        mutex_enter(&(buf_pool->mutex));
 
605
        buf_pool_mutex_enter();
368
606
 
369
607
        if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
370
 
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) {
 
608
            + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
371
609
                ut_print_timestamp(stderr);
372
610
 
373
611
                fprintf(stderr,
387
625
 
388
626
                ut_error;
389
627
 
390
 
        } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
391
 
                   + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) {
 
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) {
392
632
 
393
633
                if (!buf_lru_switched_on_innodb_mon) {
394
634
 
429
669
        }
430
670
 
431
671
        /* If there is a block in the free list, take it */
432
 
        if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
433
 
 
434
 
                block = UT_LIST_GET_FIRST(buf_pool->free);
435
 
                ut_a(block->in_free_list);
436
 
                UT_LIST_REMOVE(free, buf_pool->free, block);
437
 
                block->in_free_list = FALSE;
438
 
                ut_a(block->state != BUF_BLOCK_FILE_PAGE);
439
 
                ut_a(!block->in_LRU_list);
440
 
 
441
 
                if (srv_use_awe) {
442
 
                        if (block->frame) {
443
 
                                /* Remove from the list of mapped pages */
444
 
 
445
 
                                UT_LIST_REMOVE(awe_LRU_free_mapped,
446
 
                                               buf_pool->awe_LRU_free_mapped,
447
 
                                               block);
448
 
                        } else {
449
 
                                /* We map the page to a frame; second param
450
 
                                FALSE below because we do not want it to be
451
 
                                added to the awe_LRU_free_mapped list */
452
 
 
453
 
                                buf_awe_map_page_to_frame(block, FALSE);
454
 
                        }
 
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;
455
690
                }
456
691
 
457
 
                mutex_enter(&block->mutex);
458
 
 
459
 
                block->state = BUF_BLOCK_READY_FOR_USE;
460
 
                UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
461
 
 
462
 
                mutex_exit(&block->mutex);
463
 
 
464
 
                mutex_exit(&(buf_pool->mutex));
 
692
                buf_pool_mutex_exit();
465
693
 
466
694
                if (started_monitor) {
467
695
                        srv_print_innodb_monitor = mon_value_was;
473
701
        /* If no block was in the free list, search from the end of the LRU
474
702
        list and try to free a block there */
475
703
 
476
 
        mutex_exit(&(buf_pool->mutex));
 
704
        buf_pool_mutex_exit();
477
705
 
478
706
        freed = buf_LRU_search_and_free_block(n_iterations);
479
707
 
522
750
 
523
751
        os_aio_simulated_wake_handler_threads();
524
752
 
525
 
        mutex_enter(&(buf_pool->mutex));
 
753
        buf_pool_mutex_enter();
526
754
 
527
755
        if (buf_pool->LRU_flush_ended > 0) {
528
756
                /* We have written pages in an LRU flush. To make the insert
529
757
                buffer more efficient, we try to move these pages to the free
530
758
                list. */
531
759
 
532
 
                mutex_exit(&(buf_pool->mutex));
 
760
                buf_pool_mutex_exit();
533
761
 
534
762
                buf_LRU_try_free_flushed_blocks();
535
763
        } else {
536
 
                mutex_exit(&(buf_pool->mutex));
 
764
                buf_pool_mutex_exit();
537
765
        }
538
766
 
539
767
        if (n_iterations > 10) {
558
786
        ulint   new_len;
559
787
 
560
788
        ut_a(buf_pool->LRU_old);
561
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
562
 
        ut_ad(3 * (BUF_LRU_OLD_MIN_LEN / 8) > BUF_LRU_OLD_TOLERANCE + 5);
 
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
563
793
 
564
794
        for (;;) {
565
795
                old_len = buf_pool->LRU_old_len;
566
796
                new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
567
797
 
568
 
                ut_a(buf_pool->LRU_old->in_LRU_list);
 
798
                ut_ad(buf_pool->LRU_old->in_LRU_list);
569
799
 
570
800
                /* Update the LRU_old pointer if necessary */
571
801
 
573
803
 
574
804
                        buf_pool->LRU_old = UT_LIST_GET_PREV(
575
805
                                LRU, buf_pool->LRU_old);
576
 
                        (buf_pool->LRU_old)->old = TRUE;
 
806
                        buf_page_set_old(buf_pool->LRU_old, TRUE);
577
807
                        buf_pool->LRU_old_len++;
578
808
 
579
809
                } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
580
810
 
581
 
                        (buf_pool->LRU_old)->old = FALSE;
 
811
                        buf_page_set_old(buf_pool->LRU_old, FALSE);
582
812
                        buf_pool->LRU_old = UT_LIST_GET_NEXT(
583
813
                                LRU, buf_pool->LRU_old);
584
814
                        buf_pool->LRU_old_len--;
598
828
buf_LRU_old_init(void)
599
829
/*==================*/
600
830
{
601
 
        buf_block_t*    block;
 
831
        buf_page_t*     bpage;
602
832
 
603
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
 
833
        ut_ad(buf_pool_mutex_own());
604
834
        ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
605
835
 
606
836
        /* We first initialize all blocks in the LRU list as old and then use
607
837
        the adjust function to move the LRU_old pointer to the right
608
838
        position */
609
839
 
610
 
        block = UT_LIST_GET_FIRST(buf_pool->LRU);
 
840
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
611
841
 
612
 
        while (block != NULL) {
613
 
                ut_a(block->state == BUF_BLOCK_FILE_PAGE);
614
 
                ut_a(block->in_LRU_list);
615
 
                block->old = TRUE;
616
 
                block = UT_LIST_GET_NEXT(LRU, block);
 
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);
617
846
        }
618
847
 
619
848
        buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
623
852
}
624
853
 
625
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
/**********************************************************************
626
878
Removes a block from the LRU list. */
627
879
UNIV_INLINE
628
880
void
629
881
buf_LRU_remove_block(
630
882
/*=================*/
631
 
        buf_block_t*    block)  /* in: control block */
 
883
        buf_page_t*     bpage)  /* in: control block */
632
884
{
633
885
        ut_ad(buf_pool);
634
 
        ut_ad(block);
635
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
636
 
 
637
 
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
638
 
        ut_a(block->in_LRU_list);
 
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);
639
892
 
640
893
        /* If the LRU_old pointer is defined and points to just this block,
641
894
        move it backward one step */
642
895
 
643
 
        if (block == buf_pool->LRU_old) {
 
896
        if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
644
897
 
645
898
                /* Below: the previous block is guaranteed to exist, because
646
899
                the LRU_old pointer is only allowed to differ by the
647
900
                tolerance value from strict 3/8 of the LRU list length. */
648
901
 
649
 
                buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, block);
650
 
                (buf_pool->LRU_old)->old = TRUE;
 
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);
651
905
 
652
906
                buf_pool->LRU_old_len++;
653
 
                ut_a(buf_pool->LRU_old);
654
907
        }
655
908
 
656
909
        /* Remove the block from the LRU list */
657
 
        UT_LIST_REMOVE(LRU, buf_pool->LRU, block);
658
 
        block->in_LRU_list = FALSE;
659
 
 
660
 
        if (srv_use_awe && block->frame) {
661
 
                /* Remove from the list of mapped pages */
662
 
 
663
 
                UT_LIST_REMOVE(awe_LRU_free_mapped,
664
 
                               buf_pool->awe_LRU_free_mapped, block);
665
 
        }
 
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);
666
914
 
667
915
        /* If the LRU list is so short that LRU_old not defined, return */
668
916
        if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
675
923
        ut_ad(buf_pool->LRU_old);
676
924
 
677
925
        /* Update the LRU_old_len field if necessary */
678
 
        if (block->old) {
 
926
        if (buf_page_is_old(bpage)) {
679
927
 
680
928
                buf_pool->LRU_old_len--;
681
929
        }
685
933
}
686
934
 
687
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
/**********************************************************************
688
962
Adds a block to the LRU list end. */
689
963
UNIV_INLINE
690
964
void
691
965
buf_LRU_add_block_to_end_low(
692
966
/*=========================*/
693
 
        buf_block_t*    block)  /* in: control block */
 
967
        buf_page_t*     bpage)  /* in: control block */
694
968
{
695
 
        buf_block_t*    last_block;
 
969
        buf_page_t*     last_bpage;
696
970
 
697
971
        ut_ad(buf_pool);
698
 
        ut_ad(block);
699
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
700
 
 
701
 
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
702
 
 
703
 
        block->old = TRUE;
704
 
 
705
 
        last_block = UT_LIST_GET_LAST(buf_pool->LRU);
706
 
 
707
 
        if (last_block) {
708
 
                block->LRU_position = last_block->LRU_position;
 
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;
709
983
        } else {
710
 
                block->LRU_position = buf_pool_clock_tic();
711
 
        }
712
 
 
713
 
        ut_a(!block->in_LRU_list);
714
 
        UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block);
715
 
        block->in_LRU_list = TRUE;
716
 
 
717
 
        if (srv_use_awe && block->frame) {
718
 
                /* Add to the list of mapped pages */
719
 
 
720
 
                UT_LIST_ADD_LAST(awe_LRU_free_mapped,
721
 
                                 buf_pool->awe_LRU_free_mapped, block);
722
 
        }
 
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);
723
990
 
724
991
        if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
725
992
 
741
1008
 
742
1009
                buf_LRU_old_init();
743
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
        }
744
1017
}
745
1018
 
746
1019
/**********************************************************************
749
1022
void
750
1023
buf_LRU_add_block_low(
751
1024
/*==================*/
752
 
        buf_block_t*    block,  /* in: control block */
 
1025
        buf_page_t*     bpage,  /* in: control block */
753
1026
        ibool           old)    /* in: TRUE if should be put to the old blocks
754
1027
                                in the LRU list, else put to the start; if the
755
1028
                                LRU list is very short, the block is added to
756
1029
                                the start, regardless of this parameter */
757
1030
{
758
 
        ulint   cl;
759
 
 
760
1031
        ut_ad(buf_pool);
761
 
        ut_ad(block);
762
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
763
 
 
764
 
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
765
 
        ut_a(!block->in_LRU_list);
766
 
 
767
 
        block->old = old;
768
 
        cl = buf_pool_clock_tic();
769
 
 
770
 
        if (srv_use_awe && block->frame) {
771
 
                /* Add to the list of mapped pages; for simplicity we always
772
 
                add to the start, even if the user would have set 'old'
773
 
                TRUE */
774
 
 
775
 
                UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
776
 
                                  buf_pool->awe_LRU_free_mapped, block);
777
 
        }
 
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);
778
1039
 
779
1040
        if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
780
1041
 
781
 
                UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, block);
 
1042
                UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
782
1043
 
783
 
                block->LRU_position = cl;
784
 
                block->freed_page_clock = buf_pool->freed_page_clock;
 
1044
                bpage->LRU_position = buf_pool_clock_tic();
 
1045
                bpage->freed_page_clock = buf_pool->freed_page_clock;
785
1046
        } else {
786
1047
                UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
787
 
                                     block);
 
1048
                                     bpage);
788
1049
                buf_pool->LRU_old_len++;
789
1050
 
790
1051
                /* We copy the LRU position field of the previous block
791
1052
                to the new block */
792
1053
 
793
 
                block->LRU_position = (buf_pool->LRU_old)->LRU_position;
 
1054
                bpage->LRU_position = (buf_pool->LRU_old)->LRU_position;
794
1055
        }
795
1056
 
796
 
        block->in_LRU_list = TRUE;
 
1057
        ut_d(bpage->in_LRU_list = TRUE);
797
1058
 
798
1059
        if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
799
1060
 
810
1071
 
811
1072
                buf_LRU_old_init();
812
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
        }
813
1080
}
814
1081
 
815
1082
/**********************************************************************
816
1083
Adds a block to the LRU list. */
817
 
 
 
1084
UNIV_INTERN
818
1085
void
819
1086
buf_LRU_add_block(
820
1087
/*==============*/
821
 
        buf_block_t*    block,  /* in: control block */
 
1088
        buf_page_t*     bpage,  /* in: control block */
822
1089
        ibool           old)    /* in: TRUE if should be put to the old
823
1090
                                blocks in the LRU list, else put to the start;
824
1091
                                if the LRU list is very short, the block is
825
1092
                                added to the start, regardless of this
826
1093
                                parameter */
827
1094
{
828
 
        buf_LRU_add_block_low(block, old);
 
1095
        buf_LRU_add_block_low(bpage, old);
829
1096
}
830
1097
 
831
1098
/**********************************************************************
832
1099
Moves a block to the start of the LRU list. */
833
 
 
 
1100
UNIV_INTERN
834
1101
void
835
1102
buf_LRU_make_block_young(
836
1103
/*=====================*/
837
 
        buf_block_t*    block)  /* in: control block */
 
1104
        buf_page_t*     bpage)  /* in: control block */
838
1105
{
839
 
        buf_LRU_remove_block(block);
840
 
        buf_LRU_add_block_low(block, FALSE);
 
1106
        buf_LRU_remove_block(bpage);
 
1107
        buf_LRU_add_block_low(bpage, FALSE);
841
1108
}
842
1109
 
843
1110
/**********************************************************************
844
1111
Moves a block to the end of the LRU list. */
845
 
 
 
1112
UNIV_INTERN
846
1113
void
847
1114
buf_LRU_make_block_old(
848
1115
/*===================*/
849
 
        buf_block_t*    block)  /* in: control block */
850
 
{
851
 
        buf_LRU_remove_block(block);
852
 
        buf_LRU_add_block_to_end_low(block);
 
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);
853
1356
}
854
1357
 
855
1358
/**********************************************************************
856
1359
Puts a block back to the free list. */
857
 
 
 
1360
UNIV_INTERN
858
1361
void
859
1362
buf_LRU_block_free_non_file_page(
860
1363
/*=============================*/
861
1364
        buf_block_t*    block)  /* in: block, must not contain a file page */
862
1365
{
 
1366
        void*   data;
863
1367
 
864
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
 
1368
        ut_ad(buf_pool_mutex_own());
865
1369
        ut_ad(mutex_own(&block->mutex));
866
1370
        ut_ad(block);
867
1371
 
868
 
        ut_a((block->state == BUF_BLOCK_MEMORY)
869
 
             || (block->state == BUF_BLOCK_READY_FOR_USE));
870
 
 
871
 
        ut_a(block->n_pointers == 0);
872
 
        ut_a(!block->in_free_list);
873
 
 
874
 
        block->state = BUF_BLOCK_NOT_USED;
 
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);
875
1386
 
876
1387
        UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
877
1388
#ifdef UNIV_DEBUG
878
1389
        /* Wipe contents of page to reveal possible stale pointers to it */
879
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);
880
1395
#endif
881
 
        UT_LIST_ADD_FIRST(free, buf_pool->free, block);
882
 
        block->in_free_list = TRUE;
 
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);
883
1410
 
884
1411
        UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
885
 
 
886
 
        if (srv_use_awe && block->frame) {
887
 
                /* Add to the list of mapped pages */
888
 
 
889
 
                UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
890
 
                                  buf_pool->awe_LRU_free_mapped, block);
891
 
        }
892
1412
}
893
1413
 
894
1414
/**********************************************************************
895
 
Takes a block out of the LRU list and page hash table and sets the block
896
 
state to BUF_BLOCK_REMOVE_HASH. */
 
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. */
897
1422
static
898
 
void
 
1423
enum buf_page_state
899
1424
buf_LRU_block_remove_hashed_page(
900
1425
/*=============================*/
901
 
        buf_block_t*    block)  /* in: block, must contain a file page and
 
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
902
1431
                                be in a state where it can be freed; there
903
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 */
904
1435
{
905
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
906
 
        ut_ad(mutex_own(&block->mutex));
907
 
        ut_ad(block);
908
 
 
909
 
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
910
 
        ut_a(block->io_fix == 0);
911
 
        ut_a(block->buf_fix_count == 0);
912
 
        ut_a(ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) == 0);
913
 
 
914
 
        buf_LRU_remove_block(block);
 
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);
915
1447
 
916
1448
        buf_pool->freed_page_clock += 1;
917
1449
 
918
 
        /* Note that if AWE is enabled the block may not have a frame at all */
919
 
 
920
 
        buf_block_modify_clock_inc(block);
921
 
 
922
 
        if (block != buf_page_hash_get(block->space, block->offset)) {
 
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)) {
923
1511
                fprintf(stderr,
924
1512
                        "InnoDB: Error: page %lu %lu not found"
925
1513
                        " in the hash table\n",
926
 
                        (ulong) block->space,
927
 
                        (ulong) block->offset);
928
 
                if (buf_page_hash_get(block->space, block->offset)) {
 
1514
                        (ulong) bpage->space,
 
1515
                        (ulong) bpage->offset);
 
1516
                if (hashed_bpage) {
929
1517
                        fprintf(stderr,
930
1518
                                "InnoDB: In hash table we find block"
931
1519
                                " %p of %lu %lu which is not %p\n",
932
 
                                (void*) buf_page_hash_get
933
 
                                (block->space, block->offset),
934
 
                                (ulong) buf_page_hash_get
935
 
                                (block->space, block->offset)->space,
936
 
                                (ulong) buf_page_hash_get
937
 
                                (block->space, block->offset)->offset,
938
 
                                (void*) block);
 
1520
                                (const void*) hashed_bpage,
 
1521
                                (ulong) hashed_bpage->space,
 
1522
                                (ulong) hashed_bpage->offset,
 
1523
                                (const void*) bpage);
939
1524
                }
940
1525
 
941
 
#ifdef UNIV_DEBUG
 
1526
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 
1527
                mutex_exit(buf_page_get_mutex(bpage));
 
1528
                buf_pool_mutex_exit();
942
1529
                buf_print();
943
1530
                buf_LRU_print();
944
1531
                buf_validate();
945
1532
                buf_LRU_validate();
946
 
#endif
947
 
                ut_a(0);
948
 
        }
949
 
 
950
 
        HASH_DELETE(buf_block_t, hash, buf_pool->page_hash,
951
 
                    buf_page_address_fold(block->space, block->offset),
952
 
                    block);
953
 
 
954
 
        UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
955
 
        block->state = BUF_BLOCK_REMOVE_HASH;
 
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);
956
1595
}
957
1596
 
958
1597
/**********************************************************************
964
1603
        buf_block_t*    block)  /* in: block, must contain a file page and
965
1604
                                be in a state where it can be freed */
966
1605
{
967
 
        ut_ad(mutex_own(&(buf_pool->mutex)));
 
1606
        ut_ad(buf_pool_mutex_own());
968
1607
        ut_ad(mutex_own(&block->mutex));
969
1608
 
970
 
        ut_a(block->state == BUF_BLOCK_REMOVE_HASH);
971
 
 
972
 
        block->state = BUF_BLOCK_MEMORY;
 
1609
        buf_block_set_state(block, BUF_BLOCK_MEMORY);
973
1610
 
974
1611
        buf_LRU_block_free_non_file_page(block);
975
1612
}
976
1613
 
977
 
#ifdef UNIV_DEBUG
 
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
978
1651
/**************************************************************************
979
1652
Validates the LRU list. */
980
 
 
 
1653
UNIV_INTERN
981
1654
ibool
982
1655
buf_LRU_validate(void)
983
1656
/*==================*/
984
1657
{
 
1658
        buf_page_t*     bpage;
985
1659
        buf_block_t*    block;
986
1660
        ulint           old_len;
987
1661
        ulint           new_len;
988
1662
        ulint           LRU_pos;
989
1663
 
990
1664
        ut_ad(buf_pool);
991
 
        mutex_enter(&(buf_pool->mutex));
 
1665
        buf_pool_mutex_enter();
992
1666
 
993
1667
        if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
994
1668
 
999
1673
                ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
1000
1674
        }
1001
1675
 
1002
 
        UT_LIST_VALIDATE(LRU, buf_block_t, buf_pool->LRU);
 
1676
        UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU);
1003
1677
 
1004
 
        block = UT_LIST_GET_FIRST(buf_pool->LRU);
 
1678
        bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
1005
1679
 
1006
1680
        old_len = 0;
1007
1681
 
1008
 
        while (block != NULL) {
1009
 
 
1010
 
                ut_a(block->state == BUF_BLOCK_FILE_PAGE);
1011
 
 
1012
 
                if (block->old) {
 
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)) {
1013
1701
                        old_len++;
1014
1702
                }
1015
1703
 
1016
1704
                if (buf_pool->LRU_old && (old_len == 1)) {
1017
 
                        ut_a(buf_pool->LRU_old == block);
 
1705
                        ut_a(buf_pool->LRU_old == bpage);
1018
1706
                }
1019
1707
 
1020
 
                LRU_pos = block->LRU_position;
1021
 
 
1022
 
                block = UT_LIST_GET_NEXT(LRU, block);
1023
 
 
1024
 
                if (block) {
 
1708
                LRU_pos = buf_page_get_LRU_position(bpage);
 
1709
 
 
1710
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
 
1711
 
 
1712
                if (bpage) {
1025
1713
                        /* If the following assert fails, it may
1026
1714
                        not be an error: just the buf_pool clock
1027
1715
                        has wrapped around */
1028
 
                        ut_a(LRU_pos >= block->LRU_position);
 
1716
                        ut_a(LRU_pos >= buf_page_get_LRU_position(bpage));
1029
1717
                }
1030
1718
        }
1031
1719
 
1033
1721
                ut_a(buf_pool->LRU_old_len == old_len);
1034
1722
        }
1035
1723
 
1036
 
        UT_LIST_VALIDATE(free, buf_block_t, buf_pool->free);
1037
 
 
1038
 
        block = UT_LIST_GET_FIRST(buf_pool->free);
1039
 
 
1040
 
        while (block != NULL) {
1041
 
                ut_a(block->state == BUF_BLOCK_NOT_USED);
1042
 
 
1043
 
                block = UT_LIST_GET_NEXT(free, block);
1044
 
        }
1045
 
 
1046
 
        mutex_exit(&(buf_pool->mutex));
 
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();
1047
1745
        return(TRUE);
1048
1746
}
 
1747
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
1049
1748
 
 
1749
#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
1050
1750
/**************************************************************************
1051
1751
Prints the LRU list. */
1052
 
 
 
1752
UNIV_INTERN
1053
1753
void
1054
1754
buf_LRU_print(void)
1055
1755
/*===============*/
1056
1756
{
1057
 
        buf_block_t*    block;
1058
 
        buf_frame_t*    frame;
1059
 
        ulint           len;
 
1757
        const buf_page_t*       bpage;
1060
1758
 
1061
1759
        ut_ad(buf_pool);
1062
 
        mutex_enter(&(buf_pool->mutex));
 
1760
        buf_pool_mutex_enter();
1063
1761
 
1064
1762
        fprintf(stderr, "Pool ulint clock %lu\n",
1065
1763
                (ulong) buf_pool->ulint_clock);
1066
1764
 
1067
 
        block = UT_LIST_GET_FIRST(buf_pool->LRU);
1068
 
 
1069
 
        len = 0;
1070
 
 
1071
 
        while (block != NULL) {
1072
 
 
1073
 
                fprintf(stderr, "BLOCK %lu ", (ulong) block->offset);
1074
 
 
1075
 
                if (block->old) {
 
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)) {
1076
1774
                        fputs("old ", stderr);
1077
1775
                }
1078
1776
 
1079
 
                if (block->buf_fix_count) {
 
1777
                if (bpage->buf_fix_count) {
1080
1778
                        fprintf(stderr, "buffix count %lu ",
1081
 
                                (ulong) block->buf_fix_count);
1082
 
                }
1083
 
 
1084
 
                if (block->io_fix) {
1085
 
                        fprintf(stderr, "io_fix %lu ", (ulong) block->io_fix);
1086
 
                }
1087
 
 
1088
 
                if (ut_dulint_cmp(block->oldest_modification,
1089
 
                                  ut_dulint_zero) > 0) {
 
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) {
1090
1788
                        fputs("modif. ", stderr);
1091
1789
                }
1092
1790
 
1093
 
                frame = buf_block_get_frame(block);
1094
 
 
1095
 
                fprintf(stderr, "LRU pos %lu type %lu index id %lu ",
1096
 
                        (ulong) block->LRU_position,
1097
 
                        (ulong) fil_page_get_type(frame),
1098
 
                        (ulong) ut_dulint_get_low
1099
 
                        (btr_page_get_index_id(frame)));
1100
 
 
1101
 
                block = UT_LIST_GET_NEXT(LRU, block);
1102
 
                if (++len == 10) {
1103
 
                        len = 0;
1104
 
                        putc('\n', stderr);
 
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;
1105
1818
                }
 
1819
 
 
1820
                bpage = UT_LIST_GET_NEXT(LRU, bpage);
1106
1821
        }
1107
1822
 
1108
 
        mutex_exit(&(buf_pool->mutex));
 
1823
        buf_pool_mutex_exit();
1109
1824
}
1110
 
#endif /* UNIV_DEBUG */
 
1825
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */