~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*   Innobase relational database engine; Copyright (C) 2001 Innobase Oy
 
2
 
 
3
     This program is free software; you can redistribute it and/or modify
 
4
     it under the terms of the GNU General Public License 2
 
5
     as published by the Free Software Foundation in June 1991.
 
6
 
 
7
     This program is distributed in the hope that it will be useful,
 
8
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
     GNU General Public License for more details.
 
11
 
 
12
     You should have received a copy of the GNU General Public License 2
 
13
     along with this program (in file COPYING); if not, write to the Free
 
14
     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
15
/******************************************************
 
16
The database buffer buf_pool
 
17
 
 
18
(c) 1995 Innobase Oy
 
19
 
 
20
Created 11/5/1995 Heikki Tuuri
 
21
*******************************************************/
 
22
 
 
23
#include "buf0buf.h"
 
24
 
 
25
#ifdef UNIV_NONINL
 
26
#include "buf0buf.ic"
 
27
#endif
 
28
 
 
29
#include "mem0mem.h"
 
30
#include "btr0btr.h"
 
31
#include "fil0fil.h"
 
32
#include "lock0lock.h"
 
33
#include "btr0sea.h"
 
34
#include "ibuf0ibuf.h"
 
35
#include "dict0dict.h"
 
36
#include "log0recv.h"
 
37
#include "log0log.h"
 
38
#include "trx0undo.h"
 
39
#include "srv0srv.h"
 
40
 
 
41
/*
 
42
                IMPLEMENTATION OF THE BUFFER POOL
 
43
                =================================
 
44
 
 
45
Performance improvement:
 
46
------------------------
 
47
Thread scheduling in NT may be so slow that the OS wait mechanism should
 
48
not be used even in waiting for disk reads to complete.
 
49
Rather, we should put waiting query threads to the queue of
 
50
waiting jobs, and let the OS thread do something useful while the i/o
 
51
is processed. In this way we could remove most OS thread switches in
 
52
an i/o-intensive benchmark like TPC-C.
 
53
 
 
54
A possibility is to put a user space thread library between the database
 
55
and NT. User space thread libraries might be very fast.
 
56
 
 
57
SQL Server 7.0 can be configured to use 'fibers' which are lightweight
 
58
threads in NT. These should be studied.
 
59
 
 
60
                Buffer frames and blocks
 
61
                ------------------------
 
62
Following the terminology of Gray and Reuter, we call the memory
 
63
blocks where file pages are loaded buffer frames. For each buffer
 
64
frame there is a control block, or shortly, a block, in the buffer
 
65
control array. The control info which does not need to be stored
 
66
in the file along with the file page, resides in the control block.
 
67
 
 
68
                Buffer pool struct
 
69
                ------------------
 
70
The buffer buf_pool contains a single mutex which protects all the
 
71
control data structures of the buf_pool. The content of a buffer frame is
 
72
protected by a separate read-write lock in its control block, though.
 
73
These locks can be locked and unlocked without owning the buf_pool mutex.
 
74
The OS events in the buf_pool struct can be waited for without owning the
 
75
buf_pool mutex.
 
76
 
 
77
The buf_pool mutex is a hot-spot in main memory, causing a lot of
 
78
memory bus traffic on multiprocessor systems when processors
 
79
alternately access the mutex. On our Pentium, the mutex is accessed
 
80
maybe every 10 microseconds. We gave up the solution to have mutexes
 
81
for each control block, for instance, because it seemed to be
 
82
complicated.
 
83
 
 
84
A solution to reduce mutex contention of the buf_pool mutex is to
 
85
create a separate mutex for the page hash table. On Pentium,
 
86
accessing the hash table takes 2 microseconds, about half
 
87
of the total buf_pool mutex hold time.
 
88
 
 
89
                Control blocks
 
90
                --------------
 
91
 
 
92
The control block contains, for instance, the bufferfix count
 
93
which is incremented when a thread wants a file page to be fixed
 
94
in a buffer frame. The bufferfix operation does not lock the
 
95
contents of the frame, however. For this purpose, the control
 
96
block contains a read-write lock.
 
97
 
 
98
The buffer frames have to be aligned so that the start memory
 
99
address of a frame is divisible by the universal page size, which
 
100
is a power of two.
 
101
 
 
102
We intend to make the buffer buf_pool size on-line reconfigurable,
 
103
that is, the buf_pool size can be changed without closing the database.
 
104
Then the database administarator may adjust it to be bigger
 
105
at night, for example. The control block array must
 
106
contain enough control blocks for the maximum buffer buf_pool size
 
107
which is used in the particular database.
 
108
If the buf_pool size is cut, we exploit the virtual memory mechanism of
 
109
the OS, and just refrain from using frames at high addresses. Then the OS
 
110
can swap them to disk.
 
111
 
 
112
The control blocks containing file pages are put to a hash table
 
113
according to the file address of the page.
 
114
We could speed up the access to an individual page by using
 
115
"pointer swizzling": we could replace the page references on
 
116
non-leaf index pages by direct pointers to the page, if it exists
 
117
in the buf_pool. We could make a separate hash table where we could
 
118
chain all the page references in non-leaf pages residing in the buf_pool,
 
119
using the page reference as the hash key,
 
120
and at the time of reading of a page update the pointers accordingly.
 
121
Drawbacks of this solution are added complexity and,
 
122
possibly, extra space required on non-leaf pages for memory pointers.
 
123
A simpler solution is just to speed up the hash table mechanism
 
124
in the database, using tables whose size is a power of 2.
 
125
 
 
126
                Lists of blocks
 
127
                ---------------
 
128
 
 
129
There are several lists of control blocks. The free list contains
 
130
blocks which are currently not used.
 
131
 
 
132
The LRU-list contains all the blocks holding a file page
 
133
except those for which the bufferfix count is non-zero.
 
134
The pages are in the LRU list roughly in the order of the last
 
135
access to the page, so that the oldest pages are at the end of the
 
136
list. We also keep a pointer to near the end of the LRU list,
 
137
which we can use when we want to artificially age a page in the
 
138
buf_pool. This is used if we know that some page is not needed
 
139
again for some time: we insert the block right after the pointer,
 
140
causing it to be replaced sooner than would noramlly be the case.
 
141
Currently this aging mechanism is used for read-ahead mechanism
 
142
of pages, and it can also be used when there is a scan of a full
 
143
table which cannot fit in the memory. Putting the pages near the
 
144
of the LRU list, we make sure that most of the buf_pool stays in the
 
145
main memory, undisturbed.
 
146
 
 
147
The chain of modified blocks contains the blocks
 
148
holding file pages that have been modified in the memory
 
149
but not written to disk yet. The block with the oldest modification
 
150
which has not yet been written to disk is at the end of the chain.
 
151
 
 
152
                Loading a file page
 
153
                -------------------
 
154
 
 
155
First, a victim block for replacement has to be found in the
 
156
buf_pool. It is taken from the free list or searched for from the
 
157
end of the LRU-list. An exclusive lock is reserved for the frame,
 
158
the io_fix field is set in the block fixing the block in buf_pool,
 
159
and the io-operation for loading the page is queued. The io-handler thread
 
160
releases the X-lock on the frame and resets the io_fix field
 
161
when the io operation completes.
 
162
 
 
163
A thread may request the above operation using the function
 
164
buf_page_get(). It may then continue to request a lock on the frame.
 
165
The lock is granted when the io-handler releases the x-lock.
 
166
 
 
167
                Read-ahead
 
168
                ----------
 
169
 
 
170
The read-ahead mechanism is intended to be intelligent and
 
171
isolated from the semantically higher levels of the database
 
172
index management. From the higher level we only need the
 
173
information if a file page has a natural successor or
 
174
predecessor page. On the leaf level of a B-tree index,
 
175
these are the next and previous pages in the natural
 
176
order of the pages.
 
177
 
 
178
Let us first explain the read-ahead mechanism when the leafs
 
179
of a B-tree are scanned in an ascending or descending order.
 
180
When a read page is the first time referenced in the buf_pool,
 
181
the buffer manager checks if it is at the border of a so-called
 
182
linear read-ahead area. The tablespace is divided into these
 
183
areas of size 64 blocks, for example. So if the page is at the
 
184
border of such an area, the read-ahead mechanism checks if
 
185
all the other blocks in the area have been accessed in an
 
186
ascending or descending order. If this is the case, the system
 
187
looks at the natural successor or predecessor of the page,
 
188
checks if that is at the border of another area, and in this case
 
189
issues read-requests for all the pages in that area. Maybe
 
190
we could relax the condition that all the pages in the area
 
191
have to be accessed: if data is deleted from a table, there may
 
192
appear holes of unused pages in the area.
 
193
 
 
194
A different read-ahead mechanism is used when there appears
 
195
to be a random access pattern to a file.
 
196
If a new page is referenced in the buf_pool, and several pages
 
197
of its random access area (for instance, 32 consecutive pages
 
198
in a tablespace) have recently been referenced, we may predict
 
199
that the whole area may be needed in the near future, and issue
 
200
the read requests for the whole area.
 
201
 
 
202
                AWE implementation
 
203
                ------------------
 
204
 
 
205
By a 'block' we mean the buffer header of type buf_block_t. By a 'page'
 
206
we mean the physical 16 kB memory area allocated from RAM for that block.
 
207
By a 'frame' we mean a 16 kB area in the virtual address space of the
 
208
process, in the frame_mem of buf_pool.
 
209
 
 
210
We can map pages to the frames of the buffer pool.
 
211
 
 
212
1) A buffer block allocated to use as a non-data page, e.g., to the lock
 
213
table, is always mapped to a frame.
 
214
2) A bufferfixed or io-fixed data page is always mapped to a frame.
 
215
3) When we need to map a block to frame, we look from the list
 
216
awe_LRU_free_mapped and try to unmap its last block, but note that
 
217
bufferfixed or io-fixed pages cannot be unmapped.
 
218
4) For every frame in the buffer pool there is always a block whose page is
 
219
mapped to it. When we create the buffer pool, we map the first elements
 
220
in the free list to the frames.
 
221
5) When we have AWE enabled, we disable adaptive hash indexes.
 
222
*/
 
223
 
 
224
/* Value in microseconds */
 
225
static const int WAIT_FOR_READ  = 20000;
 
226
 
 
227
buf_pool_t*     buf_pool = NULL; /* The buffer buf_pool of the database */
 
228
 
 
229
#ifdef UNIV_DEBUG
 
230
ulint           buf_dbg_counter = 0; /* This is used to insert validation
 
231
                                        operations in excution in the
 
232
                                        debug version */
 
233
ibool           buf_debug_prints = FALSE; /* If this is set TRUE,
 
234
                                        the program prints info whenever
 
235
                                        read-ahead or flush occurs */
 
236
#endif /* UNIV_DEBUG */
 
237
/************************************************************************
 
238
Calculates a page checksum which is stored to the page when it is written
 
239
to a file. Note that we must be careful to calculate the same value on
 
240
32-bit and 64-bit architectures. */
 
241
 
 
242
ulint
 
243
buf_calc_page_new_checksum(
 
244
/*=======================*/
 
245
                        /* out: checksum */
 
246
        byte*    page)  /* in: buffer page */
 
247
{
 
248
        ulint checksum;
 
249
 
 
250
        /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
 
251
        ..._ARCH_LOG_NO, are written outside the buffer pool to the first
 
252
        pages of data files, we have to skip them in the page checksum
 
253
        calculation.
 
254
        We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
 
255
        checksum is stored, and also the last 8 bytes of page because
 
256
        there we store the old formula checksum. */
 
257
 
 
258
        checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
 
259
                                  FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
 
260
                + ut_fold_binary(page + FIL_PAGE_DATA,
 
261
                                 UNIV_PAGE_SIZE - FIL_PAGE_DATA
 
262
                                 - FIL_PAGE_END_LSN_OLD_CHKSUM);
 
263
        checksum = checksum & 0xFFFFFFFFUL;
 
264
 
 
265
        return(checksum);
 
266
}
 
267
 
 
268
/************************************************************************
 
269
In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
 
270
looked at the first few bytes of the page. This calculates that old
 
271
checksum.
 
272
NOTE: we must first store the new formula checksum to
 
273
FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
 
274
because this takes that field as an input! */
 
275
 
 
276
ulint
 
277
buf_calc_page_old_checksum(
 
278
/*=======================*/
 
279
                        /* out: checksum */
 
280
        byte*    page)  /* in: buffer page */
 
281
{
 
282
        ulint checksum;
 
283
 
 
284
        checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
 
285
 
 
286
        checksum = checksum & 0xFFFFFFFFUL;
 
287
 
 
288
        return(checksum);
 
289
}
 
290
 
 
291
/************************************************************************
 
292
Checks if a page is corrupt. */
 
293
 
 
294
ibool
 
295
buf_page_is_corrupted(
 
296
/*==================*/
 
297
                                /* out: TRUE if corrupted */
 
298
        byte*   read_buf)       /* in: a database page */
 
299
{
 
300
        ulint   checksum;
 
301
        ulint   old_checksum;
 
302
        ulint   checksum_field;
 
303
        ulint   old_checksum_field;
 
304
#ifndef UNIV_HOTBACKUP
 
305
        dulint  current_lsn;
 
306
#endif
 
307
        if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
 
308
            != mach_read_from_4(read_buf + UNIV_PAGE_SIZE
 
309
                                - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
 
310
 
 
311
                /* Stored log sequence numbers at the start and the end
 
312
                of page do not match */
 
313
 
 
314
                return(TRUE);
 
315
        }
 
316
 
 
317
#ifndef UNIV_HOTBACKUP
 
318
        if (recv_lsn_checks_on && log_peek_lsn(&current_lsn)) {
 
319
                if (ut_dulint_cmp(current_lsn,
 
320
                                  mach_read_from_8(read_buf + FIL_PAGE_LSN))
 
321
                    < 0) {
 
322
                        ut_print_timestamp(stderr);
 
323
 
 
324
                        fprintf(stderr,
 
325
                                "  InnoDB: Error: page %lu log sequence number"
 
326
                                " %lu %lu\n"
 
327
                                "InnoDB: is in the future! Current system "
 
328
                                "log sequence number %lu %lu.\n"
 
329
                                "InnoDB: Your database may be corrupt or "
 
330
                                "you may have copied the InnoDB\n"
 
331
                                "InnoDB: tablespace but not the InnoDB "
 
332
                                "log files. See\n"
 
333
                                "InnoDB: http://dev.mysql.com/doc/refman/"
 
334
                                "5.1/en/forcing-recovery.html\n"
 
335
                                "InnoDB: for more information.\n",
 
336
                                (ulong) mach_read_from_4(read_buf
 
337
                                                         + FIL_PAGE_OFFSET),
 
338
                                (ulong) ut_dulint_get_high
 
339
                                (mach_read_from_8(read_buf + FIL_PAGE_LSN)),
 
340
                                (ulong) ut_dulint_get_low
 
341
                                (mach_read_from_8(read_buf + FIL_PAGE_LSN)),
 
342
                                (ulong) ut_dulint_get_high(current_lsn),
 
343
                                (ulong) ut_dulint_get_low(current_lsn));
 
344
                }
 
345
        }
 
346
#endif
 
347
 
 
348
        /* If we use checksums validation, make additional check before
 
349
        returning TRUE to ensure that the checksum is not equal to
 
350
        BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
 
351
        disabled. Otherwise, skip checksum calculation and return FALSE */
 
352
 
 
353
        if (srv_use_checksums) {
 
354
                old_checksum = buf_calc_page_old_checksum(read_buf);
 
355
 
 
356
                old_checksum_field = mach_read_from_4(
 
357
                        read_buf + UNIV_PAGE_SIZE
 
358
                        - FIL_PAGE_END_LSN_OLD_CHKSUM);
 
359
 
 
360
                /* There are 2 valid formulas for old_checksum_field:
 
361
 
 
362
                1. Very old versions of InnoDB only stored 8 byte lsn to the
 
363
                start and the end of the page.
 
364
 
 
365
                2. Newer InnoDB versions store the old formula checksum
 
366
                there. */
 
367
 
 
368
                if (old_checksum_field != mach_read_from_4(read_buf
 
369
                                                           + FIL_PAGE_LSN)
 
370
                    && old_checksum_field != old_checksum
 
371
                    && old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
 
372
 
 
373
                        return(TRUE);
 
374
                }
 
375
 
 
376
                checksum = buf_calc_page_new_checksum(read_buf);
 
377
                checksum_field = mach_read_from_4(read_buf
 
378
                                                  + FIL_PAGE_SPACE_OR_CHKSUM);
 
379
 
 
380
                /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
 
381
                (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
 
382
 
 
383
                if (checksum_field != 0 && checksum_field != checksum
 
384
                    && checksum_field != BUF_NO_CHECKSUM_MAGIC) {
 
385
 
 
386
                        return(TRUE);
 
387
                }
 
388
        }
 
389
 
 
390
        return(FALSE);
 
391
}
 
392
 
 
393
/************************************************************************
 
394
Prints a page to stderr. */
 
395
 
 
396
void
 
397
buf_page_print(
 
398
/*===========*/
 
399
        byte*   read_buf)       /* in: a database page */
 
400
{
 
401
        dict_index_t*   index;
 
402
        ulint           checksum;
 
403
        ulint           old_checksum;
 
404
 
 
405
        ut_print_timestamp(stderr);
 
406
        fprintf(stderr, "  InnoDB: Page dump in ascii and hex (%lu bytes):\n",
 
407
                (ulint)UNIV_PAGE_SIZE);
 
408
        ut_print_buf(stderr, read_buf, UNIV_PAGE_SIZE);
 
409
        fputs("InnoDB: End of page dump\n", stderr);
 
410
 
 
411
        checksum = srv_use_checksums
 
412
                ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 
413
        old_checksum = srv_use_checksums
 
414
                ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 
415
 
 
416
        ut_print_timestamp(stderr);
 
417
        fprintf(stderr,
 
418
                "  InnoDB: Page checksum %lu, prior-to-4.0.14-form"
 
419
                " checksum %lu\n"
 
420
                "InnoDB: stored checksum %lu, prior-to-4.0.14-form"
 
421
                " stored checksum %lu\n"
 
422
                "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
 
423
                " at page end %lu\n"
 
424
                "InnoDB: Page number (if stored to page already) %lu,\n"
 
425
                "InnoDB: space id (if created with >= MySQL-4.1.1"
 
426
                " and stored already) %lu\n",
 
427
                (ulong) checksum, (ulong) old_checksum,
 
428
                (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
 
429
                (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
 
430
                                         - FIL_PAGE_END_LSN_OLD_CHKSUM),
 
431
                (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
 
432
                (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
 
433
                (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
 
434
                                         - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
 
435
                (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
 
436
                (ulong) mach_read_from_4(read_buf
 
437
                                         + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
 
438
 
 
439
        if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
 
440
            == TRX_UNDO_INSERT) {
 
441
                fprintf(stderr,
 
442
                        "InnoDB: Page may be an insert undo log page\n");
 
443
        } else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
 
444
                                    + TRX_UNDO_PAGE_TYPE)
 
445
                   == TRX_UNDO_UPDATE) {
 
446
                fprintf(stderr,
 
447
                        "InnoDB: Page may be an update undo log page\n");
 
448
        }
 
449
 
 
450
        switch (fil_page_get_type(read_buf)) {
 
451
        case FIL_PAGE_INDEX:
 
452
                fprintf(stderr,
 
453
                        "InnoDB: Page may be an index page where"
 
454
                        " index id is %lu %lu\n",
 
455
                        (ulong) ut_dulint_get_high
 
456
                        (btr_page_get_index_id(read_buf)),
 
457
                        (ulong) ut_dulint_get_low
 
458
                        (btr_page_get_index_id(read_buf)));
 
459
 
 
460
                /* If the code is in ibbackup, dict_sys may be uninitialized,
 
461
                i.e., NULL */
 
462
 
 
463
                if (dict_sys != NULL) {
 
464
 
 
465
                        index = dict_index_find_on_id_low(
 
466
                                btr_page_get_index_id(read_buf));
 
467
                        if (index) {
 
468
                                fputs("InnoDB: (", stderr);
 
469
                                dict_index_name_print(stderr, NULL, index);
 
470
                                fputs(")\n", stderr);
 
471
                        }
 
472
                }
 
473
                break;
 
474
        case FIL_PAGE_INODE:
 
475
                fputs("InnoDB: Page may be an 'inode' page\n", stderr);
 
476
                break;
 
477
        case FIL_PAGE_IBUF_FREE_LIST:
 
478
                fputs("InnoDB: Page may be an insert buffer free list page\n",
 
479
                      stderr);
 
480
                break;
 
481
        case FIL_PAGE_TYPE_ALLOCATED:
 
482
                fputs("InnoDB: Page may be a freshly allocated page\n",
 
483
                      stderr);
 
484
                break;
 
485
        case FIL_PAGE_IBUF_BITMAP:
 
486
                fputs("InnoDB: Page may be an insert buffer bitmap page\n",
 
487
                      stderr);
 
488
                break;
 
489
        case FIL_PAGE_TYPE_SYS:
 
490
                fputs("InnoDB: Page may be a system page\n",
 
491
                      stderr);
 
492
                break;
 
493
        case FIL_PAGE_TYPE_TRX_SYS:
 
494
                fputs("InnoDB: Page may be a transaction system page\n",
 
495
                      stderr);
 
496
                break;
 
497
        case FIL_PAGE_TYPE_FSP_HDR:
 
498
                fputs("InnoDB: Page may be a file space header page\n",
 
499
                      stderr);
 
500
                break;
 
501
        case FIL_PAGE_TYPE_XDES:
 
502
                fputs("InnoDB: Page may be an extent descriptor page\n",
 
503
                      stderr);
 
504
                break;
 
505
        case FIL_PAGE_TYPE_BLOB:
 
506
                fputs("InnoDB: Page may be a BLOB page\n",
 
507
                      stderr);
 
508
                break;
 
509
        }
 
510
}
 
511
 
 
512
/************************************************************************
 
513
Initializes a buffer control block when the buf_pool is created. */
 
514
static
 
515
void
 
516
buf_block_init(
 
517
/*===========*/
 
518
        buf_block_t*    block,  /* in: pointer to control block */
 
519
        byte*           frame)  /* in: pointer to buffer frame, or NULL if in
 
520
                                the case of AWE there is no frame */
 
521
{
 
522
        block->magic_n = 0;
 
523
 
 
524
        block->state = BUF_BLOCK_NOT_USED;
 
525
 
 
526
        block->frame = frame;
 
527
 
 
528
        block->awe_info = NULL;
 
529
 
 
530
        block->buf_fix_count = 0;
 
531
        block->io_fix = 0;
 
532
 
 
533
        block->modify_clock = ut_dulint_zero;
 
534
 
 
535
        block->file_page_was_freed = FALSE;
 
536
 
 
537
        block->check_index_page_at_flush = FALSE;
 
538
        block->index = NULL;
 
539
 
 
540
        block->in_free_list = FALSE;
 
541
        block->in_LRU_list = FALSE;
 
542
 
 
543
        block->n_pointers = 0;
 
544
 
 
545
        mutex_create(&block->mutex, SYNC_BUF_BLOCK);
 
546
 
 
547
        rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
 
548
        ut_ad(rw_lock_validate(&(block->lock)));
 
549
 
 
550
#ifdef UNIV_SYNC_DEBUG
 
551
        rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
 
552
#endif /* UNIV_SYNC_DEBUG */
 
553
}
 
554
 
 
555
/************************************************************************
 
556
Creates the buffer pool. */
 
557
 
 
558
buf_pool_t*
 
559
buf_pool_init(
 
560
/*==========*/
 
561
                                /* out, own: buf_pool object, NULL if not
 
562
                                enough memory or error */
 
563
        ulint   max_size,       /* in: maximum size of the buf_pool in
 
564
                                blocks */
 
565
        ulint   curr_size,      /* in: current size to use, must be <=
 
566
                                max_size, currently must be equal to
 
567
                                max_size */
 
568
        ulint   n_frames)       /* in: number of frames; if AWE is used,
 
569
                                this is the size of the address space window
 
570
                                where physical memory pages are mapped; if
 
571
                                AWE is not used then this must be the same
 
572
                                as max_size */
 
573
{
 
574
        byte*           frame;
 
575
        ulint           i;
 
576
        buf_block_t*    block;
 
577
 
 
578
        ut_a(max_size == curr_size);
 
579
        ut_a(srv_use_awe || n_frames == max_size);
 
580
 
 
581
        if (n_frames > curr_size) {
 
582
                fprintf(stderr,
 
583
                        "InnoDB: AWE: Error: you must specify in my.cnf"
 
584
                        " .._awe_mem_mb larger\n"
 
585
                        "InnoDB: than .._buffer_pool_size. Now the former"
 
586
                        " is %lu pages,\n"
 
587
                        "InnoDB: the latter %lu pages.\n",
 
588
                        (ulong) curr_size, (ulong) n_frames);
 
589
 
 
590
                return(NULL);
 
591
        }
 
592
 
 
593
        buf_pool = mem_alloc(sizeof(buf_pool_t));
 
594
 
 
595
        /* 1. Initialize general fields
 
596
        ---------------------------- */
 
597
        mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
 
598
 
 
599
        mutex_enter(&(buf_pool->mutex));
 
600
 
 
601
        if (srv_use_awe) {
 
602
                /*----------------------------------------*/
 
603
                /* Allocate the virtual address space window, i.e., the
 
604
                buffer pool frames */
 
605
 
 
606
                buf_pool->frame_mem = os_awe_allocate_virtual_mem_window(
 
607
                        UNIV_PAGE_SIZE * (n_frames + 1));
 
608
 
 
609
                /* Allocate the physical memory for AWE and the AWE info array
 
610
                for buf_pool */
 
611
 
 
612
                if ((curr_size % ((1024 * 1024) / UNIV_PAGE_SIZE)) != 0) {
 
613
 
 
614
                        fprintf(stderr,
 
615
                                "InnoDB: AWE: Error: physical memory must be"
 
616
                                " allocated in full megabytes.\n"
 
617
                                "InnoDB: Trying to allocate %lu"
 
618
                                " database pages.\n",
 
619
                                (ulong) curr_size);
 
620
 
 
621
                        return(NULL);
 
622
                }
 
623
 
 
624
                if (!os_awe_allocate_physical_mem(&(buf_pool->awe_info),
 
625
                                                  curr_size
 
626
                                                  / ((1024 * 1024)
 
627
                                                     / UNIV_PAGE_SIZE))) {
 
628
 
 
629
                        return(NULL);
 
630
                }
 
631
                /*----------------------------------------*/
 
632
        } else {
 
633
                buf_pool->frame_mem = os_mem_alloc_large(
 
634
                        UNIV_PAGE_SIZE * (n_frames + 1), TRUE, FALSE);
 
635
        }
 
636
 
 
637
        if (buf_pool->frame_mem == NULL) {
 
638
 
 
639
                return(NULL);
 
640
        }
 
641
 
 
642
        buf_pool->blocks = ut_malloc(sizeof(buf_block_t) * max_size);
 
643
 
 
644
        if (buf_pool->blocks == NULL) {
 
645
 
 
646
                return(NULL);
 
647
        }
 
648
 
 
649
        buf_pool->max_size = max_size;
 
650
        buf_pool->curr_size = curr_size;
 
651
 
 
652
        buf_pool->n_frames = n_frames;
 
653
 
 
654
        /* Align pointer to the first frame */
 
655
 
 
656
        frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
 
657
 
 
658
        buf_pool->frame_zero = frame;
 
659
        buf_pool->high_end = frame + UNIV_PAGE_SIZE * n_frames;
 
660
 
 
661
        if (srv_use_awe) {
 
662
                /*----------------------------------------*/
 
663
                /* Map an initial part of the allocated physical memory to
 
664
                the window */
 
665
 
 
666
                os_awe_map_physical_mem_to_window(buf_pool->frame_zero,
 
667
                                                  n_frames
 
668
                                                  * (UNIV_PAGE_SIZE
 
669
                                                     / OS_AWE_X86_PAGE_SIZE),
 
670
                                                  buf_pool->awe_info);
 
671
                /*----------------------------------------*/
 
672
        }
 
673
 
 
674
        buf_pool->blocks_of_frames = ut_malloc(sizeof(void*) * n_frames);
 
675
 
 
676
        if (buf_pool->blocks_of_frames == NULL) {
 
677
 
 
678
                return(NULL);
 
679
        }
 
680
 
 
681
        /* Init block structs and assign frames for them; in the case of
 
682
        AWE there are less frames than blocks. Then we assign the frames
 
683
        to the first blocks (we already mapped the memory above). We also
 
684
        init the awe_info for every block. */
 
685
 
 
686
        for (i = 0; i < max_size; i++) {
 
687
 
 
688
                block = buf_pool_get_nth_block(buf_pool, i);
 
689
 
 
690
                if (i < n_frames) {
 
691
                        frame = buf_pool->frame_zero + i * UNIV_PAGE_SIZE;
 
692
                        *(buf_pool->blocks_of_frames + i) = block;
 
693
                } else {
 
694
                        frame = NULL;
 
695
                }
 
696
 
 
697
                buf_block_init(block, frame);
 
698
 
 
699
                if (srv_use_awe) {
 
700
                        /*----------------------------------------*/
 
701
                        block->awe_info = buf_pool->awe_info
 
702
                                + i * (UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE);
 
703
                        /*----------------------------------------*/
 
704
                }
 
705
        }
 
706
 
 
707
        buf_pool->page_hash = hash_create(2 * max_size);
 
708
 
 
709
        buf_pool->n_pend_reads = 0;
 
710
 
 
711
        buf_pool->last_printout_time = time(NULL);
 
712
 
 
713
        buf_pool->n_pages_read = 0;
 
714
        buf_pool->n_pages_written = 0;
 
715
        buf_pool->n_pages_created = 0;
 
716
        buf_pool->n_pages_awe_remapped = 0;
 
717
 
 
718
        buf_pool->n_page_gets = 0;
 
719
        buf_pool->n_page_gets_old = 0;
 
720
        buf_pool->n_pages_read_old = 0;
 
721
        buf_pool->n_pages_written_old = 0;
 
722
        buf_pool->n_pages_created_old = 0;
 
723
        buf_pool->n_pages_awe_remapped_old = 0;
 
724
 
 
725
        /* 2. Initialize flushing fields
 
726
        ---------------------------- */
 
727
        UT_LIST_INIT(buf_pool->flush_list);
 
728
 
 
729
        for (i = BUF_FLUSH_LRU; i <= BUF_FLUSH_LIST; i++) {
 
730
                buf_pool->n_flush[i] = 0;
 
731
                buf_pool->init_flush[i] = FALSE;
 
732
                buf_pool->no_flush[i] = os_event_create(NULL);
 
733
        }
 
734
 
 
735
        buf_pool->LRU_flush_ended = 0;
 
736
 
 
737
        buf_pool->ulint_clock = 1;
 
738
        buf_pool->freed_page_clock = 0;
 
739
 
 
740
        /* 3. Initialize LRU fields
 
741
        ---------------------------- */
 
742
        UT_LIST_INIT(buf_pool->LRU);
 
743
 
 
744
        buf_pool->LRU_old = NULL;
 
745
 
 
746
        UT_LIST_INIT(buf_pool->awe_LRU_free_mapped);
 
747
 
 
748
        /* Add control blocks to the free list */
 
749
        UT_LIST_INIT(buf_pool->free);
 
750
 
 
751
        for (i = 0; i < curr_size; i++) {
 
752
 
 
753
                block = buf_pool_get_nth_block(buf_pool, i);
 
754
 
 
755
                if (block->frame) {
 
756
                        /* Wipe contents of frame to eliminate a Purify
 
757
                        warning */
 
758
 
 
759
#ifdef HAVE_purify
 
760
                        memset(block->frame, '\0', UNIV_PAGE_SIZE);
 
761
#endif
 
762
                        if (srv_use_awe) {
 
763
                                /* Add to the list of blocks mapped to
 
764
                                frames */
 
765
 
 
766
                                UT_LIST_ADD_LAST(awe_LRU_free_mapped,
 
767
                                                 buf_pool->awe_LRU_free_mapped,
 
768
                                                 block);
 
769
                        }
 
770
                }
 
771
 
 
772
                UT_LIST_ADD_LAST(free, buf_pool->free, block);
 
773
                block->in_free_list = TRUE;
 
774
        }
 
775
 
 
776
        mutex_exit(&(buf_pool->mutex));
 
777
 
 
778
        if (srv_use_adaptive_hash_indexes) {
 
779
                btr_search_sys_create(curr_size * UNIV_PAGE_SIZE
 
780
                                      / sizeof(void*) / 64);
 
781
        } else {
 
782
                /* Create only a small dummy system */
 
783
                btr_search_sys_create(1000);
 
784
        }
 
785
 
 
786
        return(buf_pool);
 
787
}
 
788
 
 
789
/************************************************************************
 
790
Maps the page of block to a frame, if not mapped yet. Unmaps some page
 
791
from the end of the awe_LRU_free_mapped. */
 
792
 
 
793
void
 
794
buf_awe_map_page_to_frame(
 
795
/*======================*/
 
796
        buf_block_t*    block,          /* in: block whose page should be
 
797
                                        mapped to a frame */
 
798
        ibool           add_to_mapped_list) /* in: TRUE if we in the case
 
799
                                        we need to map the page should also
 
800
                                        add the block to the
 
801
                                        awe_LRU_free_mapped list */
 
802
{
 
803
        buf_block_t*    bck;
 
804
 
 
805
        ut_ad(mutex_own(&(buf_pool->mutex)));
 
806
        ut_ad(block);
 
807
 
 
808
        if (block->frame) {
 
809
 
 
810
                return;
 
811
        }
 
812
 
 
813
        /* Scan awe_LRU_free_mapped from the end and try to find a block
 
814
        which is not bufferfixed or io-fixed */
 
815
 
 
816
        bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped);
 
817
 
 
818
        while (bck) {
 
819
                ibool skip;
 
820
 
 
821
                mutex_enter(&bck->mutex);
 
822
 
 
823
                skip = (bck->state == BUF_BLOCK_FILE_PAGE
 
824
                        && (bck->buf_fix_count != 0 || bck->io_fix != 0));
 
825
 
 
826
                if (skip) {
 
827
                        mutex_exit(&bck->mutex);
 
828
 
 
829
                        /* We have to skip this */
 
830
                        bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck);
 
831
                } else {
 
832
                        /* We can map block to the frame of bck */
 
833
 
 
834
                        os_awe_map_physical_mem_to_window(
 
835
                                bck->frame,
 
836
                                UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE,
 
837
                                block->awe_info);
 
838
 
 
839
                        block->frame = bck->frame;
 
840
 
 
841
                        *(buf_pool->blocks_of_frames
 
842
                          + (((ulint)(block->frame
 
843
                                      - buf_pool->frame_zero))
 
844
                             >> UNIV_PAGE_SIZE_SHIFT))
 
845
                                = block;
 
846
 
 
847
                        bck->frame = NULL;
 
848
                        UT_LIST_REMOVE(awe_LRU_free_mapped,
 
849
                                       buf_pool->awe_LRU_free_mapped,
 
850
                                       bck);
 
851
 
 
852
                        if (add_to_mapped_list) {
 
853
                                UT_LIST_ADD_FIRST(
 
854
                                        awe_LRU_free_mapped,
 
855
                                        buf_pool->awe_LRU_free_mapped,
 
856
                                        block);
 
857
                        }
 
858
 
 
859
                        buf_pool->n_pages_awe_remapped++;
 
860
 
 
861
                        mutex_exit(&bck->mutex);
 
862
 
 
863
                        return;
 
864
                }
 
865
        }
 
866
 
 
867
        fprintf(stderr,
 
868
                "InnoDB: AWE: Fatal error: cannot find a page to unmap\n"
 
869
                "InnoDB: awe_LRU_free_mapped list length %lu\n",
 
870
                (ulong) UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
 
871
 
 
872
        ut_a(0);
 
873
}
 
874
 
 
875
/************************************************************************
 
876
Allocates a buffer block. */
 
877
UNIV_INLINE
 
878
buf_block_t*
 
879
buf_block_alloc(void)
 
880
/*=================*/
 
881
                                /* out, own: the allocated block; also if AWE
 
882
                                is used it is guaranteed that the page is
 
883
                                mapped to a frame */
 
884
{
 
885
        buf_block_t*    block;
 
886
 
 
887
        block = buf_LRU_get_free_block();
 
888
 
 
889
        return(block);
 
890
}
 
891
 
 
892
/************************************************************************
 
893
Moves to the block to the start of the LRU list if there is a danger
 
894
that the block would drift out of the buffer pool. */
 
895
UNIV_INLINE
 
896
void
 
897
buf_block_make_young(
 
898
/*=================*/
 
899
        buf_block_t*    block)  /* in: block to make younger */
 
900
{
 
901
        ut_ad(!mutex_own(&(buf_pool->mutex)));
 
902
 
 
903
        /* Note that we read freed_page_clock's without holding any mutex:
 
904
        this is allowed since the result is used only in heuristics */
 
905
 
 
906
        if (buf_block_peek_if_too_old(block)) {
 
907
 
 
908
                mutex_enter(&buf_pool->mutex);
 
909
                /* There has been freeing activity in the LRU list:
 
910
                best to move to the head of the LRU list */
 
911
 
 
912
                buf_LRU_make_block_young(block);
 
913
                mutex_exit(&buf_pool->mutex);
 
914
        }
 
915
}
 
916
 
 
917
/************************************************************************
 
918
Moves a page to the start of the buffer pool LRU list. This high-level
 
919
function can be used to prevent an important page from from slipping out of
 
920
the buffer pool. */
 
921
 
 
922
void
 
923
buf_page_make_young(
 
924
/*================*/
 
925
        buf_frame_t*    frame)  /* in: buffer frame of a file page */
 
926
{
 
927
        buf_block_t*    block;
 
928
 
 
929
        mutex_enter(&(buf_pool->mutex));
 
930
 
 
931
        block = buf_block_align(frame);
 
932
 
 
933
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
934
 
 
935
        buf_LRU_make_block_young(block);
 
936
 
 
937
        mutex_exit(&(buf_pool->mutex));
 
938
}
 
939
 
 
940
/************************************************************************
 
941
Frees a buffer block which does not contain a file page. */
 
942
UNIV_INLINE
 
943
void
 
944
buf_block_free(
 
945
/*===========*/
 
946
        buf_block_t*    block)  /* in, own: block to be freed */
 
947
{
 
948
        mutex_enter(&(buf_pool->mutex));
 
949
 
 
950
        mutex_enter(&block->mutex);
 
951
 
 
952
        ut_a(block->state != BUF_BLOCK_FILE_PAGE);
 
953
 
 
954
        buf_LRU_block_free_non_file_page(block);
 
955
 
 
956
        mutex_exit(&block->mutex);
 
957
 
 
958
        mutex_exit(&(buf_pool->mutex));
 
959
}
 
960
 
 
961
/*************************************************************************
 
962
Allocates a buffer frame. */
 
963
 
 
964
buf_frame_t*
 
965
buf_frame_alloc(void)
 
966
/*=================*/
 
967
                                /* out: buffer frame */
 
968
{
 
969
        return(buf_block_alloc()->frame);
 
970
}
 
971
 
 
972
/*************************************************************************
 
973
Frees a buffer frame which does not contain a file page. */
 
974
 
 
975
void
 
976
buf_frame_free(
 
977
/*===========*/
 
978
        buf_frame_t*    frame)  /* in: buffer frame */
 
979
{
 
980
        buf_block_free(buf_block_align(frame));
 
981
}
 
982
 
 
983
/************************************************************************
 
984
Returns the buffer control block if the page can be found in the buffer
 
985
pool. NOTE that it is possible that the page is not yet read
 
986
from disk, though. This is a very low-level function: use with care! */
 
987
 
 
988
buf_block_t*
 
989
buf_page_peek_block(
 
990
/*================*/
 
991
                        /* out: control block if found from page hash table,
 
992
                        otherwise NULL; NOTE that the page is not necessarily
 
993
                        yet read from disk! */
 
994
        ulint   space,  /* in: space id */
 
995
        ulint   offset) /* in: page number */
 
996
{
 
997
        buf_block_t*    block;
 
998
 
 
999
        mutex_enter_fast(&(buf_pool->mutex));
 
1000
 
 
1001
        block = buf_page_hash_get(space, offset);
 
1002
 
 
1003
        mutex_exit(&(buf_pool->mutex));
 
1004
 
 
1005
        return(block);
 
1006
}
 
1007
 
 
1008
/************************************************************************
 
1009
Resets the check_index_page_at_flush field of a page if found in the buffer
 
1010
pool. */
 
1011
 
 
1012
void
 
1013
buf_reset_check_index_page_at_flush(
 
1014
/*================================*/
 
1015
        ulint   space,  /* in: space id */
 
1016
        ulint   offset) /* in: page number */
 
1017
{
 
1018
        buf_block_t*    block;
 
1019
 
 
1020
        mutex_enter_fast(&(buf_pool->mutex));
 
1021
 
 
1022
        block = buf_page_hash_get(space, offset);
 
1023
 
 
1024
        if (block) {
 
1025
                block->check_index_page_at_flush = FALSE;
 
1026
        }
 
1027
 
 
1028
        mutex_exit(&(buf_pool->mutex));
 
1029
}
 
1030
 
 
1031
/************************************************************************
 
1032
Returns the current state of is_hashed of a page. FALSE if the page is
 
1033
not in the pool. NOTE that this operation does not fix the page in the
 
1034
pool if it is found there. */
 
1035
 
 
1036
ibool
 
1037
buf_page_peek_if_search_hashed(
 
1038
/*===========================*/
 
1039
                        /* out: TRUE if page hash index is built in search
 
1040
                        system */
 
1041
        ulint   space,  /* in: space id */
 
1042
        ulint   offset) /* in: page number */
 
1043
{
 
1044
        buf_block_t*    block;
 
1045
        ibool           is_hashed;
 
1046
 
 
1047
        mutex_enter_fast(&(buf_pool->mutex));
 
1048
 
 
1049
        block = buf_page_hash_get(space, offset);
 
1050
 
 
1051
        if (!block) {
 
1052
                is_hashed = FALSE;
 
1053
        } else {
 
1054
                is_hashed = block->is_hashed;
 
1055
        }
 
1056
 
 
1057
        mutex_exit(&(buf_pool->mutex));
 
1058
 
 
1059
        return(is_hashed);
 
1060
}
 
1061
 
 
1062
/************************************************************************
 
1063
Returns TRUE if the page can be found in the buffer pool hash table. NOTE
 
1064
that it is possible that the page is not yet read from disk, though. */
 
1065
 
 
1066
ibool
 
1067
buf_page_peek(
 
1068
/*==========*/
 
1069
                        /* out: TRUE if found from page hash table,
 
1070
                        NOTE that the page is not necessarily yet read
 
1071
                        from disk! */
 
1072
        ulint   space,  /* in: space id */
 
1073
        ulint   offset) /* in: page number */
 
1074
{
 
1075
        if (buf_page_peek_block(space, offset)) {
 
1076
 
 
1077
                return(TRUE);
 
1078
        }
 
1079
 
 
1080
        return(FALSE);
 
1081
}
 
1082
 
 
1083
/************************************************************************
 
1084
Sets file_page_was_freed TRUE if the page is found in the buffer pool.
 
1085
This function should be called when we free a file page and want the
 
1086
debug version to check that it is not accessed any more unless
 
1087
reallocated. */
 
1088
 
 
1089
buf_block_t*
 
1090
buf_page_set_file_page_was_freed(
 
1091
/*=============================*/
 
1092
                        /* out: control block if found from page hash table,
 
1093
                        otherwise NULL */
 
1094
        ulint   space,  /* in: space id */
 
1095
        ulint   offset) /* in: page number */
 
1096
{
 
1097
        buf_block_t*    block;
 
1098
 
 
1099
        mutex_enter_fast(&(buf_pool->mutex));
 
1100
 
 
1101
        block = buf_page_hash_get(space, offset);
 
1102
 
 
1103
        if (block) {
 
1104
                block->file_page_was_freed = TRUE;
 
1105
        }
 
1106
 
 
1107
        mutex_exit(&(buf_pool->mutex));
 
1108
 
 
1109
        return(block);
 
1110
}
 
1111
 
 
1112
/************************************************************************
 
1113
Sets file_page_was_freed FALSE if the page is found in the buffer pool.
 
1114
This function should be called when we free a file page and want the
 
1115
debug version to check that it is not accessed any more unless
 
1116
reallocated. */
 
1117
 
 
1118
buf_block_t*
 
1119
buf_page_reset_file_page_was_freed(
 
1120
/*===============================*/
 
1121
                        /* out: control block if found from page hash table,
 
1122
                        otherwise NULL */
 
1123
        ulint   space,  /* in: space id */
 
1124
        ulint   offset) /* in: page number */
 
1125
{
 
1126
        buf_block_t*    block;
 
1127
 
 
1128
        mutex_enter_fast(&(buf_pool->mutex));
 
1129
 
 
1130
        block = buf_page_hash_get(space, offset);
 
1131
 
 
1132
        if (block) {
 
1133
                block->file_page_was_freed = FALSE;
 
1134
        }
 
1135
 
 
1136
        mutex_exit(&(buf_pool->mutex));
 
1137
 
 
1138
        return(block);
 
1139
}
 
1140
 
 
1141
/************************************************************************
 
1142
This is the general function used to get access to a database page. */
 
1143
 
 
1144
buf_frame_t*
 
1145
buf_page_get_gen(
 
1146
/*=============*/
 
1147
                                /* out: pointer to the frame or NULL */
 
1148
        ulint           space,  /* in: space id */
 
1149
        ulint           offset, /* in: page number */
 
1150
        ulint           rw_latch,/* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
 
1151
        buf_frame_t*    guess,  /* in: guessed frame or NULL */
 
1152
        ulint           mode,   /* in: BUF_GET, BUF_GET_IF_IN_POOL,
 
1153
                                BUF_GET_NO_LATCH, BUF_GET_NOWAIT */
 
1154
        const char*     file,   /* in: file name */
 
1155
        ulint           line,   /* in: line where called */
 
1156
        mtr_t*          mtr)    /* in: mini-transaction */
 
1157
{
 
1158
        buf_block_t*    block;
 
1159
        ibool           accessed;
 
1160
        ulint           fix_type;
 
1161
        ibool           success;
 
1162
        ibool           must_read;
 
1163
 
 
1164
        ut_ad(mtr);
 
1165
        ut_ad((rw_latch == RW_S_LATCH)
 
1166
              || (rw_latch == RW_X_LATCH)
 
1167
              || (rw_latch == RW_NO_LATCH));
 
1168
        ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
 
1169
        ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
 
1170
              || (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
 
1171
#ifndef UNIV_LOG_DEBUG
 
1172
        ut_ad(!ibuf_inside() || ibuf_page(space, offset));
 
1173
#endif
 
1174
        buf_pool->n_page_gets++;
 
1175
loop:
 
1176
        block = NULL;
 
1177
        mutex_enter_fast(&(buf_pool->mutex));
 
1178
 
 
1179
        if (guess) {
 
1180
                block = buf_block_align(guess);
 
1181
 
 
1182
                if ((offset != block->offset) || (space != block->space)
 
1183
                    || (block->state != BUF_BLOCK_FILE_PAGE)) {
 
1184
 
 
1185
                        block = NULL;
 
1186
                }
 
1187
        }
 
1188
 
 
1189
        if (block == NULL) {
 
1190
                block = buf_page_hash_get(space, offset);
 
1191
        }
 
1192
 
 
1193
        if (block == NULL) {
 
1194
                /* Page not in buf_pool: needs to be read from file */
 
1195
 
 
1196
                mutex_exit(&(buf_pool->mutex));
 
1197
 
 
1198
                if (mode == BUF_GET_IF_IN_POOL) {
 
1199
 
 
1200
                        return(NULL);
 
1201
                }
 
1202
 
 
1203
                buf_read_page(space, offset);
 
1204
 
 
1205
#ifdef UNIV_DEBUG
 
1206
                buf_dbg_counter++;
 
1207
 
 
1208
                if (buf_dbg_counter % 37 == 0) {
 
1209
                        ut_ad(buf_validate());
 
1210
                }
 
1211
#endif
 
1212
                goto loop;
 
1213
        }
 
1214
 
 
1215
        mutex_enter(&block->mutex);
 
1216
 
 
1217
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
1218
 
 
1219
        must_read = FALSE;
 
1220
 
 
1221
        if (block->io_fix == BUF_IO_READ) {
 
1222
 
 
1223
                must_read = TRUE;
 
1224
 
 
1225
                if (mode == BUF_GET_IF_IN_POOL) {
 
1226
                        /* The page is only being read to buffer */
 
1227
                        mutex_exit(&buf_pool->mutex);
 
1228
                        mutex_exit(&block->mutex);
 
1229
 
 
1230
                        return(NULL);
 
1231
                }
 
1232
        }
 
1233
 
 
1234
        /* If AWE is enabled and the page is not mapped to a frame, then
 
1235
        map it */
 
1236
 
 
1237
        if (block->frame == NULL) {
 
1238
                ut_a(srv_use_awe);
 
1239
 
 
1240
                /* We set second parameter TRUE because the block is in the
 
1241
                LRU list and we must put it to awe_LRU_free_mapped list once
 
1242
                mapped to a frame */
 
1243
 
 
1244
                buf_awe_map_page_to_frame(block, TRUE);
 
1245
        }
 
1246
 
 
1247
#ifdef UNIV_SYNC_DEBUG
 
1248
        buf_block_buf_fix_inc_debug(block, file, line);
 
1249
#else
 
1250
        buf_block_buf_fix_inc(block);
 
1251
#endif
 
1252
        mutex_exit(&buf_pool->mutex);
 
1253
 
 
1254
        /* Check if this is the first access to the page */
 
1255
 
 
1256
        accessed = block->accessed;
 
1257
 
 
1258
        block->accessed = TRUE;
 
1259
 
 
1260
        mutex_exit(&block->mutex);
 
1261
 
 
1262
        buf_block_make_young(block);
 
1263
 
 
1264
#ifdef UNIV_DEBUG_FILE_ACCESSES
 
1265
        ut_a(block->file_page_was_freed == FALSE);
 
1266
#endif
 
1267
 
 
1268
#ifdef UNIV_DEBUG
 
1269
        buf_dbg_counter++;
 
1270
 
 
1271
        if (buf_dbg_counter % 5771 == 0) {
 
1272
                ut_ad(buf_validate());
 
1273
        }
 
1274
#endif
 
1275
        ut_ad(block->buf_fix_count > 0);
 
1276
        ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
 
1277
 
 
1278
        if (mode == BUF_GET_NOWAIT) {
 
1279
                if (rw_latch == RW_S_LATCH) {
 
1280
                        success = rw_lock_s_lock_func_nowait(&(block->lock),
 
1281
                                                             file, line);
 
1282
                        fix_type = MTR_MEMO_PAGE_S_FIX;
 
1283
                } else {
 
1284
                        ut_ad(rw_latch == RW_X_LATCH);
 
1285
                        success = rw_lock_x_lock_func_nowait(&(block->lock),
 
1286
                                                             file, line);
 
1287
                        fix_type = MTR_MEMO_PAGE_X_FIX;
 
1288
                }
 
1289
 
 
1290
                if (!success) {
 
1291
                        mutex_enter(&block->mutex);
 
1292
 
 
1293
                        block->buf_fix_count--;
 
1294
 
 
1295
                        mutex_exit(&block->mutex);
 
1296
#ifdef UNIV_SYNC_DEBUG
 
1297
                        rw_lock_s_unlock(&(block->debug_latch));
 
1298
#endif
 
1299
 
 
1300
                        return(NULL);
 
1301
                }
 
1302
        } else if (rw_latch == RW_NO_LATCH) {
 
1303
 
 
1304
                if (must_read) {
 
1305
                        /* Let us wait until the read operation
 
1306
                        completes */
 
1307
 
 
1308
                        for (;;) {
 
1309
                                mutex_enter(&block->mutex);
 
1310
 
 
1311
                                if (block->io_fix == BUF_IO_READ) {
 
1312
 
 
1313
                                        mutex_exit(&block->mutex);
 
1314
 
 
1315
                                        os_thread_sleep(WAIT_FOR_READ);
 
1316
                                } else {
 
1317
 
 
1318
                                        mutex_exit(&block->mutex);
 
1319
 
 
1320
                                        break;
 
1321
                                }
 
1322
                        }
 
1323
                }
 
1324
 
 
1325
                fix_type = MTR_MEMO_BUF_FIX;
 
1326
        } else if (rw_latch == RW_S_LATCH) {
 
1327
 
 
1328
                rw_lock_s_lock_func(&(block->lock), 0, file, line);
 
1329
 
 
1330
                fix_type = MTR_MEMO_PAGE_S_FIX;
 
1331
        } else {
 
1332
                rw_lock_x_lock_func(&(block->lock), 0, file, line);
 
1333
 
 
1334
                fix_type = MTR_MEMO_PAGE_X_FIX;
 
1335
        }
 
1336
 
 
1337
        mtr_memo_push(mtr, block, fix_type);
 
1338
 
 
1339
        if (!accessed) {
 
1340
                /* In the case of a first access, try to apply linear
 
1341
                read-ahead */
 
1342
 
 
1343
                buf_read_ahead_linear(space, offset);
 
1344
        }
 
1345
 
 
1346
#ifdef UNIV_IBUF_DEBUG
 
1347
        ut_a(ibuf_count_get(block->space, block->offset) == 0);
 
1348
#endif
 
1349
        return(block->frame);
 
1350
}
 
1351
 
 
1352
/************************************************************************
 
1353
This is the general function used to get optimistic access to a database
 
1354
page. */
 
1355
 
 
1356
ibool
 
1357
buf_page_optimistic_get_func(
 
1358
/*=========================*/
 
1359
                                /* out: TRUE if success */
 
1360
        ulint           rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
 
1361
        buf_block_t*    block,  /* in: guessed buffer block */
 
1362
        buf_frame_t*    guess,  /* in: guessed frame; note that AWE may move
 
1363
                                frames */
 
1364
        dulint          modify_clock,/* in: modify clock value if mode is
 
1365
                                ..._GUESS_ON_CLOCK */
 
1366
        const char*     file,   /* in: file name */
 
1367
        ulint           line,   /* in: line where called */
 
1368
        mtr_t*          mtr)    /* in: mini-transaction */
 
1369
{
 
1370
        ibool           accessed;
 
1371
        ibool           success;
 
1372
        ulint           fix_type;
 
1373
 
 
1374
        ut_ad(mtr && block);
 
1375
        ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
 
1376
 
 
1377
        /* If AWE is used, block may have a different frame now, e.g., NULL */
 
1378
 
 
1379
        mutex_enter(&block->mutex);
 
1380
 
 
1381
        if (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
 
1382
            || UNIV_UNLIKELY(block->frame != guess)) {
 
1383
 
 
1384
                mutex_exit(&block->mutex);
 
1385
 
 
1386
                return(FALSE);
 
1387
        }
 
1388
 
 
1389
#ifdef UNIV_SYNC_DEBUG
 
1390
        buf_block_buf_fix_inc_debug(block, file, line);
 
1391
#else
 
1392
        buf_block_buf_fix_inc(block);
 
1393
#endif
 
1394
        accessed = block->accessed;
 
1395
        block->accessed = TRUE;
 
1396
 
 
1397
        mutex_exit(&block->mutex);
 
1398
 
 
1399
        buf_block_make_young(block);
 
1400
 
 
1401
        /* Check if this is the first access to the page */
 
1402
 
 
1403
        ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset));
 
1404
 
 
1405
        if (rw_latch == RW_S_LATCH) {
 
1406
                success = rw_lock_s_lock_func_nowait(&(block->lock),
 
1407
                                                     file, line);
 
1408
                fix_type = MTR_MEMO_PAGE_S_FIX;
 
1409
        } else {
 
1410
                success = rw_lock_x_lock_func_nowait(&(block->lock),
 
1411
                                                     file, line);
 
1412
                fix_type = MTR_MEMO_PAGE_X_FIX;
 
1413
        }
 
1414
 
 
1415
        if (UNIV_UNLIKELY(!success)) {
 
1416
                mutex_enter(&block->mutex);
 
1417
 
 
1418
                block->buf_fix_count--;
 
1419
 
 
1420
                mutex_exit(&block->mutex);
 
1421
 
 
1422
#ifdef UNIV_SYNC_DEBUG
 
1423
                rw_lock_s_unlock(&(block->debug_latch));
 
1424
#endif
 
1425
                return(FALSE);
 
1426
        }
 
1427
 
 
1428
        if (UNIV_UNLIKELY(!UT_DULINT_EQ(modify_clock, block->modify_clock))) {
 
1429
#ifdef UNIV_SYNC_DEBUG
 
1430
                buf_page_dbg_add_level(block->frame, SYNC_NO_ORDER_CHECK);
 
1431
#endif /* UNIV_SYNC_DEBUG */
 
1432
                if (rw_latch == RW_S_LATCH) {
 
1433
                        rw_lock_s_unlock(&(block->lock));
 
1434
                } else {
 
1435
                        rw_lock_x_unlock(&(block->lock));
 
1436
                }
 
1437
 
 
1438
                mutex_enter(&block->mutex);
 
1439
 
 
1440
                block->buf_fix_count--;
 
1441
 
 
1442
                mutex_exit(&block->mutex);
 
1443
 
 
1444
#ifdef UNIV_SYNC_DEBUG
 
1445
                rw_lock_s_unlock(&(block->debug_latch));
 
1446
#endif
 
1447
                return(FALSE);
 
1448
        }
 
1449
 
 
1450
        mtr_memo_push(mtr, block, fix_type);
 
1451
 
 
1452
#ifdef UNIV_DEBUG
 
1453
        buf_dbg_counter++;
 
1454
 
 
1455
        if (buf_dbg_counter % 5771 == 0) {
 
1456
                ut_ad(buf_validate());
 
1457
        }
 
1458
#endif
 
1459
        ut_ad(block->buf_fix_count > 0);
 
1460
        ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
 
1461
 
 
1462
#ifdef UNIV_DEBUG_FILE_ACCESSES
 
1463
        ut_a(block->file_page_was_freed == FALSE);
 
1464
#endif
 
1465
        if (UNIV_UNLIKELY(!accessed)) {
 
1466
                /* In the case of a first access, try to apply linear
 
1467
                read-ahead */
 
1468
 
 
1469
                buf_read_ahead_linear(buf_frame_get_space_id(guess),
 
1470
                                      buf_frame_get_page_no(guess));
 
1471
        }
 
1472
 
 
1473
#ifdef UNIV_IBUF_DEBUG
 
1474
        ut_a(ibuf_count_get(block->space, block->offset) == 0);
 
1475
#endif
 
1476
        buf_pool->n_page_gets++;
 
1477
 
 
1478
        return(TRUE);
 
1479
}
 
1480
 
 
1481
/************************************************************************
 
1482
This is used to get access to a known database page, when no waiting can be
 
1483
done. For example, if a search in an adaptive hash index leads us to this
 
1484
frame. */
 
1485
 
 
1486
ibool
 
1487
buf_page_get_known_nowait(
 
1488
/*======================*/
 
1489
                                /* out: TRUE if success */
 
1490
        ulint           rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
 
1491
        buf_frame_t*    guess,  /* in: the known page frame */
 
1492
        ulint           mode,   /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
 
1493
        const char*     file,   /* in: file name */
 
1494
        ulint           line,   /* in: line where called */
 
1495
        mtr_t*          mtr)    /* in: mini-transaction */
 
1496
{
 
1497
        buf_block_t*    block;
 
1498
        ibool           success;
 
1499
        ulint           fix_type;
 
1500
 
 
1501
        ut_ad(mtr);
 
1502
        ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
 
1503
 
 
1504
        block = buf_block_align(guess);
 
1505
 
 
1506
        mutex_enter(&block->mutex);
 
1507
 
 
1508
        if (block->state == BUF_BLOCK_REMOVE_HASH) {
 
1509
                /* Another thread is just freeing the block from the LRU list
 
1510
                of the buffer pool: do not try to access this page; this
 
1511
                attempt to access the page can only come through the hash
 
1512
                index because when the buffer block state is ..._REMOVE_HASH,
 
1513
                we have already removed it from the page address hash table
 
1514
                of the buffer pool. */
 
1515
 
 
1516
                mutex_exit(&block->mutex);
 
1517
 
 
1518
                return(FALSE);
 
1519
        }
 
1520
 
 
1521
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
1522
 
 
1523
#ifdef UNIV_SYNC_DEBUG
 
1524
        buf_block_buf_fix_inc_debug(block, file, line);
 
1525
#else
 
1526
        buf_block_buf_fix_inc(block);
 
1527
#endif
 
1528
        mutex_exit(&block->mutex);
 
1529
 
 
1530
        if (mode == BUF_MAKE_YOUNG) {
 
1531
                buf_block_make_young(block);
 
1532
        }
 
1533
 
 
1534
        ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
 
1535
 
 
1536
        if (rw_latch == RW_S_LATCH) {
 
1537
                success = rw_lock_s_lock_func_nowait(&(block->lock),
 
1538
                                                     file, line);
 
1539
                fix_type = MTR_MEMO_PAGE_S_FIX;
 
1540
        } else {
 
1541
                success = rw_lock_x_lock_func_nowait(&(block->lock),
 
1542
                                                     file, line);
 
1543
                fix_type = MTR_MEMO_PAGE_X_FIX;
 
1544
        }
 
1545
 
 
1546
        if (!success) {
 
1547
                mutex_enter(&block->mutex);
 
1548
 
 
1549
                block->buf_fix_count--;
 
1550
 
 
1551
                mutex_exit(&block->mutex);
 
1552
 
 
1553
#ifdef UNIV_SYNC_DEBUG
 
1554
                rw_lock_s_unlock(&(block->debug_latch));
 
1555
#endif
 
1556
 
 
1557
                return(FALSE);
 
1558
        }
 
1559
 
 
1560
        mtr_memo_push(mtr, block, fix_type);
 
1561
 
 
1562
#ifdef UNIV_DEBUG
 
1563
        buf_dbg_counter++;
 
1564
 
 
1565
        if (buf_dbg_counter % 5771 == 0) {
 
1566
                ut_ad(buf_validate());
 
1567
        }
 
1568
#endif
 
1569
        ut_ad(block->buf_fix_count > 0);
 
1570
        ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
 
1571
#ifdef UNIV_DEBUG_FILE_ACCESSES
 
1572
        ut_a(block->file_page_was_freed == FALSE);
 
1573
#endif
 
1574
 
 
1575
#ifdef UNIV_IBUF_DEBUG
 
1576
        ut_a((mode == BUF_KEEP_OLD)
 
1577
             || (ibuf_count_get(block->space, block->offset) == 0));
 
1578
#endif
 
1579
        buf_pool->n_page_gets++;
 
1580
 
 
1581
        return(TRUE);
 
1582
}
 
1583
 
 
1584
/************************************************************************
 
1585
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
 
1586
 
 
1587
void
 
1588
buf_page_init_for_backup_restore(
 
1589
/*=============================*/
 
1590
        ulint           space,  /* in: space id */
 
1591
        ulint           offset, /* in: offset of the page within space
 
1592
                                in units of a page */
 
1593
        buf_block_t*    block)  /* in: block to init */
 
1594
{
 
1595
        /* Set the state of the block */
 
1596
        block->magic_n          = BUF_BLOCK_MAGIC_N;
 
1597
 
 
1598
        block->state            = BUF_BLOCK_FILE_PAGE;
 
1599
        block->space            = space;
 
1600
        block->offset           = offset;
 
1601
 
 
1602
        block->lock_hash_val    = 0;
 
1603
 
 
1604
        block->freed_page_clock = 0;
 
1605
 
 
1606
        block->newest_modification = ut_dulint_zero;
 
1607
        block->oldest_modification = ut_dulint_zero;
 
1608
 
 
1609
        block->accessed         = FALSE;
 
1610
        block->buf_fix_count    = 0;
 
1611
        block->io_fix           = 0;
 
1612
 
 
1613
        block->n_hash_helps     = 0;
 
1614
        block->is_hashed        = FALSE;
 
1615
        block->n_fields         = 1;
 
1616
        block->n_bytes          = 0;
 
1617
        block->left_side        = TRUE;
 
1618
 
 
1619
        block->file_page_was_freed = FALSE;
 
1620
}
 
1621
 
 
1622
/************************************************************************
 
1623
Inits a page to the buffer buf_pool. */
 
1624
static
 
1625
void
 
1626
buf_page_init(
 
1627
/*==========*/
 
1628
        ulint           space,  /* in: space id */
 
1629
        ulint           offset, /* in: offset of the page within space
 
1630
                                in units of a page */
 
1631
        buf_block_t*    block)  /* in: block to init */
 
1632
{
 
1633
 
 
1634
        ut_ad(mutex_own(&(buf_pool->mutex)));
 
1635
        ut_ad(mutex_own(&(block->mutex)));
 
1636
        ut_a(block->state != BUF_BLOCK_FILE_PAGE);
 
1637
 
 
1638
        /* Set the state of the block */
 
1639
        block->magic_n          = BUF_BLOCK_MAGIC_N;
 
1640
 
 
1641
        block->state            = BUF_BLOCK_FILE_PAGE;
 
1642
        block->space            = space;
 
1643
        block->offset           = offset;
 
1644
 
 
1645
        block->check_index_page_at_flush = FALSE;
 
1646
        block->index            = NULL;
 
1647
 
 
1648
        block->lock_hash_val    = lock_rec_hash(space, offset);
 
1649
 
 
1650
#ifdef UNIV_DEBUG_VALGRIND
 
1651
        if (!space) {
 
1652
                /* Silence valid Valgrind warnings about uninitialized
 
1653
                data being written to data files.  There are some unused
 
1654
                bytes on some pages that InnoDB does not initialize. */
 
1655
                UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
 
1656
        }
 
1657
#endif /* UNIV_DEBUG_VALGRIND */
 
1658
 
 
1659
        /* Insert into the hash table of file pages */
 
1660
 
 
1661
        if (buf_page_hash_get(space, offset)) {
 
1662
                fprintf(stderr,
 
1663
                        "InnoDB: Error: page %lu %lu already found"
 
1664
                        " in the hash table\n",
 
1665
                        (ulong) space,
 
1666
                        (ulong) offset);
 
1667
#ifdef UNIV_DEBUG
 
1668
                buf_print();
 
1669
                buf_LRU_print();
 
1670
                buf_validate();
 
1671
                buf_LRU_validate();
 
1672
#endif /* UNIV_DEBUG */
 
1673
                ut_a(0);
 
1674
        }
 
1675
 
 
1676
        HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
 
1677
                    buf_page_address_fold(space, offset), block);
 
1678
 
 
1679
        block->freed_page_clock = 0;
 
1680
 
 
1681
        block->newest_modification = ut_dulint_zero;
 
1682
        block->oldest_modification = ut_dulint_zero;
 
1683
 
 
1684
        block->accessed         = FALSE;
 
1685
        block->buf_fix_count    = 0;
 
1686
        block->io_fix           = 0;
 
1687
 
 
1688
        block->n_hash_helps     = 0;
 
1689
        block->is_hashed        = FALSE;
 
1690
        block->n_fields         = 1;
 
1691
        block->n_bytes          = 0;
 
1692
        block->left_side        = TRUE;
 
1693
 
 
1694
        block->file_page_was_freed = FALSE;
 
1695
}
 
1696
 
 
1697
/************************************************************************
 
1698
Function which inits a page for read to the buffer buf_pool. If the page is
 
1699
(1) already in buf_pool, or
 
1700
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
 
1701
(3) if the space is deleted or being deleted,
 
1702
then this function does nothing.
 
1703
Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
 
1704
on the buffer frame. The io-handler must take care that the flag is cleared
 
1705
and the lock released later. This is one of the functions which perform the
 
1706
state transition NOT_USED => FILE_PAGE to a block (the other is
 
1707
buf_page_create). */
 
1708
 
 
1709
buf_block_t*
 
1710
buf_page_init_for_read(
 
1711
/*===================*/
 
1712
                                /* out: pointer to the block or NULL */
 
1713
        ulint*          err,    /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
 
1714
        ulint           mode,   /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
 
1715
        ulint           space,  /* in: space id */
 
1716
        ib_longlong     tablespace_version,/* in: prevents reading from a wrong
 
1717
                                version of the tablespace in case we have done
 
1718
                                DISCARD + IMPORT */
 
1719
        ulint           offset) /* in: page number */
 
1720
{
 
1721
        buf_block_t*    block;
 
1722
        mtr_t           mtr;
 
1723
 
 
1724
        ut_ad(buf_pool);
 
1725
 
 
1726
        *err = DB_SUCCESS;
 
1727
 
 
1728
        if (mode == BUF_READ_IBUF_PAGES_ONLY) {
 
1729
                /* It is a read-ahead within an ibuf routine */
 
1730
 
 
1731
                ut_ad(!ibuf_bitmap_page(offset));
 
1732
                ut_ad(ibuf_inside());
 
1733
 
 
1734
                mtr_start(&mtr);
 
1735
 
 
1736
                if (!ibuf_page_low(space, offset, &mtr)) {
 
1737
 
 
1738
                        mtr_commit(&mtr);
 
1739
 
 
1740
                        return(NULL);
 
1741
                }
 
1742
        } else {
 
1743
                ut_ad(mode == BUF_READ_ANY_PAGE);
 
1744
        }
 
1745
 
 
1746
        block = buf_block_alloc();
 
1747
 
 
1748
        ut_a(block);
 
1749
 
 
1750
        mutex_enter(&(buf_pool->mutex));
 
1751
        mutex_enter(&block->mutex);
 
1752
 
 
1753
        if (fil_tablespace_deleted_or_being_deleted_in_mem(
 
1754
                    space, tablespace_version)) {
 
1755
                *err = DB_TABLESPACE_DELETED;
 
1756
        }
 
1757
 
 
1758
        if (*err == DB_TABLESPACE_DELETED
 
1759
            || NULL != buf_page_hash_get(space, offset)) {
 
1760
 
 
1761
                /* The page belongs to a space which has been
 
1762
                deleted or is being deleted, or the page is
 
1763
                already in buf_pool, return */
 
1764
 
 
1765
                mutex_exit(&block->mutex);
 
1766
                mutex_exit(&(buf_pool->mutex));
 
1767
 
 
1768
                buf_block_free(block);
 
1769
 
 
1770
                if (mode == BUF_READ_IBUF_PAGES_ONLY) {
 
1771
 
 
1772
                        mtr_commit(&mtr);
 
1773
                }
 
1774
 
 
1775
                return(NULL);
 
1776
        }
 
1777
 
 
1778
        ut_ad(block);
 
1779
 
 
1780
        buf_page_init(space, offset, block);
 
1781
 
 
1782
        /* The block must be put to the LRU list, to the old blocks */
 
1783
 
 
1784
        buf_LRU_add_block(block, TRUE);         /* TRUE == to old blocks */
 
1785
 
 
1786
        block->io_fix = BUF_IO_READ;
 
1787
 
 
1788
        buf_pool->n_pend_reads++;
 
1789
 
 
1790
        /* We set a pass-type x-lock on the frame because then the same
 
1791
        thread which called for the read operation (and is running now at
 
1792
        this point of code) can wait for the read to complete by waiting
 
1793
        for the x-lock on the frame; if the x-lock were recursive, the
 
1794
        same thread would illegally get the x-lock before the page read
 
1795
        is completed. The x-lock is cleared by the io-handler thread. */
 
1796
 
 
1797
        rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
 
1798
 
 
1799
        mutex_exit(&block->mutex);
 
1800
        mutex_exit(&(buf_pool->mutex));
 
1801
 
 
1802
        if (mode == BUF_READ_IBUF_PAGES_ONLY) {
 
1803
 
 
1804
                mtr_commit(&mtr);
 
1805
        }
 
1806
 
 
1807
        return(block);
 
1808
}
 
1809
 
 
1810
/************************************************************************
 
1811
Initializes a page to the buffer buf_pool. The page is usually not read
 
1812
from a file even if it cannot be found in the buffer buf_pool. This is one
 
1813
of the functions which perform to a block a state transition NOT_USED =>
 
1814
FILE_PAGE (the other is buf_page_init_for_read above). */
 
1815
 
 
1816
buf_frame_t*
 
1817
buf_page_create(
 
1818
/*============*/
 
1819
                        /* out: pointer to the frame, page bufferfixed */
 
1820
        ulint   space,  /* in: space id */
 
1821
        ulint   offset, /* in: offset of the page within space in units of
 
1822
                        a page */
 
1823
        mtr_t*  mtr)    /* in: mini-transaction handle */
 
1824
{
 
1825
        buf_frame_t*    frame;
 
1826
        buf_block_t*    block;
 
1827
        buf_block_t*    free_block      = NULL;
 
1828
 
 
1829
        ut_ad(mtr);
 
1830
 
 
1831
        free_block = buf_LRU_get_free_block();
 
1832
 
 
1833
        mutex_enter(&(buf_pool->mutex));
 
1834
 
 
1835
        block = buf_page_hash_get(space, offset);
 
1836
 
 
1837
        if (block != NULL) {
 
1838
#ifdef UNIV_IBUF_DEBUG
 
1839
                ut_a(ibuf_count_get(block->space, block->offset) == 0);
 
1840
#endif
 
1841
                block->file_page_was_freed = FALSE;
 
1842
 
 
1843
                /* Page can be found in buf_pool */
 
1844
                mutex_exit(&(buf_pool->mutex));
 
1845
 
 
1846
                buf_block_free(free_block);
 
1847
 
 
1848
                frame = buf_page_get_with_no_latch(space, offset, mtr);
 
1849
 
 
1850
                return(frame);
 
1851
        }
 
1852
 
 
1853
        /* If we get here, the page was not in buf_pool: init it there */
 
1854
 
 
1855
#ifdef UNIV_DEBUG
 
1856
        if (buf_debug_prints) {
 
1857
                fprintf(stderr, "Creating space %lu page %lu to buffer\n",
 
1858
                        (ulong) space, (ulong) offset);
 
1859
        }
 
1860
#endif /* UNIV_DEBUG */
 
1861
 
 
1862
        block = free_block;
 
1863
 
 
1864
        mutex_enter(&block->mutex);
 
1865
 
 
1866
        buf_page_init(space, offset, block);
 
1867
 
 
1868
        /* The block must be put to the LRU list */
 
1869
        buf_LRU_add_block(block, FALSE);
 
1870
 
 
1871
#ifdef UNIV_SYNC_DEBUG
 
1872
        buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__);
 
1873
#else
 
1874
        buf_block_buf_fix_inc(block);
 
1875
#endif
 
1876
        buf_pool->n_pages_created++;
 
1877
 
 
1878
        mutex_exit(&(buf_pool->mutex));
 
1879
 
 
1880
        mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
 
1881
 
 
1882
        block->accessed = TRUE;
 
1883
 
 
1884
        mutex_exit(&block->mutex);
 
1885
 
 
1886
        /* Delete possible entries for the page from the insert buffer:
 
1887
        such can exist if the page belonged to an index which was dropped */
 
1888
 
 
1889
        ibuf_merge_or_delete_for_page(NULL, space, offset, TRUE);
 
1890
 
 
1891
        /* Flush pages from the end of the LRU list if necessary */
 
1892
        buf_flush_free_margin();
 
1893
 
 
1894
        frame = block->frame;
 
1895
 
 
1896
        memset(frame + FIL_PAGE_PREV, 0xff, 4);
 
1897
        memset(frame + FIL_PAGE_NEXT, 0xff, 4);
 
1898
        mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
 
1899
 
 
1900
        /* Reset to zero the file flush lsn field in the page; if the first
 
1901
        page of an ibdata file is 'created' in this function into the buffer
 
1902
        pool then we lose the original contents of the file flush lsn stamp.
 
1903
        Then InnoDB could in a crash recovery print a big, false, corruption
 
1904
        warning if the stamp contains an lsn bigger than the ib_logfile lsn. */
 
1905
 
 
1906
        memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
 
1907
 
 
1908
#ifdef UNIV_DEBUG
 
1909
        buf_dbg_counter++;
 
1910
 
 
1911
        if (buf_dbg_counter % 357 == 0) {
 
1912
                ut_ad(buf_validate());
 
1913
        }
 
1914
#endif
 
1915
#ifdef UNIV_IBUF_DEBUG
 
1916
        ut_a(ibuf_count_get(block->space, block->offset) == 0);
 
1917
#endif
 
1918
        return(frame);
 
1919
}
 
1920
 
 
1921
/************************************************************************
 
1922
Completes an asynchronous read or write request of a file page to or from
 
1923
the buffer pool. */
 
1924
 
 
1925
void
 
1926
buf_page_io_complete(
 
1927
/*=================*/
 
1928
        buf_block_t*    block)  /* in: pointer to the block in question */
 
1929
{
 
1930
        ulint           io_type;
 
1931
 
 
1932
        ut_ad(block);
 
1933
 
 
1934
        ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
1935
 
 
1936
        /* We do not need protect block->io_fix here by block->mutex to read
 
1937
        it because this is the only function where we can change the value
 
1938
        from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code
 
1939
        ensures that this is the only thread that handles the i/o for this
 
1940
        block. */
 
1941
 
 
1942
        io_type = block->io_fix;
 
1943
 
 
1944
        if (io_type == BUF_IO_READ) {
 
1945
                /* If this page is not uninitialized and not in the
 
1946
                doublewrite buffer, then the page number and space id
 
1947
                should be the same as in block. */
 
1948
                ulint   read_page_no = mach_read_from_4(
 
1949
                        block->frame + FIL_PAGE_OFFSET);
 
1950
                ulint   read_space_id = mach_read_from_4(
 
1951
                        block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
 
1952
 
 
1953
                if (!block->space
 
1954
                    && trx_doublewrite_page_inside(block->offset)) {
 
1955
 
 
1956
                        ut_print_timestamp(stderr);
 
1957
                        fprintf(stderr,
 
1958
                                "  InnoDB: Error: reading page %lu\n"
 
1959
                                "InnoDB: which is in the"
 
1960
                                " doublewrite buffer!\n",
 
1961
                                (ulong) block->offset);
 
1962
                } else if (!read_space_id && !read_page_no) {
 
1963
                        /* This is likely an uninitialized page. */
 
1964
                } else if ((block->space && block->space != read_space_id)
 
1965
                           || block->offset != read_page_no) {
 
1966
                        /* We did not compare space_id to read_space_id
 
1967
                        if block->space == 0, because the field on the
 
1968
                        page may contain garbage in MySQL < 4.1.1,
 
1969
                        which only supported block->space == 0. */
 
1970
 
 
1971
                        ut_print_timestamp(stderr);
 
1972
                        fprintf(stderr,
 
1973
                                "  InnoDB: Error: space id and page n:o"
 
1974
                                " stored in the page\n"
 
1975
                                "InnoDB: read in are %lu:%lu,"
 
1976
                                " should be %lu:%lu!\n",
 
1977
                                (ulong) read_space_id, (ulong) read_page_no,
 
1978
                                (ulong) block->space, (ulong) block->offset);
 
1979
                }
 
1980
                /* From version 3.23.38 up we store the page checksum
 
1981
                to the 4 first bytes of the page end lsn field */
 
1982
 
 
1983
                if (buf_page_is_corrupted(block->frame)) {
 
1984
                        fprintf(stderr,
 
1985
                                "InnoDB: Database page corruption on disk"
 
1986
                                " or a failed\n"
 
1987
                                "InnoDB: file read of page %lu.\n",
 
1988
                                (ulong) block->offset);
 
1989
 
 
1990
                        fputs("InnoDB: You may have to recover"
 
1991
                              " from a backup.\n", stderr);
 
1992
 
 
1993
                        buf_page_print(block->frame);
 
1994
 
 
1995
                        fprintf(stderr,
 
1996
                                "InnoDB: Database page corruption on disk"
 
1997
                                " or a failed\n"
 
1998
                                "InnoDB: file read of page %lu.\n",
 
1999
                                (ulong) block->offset);
 
2000
                        fputs("InnoDB: You may have to recover"
 
2001
                              " from a backup.\n", stderr);
 
2002
                        fputs("InnoDB: It is also possible that"
 
2003
                              " your operating\n"
 
2004
                              "InnoDB: system has corrupted its"
 
2005
                              " own file cache\n"
 
2006
                              "InnoDB: and rebooting your computer"
 
2007
                              " removes the\n"
 
2008
                              "InnoDB: error.\n"
 
2009
                              "InnoDB: If the corrupt page is an index page\n"
 
2010
                              "InnoDB: you can also try to"
 
2011
                              " fix the corruption\n"
 
2012
                              "InnoDB: by dumping, dropping,"
 
2013
                              " and reimporting\n"
 
2014
                              "InnoDB: the corrupt table."
 
2015
                              " You can use CHECK\n"
 
2016
                              "InnoDB: TABLE to scan your"
 
2017
                              " table for corruption.\n"
 
2018
                              "InnoDB: See also"
 
2019
                              " http://dev.mysql.com/doc/refman/5.1/en/"
 
2020
                              "forcing-recovery.html\n"
 
2021
                              "InnoDB: about forcing recovery.\n", stderr);
 
2022
 
 
2023
                        if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
 
2024
                                fputs("InnoDB: Ending processing because of"
 
2025
                                      " a corrupt database page.\n",
 
2026
                                      stderr);
 
2027
                                exit(1);
 
2028
                        }
 
2029
                }
 
2030
 
 
2031
                if (recv_recovery_is_on()) {
 
2032
                        recv_recover_page(FALSE, TRUE, block->frame,
 
2033
                                          block->space, block->offset);
 
2034
                }
 
2035
 
 
2036
                if (!recv_no_ibuf_operations) {
 
2037
                        ibuf_merge_or_delete_for_page(
 
2038
                                block->frame, block->space, block->offset,
 
2039
                                TRUE);
 
2040
                }
 
2041
        }
 
2042
 
 
2043
        mutex_enter(&(buf_pool->mutex));
 
2044
        mutex_enter(&block->mutex);
 
2045
 
 
2046
#ifdef UNIV_IBUF_DEBUG
 
2047
        ut_a(ibuf_count_get(block->space, block->offset) == 0);
 
2048
#endif
 
2049
        /* Because this thread which does the unlocking is not the same that
 
2050
        did the locking, we use a pass value != 0 in unlock, which simply
 
2051
        removes the newest lock debug record, without checking the thread
 
2052
        id. */
 
2053
 
 
2054
        block->io_fix = 0;
 
2055
 
 
2056
        if (io_type == BUF_IO_READ) {
 
2057
                /* NOTE that the call to ibuf may have moved the ownership of
 
2058
                the x-latch to this OS thread: do not let this confuse you in
 
2059
                debugging! */
 
2060
 
 
2061
                ut_ad(buf_pool->n_pend_reads > 0);
 
2062
                buf_pool->n_pend_reads--;
 
2063
                buf_pool->n_pages_read++;
 
2064
 
 
2065
                rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);
 
2066
 
 
2067
#ifdef UNIV_DEBUG
 
2068
                if (buf_debug_prints) {
 
2069
                        fputs("Has read ", stderr);
 
2070
                }
 
2071
#endif /* UNIV_DEBUG */
 
2072
        } else {
 
2073
                ut_ad(io_type == BUF_IO_WRITE);
 
2074
 
 
2075
                /* Write means a flush operation: call the completion
 
2076
                routine in the flush system */
 
2077
 
 
2078
                buf_flush_write_complete(block);
 
2079
 
 
2080
                rw_lock_s_unlock_gen(&(block->lock), BUF_IO_WRITE);
 
2081
 
 
2082
                buf_pool->n_pages_written++;
 
2083
 
 
2084
#ifdef UNIV_DEBUG
 
2085
                if (buf_debug_prints) {
 
2086
                        fputs("Has written ", stderr);
 
2087
                }
 
2088
#endif /* UNIV_DEBUG */
 
2089
        }
 
2090
 
 
2091
        mutex_exit(&block->mutex);
 
2092
        mutex_exit(&(buf_pool->mutex));
 
2093
 
 
2094
#ifdef UNIV_DEBUG
 
2095
        if (buf_debug_prints) {
 
2096
                fprintf(stderr, "page space %lu page no %lu\n",
 
2097
                        (ulong) block->space, (ulong) block->offset);
 
2098
        }
 
2099
#endif /* UNIV_DEBUG */
 
2100
}
 
2101
 
 
2102
/*************************************************************************
 
2103
Invalidates the file pages in the buffer pool when an archive recovery is
 
2104
completed. All the file pages buffered must be in a replaceable state when
 
2105
this function is called: not latched and not modified. */
 
2106
 
 
2107
void
 
2108
buf_pool_invalidate(void)
 
2109
/*=====================*/
 
2110
{
 
2111
        ibool   freed;
 
2112
 
 
2113
        ut_ad(buf_all_freed());
 
2114
 
 
2115
        freed = TRUE;
 
2116
 
 
2117
        while (freed) {
 
2118
                freed = buf_LRU_search_and_free_block(100);
 
2119
        }
 
2120
 
 
2121
        mutex_enter(&(buf_pool->mutex));
 
2122
 
 
2123
        ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
 
2124
 
 
2125
        mutex_exit(&(buf_pool->mutex));
 
2126
}
 
2127
 
 
2128
#ifdef UNIV_DEBUG
 
2129
/*************************************************************************
 
2130
Validates the buffer buf_pool data structure. */
 
2131
 
 
2132
ibool
 
2133
buf_validate(void)
 
2134
/*==============*/
 
2135
{
 
2136
        buf_block_t*    block;
 
2137
        ulint           i;
 
2138
        ulint           n_single_flush  = 0;
 
2139
        ulint           n_lru_flush     = 0;
 
2140
        ulint           n_list_flush    = 0;
 
2141
        ulint           n_lru           = 0;
 
2142
        ulint           n_flush         = 0;
 
2143
        ulint           n_free          = 0;
 
2144
        ulint           n_page          = 0;
 
2145
 
 
2146
        ut_ad(buf_pool);
 
2147
 
 
2148
        mutex_enter(&(buf_pool->mutex));
 
2149
 
 
2150
        for (i = 0; i < buf_pool->curr_size; i++) {
 
2151
 
 
2152
                block = buf_pool_get_nth_block(buf_pool, i);
 
2153
 
 
2154
                mutex_enter(&block->mutex);
 
2155
 
 
2156
                if (block->state == BUF_BLOCK_FILE_PAGE) {
 
2157
 
 
2158
                        ut_a(buf_page_hash_get(block->space,
 
2159
                                               block->offset) == block);
 
2160
                        n_page++;
 
2161
 
 
2162
#ifdef UNIV_IBUF_DEBUG
 
2163
                        ut_a((block->io_fix == BUF_IO_READ)
 
2164
                             || ibuf_count_get(block->space, block->offset)
 
2165
                             == 0);
 
2166
#endif
 
2167
                        if (block->io_fix == BUF_IO_WRITE) {
 
2168
 
 
2169
                                if (block->flush_type == BUF_FLUSH_LRU) {
 
2170
                                        n_lru_flush++;
 
2171
                                        ut_a(rw_lock_is_locked(
 
2172
                                                     &block->lock,
 
2173
                                                     RW_LOCK_SHARED));
 
2174
                                } else if (block->flush_type
 
2175
                                           == BUF_FLUSH_LIST) {
 
2176
                                        n_list_flush++;
 
2177
                                } else if (block->flush_type
 
2178
                                           == BUF_FLUSH_SINGLE_PAGE) {
 
2179
                                        n_single_flush++;
 
2180
                                } else {
 
2181
                                        ut_error;
 
2182
                                }
 
2183
 
 
2184
                        } else if (block->io_fix == BUF_IO_READ) {
 
2185
 
 
2186
                                ut_a(rw_lock_is_locked(&(block->lock),
 
2187
                                                       RW_LOCK_EX));
 
2188
                        }
 
2189
 
 
2190
                        n_lru++;
 
2191
 
 
2192
                        if (ut_dulint_cmp(block->oldest_modification,
 
2193
                                          ut_dulint_zero) > 0) {
 
2194
                                n_flush++;
 
2195
                        }
 
2196
 
 
2197
                } else if (block->state == BUF_BLOCK_NOT_USED) {
 
2198
                        n_free++;
 
2199
                }
 
2200
 
 
2201
                mutex_exit(&block->mutex);
 
2202
        }
 
2203
 
 
2204
        if (n_lru + n_free > buf_pool->curr_size) {
 
2205
                fprintf(stderr, "n LRU %lu, n free %lu\n",
 
2206
                        (ulong) n_lru, (ulong) n_free);
 
2207
                ut_error;
 
2208
        }
 
2209
 
 
2210
        ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
 
2211
        if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
 
2212
                fprintf(stderr, "Free list len %lu, free blocks %lu\n",
 
2213
                        (ulong) UT_LIST_GET_LEN(buf_pool->free),
 
2214
                        (ulong) n_free);
 
2215
                ut_error;
 
2216
        }
 
2217
        ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
 
2218
 
 
2219
        ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
 
2220
        ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
 
2221
        ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
 
2222
 
 
2223
        mutex_exit(&(buf_pool->mutex));
 
2224
 
 
2225
        ut_a(buf_LRU_validate());
 
2226
        ut_a(buf_flush_validate());
 
2227
 
 
2228
        return(TRUE);
 
2229
}
 
2230
 
 
2231
/*************************************************************************
 
2232
Prints info of the buffer buf_pool data structure. */
 
2233
 
 
2234
void
 
2235
buf_print(void)
 
2236
/*===========*/
 
2237
{
 
2238
        dulint*         index_ids;
 
2239
        ulint*          counts;
 
2240
        ulint           size;
 
2241
        ulint           i;
 
2242
        ulint           j;
 
2243
        dulint          id;
 
2244
        ulint           n_found;
 
2245
        buf_frame_t*    frame;
 
2246
        dict_index_t*   index;
 
2247
 
 
2248
        ut_ad(buf_pool);
 
2249
 
 
2250
        size = buf_pool->curr_size;
 
2251
 
 
2252
        index_ids = mem_alloc(sizeof(dulint) * size);
 
2253
        counts = mem_alloc(sizeof(ulint) * size);
 
2254
 
 
2255
        mutex_enter(&(buf_pool->mutex));
 
2256
 
 
2257
        fprintf(stderr,
 
2258
                "buf_pool size %lu\n"
 
2259
                "database pages %lu\n"
 
2260
                "free pages %lu\n"
 
2261
                "modified database pages %lu\n"
 
2262
                "n pending reads %lu\n"
 
2263
                "n pending flush LRU %lu list %lu single page %lu\n"
 
2264
                "pages read %lu, created %lu, written %lu\n",
 
2265
                (ulong) size,
 
2266
                (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
 
2267
                (ulong) UT_LIST_GET_LEN(buf_pool->free),
 
2268
                (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
 
2269
                (ulong) buf_pool->n_pend_reads,
 
2270
                (ulong) buf_pool->n_flush[BUF_FLUSH_LRU],
 
2271
                (ulong) buf_pool->n_flush[BUF_FLUSH_LIST],
 
2272
                (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE],
 
2273
                (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created,
 
2274
                (ulong) buf_pool->n_pages_written);
 
2275
 
 
2276
        /* Count the number of blocks belonging to each index in the buffer */
 
2277
 
 
2278
        n_found = 0;
 
2279
 
 
2280
        for (i = 0; i < size; i++) {
 
2281
                frame = buf_pool_get_nth_block(buf_pool, i)->frame;
 
2282
 
 
2283
                if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
 
2284
 
 
2285
                        id = btr_page_get_index_id(frame);
 
2286
 
 
2287
                        /* Look for the id in the index_ids array */
 
2288
                        j = 0;
 
2289
 
 
2290
                        while (j < n_found) {
 
2291
 
 
2292
                                if (ut_dulint_cmp(index_ids[j], id) == 0) {
 
2293
                                        (counts[j])++;
 
2294
 
 
2295
                                        break;
 
2296
                                }
 
2297
                                j++;
 
2298
                        }
 
2299
 
 
2300
                        if (j == n_found) {
 
2301
                                n_found++;
 
2302
                                index_ids[j] = id;
 
2303
                                counts[j] = 1;
 
2304
                        }
 
2305
                }
 
2306
        }
 
2307
 
 
2308
        mutex_exit(&(buf_pool->mutex));
 
2309
 
 
2310
        for (i = 0; i < n_found; i++) {
 
2311
                index = dict_index_get_if_in_cache(index_ids[i]);
 
2312
 
 
2313
                fprintf(stderr,
 
2314
                        "Block count for index %lu in buffer is about %lu",
 
2315
                        (ulong) ut_dulint_get_low(index_ids[i]),
 
2316
                        (ulong) counts[i]);
 
2317
 
 
2318
                if (index) {
 
2319
                        putc(' ', stderr);
 
2320
                        dict_index_name_print(stderr, NULL, index);
 
2321
                }
 
2322
 
 
2323
                putc('\n', stderr);
 
2324
        }
 
2325
 
 
2326
        mem_free(index_ids);
 
2327
        mem_free(counts);
 
2328
 
 
2329
        ut_a(buf_validate());
 
2330
}
 
2331
#endif /* UNIV_DEBUG */
 
2332
 
 
2333
/*************************************************************************
 
2334
Returns the number of latched pages in the buffer pool. */
 
2335
 
 
2336
ulint
 
2337
buf_get_latched_pages_number(void)
 
2338
{
 
2339
        buf_block_t*    block;
 
2340
        ulint           i;
 
2341
        ulint           fixed_pages_number = 0;
 
2342
 
 
2343
        mutex_enter(&(buf_pool->mutex));
 
2344
 
 
2345
        for (i = 0; i < buf_pool->curr_size; i++) {
 
2346
 
 
2347
                block = buf_pool_get_nth_block(buf_pool, i);
 
2348
 
 
2349
                if (block->magic_n == BUF_BLOCK_MAGIC_N) {
 
2350
                        mutex_enter(&block->mutex);
 
2351
 
 
2352
                        if (block->buf_fix_count != 0 || block->io_fix != 0) {
 
2353
                                fixed_pages_number++;
 
2354
                        }
 
2355
 
 
2356
                        mutex_exit(&block->mutex);
 
2357
                }
 
2358
        }
 
2359
 
 
2360
        mutex_exit(&(buf_pool->mutex));
 
2361
 
 
2362
        return(fixed_pages_number);
 
2363
}
 
2364
 
 
2365
/*************************************************************************
 
2366
Returns the number of pending buf pool ios. */
 
2367
 
 
2368
ulint
 
2369
buf_get_n_pending_ios(void)
 
2370
/*=======================*/
 
2371
{
 
2372
        return(buf_pool->n_pend_reads
 
2373
               + buf_pool->n_flush[BUF_FLUSH_LRU]
 
2374
               + buf_pool->n_flush[BUF_FLUSH_LIST]
 
2375
               + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
 
2376
}
 
2377
 
 
2378
/*************************************************************************
 
2379
Returns the ratio in percents of modified pages in the buffer pool /
 
2380
database pages in the buffer pool. */
 
2381
 
 
2382
ulint
 
2383
buf_get_modified_ratio_pct(void)
 
2384
/*============================*/
 
2385
{
 
2386
        ulint   ratio;
 
2387
 
 
2388
        mutex_enter(&(buf_pool->mutex));
 
2389
 
 
2390
        ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
 
2391
                / (1 + UT_LIST_GET_LEN(buf_pool->LRU)
 
2392
                   + UT_LIST_GET_LEN(buf_pool->free));
 
2393
 
 
2394
        /* 1 + is there to avoid division by zero */
 
2395
 
 
2396
        mutex_exit(&(buf_pool->mutex));
 
2397
 
 
2398
        return(ratio);
 
2399
}
 
2400
 
 
2401
/*************************************************************************
 
2402
Prints info of the buffer i/o. */
 
2403
 
 
2404
void
 
2405
buf_print_io(
 
2406
/*=========*/
 
2407
        FILE*   file)   /* in/out: buffer where to print */
 
2408
{
 
2409
        time_t  current_time;
 
2410
        double  time_elapsed;
 
2411
        ulint   size;
 
2412
 
 
2413
        ut_ad(buf_pool);
 
2414
        size = buf_pool->curr_size;
 
2415
 
 
2416
        mutex_enter(&(buf_pool->mutex));
 
2417
 
 
2418
        if (srv_use_awe) {
 
2419
                fprintf(stderr,
 
2420
                        "AWE: Buffer pool memory frames %lu\n",
 
2421
                        (ulong) buf_pool->n_frames);
 
2422
 
 
2423
                fprintf(stderr,
 
2424
                        "AWE: Database pages and free buffers"
 
2425
                        " mapped in frames %lu\n",
 
2426
                        (ulong)
 
2427
                        UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
 
2428
        }
 
2429
        fprintf(file,
 
2430
                "Buffer pool size   %lu\n"
 
2431
                "Free buffers       %lu\n"
 
2432
                "Database pages     %lu\n"
 
2433
                "Modified db pages  %lu\n"
 
2434
                "Pending reads %lu\n"
 
2435
                "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
 
2436
                (ulong) size,
 
2437
                (ulong) UT_LIST_GET_LEN(buf_pool->free),
 
2438
                (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
 
2439
                (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
 
2440
                (ulong) buf_pool->n_pend_reads,
 
2441
                (ulong) buf_pool->n_flush[BUF_FLUSH_LRU]
 
2442
                + buf_pool->init_flush[BUF_FLUSH_LRU],
 
2443
                (ulong) buf_pool->n_flush[BUF_FLUSH_LIST]
 
2444
                + buf_pool->init_flush[BUF_FLUSH_LIST],
 
2445
                (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
 
2446
 
 
2447
        current_time = time(NULL);
 
2448
        time_elapsed = 0.001 + difftime(current_time,
 
2449
                                        buf_pool->last_printout_time);
 
2450
        buf_pool->last_printout_time = current_time;
 
2451
 
 
2452
        fprintf(file,
 
2453
                "Pages read %lu, created %lu, written %lu\n"
 
2454
                "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
 
2455
                (ulong) buf_pool->n_pages_read,
 
2456
                (ulong) buf_pool->n_pages_created,
 
2457
                (ulong) buf_pool->n_pages_written,
 
2458
                (buf_pool->n_pages_read - buf_pool->n_pages_read_old)
 
2459
                / time_elapsed,
 
2460
                (buf_pool->n_pages_created - buf_pool->n_pages_created_old)
 
2461
                / time_elapsed,
 
2462
                (buf_pool->n_pages_written - buf_pool->n_pages_written_old)
 
2463
                / time_elapsed);
 
2464
 
 
2465
        if (srv_use_awe) {
 
2466
                fprintf(file, "AWE: %.2f page remaps/s\n",
 
2467
                        (buf_pool->n_pages_awe_remapped
 
2468
                         - buf_pool->n_pages_awe_remapped_old)
 
2469
                        / time_elapsed);
 
2470
        }
 
2471
 
 
2472
        if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
 
2473
                fprintf(file, "Buffer pool hit rate %lu / 1000\n",
 
2474
                        (ulong)
 
2475
                        (1000 - ((1000 * (buf_pool->n_pages_read
 
2476
                                          - buf_pool->n_pages_read_old))
 
2477
                                 / (buf_pool->n_page_gets
 
2478
                                    - buf_pool->n_page_gets_old))));
 
2479
        } else {
 
2480
                fputs("No buffer pool page gets since the last printout\n",
 
2481
                      file);
 
2482
        }
 
2483
 
 
2484
        buf_pool->n_page_gets_old = buf_pool->n_page_gets;
 
2485
        buf_pool->n_pages_read_old = buf_pool->n_pages_read;
 
2486
        buf_pool->n_pages_created_old = buf_pool->n_pages_created;
 
2487
        buf_pool->n_pages_written_old = buf_pool->n_pages_written;
 
2488
        buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
 
2489
 
 
2490
        mutex_exit(&(buf_pool->mutex));
 
2491
}
 
2492
 
 
2493
/**************************************************************************
 
2494
Refreshes the statistics used to print per-second averages. */
 
2495
 
 
2496
void
 
2497
buf_refresh_io_stats(void)
 
2498
/*======================*/
 
2499
{
 
2500
        buf_pool->last_printout_time = time(NULL);
 
2501
        buf_pool->n_page_gets_old = buf_pool->n_page_gets;
 
2502
        buf_pool->n_pages_read_old = buf_pool->n_pages_read;
 
2503
        buf_pool->n_pages_created_old = buf_pool->n_pages_created;
 
2504
        buf_pool->n_pages_written_old = buf_pool->n_pages_written;
 
2505
        buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
 
2506
}
 
2507
 
 
2508
/*************************************************************************
 
2509
Checks that all file pages in the buffer are in a replaceable state. */
 
2510
 
 
2511
ibool
 
2512
buf_all_freed(void)
 
2513
/*===============*/
 
2514
{
 
2515
        buf_block_t*    block;
 
2516
        ulint           i;
 
2517
 
 
2518
        ut_ad(buf_pool);
 
2519
 
 
2520
        mutex_enter(&(buf_pool->mutex));
 
2521
 
 
2522
        for (i = 0; i < buf_pool->curr_size; i++) {
 
2523
 
 
2524
                block = buf_pool_get_nth_block(buf_pool, i);
 
2525
 
 
2526
                mutex_enter(&block->mutex);
 
2527
 
 
2528
                if (block->state == BUF_BLOCK_FILE_PAGE) {
 
2529
 
 
2530
                        if (!buf_flush_ready_for_replace(block)) {
 
2531
 
 
2532
                                fprintf(stderr,
 
2533
                                        "Page %lu %lu still fixed or dirty\n",
 
2534
                                        (ulong) block->space,
 
2535
                                        (ulong) block->offset);
 
2536
                                ut_error;
 
2537
                        }
 
2538
                }
 
2539
 
 
2540
                mutex_exit(&block->mutex);
 
2541
        }
 
2542
 
 
2543
        mutex_exit(&(buf_pool->mutex));
 
2544
 
 
2545
        return(TRUE);
 
2546
}
 
2547
 
 
2548
/*************************************************************************
 
2549
Checks that there currently are no pending i/o-operations for the buffer
 
2550
pool. */
 
2551
 
 
2552
ibool
 
2553
buf_pool_check_no_pending_io(void)
 
2554
/*==============================*/
 
2555
                                /* out: TRUE if there is no pending i/o */
 
2556
{
 
2557
        ibool   ret;
 
2558
 
 
2559
        mutex_enter(&(buf_pool->mutex));
 
2560
 
 
2561
        if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU]
 
2562
            + buf_pool->n_flush[BUF_FLUSH_LIST]
 
2563
            + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
 
2564
                ret = FALSE;
 
2565
        } else {
 
2566
                ret = TRUE;
 
2567
        }
 
2568
 
 
2569
        mutex_exit(&(buf_pool->mutex));
 
2570
 
 
2571
        return(ret);
 
2572
}
 
2573
 
 
2574
/*************************************************************************
 
2575
Gets the current length of the free list of buffer blocks. */
 
2576
 
 
2577
ulint
 
2578
buf_get_free_list_len(void)
 
2579
/*=======================*/
 
2580
{
 
2581
        ulint   len;
 
2582
 
 
2583
        mutex_enter(&(buf_pool->mutex));
 
2584
 
 
2585
        len = UT_LIST_GET_LEN(buf_pool->free);
 
2586
 
 
2587
        mutex_exit(&(buf_pool->mutex));
 
2588
 
 
2589
        return(len);
 
2590
}