📄 fil0fil.c
字号:
mem_free(node); mutex_exit(&(system->mutex)); return; } space->size += size; node->space = space; UT_LIST_ADD_LAST(chain, space->chain, node); mutex_exit(&(system->mutex));}/************************************************************************Opens a the file of a node of a tablespace. The caller must own the fil_systemmutex. */staticvoidfil_node_open_file(/*===============*/ fil_node_t* node, /* in: file node */ fil_system_t* system, /* in: tablespace memory cache */ fil_space_t* space) /* in: space */{ ib_longlong size_bytes; ulint size_low; ulint size_high; ibool ret; byte* buf2; byte* page; ibool success; ulint space_id;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(system->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(node->n_pending == 0); ut_a(node->open == FALSE); if (node->size == 0) { /* It must be a single-table tablespace and we do not know the size of the file yet. First we open the file in the normal mode, no async I/O here, for simplicity. Then do some checks, and close the file again. NOTE that we could not use the simple file read function os_file_read() in Windows to read from a file opened for async I/O! */ node->handle = os_file_create_simple_no_error_handling( node->name, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Fatal error: cannot open %s\n.""InnoDB: Have you deleted .ibd files under a running mysqld server?\n", node->name); ut_a(0); } ut_a(space->purpose != FIL_LOG); ut_a(space->id != 0); os_file_get_size(node->handle, &size_low, &size_high); size_bytes = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low;#ifdef UNIV_HOTBACKUP node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);#else if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) { fprintf(stderr,"InnoDB: Error: the size of single-table tablespace file %s\n""InnoDB: is only %lu %lu, should be at least %lu!\n", node->name, (ulong) size_high, (ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE)); ut_a(0); } /* Read the first page of the tablespace */ buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); /* Align the memory for file i/o if we might have O_DIRECT set */ page = ut_align(buf2, UNIV_PAGE_SIZE); success = os_file_read(node->handle, page, 0, 0, UNIV_PAGE_SIZE); space_id = fsp_header_get_space_id(page); ut_free(buf2); /* Close the file now that we have read the space id from it */ os_file_close(node->handle); if (space_id == ULINT_UNDEFINED || space_id == 0) { fprintf(stderr,"InnoDB: Error: tablespace id %lu in file %s is not sensible\n", (ulong) space_id, node->name); ut_a(0); } if (space_id != space->id) { fprintf(stderr,"InnoDB: Error: tablespace id is %lu in the data dictionary\n""InnoDB: but in file %s it is %lu!\n", space->id, node->name, space_id); ut_a(0); } if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) { node->size = (ulint) ((size_bytes / (1024 * 1024)) * ((1024 * 1024) / UNIV_PAGE_SIZE)); } else { node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); }#endif space->size += node->size; } /* printf("Opening file %s\n", node->name); */ /* Open the file for reading and writing, in Windows normally in the unbuffered async I/O mode, though global variables may make os_file_create() to fall back to the normal file I/O mode. */ if (space->purpose == FIL_LOG) { node->handle = os_file_create(node->name, OS_FILE_OPEN, OS_FILE_AIO, OS_LOG_FILE, &ret); } else if (node->is_raw_disk) { node->handle = os_file_create(node->name, OS_FILE_OPEN_RAW, OS_FILE_AIO, OS_DATA_FILE, &ret); } else { node->handle = os_file_create(node->name, OS_FILE_OPEN, OS_FILE_AIO, OS_DATA_FILE, &ret); } ut_a(ret); node->open = TRUE; system->n_open++; if (space->purpose == FIL_TABLESPACE && space->id != 0) { /* Put the node to the LRU list */ UT_LIST_ADD_FIRST(LRU, system->LRU, node); }}/**************************************************************************Closes a file. */staticvoidfil_node_close_file(/*================*/ fil_node_t* node, /* in: file node */ fil_system_t* system) /* in: tablespace memory cache */{ ibool ret; ut_ad(node && system);#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(system->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(node->open); ut_a(node->n_pending == 0); ut_a(node->n_pending_flushes == 0); ut_a(node->modification_counter == node->flush_counter); ret = os_file_close(node->handle); ut_a(ret); /* printf("Closing file %s\n", node->name); */ node->open = FALSE; ut_a(system->n_open > 0); system->n_open--; if (node->space->purpose == FIL_TABLESPACE && node->space->id != 0) { ut_a(UT_LIST_GET_LEN(system->LRU) > 0); /* The node is in the LRU list, remove it */ UT_LIST_REMOVE(LRU, system->LRU, node); }}/************************************************************************Tries to close a file in the LRU list. The caller must hold the fil_sysmutex. */staticiboolfil_try_to_close_file_in_LRU(/*=========================*/ /* out: TRUE if success, FALSE if should retry later; since i/o's generally complete in < 100 ms, and as InnoDB writes at most 128 pages from the buffer pool in a batch, and then immediately flushes the files, there is a good chance that the next time we find a suitable node from the LRU list */ ibool print_info) /* in: if TRUE, prints information why it cannot close a file */{ fil_system_t* system = fil_system; fil_node_t* node;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(system->mutex)));#endif /* UNIV_SYNC_DEBUG */ node = UT_LIST_GET_LAST(system->LRU); if (print_info) { fprintf(stderr,"InnoDB: fil_sys open file LRU len %lu\n", (ulong) UT_LIST_GET_LEN(system->LRU)); } while (node != NULL) { if (node->modification_counter == node->flush_counter && node->n_pending_flushes == 0) { fil_node_close_file(node, system); return(TRUE); } if (print_info && node->n_pending_flushes > 0) { fputs("InnoDB: cannot close file ", stderr); ut_print_filename(stderr, node->name); fprintf(stderr, ", because n_pending_flushes %lu\n", (ulong) node->n_pending_flushes); } if (print_info && node->modification_counter != node->flush_counter) { fputs("InnoDB: cannot close file ", stderr); ut_print_filename(stderr, node->name); fprintf(stderr, ", because mod_count %ld != fl_count %ld\n", (long) node->modification_counter, (long) node->flush_counter); } node = UT_LIST_GET_PREV(LRU, node); } return(FALSE);}/***********************************************************************Reserves the fil_system mutex and tries to make sure we can open at least onefile while holding it. This should be called before callingfil_node_prepare_for_io(), because that function may need to open a file. */staticvoidfil_mutex_enter_and_prepare_for_io(/*===============================*/ ulint space_id) /* in: space id */{ fil_system_t* system = fil_system; fil_space_t* space; ibool success; ibool print_info = FALSE; ulint count = 0; ulint count2 = 0;#ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&(system->mutex)));#endif /* UNIV_SYNC_DEBUG */retry: mutex_enter(&(system->mutex)); if (space_id == 0 || space_id >= SRV_LOG_SPACE_FIRST_ID) { /* We keep log files and system tablespace files always open; this is important in preventing deadlocks in this module, as a page read completion often performs another read from the insert buffer. The insert buffer is in tablespace 0, and we cannot end up waiting in this function. */ return; } if (system->n_open < system->max_n_open) { return; } HASH_SEARCH(hash, system->spaces, space_id, space, space->id == space_id); if (space != NULL && space->stop_ios) { /* We are going to do a rename file and want to stop new i/o's for a while */ if (count2 > 20000) { fputs("InnoDB: Warning: tablespace ", stderr); ut_print_filename(stderr, space->name); fprintf(stderr, " has i/o ops stopped for a long time %lu\n", (ulong) count2); } mutex_exit(&(system->mutex)); os_thread_sleep(20000); count2++; goto retry; } /* If the file is already open, no need to do anything; if the space does not exist, we handle the situation in the function which called this function */ if (!space || UT_LIST_GET_FIRST(space->chain)->open) { return; } if (count > 1) { print_info = TRUE; } /* Too many files are open, try to close some */close_more: success = fil_try_to_close_file_in_LRU(print_info); if (success && system->n_open >= system->max_n_open) { goto close_more; } if (system->n_open < system->max_n_open) { /* Ok */ return; } if (count >= 2) { ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Warning: too many (%lu) files stay open while the maximum\n""InnoDB: allowed value would be %lu.\n""InnoDB: You may need to raise the value of innodb_max_files_open in\n""InnoDB: my.cnf.\n", (ulong) system->n_open, (ulong) system->max_n_open); return; } mutex_exit(&(system->mutex));#ifndef UNIV_HOTBACKUP /* Wake the i/o-handler threads to make sure pending i/o's are performed */ os_aio_simulated_wake_handler_threads(); os_thread_sleep(20000);#endif /* Flush tablespaces so that we can close modified files in the LRU list */ fil_flush_file_spaces(FIL_TABLESPACE); count++; goto retry;}/***********************************************************************Frees a file node object from a tablespace memory cache. */staticvoidfil_node_free(/*==========*/ fil_node_t* node, /* in, own: file node */ fil_system_t* system, /* in: tablespace memory cache */ fil_space_t* space) /* in: space where the file node is chained */{ ut_ad(node && system && space);#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(system->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(node->magic_n == FIL_NODE_MAGIC_N); ut_a(node->n_pending == 0); if (node->open) { /* We fool the assertion in fil_node_close_file() to think there are no unflushed modifications in the file */ node->modification_counter = node->flush_counter; if (space->is_in_unflushed_spaces && fil_space_is_flushed(space)) { space->is_in_unflushed_spaces = FALSE; UT_LIST_REMOVE(unflushed_spaces, system->unflushed_spaces, space); } fil_node_close_file(node, system); } space->size -= node->size; UT_LIST_REMOVE(chain, space->chain, node); mem_free(node->name); mem_free(node);}/********************************************************************Drops files from the start of a file space, so that its size is cut bythe amount given. */voidfil_space_truncate_start(/*=====================*/ ulint id, /* in: space id */ ulint trunc_len) /* in: truncate by this much; it is an error if this does not equal to the combined size of some initial files in the space */{ fil_system_t* system = fil_system; fil_node_t* node; fil_space_t* space; mutex_enter(&(system->mutex)); HASH_SEARCH(hash, system->spaces, id, space, space->id == id); ut_a(space); while (trunc_len > 0) { node = UT_LIST_GET_FIRST(space->chain); ut_a(node->size * UNIV_PAGE_SIZE >= trunc_len); trunc_len -= node->size * UNIV_PAGE_SIZE; fil_node_free(node, system, space); } mutex_exit(&(system->mutex));}/***********************************************************************Creates a space memory object and puts it to the tablespace memory cache. Ifthere is an error, prints an error message to the .err log. */iboolfil_space_create(/*=============*/ /* out: TRUE if success */ const char* name, /* in: space name */ ulint id, /* in: space id */ ulint purpose)/* in: FIL_TABLESPACE, or FIL_LOG if log */{ fil_system_t* system = fil_system; fil_space_t* space; ulint namesake_id;try_again: /*printf( "InnoDB: Adding tablespace %lu of name %s, purpose %lu\n", id, name, purpose);*/ ut_a(system); ut_a(name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -