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

MySQL数据库

开发平台:

Visual C++

  1. /******************************************************
  2. The database buffer read
  3. (c) 1995 Innobase Oy
  4. Created 11/5/1995 Heikki Tuuri
  5. *******************************************************/
  6. #include "buf0rea.h"
  7. #include "fil0fil.h"
  8. #include "mtr0mtr.h"
  9. #include "buf0buf.h"
  10. #include "buf0flu.h"
  11. #include "buf0lru.h"
  12. #include "ibuf0ibuf.h"
  13. #include "log0recv.h"
  14. #include "trx0sys.h"
  15. #include "os0file.h"
  16. /* The size in blocks of the area where the random read-ahead algorithm counts
  17. the accessed pages when deciding whether to read-ahead */
  18. #define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA
  19. /* There must be at least this many pages in buf_pool in the area to start
  20. a random read-ahead */
  21. #define BUF_READ_AHEAD_RANDOM_THRESHOLD (5 + BUF_READ_AHEAD_RANDOM_AREA / 8)
  22. /* The linear read-ahead area size */
  23. #define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
  24. /* The linear read-ahead threshold */
  25. #define BUF_READ_AHEAD_LINEAR_THRESHOLD (3 * BUF_READ_AHEAD_LINEAR_AREA / 8)
  26. /* If there are buf_pool->curr_size per the number below pending reads, then
  27. read-ahead is not done: this is to prevent flooding the buffer pool with
  28. i/o-fixed buffer blocks */
  29. #define BUF_READ_AHEAD_PEND_LIMIT 2
  30. /************************************************************************
  31. Low-level function which reads a page asynchronously from a file to the
  32. buffer buf_pool if it is not already there, in which case does nothing.
  33. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The
  34. flag is cleared and the x-lock released by an i/o-handler thread. */
  35. static
  36. ulint
  37. buf_read_page_low(
  38. /*==============*/
  39. /* out: 1 if a read request was queued, 0 if the page
  40. already resided in buf_pool */
  41. ibool sync, /* in: TRUE if synchronous aio is desired */
  42. ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ...,
  43. ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
  44. at read-ahead functions) */
  45. ulint space, /* in: space id */
  46. ulint offset) /* in: page number */
  47. {
  48. buf_block_t* block;
  49. ulint wake_later;
  50. wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
  51. mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
  52. #ifdef UNIV_LOG_DEBUG
  53. if (space % 2 == 1) {
  54. /* We are updating a replicate space while holding the
  55. log mutex: the read must be handled before other reads
  56. which might incur ibuf operations and thus write to the log */
  57. printf("Log debug: reading replicate page in sync moden");
  58. sync = TRUE;
  59. }
  60. #endif
  61. if (trx_sys_hdr_page(space, offset)) {
  62. /* Trx sys header is so low in the latching order that we play
  63. safe and do not leave the i/o-completion to an asynchronous
  64. i/o-thread: */
  65. sync = TRUE;
  66. }
  67. block = buf_page_init_for_read(mode, space, offset);
  68. if (block != NULL) {
  69. fil_io(OS_FILE_READ | wake_later,
  70. sync, space, offset, 0, UNIV_PAGE_SIZE,
  71. (void*)block->frame, (void*)block);
  72. if (sync) {
  73. /* The i/o is already completed when we arrive from
  74. fil_read */
  75. buf_page_io_complete(block);
  76. }
  77. return(1);
  78. }
  79. return(0);
  80. }
  81. /************************************************************************
  82. Applies a random read-ahead in buf_pool if there are at least a threshold
  83. value of accessed pages from the random read-ahead area. Does not read any
  84. page, not even the one at the position (space, offset), if the read-ahead
  85. mechanism is not activated. NOTE 1: the calling thread may own latches on
  86. pages: to avoid deadlocks this function must be written such that it cannot
  87. end up waiting for these latches! NOTE 2: the calling thread must want
  88. access to the page given: this rule is set to prevent unintended read-aheads
  89. performed by ibuf routines, a situation which could result in a deadlock if
  90. the OS does not support asynchronous i/o. */
  91. static
  92. ulint
  93. buf_read_ahead_random(
  94. /*==================*/
  95. /* out: number of page read requests issued; NOTE
  96. that if we read ibuf pages, it may happen that
  97. the page at the given page number does not get
  98. read even if we return a value > 0! */
  99. ulint space, /* in: space id */
  100. ulint offset) /* in: page number of a page which the current thread
  101. wants to access */
  102. {
  103. buf_block_t* block;
  104. ulint recent_blocks = 0;
  105. ulint count;
  106. ulint LRU_recent_limit;
  107. ulint ibuf_mode;
  108. ulint low, high;
  109. ulint i;
  110. if (ibuf_bitmap_page(offset)) {
  111. /* If it is an ibuf bitmap page, we do no read-ahead, as
  112. that could break the ibuf page access order */
  113. return(0);
  114. }
  115. low  = (offset / BUF_READ_AHEAD_RANDOM_AREA)
  116. * BUF_READ_AHEAD_RANDOM_AREA;
  117. high = (offset / BUF_READ_AHEAD_RANDOM_AREA + 1)
  118. * BUF_READ_AHEAD_RANDOM_AREA;
  119. if (high > fil_space_get_size(space)) {
  120. high = fil_space_get_size(space);
  121. }
  122. /* Get the minimum LRU_position field value for an initial segment
  123. of the LRU list, to determine which blocks have recently been added
  124. to the start of the list. */
  125. LRU_recent_limit = buf_LRU_get_recent_limit();
  126. mutex_enter(&(buf_pool->mutex));
  127. if (buf_pool->n_pend_reads >
  128. buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
  129. mutex_exit(&(buf_pool->mutex));
  130. return(0);
  131. }
  132. /* Count how many blocks in the area have been recently accessed,
  133. that is, reside near the start of the LRU list. */
  134. for (i = low; i < high; i++) {
  135. block = buf_page_hash_get(space, i);
  136. if ((block)
  137.     && (block->LRU_position > LRU_recent_limit)
  138.     && block->accessed) {
  139. recent_blocks++;
  140. }
  141. }
  142. mutex_exit(&(buf_pool->mutex));
  143. if (recent_blocks < BUF_READ_AHEAD_RANDOM_THRESHOLD) {
  144. /* Do nothing */
  145. return(0);
  146. }
  147. /* Read all the suitable blocks within the area */
  148. if (ibuf_inside()) {
  149. ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
  150. } else {
  151. ibuf_mode = BUF_READ_ANY_PAGE;
  152. }
  153. count = 0;
  154. for (i = low; i < high; i++) {
  155. /* It is only sensible to do read-ahead in the non-sync aio
  156. mode: hence FALSE as the first parameter */
  157. if (!ibuf_bitmap_page(i)) {
  158. count += buf_read_page_low(FALSE, ibuf_mode
  159. | OS_AIO_SIMULATED_WAKE_LATER,
  160. space, i);
  161. }
  162. }
  163. /* In simulated aio we wake the aio handler threads only after
  164. queuing all aio requests, in native aio the following call does
  165. nothing: */
  166. os_aio_simulated_wake_handler_threads();
  167. if (buf_debug_prints && (count > 0)) {
  168. printf("Random read-ahead space %lu offset %lu pages %lun",
  169. space, offset, count);
  170. }
  171. return(count);
  172. }
  173. /************************************************************************
  174. High-level function which reads a page asynchronously from a file to the
  175. buffer buf_pool if it is not already there. Sets the io_fix flag and sets
  176. an exclusive lock on the buffer frame. The flag is cleared and the x-lock
  177. released by the i/o-handler thread. Does a random read-ahead if it seems
  178. sensible. */
  179. ulint
  180. buf_read_page(
  181. /*==========*/
  182. /* out: number of page read requests issued: this can
  183. be > 1 if read-ahead occurred */
  184. ulint space, /* in: space id */
  185. ulint offset) /* in: page number */
  186. {
  187. ulint count;
  188. ulint count2;
  189. count = buf_read_ahead_random(space, offset);
  190. /* We do the i/o in the synchronous aio mode to save thread
  191. switches: hence TRUE */
  192. count2 = buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space, offset);
  193. /* Flush pages from the end of the LRU list if necessary */
  194. buf_flush_free_margin();
  195. return(count + count2);
  196. }
  197. /************************************************************************
  198. Applies linear read-ahead if in the buf_pool the page is a border page of
  199. a linear read-ahead area and all the pages in the area have been accessed.
  200. Does not read any page if the read-ahead mechanism is not activated. Note
  201. that the the algorithm looks at the 'natural' adjacent successor and
  202. predecessor of the page, which on the leaf level of a B-tree are the next
  203. and previous page in the chain of leaves. To know these, the page specified
  204. in (space, offset) must already be present in the buf_pool. Thus, the
  205. natural way to use this function is to call it when a page in the buf_pool
  206. is accessed the first time, calling this function just after it has been
  207. bufferfixed.
  208. NOTE 1: as this function looks at the natural predecessor and successor
  209. fields on the page, what happens, if these are not initialized to any
  210. sensible value? No problem, before applying read-ahead we check that the
  211. area to read is within the span of the space, if not, read-ahead is not
  212. applied. An uninitialized value may result in a useless read operation, but
  213. only very improbably.
  214. NOTE 2: the calling thread may own latches on pages: to avoid deadlocks this
  215. function must be written such that it cannot end up waiting for these
  216. latches!
  217. NOTE 3: the calling thread must want access to the page given: this rule is
  218. set to prevent unintended read-aheads performed by ibuf routines, a situation
  219. which could result in a deadlock if the OS does not support asynchronous io. */
  220. ulint
  221. buf_read_ahead_linear(
  222. /*==================*/
  223. /* out: number of page read requests issued */
  224. ulint space, /* in: space id */
  225. ulint offset) /* in: page number of a page; NOTE: the current thread
  226. must want access to this page (see NOTE 3 above) */
  227. {
  228. buf_block_t* block;
  229. buf_frame_t* frame;
  230. buf_block_t* pred_block = NULL;
  231. ulint pred_offset;
  232. ulint succ_offset;
  233. ulint count;
  234. int asc_or_desc;
  235. ulint new_offset;
  236. ulint fail_count;
  237. ulint ibuf_mode;
  238. ulint low, high;
  239. ulint i;
  240. if (ibuf_bitmap_page(offset)) {
  241. /* If it is an ibuf bitmap page, we do no read-ahead, as
  242. that could break the ibuf page access order */
  243. return(0);
  244. }
  245. low  = (offset / BUF_READ_AHEAD_LINEAR_AREA)
  246. * BUF_READ_AHEAD_LINEAR_AREA;
  247. high = (offset / BUF_READ_AHEAD_LINEAR_AREA + 1)
  248. * BUF_READ_AHEAD_LINEAR_AREA;
  249. if ((offset != low) && (offset != high - 1)) {
  250. /* This is not a border page of the area: return */
  251. return(0);
  252. }
  253. if (high > fil_space_get_size(space)) {
  254. /* The area is not whole, return */
  255. return(0);
  256. }
  257. mutex_enter(&(buf_pool->mutex));
  258. if (buf_pool->n_pend_reads >
  259. buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
  260. mutex_exit(&(buf_pool->mutex));
  261. return(0);
  262. }
  263. /* Check that almost all pages in the area have been accessed; if
  264. offset == low, the accesses must be in a descending order, otherwise,
  265. in an ascending order. */
  266. asc_or_desc = 1;
  267. if (offset == low) {
  268. asc_or_desc = -1;
  269. }
  270. fail_count = 0;
  271. for (i = low; i < high; i++) {
  272. block = buf_page_hash_get(space, i);
  273. if ((block == NULL) || !block->accessed) {
  274. /* Not accessed */
  275. fail_count++;
  276. } else if (pred_block && (ut_ulint_cmp(block->LRU_position,
  277.            pred_block->LRU_position)
  278.           != asc_or_desc)) {
  279. /* Accesses not in the right order */
  280. fail_count++;
  281. pred_block = block;
  282. }
  283. }
  284. if (fail_count > BUF_READ_AHEAD_LINEAR_AREA -
  285.  BUF_READ_AHEAD_LINEAR_THRESHOLD) {
  286. /* Too many failures: return */
  287. mutex_exit(&(buf_pool->mutex));
  288. return(0);
  289. }
  290. /* If we got this far, we know that enough pages in the area have
  291. been accessed in the right order: linear read-ahead can be sensible */
  292. block = buf_page_hash_get(space, offset);
  293. if (block == NULL) {
  294. mutex_exit(&(buf_pool->mutex));
  295. return(0);
  296. }
  297. frame = block->frame;
  298. /* Read the natural predecessor and successor page addresses from
  299. the page; NOTE that because the calling thread may have an x-latch
  300. on the page, we do not acquire an s-latch on the page, this is to
  301. prevent deadlocks. Even if we read values which are nonsense, the
  302. algorithm will work. */ 
  303. pred_offset = fil_page_get_prev(frame);
  304. succ_offset = fil_page_get_next(frame);
  305. mutex_exit(&(buf_pool->mutex));
  306. if ((offset == low) && (succ_offset == offset + 1)) {
  307.      /* This is ok, we can continue */
  308.      new_offset = pred_offset;
  309. } else if ((offset == high - 1) && (pred_offset == offset - 1)) {
  310.      /* This is ok, we can continue */
  311.      new_offset = succ_offset;
  312. } else {
  313. /* Successor or predecessor not in the right order */
  314. return(0);
  315. }
  316. low  = (new_offset / BUF_READ_AHEAD_LINEAR_AREA)
  317. * BUF_READ_AHEAD_LINEAR_AREA;
  318. high = (new_offset / BUF_READ_AHEAD_LINEAR_AREA + 1)
  319. * BUF_READ_AHEAD_LINEAR_AREA;
  320. if ((new_offset != low) && (new_offset != high - 1)) {
  321. /* This is not a border page of the area: return */
  322. return(0);
  323. }
  324. if (high > fil_space_get_size(space)) {
  325. /* The area is not whole, return */
  326. return(0);
  327. }
  328. /* If we got this far, read-ahead can be sensible: do it */     
  329. if (ibuf_inside()) {
  330. ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
  331. } else {
  332. ibuf_mode = BUF_READ_ANY_PAGE;
  333. }
  334. count = 0;
  335. for (i = low; i < high; i++) {
  336. /* It is only sensible to do read-ahead in the non-sync
  337. aio mode: hence FALSE as the first parameter */
  338. if (!ibuf_bitmap_page(i)) {
  339. count += buf_read_page_low(FALSE, ibuf_mode
  340. | OS_AIO_SIMULATED_WAKE_LATER,
  341. space, i);
  342. }
  343. }
  344. /* In simulated aio we wake the aio handler threads only after
  345. queuing all aio requests, in native aio the following call does
  346. nothing: */
  347. os_aio_simulated_wake_handler_threads();
  348. /* Flush pages from the end of the LRU list if necessary */
  349. buf_flush_free_margin();
  350. if (buf_debug_prints && (count > 0)) {
  351. printf(
  352. "LINEAR read-ahead space %lu offset %lu pages %lun",
  353. space, offset, count);
  354. }
  355. return(count);
  356. }
  357. /************************************************************************
  358. Issues read requests for pages which the ibuf module wants to read in, in
  359. order to contract insert buffer trees. Technically, this function is like
  360. a read-ahead function. */
  361. void
  362. buf_read_ibuf_merge_pages(
  363. /*======================*/
  364. ibool sync, /* in: TRUE if the caller wants this function
  365. to wait for the highest address page to get
  366. read in, before this function returns */
  367. ulint space, /* in: space id */
  368. ulint* page_nos, /* in: array of page numbers to read, with the
  369. highest page number the last in the array */
  370. ulint n_stored) /* in: number of page numbers in the array */
  371. {
  372. ulint i;
  373. ut_ad(!ibuf_inside());
  374. #ifdef UNIV_IBUF_DEBUG
  375. ut_a(n_stored < UNIV_PAGE_SIZE);
  376. #endif
  377. while (buf_pool->n_pend_reads >
  378. buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
  379. os_thread_sleep(500000);
  380. }
  381. for (i = 0; i < n_stored; i++) {
  382. if ((i + 1 == n_stored) && sync) {
  383. buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space,
  384. page_nos[i]);
  385. } else {
  386. buf_read_page_low(FALSE, BUF_READ_ANY_PAGE, space,
  387. page_nos[i]);
  388. }
  389. }
  390. /* Flush pages from the end of the LRU list if necessary */
  391. buf_flush_free_margin();
  392. if (buf_debug_prints) {
  393. printf("Ibuf merge read-ahead space %lu pages %lun",
  394. space, n_stored);
  395. }
  396. }
  397. /************************************************************************
  398. Issues read requests for pages which recovery wants to read in. */
  399. void
  400. buf_read_recv_pages(
  401. /*================*/
  402. ibool sync, /* in: TRUE if the caller wants this function
  403. to wait for the highest address page to get
  404. read in, before this function returns */
  405. ulint space, /* in: space id */
  406. ulint* page_nos, /* in: array of page numbers to read, with the
  407. highest page number the last in the array */
  408. ulint n_stored) /* in: number of page numbers in the array */
  409. {
  410. ulint i;
  411. for (i = 0; i < n_stored; i++) {
  412. while (buf_pool->n_pend_reads >= RECV_POOL_N_FREE_BLOCKS / 2) {
  413. os_aio_simulated_wake_handler_threads();
  414. os_thread_sleep(500000);
  415. }
  416. if ((i + 1 == n_stored) && sync) {
  417. buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space,
  418. page_nos[i]);
  419. } else {
  420. buf_read_page_low(FALSE, BUF_READ_ANY_PAGE
  421. | OS_AIO_SIMULATED_WAKE_LATER,
  422. space, page_nos[i]);
  423. }
  424. }
  425. os_aio_simulated_wake_handler_threads();
  426. /* Flush pages from the end of the LRU list if necessary */
  427. buf_flush_free_margin();
  428. if (buf_debug_prints) {
  429. printf("Recovery applies read-ahead pages %lun", n_stored);
  430. }
  431. }