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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The database buffer replacement algorithm
  3. (c) 1995 Innobase Oy
  4. Created 11/5/1995 Heikki Tuuri
  5. *******************************************************/
  6. #include "buf0lru.h"
  7. #ifdef UNIV_NONINL
  8. #include "buf0lru.ic"
  9. #endif
  10. #include "ut0byte.h"
  11. #include "ut0lst.h"
  12. #include "ut0rnd.h"
  13. #include "sync0sync.h"
  14. #include "sync0rw.h"
  15. #include "hash0hash.h"
  16. #include "os0sync.h"
  17. #include "fil0fil.h"
  18. #include "btr0btr.h"
  19. #include "buf0buf.h"
  20. #include "buf0flu.h"
  21. #include "buf0rea.h"
  22. #include "btr0sea.h"
  23. #include "os0file.h"
  24. /* The number of blocks from the LRU_old pointer onward, including the block
  25. pointed to, must be 3/8 of the whole LRU list length, except that the
  26. tolerance defined below is allowed. Note that the tolerance must be small
  27. enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the
  28. LRU_old pointer is not allowed to point to either end of the LRU list. */
  29. #define BUF_LRU_OLD_TOLERANCE 20
  30. /* The whole LRU list length is divided by this number to determine an
  31. initial segment in buf_LRU_get_recent_limit */
  32. #define BUF_LRU_INITIAL_RATIO 8
  33. /**********************************************************************
  34. Takes a block out of the LRU list and page hash table and sets the block
  35. state to BUF_BLOCK_REMOVE_HASH. */
  36. static
  37. void
  38. buf_LRU_block_remove_hashed_page(
  39. /*=============================*/
  40. buf_block_t* block); /* in: block, must contain a file page and
  41. be in a state where it can be freed; there
  42. may or may not be a hash index to the page */
  43. /**********************************************************************
  44. Puts a file page whose has no hash index to the free list. */
  45. static
  46. void
  47. buf_LRU_block_free_hashed_page(
  48. /*===========================*/
  49. buf_block_t* block); /* in: block, must contain a file page and
  50. be in a state where it can be freed */
  51. /**********************************************************************
  52. Gets the minimum LRU_position field for the blocks in an initial segment
  53. (determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
  54. guaranteed to be precise, because the ulint_clock may wrap around. */
  55. ulint
  56. buf_LRU_get_recent_limit(void)
  57. /*==========================*/
  58. /* out: the limit; zero if could not determine it */
  59. {
  60. buf_block_t* block;
  61. ulint len;
  62. ulint limit;
  63. mutex_enter(&(buf_pool->mutex));
  64. len = UT_LIST_GET_LEN(buf_pool->LRU);
  65. if (len < BUF_LRU_OLD_MIN_LEN) {
  66. /* The LRU list is too short to do read-ahead */
  67. mutex_exit(&(buf_pool->mutex));
  68. return(0);
  69. }
  70. block = UT_LIST_GET_FIRST(buf_pool->LRU);
  71. limit = block->LRU_position - len / BUF_LRU_INITIAL_RATIO;
  72. mutex_exit(&(buf_pool->mutex));
  73. return(limit);
  74. }
  75. /**********************************************************************
  76. Look for a replaceable block from the end of the LRU list and put it to
  77. the free list if found. */
  78. ibool
  79. buf_LRU_search_and_free_block(
  80. /*==========================*/
  81. /* out: TRUE if freed */
  82. ulint n_iterations) /* in: how many times this has been called
  83. repeatedly without result: a high value
  84. means that we should search farther */
  85. {
  86. buf_block_t* block;
  87. ulint distance;
  88. ibool freed;
  89. ulint i;
  90. mutex_enter(&(buf_pool->mutex));
  91. freed = FALSE;
  92. distance = BUF_LRU_FREE_SEARCH_LEN * (1 + n_iterations / 5);
  93. i = 0;
  94. block = UT_LIST_GET_LAST(buf_pool->LRU);
  95. while (i < distance && block != NULL) {
  96. if (buf_flush_ready_for_replace(block)) {
  97. if (buf_debug_prints) {
  98. printf(
  99. "Putting space %lu page %lu to free listn",
  100. block->space, block->offset);
  101. }
  102. buf_LRU_block_remove_hashed_page(block);
  103. mutex_exit(&(buf_pool->mutex));
  104. btr_search_drop_page_hash_index(block->frame);
  105. mutex_enter(&(buf_pool->mutex));
  106. ut_a(block->buf_fix_count == 0);
  107. buf_LRU_block_free_hashed_page(block);
  108. freed = TRUE;
  109. break;
  110. }
  111. block = UT_LIST_GET_PREV(LRU, block);
  112. }
  113. if (buf_pool->LRU_flush_ended > 0) {
  114. buf_pool->LRU_flush_ended--;
  115. }
  116.  
  117. if (!freed) {
  118. buf_pool->LRU_flush_ended = 0;
  119. }
  120. mutex_exit(&(buf_pool->mutex));
  121. return(freed);
  122. }
  123. /**********************************************************************
  124. Tries to remove LRU flushed blocks from the end of the LRU list and put them
  125. to the free list. This is beneficial for the efficiency of the insert buffer
  126. operation, as flushed pages from non-unique non-clustered indexes are here
  127. taken out of the buffer pool, and their inserts redirected to the insert
  128. buffer. Otherwise, the flushed blocks could get modified again before read
  129. operations need new buffer blocks, and the i/o work done in flushing would be
  130. wasted. */
  131. void
  132. buf_LRU_try_free_flushed_blocks(void)
  133. /*=================================*/
  134. {
  135. mutex_enter(&(buf_pool->mutex));
  136. while (buf_pool->LRU_flush_ended > 0) {
  137. mutex_exit(&(buf_pool->mutex));
  138. buf_LRU_search_and_free_block(0);
  139. mutex_enter(&(buf_pool->mutex));
  140. }
  141. mutex_exit(&(buf_pool->mutex));
  142. }
  143. /**********************************************************************
  144. Returns a free block from buf_pool. The block is taken off the free list.
  145. If it is empty, blocks are moved from the end of the LRU list to the free
  146. list. */
  147. buf_block_t*
  148. buf_LRU_get_free_block(void)
  149. /*========================*/
  150. /* out: the free control block */
  151. {
  152. buf_block_t* block = NULL;
  153. ibool freed;
  154. ulint n_iterations = 0;
  155. loop:
  156. mutex_enter(&(buf_pool->mutex));
  157. if (buf_pool->LRU_flush_ended > 0) {
  158. mutex_exit(&(buf_pool->mutex));
  159. buf_LRU_try_free_flushed_blocks();
  160. mutex_enter(&(buf_pool->mutex));
  161. }
  162. /* If there is a block in the free list, take it */
  163. if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
  164. block = UT_LIST_GET_FIRST(buf_pool->free);
  165. UT_LIST_REMOVE(free, buf_pool->free, block);
  166. block->state = BUF_BLOCK_READY_FOR_USE;
  167. mutex_exit(&(buf_pool->mutex));
  168. return(block);
  169. }
  170. /* If no block was in the free list, search from the end of the LRU
  171. list and try to free a block there */
  172. mutex_exit(&(buf_pool->mutex));
  173. freed = buf_LRU_search_and_free_block(n_iterations);
  174. if (freed > 0) {
  175. goto loop;
  176. }
  177. /* No free block was found near the end of the list: try to flush
  178. the LRU list */
  179. buf_flush_free_margin();
  180. os_event_wait(buf_pool->no_flush[BUF_FLUSH_LRU]);
  181. n_iterations++;
  182. os_aio_simulated_wake_handler_threads();
  183. if (n_iterations > 10) {
  184. os_thread_sleep(500000);
  185. }
  186. if (n_iterations > 20) {
  187. /* buf_print();
  188. os_aio_print();
  189. rw_lock_list_print_info();
  190. */
  191. if (n_iterations > 30) {
  192. fprintf(stderr,
  193. "Innobase: Warning: difficult to find free blocks fromn"
  194. "Innobase: the buffer pool! Consider increasing then"
  195. "Innobase: buffer pool size.n");
  196. }
  197. }
  198. goto loop;
  199. }
  200. /***********************************************************************
  201. Moves the LRU_old pointer so that the length of the old blocks list
  202. is inside the allowed limits. */
  203. UNIV_INLINE
  204. void
  205. buf_LRU_old_adjust_len(void)
  206. /*========================*/
  207. {
  208. ulint old_len;
  209. ulint new_len;
  210. ut_ad(buf_pool->LRU_old);
  211. ut_ad(mutex_own(&(buf_pool->mutex)));
  212. ut_ad(3 * (BUF_LRU_OLD_MIN_LEN / 8) > BUF_LRU_OLD_TOLERANCE + 5);
  213. for (;;) {
  214. old_len = buf_pool->LRU_old_len;
  215. new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
  216. /* Update the LRU_old pointer if necessary */
  217. if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
  218. buf_pool->LRU_old = UT_LIST_GET_PREV(LRU,
  219. buf_pool->LRU_old);
  220. (buf_pool->LRU_old)->old = TRUE;
  221. buf_pool->LRU_old_len++;
  222. } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
  223. (buf_pool->LRU_old)->old = FALSE;
  224. buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU,
  225. buf_pool->LRU_old);
  226. buf_pool->LRU_old_len--;
  227. } else {
  228. ut_ad(buf_pool->LRU_old); /* Check that we did not
  229. fall out of the LRU list */
  230. return;
  231. }
  232. }
  233. }
  234. /***********************************************************************
  235. Initializes the old blocks pointer in the LRU list.
  236. This function should be called when the LRU list grows to
  237. BUF_LRU_OLD_MIN_LEN length. */
  238. static
  239. void
  240. buf_LRU_old_init(void)
  241. /*==================*/
  242. {
  243. buf_block_t* block;
  244. ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
  245. /* We first initialize all blocks in the LRU list as old and then use
  246. the adjust function to move the LRU_old pointer to the right
  247. position */
  248. block = UT_LIST_GET_FIRST(buf_pool->LRU);
  249. while (block != NULL) {
  250. block->old = TRUE;
  251. block = UT_LIST_GET_NEXT(LRU, block);
  252. }
  253. buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
  254. buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
  255. buf_LRU_old_adjust_len();
  256. }     
  257. /**********************************************************************
  258. Removes a block from the LRU list. */
  259. UNIV_INLINE
  260. void
  261. buf_LRU_remove_block(
  262. /*=================*/
  263. buf_block_t* block) /* in: control block */
  264. {
  265. ut_ad(buf_pool);
  266. ut_ad(block);
  267. ut_ad(mutex_own(&(buf_pool->mutex)));
  268. /* If the LRU_old pointer is defined and points to just this block,
  269. move it backward one step */
  270. if (block == buf_pool->LRU_old) {
  271. /* Below: the previous block is guaranteed to exist, because
  272. the LRU_old pointer is only allowed to differ by the
  273. tolerance value from strict 3/8 of the LRU list length. */
  274. buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, block);
  275. (buf_pool->LRU_old)->old = TRUE;
  276. buf_pool->LRU_old_len++;
  277. ut_ad(buf_pool->LRU_old);
  278. }
  279. /* Remove the block from the LRU list */
  280. UT_LIST_REMOVE(LRU, buf_pool->LRU, block);
  281. /* If the LRU list is so short that LRU_old not defined, return */
  282. if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
  283. buf_pool->LRU_old = NULL;
  284. return;
  285. }
  286. ut_ad(buf_pool->LRU_old);
  287. /* Update the LRU_old_len field if necessary */
  288. if (block->old) {
  289. buf_pool->LRU_old_len--;
  290. }
  291. /* Adjust the length of the old block list if necessary */
  292. buf_LRU_old_adjust_len();
  293. }     
  294. /**********************************************************************
  295. Adds a block to the LRU list end. */
  296. UNIV_INLINE
  297. void
  298. buf_LRU_add_block_to_end_low(
  299. /*=========================*/
  300. buf_block_t* block) /* in: control block */
  301. {
  302. buf_block_t* last_block;
  303. ut_ad(buf_pool);
  304. ut_ad(block);
  305. ut_ad(mutex_own(&(buf_pool->mutex)));
  306. block->old = TRUE;
  307. last_block = UT_LIST_GET_LAST(buf_pool->LRU);
  308. if (last_block) {
  309. block->LRU_position = last_block->LRU_position;
  310. } else {
  311. block->LRU_position = buf_pool_clock_tic();
  312. }
  313. UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block);
  314. if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
  315. buf_pool->LRU_old_len++;
  316. }
  317. if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
  318. ut_ad(buf_pool->LRU_old);
  319. /* Adjust the length of the old block list if necessary */
  320. buf_LRU_old_adjust_len();
  321. } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
  322. /* The LRU list is now long enough for LRU_old to become
  323. defined: init it */
  324. buf_LRU_old_init();
  325. }
  326. }     
  327. /**********************************************************************
  328. Adds a block to the LRU list. */
  329. UNIV_INLINE
  330. void
  331. buf_LRU_add_block_low(
  332. /*==================*/
  333. buf_block_t* block, /* in: control block */
  334. ibool old) /* in: TRUE if should be put to the old blocks
  335. in the LRU list, else put to the start; if the
  336. LRU list is very short, the block is added to
  337. the start, regardless of this parameter */
  338. {
  339. ulint cl;
  340. ut_ad(buf_pool);
  341. ut_ad(block);
  342. ut_ad(mutex_own(&(buf_pool->mutex)));
  343. block->old = old;
  344. cl = buf_pool_clock_tic();
  345. if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
  346. UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, block);
  347. block->LRU_position = cl;
  348. block->freed_page_clock = buf_pool->freed_page_clock;
  349. } else {
  350. UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
  351. block);
  352. buf_pool->LRU_old_len++;
  353. /* We copy the LRU position field of the previous block
  354. to the new block */
  355. block->LRU_position = (buf_pool->LRU_old)->LRU_position;
  356. }
  357. if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
  358. ut_ad(buf_pool->LRU_old);
  359. /* Adjust the length of the old block list if necessary */
  360. buf_LRU_old_adjust_len();
  361. } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
  362. /* The LRU list is now long enough for LRU_old to become
  363. defined: init it */
  364. buf_LRU_old_init();
  365. }
  366. }     
  367. /**********************************************************************
  368. Adds a block to the LRU list. */
  369. void
  370. buf_LRU_add_block(
  371. /*==============*/
  372. buf_block_t* block, /* in: control block */
  373. ibool old) /* in: TRUE if should be put to the old
  374. blocks in the LRU list, else put to the start;
  375. if the LRU list is very short, the block is
  376. added to the start, regardless of this
  377. parameter */
  378. {
  379. buf_LRU_add_block_low(block, old);
  380. }
  381. /**********************************************************************
  382. Moves a block to the start of the LRU list. */
  383. void
  384. buf_LRU_make_block_young(
  385. /*=====================*/
  386. buf_block_t* block) /* in: control block */
  387. {
  388. buf_LRU_remove_block(block);
  389. buf_LRU_add_block_low(block, FALSE);
  390. }
  391. /**********************************************************************
  392. Moves a block to the end of the LRU list. */
  393. void
  394. buf_LRU_make_block_old(
  395. /*===================*/
  396. buf_block_t* block) /* in: control block */
  397. {
  398. buf_LRU_remove_block(block);
  399. buf_LRU_add_block_to_end_low(block);
  400. }
  401. /**********************************************************************
  402. Puts a block back to the free list. */
  403. void
  404. buf_LRU_block_free_non_file_page(
  405. /*=============================*/
  406. buf_block_t* block) /* in: block, must not contain a file page */
  407. {
  408. ut_ad(mutex_own(&(buf_pool->mutex)));
  409. ut_ad(block);
  410. ut_ad((block->state == BUF_BLOCK_MEMORY)
  411.       || (block->state == BUF_BLOCK_READY_FOR_USE));
  412. block->state = BUF_BLOCK_NOT_USED;
  413. UT_LIST_ADD_FIRST(free, buf_pool->free, block);
  414. }
  415. /**********************************************************************
  416. Takes a block out of the LRU list and page hash table and sets the block
  417. state to BUF_BLOCK_REMOVE_HASH. */
  418. static
  419. void
  420. buf_LRU_block_remove_hashed_page(
  421. /*=============================*/
  422. buf_block_t* block) /* in: block, must contain a file page and
  423. be in a state where it can be freed; there
  424. may or may not be a hash index to the page */
  425. {
  426. ut_ad(mutex_own(&(buf_pool->mutex)));
  427. ut_ad(block);
  428. ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
  429. ut_a(block->io_fix == 0);
  430. ut_a(block->buf_fix_count == 0);
  431. ut_a(ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) == 0);
  432. buf_LRU_remove_block(block);
  433. buf_pool->freed_page_clock += 1;
  434.   buf_frame_modify_clock_inc(block->frame);
  435. HASH_DELETE(buf_block_t, hash, buf_pool->page_hash,
  436. buf_page_address_fold(block->space, block->offset),
  437. block);
  438. block->state = BUF_BLOCK_REMOVE_HASH;
  439. }
  440. /**********************************************************************
  441. Puts a file page whose has no hash index to the free list. */
  442. static
  443. void
  444. buf_LRU_block_free_hashed_page(
  445. /*===========================*/
  446. buf_block_t* block) /* in: block, must contain a file page and
  447. be in a state where it can be freed */
  448. {
  449. ut_ad(mutex_own(&(buf_pool->mutex)));
  450. ut_ad(block->state == BUF_BLOCK_REMOVE_HASH);
  451. block->state = BUF_BLOCK_MEMORY;
  452. buf_LRU_block_free_non_file_page(block);
  453. }
  454. /**************************************************************************
  455. Validates the LRU list. */
  456. ibool
  457. buf_LRU_validate(void)
  458. /*==================*/
  459. {
  460. buf_block_t* block;
  461. ulint old_len;
  462. ulint new_len;
  463. ulint LRU_pos;
  464. ut_ad(buf_pool);
  465. mutex_enter(&(buf_pool->mutex));
  466. if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
  467. ut_a(buf_pool->LRU_old);
  468. old_len = buf_pool->LRU_old_len;
  469. new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
  470. ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
  471. ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
  472. }
  473. UT_LIST_VALIDATE(LRU, buf_block_t, buf_pool->LRU);
  474. block = UT_LIST_GET_FIRST(buf_pool->LRU);
  475. old_len = 0;
  476. while (block != NULL) {
  477. ut_a(block->state == BUF_BLOCK_FILE_PAGE);
  478. if (block->old) {
  479. old_len++;
  480. }
  481. if (buf_pool->LRU_old && (old_len == 1)) {
  482. ut_a(buf_pool->LRU_old == block);
  483. }
  484. LRU_pos = block->LRU_position;
  485. block = UT_LIST_GET_NEXT(LRU, block);
  486. if (block) {
  487. /* If the following assert fails, it may
  488. not be an error: just the buf_pool clock
  489. has wrapped around */
  490. ut_a(LRU_pos >= block->LRU_position);
  491. }
  492. }
  493. if (buf_pool->LRU_old) {
  494. ut_a(buf_pool->LRU_old_len == old_len);
  495. UT_LIST_VALIDATE(free, buf_block_t, buf_pool->free);
  496. block = UT_LIST_GET_FIRST(buf_pool->free);
  497. while (block != NULL) {
  498. ut_a(block->state == BUF_BLOCK_NOT_USED);
  499. block = UT_LIST_GET_NEXT(free, block);
  500. }
  501. mutex_exit(&(buf_pool->mutex));
  502. return(TRUE);
  503. }
  504. /**************************************************************************
  505. Prints the LRU list. */
  506. void
  507. buf_LRU_print(void)
  508. /*===============*/
  509. {
  510. buf_block_t* block;
  511. buf_frame_t* frame;
  512. ulint len;
  513. ut_ad(buf_pool);
  514. mutex_enter(&(buf_pool->mutex));
  515. printf("Pool ulint clock %lun", buf_pool->ulint_clock);
  516. block = UT_LIST_GET_FIRST(buf_pool->LRU);
  517. len = 0;
  518. while (block != NULL) {
  519. printf("BLOCK %lu ", block->offset);
  520. if (block->old) {
  521. printf("old ");
  522. }
  523. if (block->buf_fix_count) {
  524. printf("buffix count %lu ", block->buf_fix_count);
  525. }
  526. if (block->io_fix) {
  527. printf("io_fix %lu ", block->io_fix);
  528. }
  529. if (ut_dulint_cmp(block->oldest_modification,
  530. ut_dulint_zero) > 0) {
  531. printf("modif. ");
  532. }
  533. printf("LRU pos %lu ", block->LRU_position);
  534. frame = buf_block_get_frame(block);
  535. printf("type %lu ", fil_page_get_type(frame));
  536. printf("index id %lu ", ut_dulint_get_low(
  537. btr_page_get_index_id(frame)));
  538. block = UT_LIST_GET_NEXT(LRU, block);
  539. len++;
  540. if (len % 10 == 0) {
  541. printf("n");
  542. }
  543. }
  544. mutex_exit(&(buf_pool->mutex));
  545. }