buf0buf.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:40k
源码类别:

MySQL数据库

开发平台:

Visual C++

  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. (c) 1995 Innobase Oy
  18. Created 11/5/1995 Heikki Tuuri
  19. *******************************************************/
  20. #include "buf0buf.h"
  21. #ifdef UNIV_NONINL
  22. #include "buf0buf.ic"
  23. #endif
  24. #include "mem0mem.h"
  25. #include "btr0btr.h"
  26. #include "fil0fil.h"
  27. #include "lock0lock.h"
  28. #include "btr0sea.h"
  29. #include "ibuf0ibuf.h"
  30. #include "dict0dict.h"
  31. #include "log0recv.h"
  32. /*
  33. IMPLEMENTATION OF THE BUFFER POOL
  34. =================================
  35. Performance improvement: 
  36. ------------------------
  37. Thread scheduling in NT may be so slow that the OS wait mechanism should
  38. not be used even in waiting for disk reads to complete.
  39. Rather, we should put waiting query threads to the queue of
  40. waiting jobs, and let the OS thread do something useful while the i/o
  41. is processed. In this way we could remove most OS thread switches in
  42. an i/o-intensive benchmark like TPC-C.
  43. A possibility is to put a user space thread library between the database
  44. and NT. User space thread libraries might be very fast.
  45. SQL Server 7.0 can be configured to use 'fibers' which are lightweight
  46. threads in NT. These should be studied.
  47. Buffer frames and blocks
  48. ------------------------
  49. Following the terminology of Gray and Reuter, we call the memory
  50. blocks where file pages are loaded buffer frames. For each buffer
  51. frame there is a control block, or shortly, a block, in the buffer
  52. control array. The control info which does not need to be stored
  53. in the file along with the file page, resides in the control block.
  54. Buffer pool struct
  55. ------------------
  56. The buffer buf_pool contains a single mutex which protects all the
  57. control data structures of the buf_pool. The content of a buffer frame is
  58. protected by a separate read-write lock in its control block, though.
  59. These locks can be locked and unlocked without owning the buf_pool mutex.
  60. The OS events in the buf_pool struct can be waited for without owning the
  61. buf_pool mutex.
  62. The buf_pool mutex is a hot-spot in main memory, causing a lot of
  63. memory bus traffic on multiprocessor systems when processors
  64. alternately access the mutex. On our Pentium, the mutex is accessed
  65. maybe every 10 microseconds. We gave up the solution to have mutexes
  66. for each control block, for instance, because it seemed to be
  67. complicated.
  68. A solution to reduce mutex contention of the buf_pool mutex is to
  69. create a separate mutex for the page hash table. On Pentium,
  70. accessing the hash table takes 2 microseconds, about half
  71. of the total buf_pool mutex hold time.
  72. Control blocks
  73. --------------
  74. The control block contains, for instance, the bufferfix count
  75. which is incremented when a thread wants a file page to be fixed
  76. in a buffer frame. The bufferfix operation does not lock the
  77. contents of the frame, however. For this purpose, the control
  78. block contains a read-write lock.
  79. The buffer frames have to be aligned so that the start memory
  80. address of a frame is divisible by the universal page size, which
  81. is a power of two.
  82. We intend to make the buffer buf_pool size on-line reconfigurable,
  83. that is, the buf_pool size can be changed without closing the database.
  84. Then the database administarator may adjust it to be bigger
  85. at night, for example. The control block array must
  86. contain enough control blocks for the maximum buffer buf_pool size
  87. which is used in the particular database.
  88. If the buf_pool size is cut, we exploit the virtual memory mechanism of
  89. the OS, and just refrain from using frames at high addresses. Then the OS
  90. can swap them to disk.
  91. The control blocks containing file pages are put to a hash table
  92. according to the file address of the page.
  93. We could speed up the access to an individual page by using
  94. "pointer swizzling": we could replace the page references on
  95. non-leaf index pages by direct pointers to the page, if it exists
  96. in the buf_pool. We could make a separate hash table where we could
  97. chain all the page references in non-leaf pages residing in the buf_pool,
  98. using the page reference as the hash key,
  99. and at the time of reading of a page update the pointers accordingly.
  100. Drawbacks of this solution are added complexity and,
  101. possibly, extra space required on non-leaf pages for memory pointers.
  102. A simpler solution is just to speed up the hash table mechanism
  103. in the database, using tables whose size is a power of 2.
  104. Lists of blocks
  105. ---------------
  106. There are several lists of control blocks. The free list contains
  107. blocks which are currently not used.
  108. The LRU-list contains all the blocks holding a file page
  109. except those for which the bufferfix count is non-zero.
  110. The pages are in the LRU list roughly in the order of the last
  111. access to the page, so that the oldest pages are at the end of the
  112. list. We also keep a pointer to near the end of the LRU list,
  113. which we can use when we want to artificially age a page in the
  114. buf_pool. This is used if we know that some page is not needed
  115. again for some time: we insert the block right after the pointer,
  116. causing it to be replaced sooner than would noramlly be the case.
  117. Currently this aging mechanism is used for read-ahead mechanism
  118. of pages, and it can also be used when there is a scan of a full
  119. table which cannot fit in the memory. Putting the pages near the
  120. of the LRU list, we make sure that most of the buf_pool stays in the
  121. main memory, undisturbed.
  122. The chain of modified blocks contains the blocks
  123. holding file pages that have been modified in the memory
  124. but not written to disk yet. The block with the oldest modification
  125. which has not yet been written to disk is at the end of the chain.
  126. Loading a file page
  127. -------------------
  128. First, a victim block for replacement has to be found in the
  129. buf_pool. It is taken from the free list or searched for from the
  130. end of the LRU-list. An exclusive lock is reserved for the frame,
  131. the io_fix field is set in the block fixing the block in buf_pool,
  132. and the io-operation for loading the page is queued. The io-handler thread
  133. releases the X-lock on the frame and resets the io_fix field
  134. when the io operation completes.
  135. A thread may request the above operation using the buf_page_get-
  136. function. It may then continue to request a lock on the frame.
  137. The lock is granted when the io-handler releases the x-lock.
  138. Read-ahead
  139. ----------
  140. The read-ahead mechanism is intended to be intelligent and
  141. isolated from the semantically higher levels of the database
  142. index management. From the higher level we only need the
  143. information if a file page has a natural successor or
  144. predecessor page. On the leaf level of a B-tree index,
  145. these are the next and previous pages in the natural
  146. order of the pages.
  147. Let us first explain the read-ahead mechanism when the leafs
  148. of a B-tree are scanned in an ascending or descending order.
  149. When a read page is the first time referenced in the buf_pool,
  150. the buffer manager checks if it is at the border of a so-called
  151. linear read-ahead area. The tablespace is divided into these
  152. areas of size 64 blocks, for example. So if the page is at the
  153. border of such an area, the read-ahead mechanism checks if
  154. all the other blocks in the area have been accessed in an
  155. ascending or descending order. If this is the case, the system
  156. looks at the natural successor or predecessor of the page,
  157. checks if that is at the border of another area, and in this case
  158. issues read-requests for all the pages in that area. Maybe
  159. we could relax the condition that all the pages in the area
  160. have to be accessed: if data is deleted from a table, there may
  161. appear holes of unused pages in the area.
  162. A different read-ahead mechanism is used when there appears
  163. to be a random access pattern to a file.
  164. If a new page is referenced in the buf_pool, and several pages
  165. of its random access area (for instance, 32 consecutive pages
  166. in a tablespace) have recently been referenced, we may predict
  167. that the whole area may be needed in the near future, and issue
  168. the read requests for the whole area. */
  169. buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */
  170. ulint buf_dbg_counter = 0; /* This is used to insert validation
  171. operations in excution in the
  172. debug version */
  173. ibool buf_debug_prints = FALSE; /* If this is set TRUE,
  174. the program prints info whenever
  175. read-ahead or flush occurs */
  176. /************************************************************************
  177. Initializes a buffer control block when the buf_pool is created. */
  178. static
  179. void
  180. buf_block_init(
  181. /*===========*/
  182. buf_block_t* block, /* in: pointer to control block */
  183. byte* frame) /* in: pointer to buffer frame */
  184. {
  185. block->state = BUF_BLOCK_NOT_USED;
  186. block->frame = frame;
  187. block->modify_clock = ut_dulint_zero;
  188. rw_lock_create(&(block->lock));
  189. ut_ad(rw_lock_validate(&(block->lock)));
  190. rw_lock_create(&(block->read_lock));
  191. rw_lock_set_level(&(block->read_lock), SYNC_NO_ORDER_CHECK);
  192. rw_lock_create(&(block->debug_latch));
  193. rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
  194. }
  195. /************************************************************************
  196. Creates a buffer buf_pool object. */
  197. static
  198. buf_pool_t*
  199. buf_pool_create(
  200. /*============*/
  201. /* out, own: buf_pool object, NULL if not
  202. enough memory */
  203. ulint max_size, /* in: maximum size of the buf_pool in
  204. blocks */
  205. ulint curr_size) /* in: current size to use, must be <=
  206. max_size, currently must be equal to
  207. max_size */
  208. {
  209. byte* frame;
  210. ulint i;
  211. buf_block_t* block;
  212. ut_a(max_size == curr_size);
  213. buf_pool = mem_alloc(sizeof(buf_pool_t));
  214. /* 1. Initialize general fields
  215.    ---------------------------- */
  216. mutex_create(&(buf_pool->mutex));
  217. mutex_set_level(&(buf_pool->mutex), SYNC_BUF_POOL);
  218. mutex_enter(&(buf_pool->mutex));
  219. buf_pool->frame_mem = ut_malloc(UNIV_PAGE_SIZE * (max_size + 1));
  220. if (buf_pool->frame_mem == NULL) {
  221. return(NULL);
  222. }
  223. buf_pool->blocks = ut_malloc(sizeof(buf_block_t) * max_size);
  224. if (buf_pool->blocks == NULL) {
  225. return(NULL);
  226. }
  227. buf_pool->max_size = max_size;
  228. buf_pool->curr_size = curr_size;
  229. /* Align pointer to the first frame */
  230. frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
  231. buf_pool->frame_zero = frame;
  232. /* Init block structs and assign frames for them */
  233. for (i = 0; i < max_size; i++) {
  234. block = buf_pool_get_nth_block(buf_pool, i);
  235. buf_block_init(block, frame);
  236. frame = frame + UNIV_PAGE_SIZE;
  237. }
  238. buf_pool->page_hash = hash_create(2 * max_size);
  239. buf_pool->n_pend_reads = 0;
  240. buf_pool->n_pages_read = 0;
  241. buf_pool->n_pages_written = 0;
  242. buf_pool->n_pages_created = 0;
  243. /* 2. Initialize flushing fields
  244.    ---------------------------- */
  245. UT_LIST_INIT(buf_pool->flush_list);
  246. for (i = BUF_FLUSH_LRU; i <= BUF_FLUSH_LIST; i++) {
  247. buf_pool->n_flush[i] = 0;
  248. buf_pool->no_flush[i] = os_event_create(NULL);
  249. }
  250. buf_pool->LRU_flush_ended = 0;
  251. buf_pool->ulint_clock = 1;
  252. buf_pool->freed_page_clock = 0;
  253. /* 3. Initialize LRU fields
  254.    ---------------------------- */
  255. UT_LIST_INIT(buf_pool->LRU);
  256. buf_pool->LRU_old = NULL;
  257. /* Add control blocks to the free list */
  258. UT_LIST_INIT(buf_pool->free);
  259. for (i = 0; i < curr_size; i++) {
  260. block = buf_pool_get_nth_block(buf_pool, i);
  261. UT_LIST_ADD_FIRST(free, buf_pool->free, block);
  262. }
  263. mutex_exit(&(buf_pool->mutex));
  264. btr_search_sys_create(curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64);
  265. return(buf_pool);
  266. }
  267. /************************************************************************
  268. Initializes the buffer buf_pool of the database. */
  269. void
  270. buf_pool_init(
  271. /*==========*/
  272. ulint max_size, /* in: maximum size of the buf_pool in blocks */
  273. ulint curr_size) /* in: current size to use, must be <=
  274. max_size */
  275. {
  276. ut_a(buf_pool == NULL);
  277. buf_pool_create(max_size, curr_size);
  278. ut_ad(buf_validate());
  279. }
  280. /************************************************************************
  281. Allocates a buffer block. */
  282. UNIV_INLINE
  283. buf_block_t*
  284. buf_block_alloc(void)
  285. /*=================*/
  286. /* out, own: the allocated block */
  287. {
  288. buf_block_t* block;
  289. block = buf_LRU_get_free_block();
  290. return(block);
  291. }
  292. /************************************************************************
  293. Moves to the block to the start of the LRU list if there is a danger
  294. that the block would drift out of the buffer pool. */
  295. UNIV_INLINE
  296. void
  297. buf_block_make_young(
  298. /*=================*/
  299. buf_block_t* block) /* in: block to make younger */
  300. {
  301. if (buf_pool->freed_page_clock >= block->freed_page_clock 
  302. + 1 + (buf_pool->curr_size / 1024)) {
  303. /* There has been freeing activity in the LRU list:
  304. best to move to the head of the LRU list */
  305. buf_LRU_make_block_young(block);
  306. }
  307. }
  308. /************************************************************************
  309. Moves a page to the start of the buffer pool LRU list. This high-level
  310. function can be used to prevent an important page from from slipping out of
  311. the buffer pool. */
  312. void
  313. buf_page_make_young(
  314. /*=================*/
  315. buf_frame_t* frame) /* in: buffer frame of a file page */
  316. {
  317. buf_block_t* block;
  318. mutex_enter(&(buf_pool->mutex));
  319. block = buf_block_align(frame);
  320. ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
  321. buf_LRU_make_block_young(block);
  322. mutex_exit(&(buf_pool->mutex));
  323. }
  324. /************************************************************************
  325. Frees a buffer block which does not contain a file page. */
  326. UNIV_INLINE
  327. void
  328. buf_block_free(
  329. /*===========*/
  330. buf_block_t* block) /* in, own: block to be freed */
  331. {
  332. ut_ad(block->state != BUF_BLOCK_FILE_PAGE);
  333. mutex_enter(&(buf_pool->mutex));
  334. buf_LRU_block_free_non_file_page(block);
  335. mutex_exit(&(buf_pool->mutex));
  336. }
  337. /*************************************************************************
  338. Allocates a buffer frame. */
  339. buf_frame_t*
  340. buf_frame_alloc(void)
  341. /*=================*/
  342. /* out: buffer frame */
  343. {
  344. return(buf_block_alloc()->frame);
  345. }
  346. /*************************************************************************
  347. Frees a buffer frame which does not contain a file page. */
  348. void
  349. buf_frame_free(
  350. /*===========*/
  351. buf_frame_t* frame) /* in: buffer frame */
  352. {
  353. buf_block_free(buf_block_align(frame));
  354. }
  355. /************************************************************************
  356. Returns the buffer control block if the page can be found in the buffer
  357. pool. NOTE that it is possible that the page is not yet read
  358. from disk, though. This is a very low-level function: use with care! */
  359. buf_block_t*
  360. buf_page_peek_block(
  361. /*================*/
  362. /* out: control block if found from page hash table,
  363. otherwise NULL; NOTE that the page is not necessarily
  364. yet read from disk! */
  365. ulint space, /* in: space id */
  366. ulint offset) /* in: page number */
  367. {
  368. buf_block_t* block;
  369. mutex_enter_fast(&(buf_pool->mutex));
  370. block = buf_page_hash_get(space, offset);
  371. mutex_exit(&(buf_pool->mutex));
  372. return(block);
  373. }
  374. /************************************************************************
  375. Returns the current state of is_hashed of a page. FALSE if the page is
  376. not in the pool. NOTE that this operation does not fix the page in the
  377. pool if it is found there. */
  378. ibool
  379. buf_page_peek_if_search_hashed(
  380. /*===========================*/
  381. /* out: TRUE if page hash index is built in search
  382. system */
  383. ulint space, /* in: space id */
  384. ulint offset) /* in: page number */
  385. {
  386. buf_block_t* block;
  387. ibool is_hashed;
  388. mutex_enter_fast(&(buf_pool->mutex));
  389. block = buf_page_hash_get(space, offset);
  390. if (!block) {
  391. is_hashed = FALSE;
  392. } else {
  393. is_hashed = block->is_hashed;
  394. }
  395. mutex_exit(&(buf_pool->mutex));
  396. return(is_hashed);
  397. }
  398. /************************************************************************
  399. Returns TRUE if the page can be found in the buffer pool hash table. NOTE
  400. that it is possible that the page is not yet read from disk, though. */
  401. ibool
  402. buf_page_peek(
  403. /*==========*/
  404. /* out: TRUE if found from page hash table,
  405. NOTE that the page is not necessarily yet read
  406. from disk! */
  407. ulint space, /* in: space id */
  408. ulint offset) /* in: page number */
  409. {
  410. if (buf_page_peek_block(space, offset)) {
  411. return(TRUE);
  412. }
  413. return(FALSE);
  414. }
  415. /************************************************************************
  416. This is the general function used to get access to a database page. */
  417. buf_frame_t*
  418. buf_page_get_gen(
  419. /*=============*/
  420. /* out: pointer to the frame or NULL */
  421. ulint space, /* in: space id */
  422. ulint offset, /* in: page number */
  423. ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
  424. buf_frame_t* guess, /* in: guessed frame or NULL */
  425. ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
  426. BUF_GET_NO_LATCH, BUF_GET_NOWAIT */
  427. #ifdef UNIV_SYNC_DEBUG
  428. char* file, /* in: file name */
  429. ulint line, /* in: line where called */
  430. #endif
  431. mtr_t* mtr) /* in: mini-transaction */
  432. {
  433. buf_block_t* block;
  434. ibool accessed;
  435. ulint fix_type;
  436. ibool success;
  437. ibool must_read;
  438. ut_ad(mtr);
  439. ut_ad((rw_latch == RW_S_LATCH)
  440.       || (rw_latch == RW_X_LATCH)
  441.       || (rw_latch == RW_NO_LATCH));
  442. ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
  443. ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
  444.       || (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
  445. #ifndef UNIV_LOG_DEBUG
  446. ut_ad(!ibuf_inside() || ibuf_page(space, offset));
  447. #endif
  448. loop:
  449. mutex_enter_fast(&(buf_pool->mutex));
  450. block = NULL;
  451. if (guess) {
  452. block = buf_block_align(guess);
  453. if ((offset != block->offset) || (space != block->space)
  454. || (block->state != BUF_BLOCK_FILE_PAGE)) {
  455. block = NULL;
  456. }
  457. }
  458. if (block == NULL) {
  459. block = buf_page_hash_get(space, offset);
  460. }
  461. if (block == NULL) {
  462. /* Page not in buf_pool: needs to be read from file */
  463. mutex_exit(&(buf_pool->mutex));
  464. if (mode == BUF_GET_IF_IN_POOL) {
  465. return(NULL);
  466. }
  467. buf_read_page(space, offset);
  468. #ifdef UNIV_DEBUG
  469. buf_dbg_counter++;
  470. if (buf_dbg_counter % 37 == 0) {
  471. ut_ad(buf_validate());
  472. }
  473. #endif
  474. goto loop;
  475. }
  476. must_read = FALSE;
  477. if (block->io_fix == BUF_IO_READ) {
  478. must_read = TRUE;
  479. if (mode == BUF_GET_IF_IN_POOL) {
  480. /* The page is only being read to buffer */
  481. mutex_exit(&(buf_pool->mutex));
  482. return(NULL);
  483. }
  484. }
  485. #ifdef UNIV_SYNC_DEBUG
  486. buf_block_buf_fix_inc_debug(block, file, line);
  487. #else
  488. buf_block_buf_fix_inc(block);
  489. #endif
  490. buf_block_make_young(block);
  491. /* Check if this is the first access to the page */
  492. accessed = block->accessed;
  493. block->accessed = TRUE;
  494. mutex_exit(&(buf_pool->mutex));
  495. #ifdef UNIV_DEBUG
  496. buf_dbg_counter++;
  497. if (buf_dbg_counter % 5771 == 0) {
  498. ut_ad(buf_validate());
  499. }
  500. #endif
  501. ut_ad(block->buf_fix_count > 0);
  502. ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
  503. if (mode == BUF_GET_NOWAIT) {
  504. if (rw_latch == RW_S_LATCH) {
  505. success = rw_lock_s_lock_func_nowait(&(block->lock)
  506. #ifdef UNIV_SYNC_DEBUG
  507. ,file, line
  508. #endif
  509.     );
  510. fix_type = MTR_MEMO_PAGE_S_FIX;
  511. } else {
  512. ut_ad(rw_latch == RW_X_LATCH);
  513. success = rw_lock_x_lock_func_nowait(&(block->lock)
  514. #ifdef UNIV_SYNC_DEBUG
  515. ,file, line
  516. #endif
  517.     );
  518. fix_type = MTR_MEMO_PAGE_X_FIX;
  519. }
  520. if (!success) {
  521. mutex_enter(&(buf_pool->mutex));
  522. block->buf_fix_count--;
  523. #ifdef UNIV_SYNC_DEBUG
  524. rw_lock_s_unlock(&(block->debug_latch));
  525. #endif
  526. mutex_exit(&(buf_pool->mutex));
  527. return(NULL);
  528. }
  529. } else if (rw_latch == RW_NO_LATCH) {
  530. if (must_read) {
  531. rw_lock_x_lock(&(block->read_lock));
  532. rw_lock_x_unlock(&(block->read_lock));
  533. }
  534. fix_type = MTR_MEMO_BUF_FIX;
  535. } else if (rw_latch == RW_S_LATCH) {
  536. rw_lock_s_lock_func(&(block->lock)
  537. #ifdef UNIV_SYNC_DEBUG
  538. ,0, file, line
  539. #endif
  540.     );
  541. fix_type = MTR_MEMO_PAGE_S_FIX;
  542. } else {
  543. rw_lock_x_lock_func(&(block->lock), 0
  544. #ifdef UNIV_SYNC_DEBUG
  545. , file, line
  546. #endif
  547.     );
  548. fix_type = MTR_MEMO_PAGE_X_FIX;
  549. }
  550. mtr_memo_push(mtr, block, fix_type);
  551. if (!accessed) {
  552. /* In the case of a first access, try to apply linear
  553. read-ahead */
  554. buf_read_ahead_linear(space, offset);
  555. }
  556. #ifdef UNIV_IBUF_DEBUG
  557. ut_a(ibuf_count_get(block->space, block->offset) == 0);
  558. #endif
  559. return(block->frame);
  560. }
  561. /************************************************************************
  562. This is the general function used to get optimistic access to a database
  563. page. */
  564. ibool
  565. buf_page_optimistic_get_func(
  566. /*=========================*/
  567. /* out: TRUE if success */
  568. ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
  569. buf_frame_t* guess, /* in: guessed frame */
  570. dulint modify_clock,/* in: modify clock value if mode is
  571. ..._GUESS_ON_CLOCK */
  572. #ifdef UNIV_SYNC_DEBUG
  573. char* file, /* in: file name */
  574. ulint line, /* in: line where called */
  575. #endif
  576. mtr_t* mtr) /* in: mini-transaction */
  577. {
  578. buf_block_t* block;
  579. ibool accessed;
  580. ibool success;
  581. ulint fix_type;
  582. ut_ad(mtr && guess);
  583. ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
  584. block = buf_block_align(guess);
  585. mutex_enter(&(buf_pool->mutex));
  586. if (block->state != BUF_BLOCK_FILE_PAGE) {
  587. mutex_exit(&(buf_pool->mutex));
  588. return(FALSE);
  589. }
  590. #ifdef UNIV_SYNC_DEBUG
  591. buf_block_buf_fix_inc_debug(block, file, line);
  592. #else
  593. buf_block_buf_fix_inc(block);
  594. #endif
  595. buf_block_make_young(block);
  596. /* Check if this is the first access to the page */
  597. accessed = block->accessed;
  598. block->accessed = TRUE;
  599. mutex_exit(&(buf_pool->mutex));
  600. ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset));
  601. if (rw_latch == RW_S_LATCH) {
  602. success = rw_lock_s_lock_func_nowait(&(block->lock)
  603. #ifdef UNIV_SYNC_DEBUG
  604. , file, line
  605. #endif
  606. );
  607. fix_type = MTR_MEMO_PAGE_S_FIX;
  608. } else {
  609. success = rw_lock_x_lock_func_nowait(&(block->lock)
  610. #ifdef UNIV_SYNC_DEBUG
  611. , file, line
  612. #endif
  613. );
  614. fix_type = MTR_MEMO_PAGE_X_FIX;
  615. }
  616. if (!success) {
  617. mutex_enter(&(buf_pool->mutex));
  618. block->buf_fix_count--;
  619. #ifdef UNIV_SYNC_DEBUG
  620. rw_lock_s_unlock(&(block->debug_latch));
  621. #endif
  622. mutex_exit(&(buf_pool->mutex));
  623. return(FALSE);
  624. }
  625. if (!UT_DULINT_EQ(modify_clock, block->modify_clock)) {
  626. buf_page_dbg_add_level(block->frame, SYNC_NO_ORDER_CHECK);
  627. if (rw_latch == RW_S_LATCH) {
  628. rw_lock_s_unlock(&(block->lock));
  629. } else {
  630. rw_lock_x_unlock(&(block->lock));
  631. }
  632. mutex_enter(&(buf_pool->mutex));
  633. block->buf_fix_count--;
  634. #ifdef UNIV_SYNC_DEBUG
  635. rw_lock_s_unlock(&(block->debug_latch));
  636. #endif
  637. mutex_exit(&(buf_pool->mutex));
  638. return(FALSE);
  639. }
  640. mtr_memo_push(mtr, block, fix_type);
  641. #ifdef UNIV_DEBUG
  642. buf_dbg_counter++;
  643. if (buf_dbg_counter % 5771 == 0) {
  644. ut_ad(buf_validate());
  645. }
  646. #endif
  647. ut_ad(block->buf_fix_count > 0);
  648. ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
  649. if (!accessed) {
  650. /* In the case of a first access, try to apply linear
  651. read-ahead */
  652. buf_read_ahead_linear(buf_frame_get_space_id(guess),
  653. buf_frame_get_page_no(guess));
  654. }
  655. #ifdef UNIV_IBUF_DEBUG
  656. ut_a(ibuf_count_get(block->space, block->offset) == 0);
  657. #endif
  658. return(TRUE);
  659. }
  660. /************************************************************************
  661. This is used to get access to a known database page, when no waiting can be
  662. done. */
  663. ibool
  664. buf_page_get_known_nowait(
  665. /*======================*/
  666. /* out: TRUE if success */
  667. ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
  668. buf_frame_t* guess, /* in: the known page frame */
  669. ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
  670. #ifdef UNIV_SYNC_DEBUG
  671. char* file, /* in: file name */
  672. ulint line, /* in: line where called */
  673. #endif
  674. mtr_t* mtr) /* in: mini-transaction */
  675. {
  676. buf_block_t* block;
  677. ibool success;
  678. ulint fix_type;
  679. ut_ad(mtr);
  680. ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
  681. block = buf_block_align(guess);
  682. mutex_enter(&(buf_pool->mutex));
  683. if (block->state == BUF_BLOCK_REMOVE_HASH) {
  684.         /* Another thread is just freeing the block from the LRU list
  685.         of the buffer pool: do not try to access this page; this
  686. attempt to access the page can only come through the hash
  687. index because when the buffer block state is ..._REMOVE_HASH,
  688. we have already removed it from the page address hash table
  689. of the buffer pool. */
  690.         mutex_exit(&(buf_pool->mutex));
  691. return(FALSE);
  692. }
  693. #ifdef UNIV_SYNC_DEBUG
  694. buf_block_buf_fix_inc_debug(block, file, line);
  695. #else
  696. buf_block_buf_fix_inc(block);
  697. #endif
  698. if (mode == BUF_MAKE_YOUNG) {
  699. buf_block_make_young(block);
  700. }
  701. mutex_exit(&(buf_pool->mutex));
  702. ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
  703. if (rw_latch == RW_S_LATCH) {
  704. success = rw_lock_s_lock_func_nowait(&(block->lock)
  705. #ifdef UNIV_SYNC_DEBUG
  706. , file, line
  707. #endif
  708. );
  709. fix_type = MTR_MEMO_PAGE_S_FIX;
  710. } else {
  711. success = rw_lock_x_lock_func_nowait(&(block->lock)
  712. #ifdef UNIV_SYNC_DEBUG
  713. , file, line
  714. #endif
  715. );
  716. fix_type = MTR_MEMO_PAGE_X_FIX;
  717. }
  718. if (!success) {
  719. mutex_enter(&(buf_pool->mutex));
  720. block->buf_fix_count--;
  721. #ifdef UNIV_SYNC_DEBUG
  722. rw_lock_s_unlock(&(block->debug_latch));
  723. #endif
  724. mutex_exit(&(buf_pool->mutex));
  725. return(FALSE);
  726. }
  727. mtr_memo_push(mtr, block, fix_type);
  728. #ifdef UNIV_DEBUG
  729. buf_dbg_counter++;
  730. if (buf_dbg_counter % 5771 == 0) {
  731. ut_ad(buf_validate());
  732. }
  733. #endif
  734. ut_ad(block->buf_fix_count > 0);
  735. ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
  736. #ifdef UNIV_IBUF_DEBUG
  737. ut_a((mode == BUF_KEEP_OLD)
  738. || (ibuf_count_get(block->space, block->offset) == 0));
  739. #endif
  740. return(TRUE);
  741. }
  742. /************************************************************************
  743. Inits a page to the buffer buf_pool. */
  744. static
  745. void
  746. buf_page_init(
  747. /*==========*/
  748. /* out: pointer to the block */
  749. ulint space, /* in: space id */
  750. ulint offset, /* in: offset of the page within space
  751. in units of a page */
  752. buf_block_t* block) /* in: block to init */
  753. {
  754. ut_ad(mutex_own(&(buf_pool->mutex)));
  755. ut_ad(block->state == BUF_BLOCK_READY_FOR_USE);
  756. /* Set the state of the block */
  757. block->state  = BUF_BLOCK_FILE_PAGE;
  758. block->space  = space;
  759. block->offset  = offset;
  760. block->lock_hash_val = lock_rec_hash(space, offset);
  761. block->lock_mutex = NULL;
  762. /* Insert into the hash table of file pages */
  763. HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
  764. buf_page_address_fold(space, offset), block);
  765. block->freed_page_clock = 0;
  766. block->newest_modification = ut_dulint_zero;
  767. block->oldest_modification = ut_dulint_zero;
  768. block->accessed = FALSE;
  769. block->buf_fix_count  = 0;
  770. block->io_fix = 0;
  771. block->n_hash_helps = 0;
  772. block->is_hashed = FALSE;
  773. }
  774. /************************************************************************
  775. Function which inits a page for read to the buffer buf_pool. If the page is
  776. already in buf_pool, does nothing. Sets the io_fix flag to BUF_IO_READ and
  777. sets a non-recursive exclusive lock on the buffer frame. The io-handler must
  778. take care that the flag is cleared and the lock released later. This is one
  779. of the functions which perform the state transition NOT_USED => FILE_PAGE to
  780. a block (the other is buf_page_create). */ 
  781. buf_block_t*
  782. buf_page_init_for_read(
  783. /*===================*/
  784. /* out: pointer to the block or NULL */
  785. ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
  786. ulint space, /* in: space id */
  787. ulint offset) /* in: page number */
  788. {
  789. buf_block_t* block;
  790. mtr_t mtr;
  791. ut_ad(buf_pool);
  792. if (mode == BUF_READ_IBUF_PAGES_ONLY) {
  793. /* It is a read-ahead within an ibuf routine */
  794. ut_ad(!ibuf_bitmap_page(offset));
  795. ut_ad(ibuf_inside());
  796. mtr_start(&mtr);
  797. if (!ibuf_page_low(space, offset, &mtr)) {
  798. mtr_commit(&mtr);
  799. return(NULL);
  800. }
  801. } else {
  802. ut_ad(mode == BUF_READ_ANY_PAGE);
  803. }
  804. block = buf_block_alloc();
  805. ut_ad(block);
  806. mutex_enter(&(buf_pool->mutex));
  807. if (NULL != buf_page_hash_get(space, offset)) {
  808. /* The page is already in buf_pool, return */
  809. mutex_exit(&(buf_pool->mutex));
  810. buf_block_free(block);
  811. if (mode == BUF_READ_IBUF_PAGES_ONLY) {
  812. mtr_commit(&mtr);
  813. }
  814. return(NULL);
  815. }
  816. ut_ad(block);
  817. buf_page_init(space, offset, block);
  818. /* The block must be put to the LRU list, to the old blocks */
  819. buf_LRU_add_block(block, TRUE);  /* TRUE == to old blocks */
  820. block->io_fix = BUF_IO_READ;
  821. buf_pool->n_pend_reads++;
  822. /* We set a pass-type x-lock on the frame because then the same
  823. thread which called for the read operation (and is running now at
  824. this point of code) can wait for the read to complete by waiting
  825. for the x-lock on the frame; if the x-lock were recursive, the
  826. same thread would illegally get the x-lock before the page read
  827. is completed. The x-lock is cleared by the io-handler thread. */
  828. rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
  829. rw_lock_x_lock_gen(&(block->read_lock), BUF_IO_READ);
  830.   mutex_exit(&(buf_pool->mutex));
  831. if (mode == BUF_READ_IBUF_PAGES_ONLY) {
  832. mtr_commit(&mtr);
  833. }
  834. return(block);
  835. }
  836. /************************************************************************
  837. Initializes a page to the buffer buf_pool. The page is usually not read
  838. from a file even if it cannot be found in the buffer buf_pool. This is one
  839. of the functions which perform to a block a state transition NOT_USED =>
  840. FILE_PAGE (the other is buf_page_init_for_read above). */
  841. buf_frame_t*
  842. buf_page_create(
  843. /*============*/
  844. /* out: pointer to the frame, page bufferfixed */
  845. ulint space, /* in: space id */
  846. ulint offset, /* in: offset of the page within space in units of
  847. a page */
  848. mtr_t* mtr) /* in: mini-transaction handle */
  849. {
  850. buf_frame_t* frame;
  851. buf_block_t* block;
  852. buf_block_t* free_block = NULL;
  853. ut_ad(mtr);
  854. free_block = buf_LRU_get_free_block();
  855. /* Delete possible entries for the page from the insert buffer:
  856. such can exist if the page belonged to an index which was dropped */
  857. ibuf_merge_or_delete_for_page(NULL, space, offset);
  858. mutex_enter(&(buf_pool->mutex));
  859. block = buf_page_hash_get(space, offset);
  860. if (block != NULL) {
  861. #ifdef UNIV_IBUF_DEBUG
  862. ut_a(ibuf_count_get(block->space, block->offset) == 0);
  863. #endif
  864. /* Page can be found in buf_pool */
  865. mutex_exit(&(buf_pool->mutex));
  866. buf_block_free(free_block);
  867. frame = buf_page_get_with_no_latch(space, offset, mtr);
  868. return(frame);
  869. }
  870. /* If we get here, the page was not in buf_pool: init it there */
  871. if (buf_debug_prints) {
  872. printf("Creating space %lu page %lu to buffern", space,
  873. offset);
  874. }
  875. block = free_block;
  876. buf_page_init(space, offset, block);
  877. /* The block must be put to the LRU list */
  878. buf_LRU_add_block(block, FALSE);
  879. #ifdef UNIV_SYNC_DEBUG
  880. buf_block_buf_fix_inc_debug(block, IB__FILE__, __LINE__);
  881. #else
  882. buf_block_buf_fix_inc(block);
  883. #endif
  884. mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
  885. block->accessed = TRUE;
  886. buf_pool->n_pages_created++;
  887. mutex_exit(&(buf_pool->mutex));
  888. /* Flush pages from the end of the LRU list if necessary */
  889. buf_flush_free_margin();
  890. frame = block->frame;
  891. #ifdef UNIV_DEBUG
  892. buf_dbg_counter++;
  893. if (buf_dbg_counter % 357 == 0) {
  894. ut_ad(buf_validate());
  895. }
  896. #endif
  897. #ifdef UNIV_IBUF_DEBUG
  898. ut_a(ibuf_count_get(block->space, block->offset) == 0);
  899. #endif
  900. return(frame);
  901. }
  902. /************************************************************************
  903. Completes an asynchronous read or write request of a file page to or from
  904. the buffer pool. */
  905. void
  906. buf_page_io_complete(
  907. /*=================*/
  908. buf_block_t* block) /* in: pointer to the block in question */
  909. {
  910. dulint id;
  911. dict_index_t* index;
  912. ulint io_type;
  913. ut_ad(block);
  914. io_type = block->io_fix;
  915. if (io_type == BUF_IO_READ) {
  916. if (recv_recovery_is_on()) {
  917. recv_recover_page(TRUE, block->frame, block->space,
  918. block->offset);
  919. }
  920. if (!recv_no_ibuf_operations) {
  921. ibuf_merge_or_delete_for_page(block->frame,
  922. block->space, block->offset);
  923. }
  924. }
  925. #ifdef UNIV_IBUF_DEBUG
  926. ut_a(ibuf_count_get(block->space, block->offset) == 0);
  927. #endif
  928. mutex_enter(&(buf_pool->mutex));
  929. /* Because this thread which does the unlocking is not the same that
  930. did the locking, we use a pass value != 0 in unlock, which simply
  931. removes the newest lock debug record, without checking the thread
  932. id. */
  933. block->io_fix = 0;
  934. if (io_type == BUF_IO_READ) {
  935. /* NOTE that the call to ibuf may have moved the ownership of
  936. the x-latch to this OS thread: do not let this confuse you in
  937. debugging! */
  938. ut_ad(buf_pool->n_pend_reads > 0);
  939. buf_pool->n_pend_reads--;
  940. buf_pool->n_pages_read++;
  941. /*
  942. if (0 != ut_dulint_cmp(
  943. mach_read_from_8(block->frame + FIL_PAGE_LSN),
  944. mach_read_from_8(block->frame + UNIV_PAGE_SIZE
  945. - FIL_PAGE_END_LSN))) {
  946. printf("DB error: file page corrupted!n");
  947. ut_error;
  948. }
  949. */
  950. rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);
  951. rw_lock_x_unlock_gen(&(block->read_lock), BUF_IO_READ);
  952. if (buf_debug_prints) {
  953. printf("Has read ");
  954. }
  955. } else {
  956. ut_ad(io_type == BUF_IO_WRITE);
  957. /* Write means a flush operation: call the completion
  958. routine in the flush system */
  959. buf_flush_write_complete(block);
  960. rw_lock_s_unlock_gen(&(block->lock), BUF_IO_WRITE);
  961. buf_pool->n_pages_written++;
  962. if (buf_debug_prints) {
  963. printf("Has written ");
  964. }
  965. }
  966. mutex_exit(&(buf_pool->mutex));
  967. if (buf_debug_prints) {
  968. printf("page space %lu page no %lu", block->space,
  969. block->offset);
  970. id = btr_page_get_index_id(block->frame);
  971. index = NULL;
  972. /* The following can cause deadlocks if used: */
  973. /*
  974. index = dict_index_get_if_in_cache(id);
  975.    if (index) {
  976. printf(" index name %s table %s", index->name,
  977. index->table->name);
  978. }
  979. */
  980. printf("n");
  981. }
  982. }
  983. /*************************************************************************
  984. Invalidates the file pages in the buffer pool when an archive recovery is
  985. completed. All the file pages buffered must be in a replaceable state when
  986. this function is called: not latched and not modified. */
  987. void
  988. buf_pool_invalidate(void)
  989. /*=====================*/
  990. {
  991. ibool freed;
  992. ut_ad(buf_all_freed());
  993. freed = TRUE;
  994. while (freed) {
  995. freed = buf_LRU_search_and_free_block(0);
  996. }
  997. mutex_enter(&(buf_pool->mutex));
  998. ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
  999. mutex_exit(&(buf_pool->mutex));
  1000. }
  1001. /*************************************************************************
  1002. Validates the buffer buf_pool data structure. */
  1003. ibool
  1004. buf_validate(void)
  1005. /*==============*/
  1006. {
  1007. buf_block_t* block;
  1008. ulint i;
  1009. ulint n_single_flush = 0;
  1010. ulint n_lru_flush = 0;
  1011. ulint n_list_flush = 0;
  1012. ulint n_lru = 0;
  1013. ulint n_flush = 0;
  1014. ulint n_free = 0;
  1015. ulint n_page = 0;
  1016. ut_ad(buf_pool);
  1017. mutex_enter(&(buf_pool->mutex));
  1018. for (i = 0; i < buf_pool->curr_size; i++) {
  1019. block = buf_pool_get_nth_block(buf_pool, i);
  1020. if (block->state == BUF_BLOCK_FILE_PAGE) {
  1021. ut_a(buf_page_hash_get(block->space,
  1022. block->offset) == block);
  1023. n_page++;
  1024. #ifdef UNIV_IBUF_DEBUG
  1025. ut_a((block->io_fix == BUF_IO_READ)
  1026.      || ibuf_count_get(block->space, block->offset)
  1027. == 0);
  1028. #endif
  1029. if (block->io_fix == BUF_IO_WRITE) {
  1030. if (block->flush_type == BUF_FLUSH_LRU) {
  1031. n_lru_flush++;
  1032. ut_a(rw_lock_is_locked(&(block->lock),
  1033. RW_LOCK_SHARED));
  1034. } else if (block->flush_type ==
  1035. BUF_FLUSH_LIST) {
  1036. n_list_flush++;
  1037. } else if (block->flush_type ==
  1038. BUF_FLUSH_SINGLE_PAGE) {
  1039. n_single_flush++;
  1040. } else {
  1041. ut_error;
  1042. }
  1043. } else if (block->io_fix == BUF_IO_READ) {
  1044. ut_a(rw_lock_is_locked(&(block->lock),
  1045. RW_LOCK_EX));
  1046. }
  1047. n_lru++;
  1048. if (ut_dulint_cmp(block->oldest_modification,
  1049. ut_dulint_zero) > 0) {
  1050. n_flush++;
  1051. }
  1052. } else if (block->state == BUF_BLOCK_NOT_USED) {
  1053. n_free++;
  1054. }
  1055.   }
  1056. if (n_lru + n_free > buf_pool->curr_size) {
  1057. printf("n LRU %lu, n free %lun", n_lru, n_free);
  1058. ut_error;
  1059. }
  1060. ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
  1061. if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
  1062. printf("Free list len %lu, free blocks %lun",
  1063.     UT_LIST_GET_LEN(buf_pool->free), n_free);
  1064. ut_error;
  1065. }
  1066. ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
  1067. ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
  1068. ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
  1069. ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
  1070. mutex_exit(&(buf_pool->mutex));
  1071. ut_a(buf_LRU_validate());
  1072. ut_a(buf_flush_validate());
  1073. return(TRUE);
  1074. }
  1075. /*************************************************************************
  1076. Prints info of the buffer buf_pool data structure. */
  1077. void
  1078. buf_print(void)
  1079. /*===========*/
  1080. {
  1081. dulint* index_ids;
  1082. ulint* counts;
  1083. ulint size;
  1084. ulint i;
  1085. ulint j;
  1086. dulint id;
  1087. ulint n_found;
  1088. buf_frame_t*  frame;
  1089. dict_index_t* index;
  1090. ut_ad(buf_pool);
  1091. size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE;
  1092. index_ids = mem_alloc(sizeof(dulint) * size);
  1093. counts = mem_alloc(sizeof(ulint) * size);
  1094. mutex_enter(&(buf_pool->mutex));
  1095. printf("LRU len %lu n", UT_LIST_GET_LEN(buf_pool->LRU));
  1096. printf("free len %lu n", UT_LIST_GET_LEN(buf_pool->free));
  1097. printf("flush len %lu n", UT_LIST_GET_LEN(buf_pool->flush_list));
  1098. printf("buf_pool size %lu n", size);
  1099. printf("n pending reads %lu n", buf_pool->n_pend_reads);
  1100. printf("n pending flush LRU %lu list %lu single page %lun",
  1101. buf_pool->n_flush[BUF_FLUSH_LRU],
  1102. buf_pool->n_flush[BUF_FLUSH_LIST],
  1103. buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
  1104. printf("pages read %lu, created %lu, written %lun",
  1105. buf_pool->n_pages_read, buf_pool->n_pages_created,
  1106. buf_pool->n_pages_written);
  1107. /* Count the number of blocks belonging to each index in the buffer */
  1108. n_found = 0;
  1109. for (i = 0 ; i < size; i++) {
  1110. counts[i] = 0;
  1111. }
  1112. for (i = 0; i < size; i++) {
  1113. frame = buf_pool_get_nth_block(buf_pool, i)->frame;
  1114. if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
  1115. id = btr_page_get_index_id(frame);
  1116. /* Look for the id in the index_ids array */
  1117. j = 0;
  1118. while (j < n_found) {
  1119. if (ut_dulint_cmp(index_ids[j], id) == 0) {
  1120. (counts[j])++;
  1121. break;
  1122. }
  1123. j++;
  1124. }
  1125. if (j == n_found) {
  1126. n_found++;
  1127. index_ids[j] = id;
  1128. counts[j] = 1;
  1129. }
  1130. }
  1131. }
  1132. mutex_exit(&(buf_pool->mutex));
  1133. for (i = 0; i < n_found; i++) {
  1134. index = dict_index_get_if_in_cache(index_ids[i]);
  1135. printf("Block count for index %lu in buffer is about %lu",
  1136. ut_dulint_get_low(index_ids[i]), counts[i]);
  1137. if (index) {
  1138. printf(" index name %s table %s", index->name,
  1139. index->table->name);
  1140. }
  1141. printf("n");
  1142. }
  1143. mem_free(index_ids);
  1144. mem_free(counts);
  1145. ut_a(buf_validate());
  1146. }
  1147. /*************************************************************************
  1148. Prints info of the buffer i/o. */
  1149. void
  1150. buf_print_io(void)
  1151. /*==============*/
  1152. {
  1153. ut_ad(buf_pool);
  1154. mutex_enter(&(buf_pool->mutex));
  1155. printf("pages read %lu, created %lu, written %lun",
  1156. buf_pool->n_pages_read, buf_pool->n_pages_created,
  1157. buf_pool->n_pages_written);
  1158. mutex_exit(&(buf_pool->mutex));
  1159. }
  1160. /*************************************************************************
  1161. Checks that all file pages in the buffer are in a replaceable state. */
  1162. ibool
  1163. buf_all_freed(void)
  1164. /*===============*/
  1165. {
  1166. buf_block_t* block;
  1167. ulint i;
  1168. ut_ad(buf_pool);
  1169. mutex_enter(&(buf_pool->mutex));
  1170. for (i = 0; i < buf_pool->curr_size; i++) {
  1171. block = buf_pool_get_nth_block(buf_pool, i);
  1172. if (block->state == BUF_BLOCK_FILE_PAGE) {
  1173. if (!buf_flush_ready_for_replace(block)) {
  1174.      /* printf("Page %lu %lu still fixed or dirtyn",
  1175.      block->space, block->offset); */
  1176.      ut_error;
  1177. }
  1178. }
  1179.   }
  1180. mutex_exit(&(buf_pool->mutex));
  1181. return(TRUE);
  1182. }
  1183. /*************************************************************************
  1184. Checks that there currently are no pending i/o-operations for the buffer
  1185. pool. */
  1186. ibool
  1187. buf_pool_check_no_pending_io(void)
  1188. /*==============================*/
  1189. /* out: TRUE if there is no pending i/o */
  1190. {
  1191. ibool ret;
  1192. mutex_enter(&(buf_pool->mutex));
  1193. if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU]
  1194. + buf_pool->n_flush[BUF_FLUSH_LIST]
  1195. + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
  1196. ret = FALSE;
  1197. } else {
  1198. ret = TRUE;
  1199. }
  1200. mutex_exit(&(buf_pool->mutex));
  1201. return(ret);
  1202. }
  1203. /*************************************************************************
  1204. Gets the current length of the free list of buffer blocks. */
  1205. ulint
  1206. buf_get_free_list_len(void)
  1207. /*=======================*/
  1208. {
  1209. ulint len;
  1210. mutex_enter(&(buf_pool->mutex));
  1211. len = UT_LIST_GET_LEN(buf_pool->free);
  1212. mutex_exit(&(buf_pool->mutex));
  1213. return(len);
  1214. }