📄 buf0rea.c
字号:
NOTE 2: the calling thread may own latches on pages: to avoid deadlocks thisfunction must be written such that it cannot end up waiting for theselatches!NOTE 3: the calling thread must want access to the page given: this rule isset to prevent unintended read-aheads performed by ibuf routines, a situationwhich could result in a deadlock if the OS does not support asynchronous io. */ulintbuf_read_ahead_linear(/*==================*/ /* out: number of page read requests issued */ ulint space, /* in: space id */ ulint offset) /* in: page number of a page; NOTE: the current thread must want access to this page (see NOTE 3 above) */{ ib_longlong tablespace_version; buf_block_t* block; buf_frame_t* frame; buf_block_t* pred_block = NULL; ulint pred_offset; ulint succ_offset; ulint count; int asc_or_desc; ulint new_offset; ulint fail_count; ulint ibuf_mode; ulint low, high; ulint err; ulint i; if (srv_startup_is_before_trx_rollback_phase) { /* No read-ahead to avoid thread deadlocks */ return(0); } if (ibuf_bitmap_page(offset) || trx_sys_hdr_page(space, offset)) { /* If it is an ibuf bitmap page or trx sys hdr, we do no read-ahead, as that could break the ibuf page access order */ return(0); } low = (offset / BUF_READ_AHEAD_LINEAR_AREA) * BUF_READ_AHEAD_LINEAR_AREA; high = (offset / BUF_READ_AHEAD_LINEAR_AREA + 1) * BUF_READ_AHEAD_LINEAR_AREA; if ((offset != low) && (offset != high - 1)) { /* This is not a border page of the area: return */ return(0); } /* Remember the tablespace version before we ask te tablespace size below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we do not try to read outside the bounds of the tablespace! */ tablespace_version = fil_space_get_version(space); mutex_enter(&(buf_pool->mutex)); if (high > fil_space_get_size(space)) { mutex_exit(&(buf_pool->mutex)); /* The area is not whole, return */ return(0); } if (buf_pool->n_pend_reads > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { mutex_exit(&(buf_pool->mutex)); return(0); } /* Check that almost all pages in the area have been accessed; if offset == low, the accesses must be in a descending order, otherwise, in an ascending order. */ asc_or_desc = 1; if (offset == low) { asc_or_desc = -1; } fail_count = 0; for (i = low; i < high; i++) { block = buf_page_hash_get(space, i); if ((block == NULL) || !block->accessed) { /* Not accessed */ fail_count++; } else if (pred_block && (ut_ulint_cmp(block->LRU_position, pred_block->LRU_position) != asc_or_desc)) { /* Accesses not in the right order */ fail_count++; pred_block = block; } } if (fail_count > BUF_READ_AHEAD_LINEAR_AREA - BUF_READ_AHEAD_LINEAR_THRESHOLD) { /* Too many failures: return */ mutex_exit(&(buf_pool->mutex)); return(0); } /* If we got this far, we know that enough pages in the area have been accessed in the right order: linear read-ahead can be sensible */ block = buf_page_hash_get(space, offset); if (block == NULL) { mutex_exit(&(buf_pool->mutex)); return(0); } frame = block->frame; /* Read the natural predecessor and successor page addresses from the page; NOTE that because the calling thread may have an x-latch on the page, we do not acquire an s-latch on the page, this is to prevent deadlocks. Even if we read values which are nonsense, the algorithm will work. */ pred_offset = fil_page_get_prev(frame); succ_offset = fil_page_get_next(frame); mutex_exit(&(buf_pool->mutex)); if ((offset == low) && (succ_offset == offset + 1)) { /* This is ok, we can continue */ new_offset = pred_offset; } else if ((offset == high - 1) && (pred_offset == offset - 1)) { /* This is ok, we can continue */ new_offset = succ_offset; } else { /* Successor or predecessor not in the right order */ return(0); } low = (new_offset / BUF_READ_AHEAD_LINEAR_AREA) * BUF_READ_AHEAD_LINEAR_AREA; high = (new_offset / BUF_READ_AHEAD_LINEAR_AREA + 1) * BUF_READ_AHEAD_LINEAR_AREA; if ((new_offset != low) && (new_offset != high - 1)) { /* This is not a border page of the area: return */ return(0); } if (high > fil_space_get_size(space)) { /* The area is not whole, return */ return(0); } /* If we got this far, read-ahead can be sensible: do it */ if (ibuf_inside()) { ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; } else { ibuf_mode = BUF_READ_ANY_PAGE; } count = 0; /* Since Windows XP seems to schedule the i/o handler thread very eagerly, and consequently it does not wait for the full read batch to be posted, we use special heuristics here */ os_aio_simulated_put_read_threads_to_sleep(); for (i = low; i < high; i++) { /* It is only sensible to do read-ahead in the non-sync aio mode: hence FALSE as the first parameter */ if (!ibuf_bitmap_page(i)) { count += buf_read_page_low(&err, FALSE, ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, space, tablespace_version, i); if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Warning: in linear readahead trying to access tablespace\n""InnoDB: %lu page no. %lu,\n""InnoDB: but the tablespace does not exist or is just being dropped.\n", (ulong) space, (ulong) i); } } } /* In simulated aio we wake the aio handler threads only after queuing all aio requests, in native aio the following call does nothing: */ os_aio_simulated_wake_handler_threads(); /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin();#ifdef UNIV_DEBUG if (buf_debug_prints && (count > 0)) { fprintf(stderr, "LINEAR read-ahead space %lu offset %lu pages %lu\n", (ulong) space, (ulong) offset, (ulong) count); }#endif /* UNIV_DEBUG */ ++srv_read_ahead_seq; return(count);}/************************************************************************Issues read requests for pages which the ibuf module wants to read in, inorder to contract the insert buffer tree. Technically, this function is likea read-ahead function. */voidbuf_read_ibuf_merge_pages(/*======================*/ ibool sync, /* in: TRUE if the caller wants this function to wait for the highest address page to get read in, before this function returns */ ulint* space_ids, /* in: array of space ids */ ib_longlong* space_versions,/* in: the spaces must have this version number (timestamp), otherwise we discard the read; we use this to cancel reads if DISCARD + IMPORT may have changed the tablespace size */ ulint* page_nos, /* in: array of page numbers to read, with the highest page number the last in the array */ ulint n_stored) /* in: number of page numbers in the array */{ ulint err; ulint i; ut_ad(!ibuf_inside());#ifdef UNIV_IBUF_DEBUG ut_a(n_stored < UNIV_PAGE_SIZE);#endif while (buf_pool->n_pend_reads > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { os_thread_sleep(500000); } for (i = 0; i < n_stored; i++) { if ((i + 1 == n_stored) && sync) { buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space_ids[i], space_versions[i], page_nos[i]); } else { buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE, space_ids[i], space_versions[i], page_nos[i]); } if (err == DB_TABLESPACE_DELETED) { /* We have deleted or are deleting the single-table tablespace: remove the entries for that page */ ibuf_merge_or_delete_for_page(NULL, space_ids[i], page_nos[i], FALSE); } } os_aio_simulated_wake_handler_threads(); /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin();#ifdef UNIV_DEBUG if (buf_debug_prints) { fprintf(stderr, "Ibuf merge read-ahead space %lu pages %lu\n", (ulong) space_ids[0], (ulong) n_stored); }#endif /* UNIV_DEBUG */}/************************************************************************Issues read requests for pages which recovery wants to read in. */voidbuf_read_recv_pages(/*================*/ ibool sync, /* in: TRUE if the caller wants this function to wait for the highest address page to get read in, before this function returns */ ulint space, /* in: space id */ ulint* page_nos, /* in: array of page numbers to read, with the highest page number the last in the array */ ulint n_stored) /* in: number of page numbers in the array */{ ib_longlong tablespace_version; ulint count; ulint err; ulint i; tablespace_version = fil_space_get_version(space); for (i = 0; i < n_stored; i++) { count = 0; os_aio_print_debug = FALSE; while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) { os_aio_simulated_wake_handler_threads(); os_thread_sleep(500000); count++; if (count > 100) { fprintf(stderr,"InnoDB: Error: InnoDB has waited for 50 seconds for pending\n""InnoDB: reads to the buffer pool to be finished.\n""InnoDB: Number of pending reads %lu, pending pread calls %lu\n", (ulong) buf_pool->n_pend_reads, (ulong)os_file_n_pending_preads); os_aio_print_debug = TRUE; } } os_aio_print_debug = FALSE; if ((i + 1 == n_stored) && sync) { buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, tablespace_version, page_nos[i]); } else { buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE | OS_AIO_SIMULATED_WAKE_LATER, space, tablespace_version, page_nos[i]); } } os_aio_simulated_wake_handler_threads(); /* Flush pages from the end of the LRU list if necessary */ buf_flush_free_margin();#ifdef UNIV_DEBUG if (buf_debug_prints) { fprintf(stderr, "Recovery applies read-ahead pages %lu\n", (ulong) n_stored); }#endif /* UNIV_DEBUG */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -