📄 fil0fil.c
字号:
if (space->n_pending_ibuf_merges == 0) { mutex_exit(&(system->mutex)); count = 0; goto try_again; } else { if (count > 5000) { ut_print_timestamp(stderr); fputs(" InnoDB: Warning: trying to delete tablespace ", stderr); ut_print_filename(stderr, space->name); fprintf(stderr, ",\n""InnoDB: but there are %lu pending ibuf merges on it.\n""InnoDB: Loop %lu.\n", (ulong) space->n_pending_ibuf_merges, (ulong) count); } mutex_exit(&(system->mutex)); os_thread_sleep(20000); count++; goto stop_ibuf_merges; } } mutex_exit(&(system->mutex)); count = 0;try_again: mutex_enter(&(system->mutex)); HASH_SEARCH(hash, system->spaces, id, space, space->id == id); if (space == NULL) { ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Error: cannot delete tablespace %lu\n""InnoDB: because it is not found in the tablespace memory cache.\n", (ulong) id); mutex_exit(&(system->mutex)); return(FALSE); } ut_a(space); ut_a(space->n_pending_ibuf_merges == 0); space->is_being_deleted = TRUE; ut_a(UT_LIST_GET_LEN(space->chain) == 1); node = UT_LIST_GET_FIRST(space->chain); if (space->n_pending_flushes > 0 || node->n_pending > 0) { if (count > 1000) { ut_print_timestamp(stderr); fputs(" InnoDB: Warning: trying to delete tablespace ", stderr); ut_print_filename(stderr, space->name); fprintf(stderr, ",\n""InnoDB: but there are %lu flushes and %lu pending i/o's on it\n""InnoDB: Loop %lu.\n", (ulong) space->n_pending_flushes, (ulong) node->n_pending, (ulong) count); } mutex_exit(&(system->mutex)); os_thread_sleep(20000); count++; goto try_again; } path = mem_strdup(space->name); mutex_exit(&(system->mutex));#ifndef UNIV_HOTBACKUP /* Invalidate in the buffer pool all pages belonging to the tablespace. Since we have set space->is_being_deleted = TRUE, readahead or ibuf merge can no longer read more pages of this tablespace to the buffer pool. Thus we can clean the tablespace out of the buffer pool completely and permanently. The flag is_being_deleted also prevents fil_flush() from being applied to this tablespace. */ buf_LRU_invalidate_tablespace(id);#endif /* printf("Deleting tablespace %s id %lu\n", space->name, id); */ success = fil_space_free(id); if (success) { success = os_file_delete(path); if (!success) { success = os_file_delete_if_exists(path); } } if (success) {#ifndef UNIV_HOTBACKUP /* Write a log record about the deletion of the .ibd file, so that ibbackup can replay it in the --apply-log phase. We use a dummy mtr and the familiar log write mechanism. */ mtr_t mtr; /* When replaying the operation in ibbackup, do not try to write any log record */ mtr_start(&mtr); fil_op_write_log(MLOG_FILE_DELETE, id, path, NULL, &mtr); mtr_commit(&mtr);#endif mem_free(path); return(TRUE); } mem_free(path); return(FALSE);}/***********************************************************************Discards a single-table tablespace. The tablespace must be cached in thememory cache. Discarding is like deleting a tablespace, but1) we do not drop the table from the data dictionary;2) we remove all insert buffer entries for the tablespace immediately; in DROPTABLE they are only removed gradually in the background;3) when the user does IMPORT TABLESPACE, the tablespace will have the same idas it originally had. */iboolfil_discard_tablespace(/*===================*/ /* out: TRUE if success */ ulint id) /* in: space id */{ ibool success; success = fil_delete_tablespace(id); if (!success) { fprintf(stderr,"InnoDB: Warning: cannot delete tablespace %lu in DISCARD TABLESPACE.\n""InnoDB: But let us remove the insert buffer entries for this tablespace.\n", (ulong) id); } /* Remove all insert buffer entries for the tablespace */ ibuf_delete_for_discarded_space(id); return(TRUE);}/***********************************************************************Renames the memory cache structures of a single-table tablespace. */staticiboolfil_rename_tablespace_in_mem(/*=========================*/ /* out: TRUE if success */ fil_space_t* space, /* in: tablespace memory object */ fil_node_t* node, /* in: file node of that tablespace */ const char* path) /* in: new name */{ fil_system_t* system = fil_system; fil_space_t* space2; const char* old_name = space->name; HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(old_name), space2, 0 == strcmp(old_name, space2->name)); if (space != space2) { fputs("InnoDB: Error: cannot find ", stderr); ut_print_filename(stderr, old_name); fputs(" in tablespace memory cache\n", stderr); return(FALSE); } HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(path), space2, 0 == strcmp(path, space2->name)); if (space2 != NULL) { fputs("InnoDB: Error: ", stderr); ut_print_filename(stderr, path); fputs(" is already in tablespace memory cache\n", stderr); return(FALSE); } HASH_DELETE(fil_space_t, name_hash, system->name_hash, ut_fold_string(space->name), space); mem_free(space->name); mem_free(node->name); space->name = mem_strdup(path); node->name = mem_strdup(path); HASH_INSERT(fil_space_t, name_hash, system->name_hash, ut_fold_string(path), space); return(TRUE);}/***********************************************************************Allocates a file name for a single-table tablespace. The string must be freedby caller with mem_free(). */staticchar*fil_make_ibd_name(/*==============*/ /* out, own: file name */ const char* name, /* in: table name or a dir path of a TEMPORARY table */ ibool is_temp) /* in: TRUE if it is a dir path */{ ulint namelen = strlen(name); ulint dirlen = strlen(fil_path_to_mysql_datadir); char* filename = mem_alloc(namelen + dirlen + sizeof "/.ibd"); if (is_temp) { memcpy(filename, name, namelen); memcpy(filename + namelen, ".ibd", sizeof ".ibd"); } else { memcpy(filename, fil_path_to_mysql_datadir, dirlen); filename[dirlen] = '/'; memcpy(filename + dirlen + 1, name, namelen); memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd"); } srv_normalize_path_for_win(filename); return(filename);}/***********************************************************************Renames a single-table tablespace. The tablespace must be cached in thetablespace memory cache. */iboolfil_rename_tablespace(/*==================*/ /* out: TRUE if success */ const char* old_name, /* in: old table name in the standard databasename/tablename format of InnoDB, or NULL if we do the rename based on the space id only */ ulint id, /* in: space id */ const char* new_name) /* in: new table name in the standard databasename/tablename format of InnoDB */{ fil_system_t* system = fil_system; ibool success; fil_space_t* space; fil_node_t* node; ulint count = 0; char* path; ibool old_name_was_specified = TRUE; char* old_path; ut_a(id != 0); if (old_name == NULL) { old_name = "(name not specified)"; old_name_was_specified = FALSE; }retry: count++; if (count > 1000) { ut_print_timestamp(stderr); fputs(" InnoDB: Warning: problems renaming ", stderr); ut_print_filename(stderr, old_name); fputs(" to ", stderr); ut_print_filename(stderr, new_name); fprintf(stderr, ", %lu iterations\n", (ulong) count); } mutex_enter(&(system->mutex)); HASH_SEARCH(hash, system->spaces, id, space, space->id == id); if (space == NULL) { fprintf(stderr,"InnoDB: Error: cannot find space id %lu from the tablespace memory cache\n""InnoDB: though the table ", (ulong) id); ut_print_filename(stderr, old_name); fputs(" in a rename operation should have that id\n", stderr); mutex_exit(&(system->mutex)); return(FALSE); } if (count > 25000) { space->stop_ios = FALSE; mutex_exit(&(system->mutex)); return(FALSE); } /* We temporarily close the .ibd file because we do not trust that operating systems can rename an open file. For the closing we have to wait until there are no pending i/o's or flushes on the file. */ space->stop_ios = TRUE; ut_a(UT_LIST_GET_LEN(space->chain) == 1); node = UT_LIST_GET_FIRST(space->chain); if (node->n_pending > 0 || node->n_pending_flushes > 0) { /* There are pending i/o's or flushes, sleep for a while and retry */ mutex_exit(&(system->mutex)); os_thread_sleep(20000); goto retry; } else if (node->modification_counter > node->flush_counter) { /* Flush the space */ mutex_exit(&(system->mutex)); os_thread_sleep(20000); fil_flush(id); goto retry; } else if (node->open) { /* Close the file */ fil_node_close_file(node, system); } /* Check that the old name in the space is right */ if (old_name_was_specified) { old_path = fil_make_ibd_name(old_name, FALSE); ut_a(strcmp(space->name, old_path) == 0); ut_a(strcmp(node->name, old_path) == 0); } else { old_path = mem_strdup(space->name); } /* Rename the tablespace and the node in the memory cache */ path = fil_make_ibd_name(new_name, FALSE); success = fil_rename_tablespace_in_mem(space, node, path); if (success) { success = os_file_rename(old_path, path); if (!success) { /* We have to revert the changes we made to the tablespace memory cache */ ut_a(fil_rename_tablespace_in_mem(space, node, old_path)); } } mem_free(path); mem_free(old_path); space->stop_ios = FALSE; mutex_exit(&(system->mutex));#ifndef UNIV_HOTBACKUP if (success) { mtr_t mtr; mtr_start(&mtr); fil_op_write_log(MLOG_FILE_RENAME, id, old_name, new_name, &mtr); mtr_commit(&mtr); }#endif return(success);}/***********************************************************************Creates a new single-table tablespace to a database directory of MySQL.Database directories are under the 'datadir' of MySQL. The datadir is thedirectory of a running mysqld program. We can refer to it by simply thepath '.'. Tables created with CREATE TEMPORARY TABLE we place in the tempdir of the mysqld server. */ulintfil_create_new_single_table_tablespace(/*===================================*/ /* out: DB_SUCCESS or error code */ ulint* space_id, /* in/out: space id; if this is != 0, then this is an input parameter, otherwise output */ const char* tablename, /* in: the table name in the usual databasename/tablename format of InnoDB, or a dir path to a temp table */ ibool is_temp, /* in: TRUE if a table created with CREATE TEMPORARY TABLE */ ulint size) /* in: the initial size of the tablespace file in pages, must be >= FIL_IBD_FILE_INITIAL_SIZE */{ os_file_t file; ibool ret; ulint err; byte* buf2; byte* page; ibool success; char* path; ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); path = fil_make_ibd_name(tablename, is_temp); file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL, OS_DATA_FILE, &ret); if (ret == FALSE) { ut_print_timestamp(stderr); fputs(" InnoDB: Error creating file ", stderr); ut_print_filename(stderr, path); fputs(".\n", stderr); /* The following call will print an error message */ err = os_file_get_last_error(TRUE); if (err == OS_FILE_ALREADY_EXISTS) { fputs("InnoDB: The file already exists though the corresponding table did not\n""InnoDB: exist in the InnoDB data dictionary. Have you moved InnoDB\n""InnoDB: .ibd files around without using the SQL commands\n""InnoDB: DISCARD TABLESPACE and IMPORT TABLESPACE, or did\n""InnoDB: mysqld crash in the middle of CREATE TABLE? You can\n""InnoDB: resolve the problem by removing the file ", stderr); ut_print_filename(stderr, path); fputs("\n""InnoDB: under the 'datadir' of MySQL.\n", stderr); mem_free(path); return(DB_TABLESPACE_ALREADY_EXISTS); } if (err == OS_FILE_DISK_FULL) { mem_free(path); return(DB_OUT_OF_FILE_SPACE); } mem_free(path); return(DB_ERROR); } 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); ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0); if (!ret) { ut_free(buf2); os_file_close(file); os_file_delete(path); mem_free(path); return(DB_OUT_OF_FILE_SPACE); } if (*space_id == 0) { *space_id = fil_assign_new_space_id();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -