/* * __wt_schema_colcheck -- * Check that a list of columns matches a (key,value) format pair. */ int __wt_schema_colcheck(WT_SESSION_IMPL *session, const char *key_format, const char *value_format, WT_CONFIG_ITEM *colconf, u_int *kcolsp, u_int *vcolsp) { WT_CONFIG conf; WT_CONFIG_ITEM k, v; WT_DECL_PACK_VALUE(pv); WT_DECL_RET; WT_PACK pack; u_int kcols, ncols, vcols; WT_RET(__pack_init(session, &pack, key_format)); for (kcols = 0; (ret = __pack_next(&pack, &pv)) == 0; kcols++) ; WT_RET_TEST(ret != WT_NOTFOUND, ret); WT_RET(__pack_init(session, &pack, value_format)); for (vcols = 0; (ret = __pack_next(&pack, &pv)) == 0; vcols++) ; WT_RET_TEST(ret != WT_NOTFOUND, ret); /* Walk through the named columns. */ WT_RET(__wt_config_subinit(session, &conf, colconf)); for (ncols = 0; (ret = __wt_config_next(&conf, &k, &v)) == 0; ncols++) ; WT_RET_TEST(ret != WT_NOTFOUND, ret); if (ncols != 0 && ncols != kcols + vcols) WT_RET_MSG(session, EINVAL, "Number of columns in '%.*s' " "does not match key format '%s' plus value format '%s'", (int)colconf->len, colconf->str, key_format, value_format); if (kcolsp != NULL) *kcolsp = kcols; if (vcolsp != NULL) *vcolsp = vcols; return (0); }
/* * __wt_curfile_open -- * WT_SESSION->open_cursor method for the btree cursor type. */ int __wt_curfile_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CONFIG_ITEM cval; WT_DECL_RET; int bitmap, bulk; uint32_t flags; flags = 0; WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval)); if (cval.type == ITEM_NUM && (cval.val == 0 || cval.val == 1)) { bitmap = 0; bulk = (cval.val != 0); } else if (WT_STRING_MATCH("bitmap", cval.str, cval.len)) bitmap = bulk = 1; else WT_RET_MSG(session, EINVAL, "Value for 'bulk' must be a boolean or 'bitmap'"); /* Bulk handles require exclusive access. */ if (bulk) LF_SET(WT_BTREE_BULK | WT_BTREE_EXCLUSIVE); /* TODO: handle projections. */ /* Get the handle and lock it while the cursor is using it. */ if (WT_PREFIX_MATCH(uri, "file:")) WT_RET(__wt_session_get_btree_ckpt(session, uri, cfg, flags)); else WT_RET(__wt_bad_object_type(session, uri)); WT_ERR(__wt_curfile_create(session, owner, cfg, bulk, bitmap, cursorp)); return (0); err: /* If the cursor could not be opened, release the handle. */ WT_TRET(__wt_session_release_btree(session)); return (ret); }
/* * __wt_rwlock_destroy -- * Destroy a mutex. */ int __wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp) { WT_DECL_RET; WT_RWLOCK *rwlock; rwlock = *rwlockp; /* Clear our caller's reference. */ if (rwlock == NULL) return (0); *rwlockp = NULL; WT_VERBOSE_RET(session, mutex, "rwlock: destroy %s (%p)", rwlock->name, rwlock); if ((ret = pthread_rwlock_destroy(&rwlock->rwlock)) == 0) { __wt_free(session, rwlock); return (0); } /* Deliberately leak memory on error. */ WT_RET_MSG(session, ret, "pthread_rwlock_destroy: %s", rwlock->name); }
/* * __lsm_tree_open_check -- * Validate the configuration of an LSM tree. */ static int __lsm_tree_open_check(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_CONFIG_ITEM cval; uint64_t required; uint32_t maxleafpage; const char *cfg[] = { WT_CONFIG_BASE( session, session_create), lsm_tree->file_config, NULL }; WT_RET(__wt_config_gets(session, cfg, "leaf_page_max", &cval)); maxleafpage = (uint32_t)cval.val; /* Three chunks, plus one page for each participant in a merge. */ required = 3 * lsm_tree->chunk_size + lsm_tree->merge_threads * (lsm_tree->merge_max * maxleafpage); if (S2C(session)->cache_size < required) WT_RET_MSG(session, EINVAL, "The LSM configuration requires a cache size of at least %" PRIu64 ". Configured size is %" PRIu64, required, S2C(session)->cache_size); return (0); }
/* * __wt_filesize_name -- * Return the size of a file in bytes, given a file name. */ int __wt_filesize_name( WT_SESSION_IMPL *session, const char *filename, wt_off_t *sizep) { WT_DECL_RET; WIN32_FILE_ATTRIBUTE_DATA data; char *path; WT_RET(__wt_filename(session, filename, &path)); ret = GetFileAttributesExA(path, GetFileExInfoStandard, &data); __wt_free(session, path); if (ret != 0) { *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow; return (0); } WT_RET_MSG(session, __wt_errno(), "%s: GetFileAttributesEx", filename); }
/* * __wt_getenv -- * Get a non-NULL, greater than zero-length environment variable. */ int __wt_getenv(WT_SESSION_IMPL *session, const char *variable, const char **envp) { WT_DECL_RET; DWORD size; *envp = NULL; size = GetEnvironmentVariableA(variable, NULL, 0); if (size <= 1) return (WT_NOTFOUND); WT_RET(__wt_calloc(session, 1, size, envp)); ret = GetEnvironmentVariableA(variable, *envp, size); /* We expect the number of bytes not including nul terminator. */ if ((ret + 1) != size) WT_RET_MSG(session, __wt_getlasterror(), "GetEnvironmentVariableA failed: %s", variable); return (0); }
/* * __wt_log_truncate_files -- * Truncate log files via archive once. Requires that the server is not * currently running. */ int __wt_log_truncate_files( WT_SESSION_IMPL *session, WT_CURSOR *cursor, const char *cfg[]) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_LOG *log; uint32_t backup_file; bool locked; WT_UNUSED(cfg); conn = S2C(session); if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) return (0); if (F_ISSET(conn, WT_CONN_SERVER_RUN) && FLD_ISSET(conn->log_flags, WT_CONN_LOG_ARCHIVE)) WT_RET_MSG(session, EINVAL, "Attempt to archive manually while a server is running"); log = conn->log; backup_file = 0; if (cursor != NULL) backup_file = WT_CURSOR_BACKUP_ID(cursor); WT_ASSERT(session, backup_file <= log->alloc_lsn.l.file); WT_RET(__wt_verbose(session, WT_VERB_LOG, "log_truncate_files: Archive once up to %" PRIu32, backup_file)); WT_RET(__wt_writelock(session, log->log_archive_lock)); locked = true; WT_ERR(__log_archive_once(session, backup_file)); WT_ERR(__wt_writeunlock(session, log->log_archive_lock)); locked = false; err: if (locked) WT_RET(__wt_writeunlock(session, log->log_archive_lock)); return (ret); }
/* * __wt_table_check -- * Make sure all columns appear in a column group. */ int __wt_table_check(WT_SESSION_IMPL *session, WT_TABLE *table) { WT_CONFIG conf; WT_CONFIG_ITEM k, v; WT_DECL_RET; u_int cg, col, i; char coltype; if (table->is_simple) return (0); /* Walk through the columns. */ __wt_config_subinit(session, &conf, &table->colconf); /* Skip over the key columns. */ for (i = 0; i < table->nkey_columns; i++) WT_RET(__wt_config_next(&conf, &k, &v)); cg = col = 0; coltype = 0; while ((ret = __wt_config_next(&conf, &k, &v)) == 0) { if (__find_next_col( session, table, &k, &cg, &col, &coltype) != 0) WT_RET_MSG(session, EINVAL, "Column '%.*s' in '%s' does not appear in a " "column group", (int)k.len, k.str, table->iface.name); /* * Column groups can't store key columns in their value: * __wt_struct_reformat should have already detected this case. */ WT_ASSERT(session, coltype == WT_PROJ_VALUE); } WT_RET_TEST(ret != WT_NOTFOUND, ret); return (0); }
/* * __conn_config_env -- * Read configuration from an environment variable, if set. */ static int __conn_config_env(WT_SESSION_IMPL *session, const char **cfg) { WT_CONFIG_ITEM cval; const char *env_config; if ((env_config = getenv("WIREDTIGER_CONFIG")) == NULL || strlen(env_config) == 0) return (0); /* * Security stuff: * * If the "use_environment_priv" configuration string is set, use the * environment variable if the process has appropriate privileges. */ WT_RET(__wt_config_gets(session, cfg, "use_environment_priv", &cval)); if (cval.val == 0 && __wt_has_priv()) WT_RET_MSG(session, WT_ERROR, "%s", "WIREDTIGER_CONFIG environment variable set but process " "lacks privileges to use that environment variable"); /* Check the configuration string. */ WT_RET(__wt_config_check( session, __wt_confchk_wiredtiger_open, env_config, 0)); /* * The environment setting comes second-to-last: it overrides the * WiredTiger.config file (if any), but not the config passed by the * application. */ while (cfg[1] != NULL) ++cfg; cfg[1] = cfg[0]; cfg[0] = env_config; return (0); }
/* * __huffman_confchk_file -- * Check for a Huffman configuration file and return the file name. */ static int __huffman_confchk_file( WT_SESSION_IMPL *session, WT_CONFIG_ITEM *v, int *is_utf8p, FILE **fpp) { FILE *fp; WT_DECL_RET; size_t len; char *fname; /* Look for a prefix and file name. */ len = 0; if (is_utf8p != NULL) *is_utf8p = 0; if (WT_PREFIX_MATCH(v->str, "utf8")) { if (is_utf8p != NULL) *is_utf8p = 1; len = strlen("utf8"); } else if (WT_PREFIX_MATCH(v->str, "utf16")) len = strlen("utf16"); if (len == 0 || len >= v->len) WT_RET_MSG(session, EINVAL, "illegal Huffman configuration: %.*s", (int)v->len, v->str); /* Check the file exists. */ WT_RET(__wt_strndup(session, v->str + len, v->len - len, &fname)); WT_ERR(__wt_fopen(session, fname, WT_FHANDLE_READ, WT_FOPEN_FIXED, &fp)); /* Optionally return the file handle. */ if (fpp == NULL) (void)__wt_fclose(&fp, WT_FHANDLE_READ); else *fpp = fp; err: __wt_free(session, fname); return (ret); }
/* * __wt_btcur_compare -- * Return a comparison between two cursors. */ int __wt_btcur_compare(WT_CURSOR_BTREE *a_arg, WT_CURSOR_BTREE *b_arg, int *cmpp) { WT_CURSOR *a, *b; WT_SESSION_IMPL *session; a = (WT_CURSOR *)a_arg; b = (WT_CURSOR *)b_arg; session = (WT_SESSION_IMPL *)a->session; /* Confirm both cursors reference the same object. */ if (a_arg->btree != b_arg->btree) WT_RET_MSG( session, EINVAL, "Cursors must reference the same object"); switch (a_arg->btree->type) { case BTREE_COL_FIX: case BTREE_COL_VAR: /* * Compare the interface's cursor record, not the underlying * cursor reference: the interface's cursor reference is the * one being returned to the application. */ if (a->recno < b->recno) *cmpp = -1; else if (a->recno == b->recno) *cmpp = 0; else *cmpp = 1; break; case BTREE_ROW: WT_RET(__wt_compare( session, a_arg->btree->collator, &a->key, &b->key, cmpp)); break; WT_ILLEGAL_VALUE(session); } return (0); }
/* * __wt_rename -- * Rename a file. */ int __wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to) { WT_DECL_RET; uint32_t lasterror; char *from_path, *to_path; WT_RET(__wt_verbose( session, WT_VERB_FILEOPS, "rename %s to %s", from, to)); from_path = to_path = NULL; WT_RET(__wt_filename(session, from, &from_path)); WT_TRET(__wt_filename(session, to, &to_path)); /* * Check if file exists since Windows does not override the file if * it exists. */ if ((ret = GetFileAttributesA(to_path)) != INVALID_FILE_ATTRIBUTES) { if ((ret = DeleteFileA(to_path)) == FALSE) { lasterror = GetLastError(); goto err; } } if ((MoveFileA(from_path, to_path)) == FALSE) lasterror = GetLastError(); err: __wt_free(session, from_path); __wt_free(session, to_path); if (ret != FALSE) return (0); WT_RET_MSG(session, lasterror, "MoveFile %s to %s", from, to); }
/* * __wt_schema_get_colgroup -- * Find a column group by URI. */ int __wt_schema_get_colgroup(WT_SESSION_IMPL *session, const char *uri, bool quiet, WT_TABLE **tablep, WT_COLGROUP **colgroupp) { WT_COLGROUP *colgroup; WT_TABLE *table; const char *tablename, *tend; u_int i; *colgroupp = NULL; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "colgroup:")) return (__wt_bad_object_type(session, uri)); if ((tend = strchr(tablename, ':')) == NULL) tend = tablename + strlen(tablename); WT_RET(__wt_schema_get_table(session, tablename, WT_PTRDIFF(tend, tablename), false, &table)); for (i = 0; i < WT_COLGROUPS(table); i++) { colgroup = table->cgroups[i]; if (strcmp(colgroup->name, uri) == 0) { *colgroupp = colgroup; if (tablep != NULL) *tablep = table; else __wt_schema_release_table(session, table); return (0); } } __wt_schema_release_table(session, table); if (quiet) WT_RET(ENOENT); WT_RET_MSG(session, ENOENT, "%s not found in table", uri); }
/* * __posix_fs_remove -- * Remove a file. */ static int __posix_fs_remove( WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name) { WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; /* * ISO C doesn't require remove return -1 on failure or set errno (note * POSIX 1003.1 extends C with those requirements). Regardless, use the * unlink system call, instead of remove, to simplify error handling; * where we're not doing any special checking for standards compliance, * using unlink may be marginally safer. */ WT_SYSCALL(unlink(name), ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s: file-remove: unlink", name); }
/* * __posix_fs_exist -- * Return if the file exists. */ static int __posix_fs_exist(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, bool *existp) { struct stat sb; WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_SYSCALL(stat(name, &sb), ret); if (ret == 0) { *existp = true; return (0); } if (ret == ENOENT) { *existp = false; return (0); } WT_RET_MSG(session, ret, "%s: file-exist: stat", name); }
/* * __posix_fs_rename -- * Rename a file. */ static int __posix_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to) { WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; /* * ISO C doesn't require rename return -1 on failure or set errno (note * POSIX 1003.1 extends C with those requirements). Be cautious, force * any non-zero return to -1 so we'll check errno. We can still end up * with the wrong errno (if errno is garbage), or the generic WT_ERROR * return (if errno is 0), but we've done the best we can. */ WT_SYSCALL(rename(from, to) != 0 ? -1 : 0, ret); if (ret == 0) return (0); WT_RET_MSG(session, ret, "%s to %s: file-rename: rename", from, to); }
/* * __wt_remove -- * Remove a file. */ int __wt_remove(WT_SESSION_IMPL *session, const char *name) { WT_DECL_RET; char *path; uint32_t lasterror; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: remove", name)); __remove_file_check(session, name); WT_RET(__wt_filename(session, name, &path)); if ((ret = DeleteFileA(path)) == FALSE) lasterror = __wt_errno(); __wt_free(session, path); if (ret != FALSE) return (0); WT_RET_MSG(session, lasterror, "%s: remove", name); }
/* * __debug_config -- * Configure debugging output. */ static int __debug_config(WT_SESSION_IMPL *session, WT_DBG *ds, const char *ofile) { memset(ds, 0, sizeof(WT_DBG)); ds->session = session; WT_RET(__wt_scr_alloc(session, 512, &ds->tmp)); /* * If we weren't given a file, we use the default event handler, and * we'll have to buffer messages. */ if (ofile == NULL) return (__wt_scr_alloc(session, 512, &ds->msg)); /* If we're using a file, flush on each line. */ if ((ds->fp = fopen(ofile, "w")) == NULL) WT_RET_MSG(session, __wt_errno(), "%s", ofile); (void)setvbuf(ds->fp, NULL, _IOLBF, 0); return (0); }
/* * __wt_mmap_preload -- * Cause a section of a memory map to be faulted in. */ int __wt_mmap_preload(WT_SESSION_IMPL *session, const void *p, size_t size) { #ifdef HAVE_POSIX_MADVISE /* Linux requires the address be aligned to a 4KB boundary. */ WT_BM *bm = S2BT(session)->bm; WT_DECL_RET; void *blk = (void *)((uintptr_t)p & ~(uintptr_t)(WT_VM_PAGESIZE - 1)); size += WT_PTRDIFF(p, blk); /* XXX proxy for "am I doing a scan?" -- manual read-ahead */ if (F_ISSET(session, WT_SESSION_NO_CACHE)) { /* Read in 2MB blocks every 1MB of data. */ if (((uintptr_t)((uint8_t *)blk + size) & (uintptr_t)((1<<20) - 1)) < (uintptr_t)blk) return (0); size = WT_MIN(WT_MAX(20 * size, 2 << 20), WT_PTRDIFF((uint8_t *)bm->map + bm->maplen, blk)); } /* * Manual pages aren't clear on whether alignment is required for the * size, so we will be conservative. */ size &= ~(size_t)(WT_VM_PAGESIZE - 1); if (size > WT_VM_PAGESIZE && (ret = posix_madvise(blk, size, POSIX_MADV_WILLNEED)) != 0) WT_RET_MSG(session, ret, "posix_madvise will need"); #else WT_UNUSED(session); WT_UNUSED(p); WT_UNUSED(size); #endif return (0); }
/* * __verify_config -- * Verification supports dumping pages in various formats. */ static int __verify_config(WT_SESSION_IMPL *session, const char *cfg[], WT_VSTUFF *vs) { WT_CONFIG_ITEM cval; WT_DECL_RET; ret = __wt_config_gets(session, cfg, "dump_address", &cval); if (ret != 0 && ret != WT_NOTFOUND) WT_RET(ret); if (ret == 0 && cval.val != 0) vs->dump_address = 1; ret = __wt_config_gets(session, cfg, "dump_blocks", &cval); if (ret != 0 && ret != WT_NOTFOUND) WT_RET(ret); if (ret == 0 && cval.val != 0) vs->dump_blocks = 1; ret = __wt_config_gets(session, cfg, "dump_pages", &cval); if (ret != 0 && ret != WT_NOTFOUND) WT_RET(ret); if (ret == 0 && cval.val != 0) vs->dump_pages = 1; #ifdef HAVE_DIAGNOSTIC /* * We use the verification code to do debugging dumps because if we're * dumping in debugging mode, we want to confirm the page is OK before * walking it. */ #else if (vs->dump_address || vs->dump_blocks || vs->dump_pages) WT_RET_MSG(session, ENOTSUP, "the WiredTiger library was not built in diagnostic mode"); #endif return (0); }
/* * __wt_block_ckpt_init -- * Initialize a checkpoint structure. */ int __wt_block_ckpt_init(WT_SESSION_IMPL *session, WT_BLOCK *block, WT_BLOCK_CKPT *ci, const char *name, int is_live) { WT_DECL_RET; /* * If we're loading a new live checkpoint, there shouldn't be one * already loaded. The btree engine should prevent this from ever * happening, but paranoia is a healthy thing. */ if (is_live) { __wt_spin_lock(session, &block->live_lock); if (block->live_load) ret = EINVAL; else block->live_load = 1; __wt_spin_unlock(session, &block->live_lock); if (ret) WT_RET_MSG( session, EINVAL, "checkpoint already loaded"); } memset(ci, 0, sizeof(*ci)); ci->root_offset = WT_BLOCK_INVALID_OFFSET; WT_RET(__wt_block_extlist_init(session, &ci->alloc, name, "alloc")); WT_RET(__wt_block_extlist_init(session, &ci->avail, name, "avail")); WT_RET(__wt_block_extlist_init(session, &ci->discard, name, "discard")); ci->file_size = WT_BLOCK_DESC_SECTOR; WT_RET(__wt_block_extlist_init( session, &ci->ckpt_avail, name, "ckpt_avail")); return (0); }
/* * __wt_mmap -- * Map a file into memory. */ int __wt_mmap(WT_SESSION_IMPL *session, WT_FH *fh, void *mapp, size_t *lenp) { void *map; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "%s: map %" PRIuMAX " bytes", fh->name, (uintmax_t)fh->size)); if ((map = mmap(NULL, (size_t)fh->size, PROT_READ, #ifdef MAP_NOCORE MAP_NOCORE | #endif MAP_PRIVATE, fh->fd, (off_t)0)) == MAP_FAILED) { WT_RET_MSG(session, __wt_errno(), "%s map error: failed to map %" PRIuMAX " bytes", fh->name, (uintmax_t)fh->size); } *(void **)mapp = map; *lenp = (size_t)fh->size; return (0); }
/* * __wt_metadata_remove -- * Remove a row from the metadata. */ int __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key) { WT_CURSOR *cursor; WT_DECL_RET; WT_RET(__wt_verbose(session, WT_VERB_METADATA, "Remove: key: %s, tracking: %s, %s" "turtle", key, WT_META_TRACKING(session) ? "true" : "false", __metadata_turtle(key) ? "" : "not ")); if (__metadata_turtle(key)) WT_RET_MSG(session, EINVAL, "%s: remove not supported on the turtle file", key); WT_RET(__wt_metadata_cursor(session, &cursor)); cursor->set_key(cursor, key); WT_ERR(cursor->search(cursor)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_update(session, key)); WT_ERR(cursor->remove(cursor)); err: WT_TRET(__wt_metadata_cursor_release(session, &cursor)); return (ret); }
/* * __wt_bulk_init -- * Start a bulk load. */ int __wt_bulk_init(WT_CURSOR_BULK *cbulk) { WT_BTREE *btree; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)cbulk->cbt.iface.session; btree = S2BT(session); /* * Bulk-load is only permitted on newly created files, not any empty * file -- see the checkpoint code for a discussion. */ if (!btree->bulk_load_ok) WT_RET_MSG(session, EINVAL, "bulk-load is only possible for newly created trees"); /* Set a reference to the empty leaf page. */ cbulk->leaf = btree->root_page->u.intl.t->page; WT_RET(__wt_rec_bulk_init(cbulk)); return (0); }
/* * __wt_exist -- * Return if the file exists. */ int __wt_exist(WT_SESSION_IMPL *session, const char *filename, bool *existp) { struct stat sb; WT_DECL_RET; char *path; *existp = false; WT_RET(__wt_filename(session, filename, &path)); WT_SYSCALL_RETRY(stat(path, &sb), ret); __wt_free(session, path); if (ret == 0) { *existp = true; return (0); } if (ret == ENOENT) return (0); WT_RET_MSG(session, ret, "%s: fstat", filename); }
int __wt_schema_rename(WT_SESSION_IMPL *session, const char *uri, const char *newuri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *p, *t; /* The target type must match the source type. 匹配前面的关键字,例如file: table:*/ for (p = uri, t = newuri; *p == *t && *p != ':'; ++p, ++t) ; if (*p != ':' || *t != ':') WT_RET_MSG(session, EINVAL, "rename target type must match URI: %s to %s", uri, newuri); /* * We track rename operations, if we fail in the middle, we want to * back it all out. */ WT_RET(__wt_meta_track_on(session)); if (WT_PREFIX_MATCH(uri, "file:")) ret = __rename_file(session, uri, newuri); else if (WT_PREFIX_MATCH(uri, "lsm:")) ret = __wt_lsm_tree_rename(session, uri, newuri, cfg); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __rename_table(session, uri, newuri, cfg); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) ret = dsrc->rename == NULL ? __wt_object_unsupported(session, uri) : dsrc->rename(dsrc, &session->iface, uri, newuri, (WT_CONFIG_ARG *)cfg); else ret = __wt_bad_object_type(session, uri); /* Bump the schema generation so that stale data is ignored. */ ++S2C(session)->schema_gen; WT_TRET(__wt_meta_track_off(session, 1, ret != 0)); return (ret == WT_NOTFOUND ? ENOENT : ret); }
/*调用rename系统调用*/ int __wt_rename(WT_SESSION_IMPL *session, const char *from, const char *to) { WT_DECL_RET; char *from_path, *to_path; WT_RET(__wt_verbose(session, WT_VERB_FILEOPS, "rename %s to %s", from, to)); from_path = to_path = NULL; /*对路劲进行校验,如果不合法路径,直接返回*/ WT_RET(__wt_filename(session, from, &from_path)); WT_TRET(__wt_filename(session, to, &to_path)); if (ret == 0) WT_SYSCALL_RETRY(rename(from_path, to_path), ret); __wt_free(session, from_path); __wt_free(session, to_path); if(ret == 0) return 0; WT_RET_MSG(session, ret, "rename %s to %s", from, to); }
/* * __verify_config -- * Debugging: verification supports dumping pages in various formats. */ static int __verify_config(WT_SESSION_IMPL *session, const char *cfg[], WT_VSTUFF *vs) { WT_CONFIG_ITEM cval; WT_RET(__wt_config_gets(session, cfg, "dump_address", &cval)); vs->dump_address = cval.val != 0; WT_RET(__wt_config_gets(session, cfg, "dump_blocks", &cval)); vs->dump_blocks = cval.val != 0; WT_RET(__wt_config_gets(session, cfg, "dump_pages", &cval)); vs->dump_pages = cval.val != 0; WT_RET(__wt_config_gets(session, cfg, "dump_shape", &cval)); vs->dump_shape = cval.val != 0; #if !defined(HAVE_DIAGNOSTIC) if (vs->dump_blocks || vs->dump_pages) WT_RET_MSG(session, ENOTSUP, "the WiredTiger library was not built in diagnostic mode"); #endif return (0); }
/* * __posix_open_file_cloexec -- * Prevent child access to file handles. */ static inline int __posix_open_file_cloexec(WT_SESSION_IMPL *session, int fd, const char *name) { #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(O_CLOEXEC) int f; /* * Security: * The application may spawn a new process, and we don't want another * process to have access to our file handles. There's an obvious race * between the open and this call, prefer the flag to open if available. */ if ((f = fcntl(fd, F_GETFD)) == -1 || fcntl(fd, F_SETFD, f | FD_CLOEXEC) == -1) WT_RET_MSG(session, __wt_errno(), "%s: handle-open: fcntl", name); return (0); #else WT_UNUSED(session); WT_UNUSED(fd); WT_UNUSED(name); return (0); #endif }
/* * __recovery_setup_file -- * Set up the recovery slot for a file. */ static int __recovery_setup_file(WT_RECOVERY *r, const char *uri, const char *config) { WT_CONFIG_ITEM cval; WT_LSN lsn; uint32_t fileid; WT_RET(__wt_config_getones(r->session, config, "id", &cval)); fileid = (uint32_t)cval.val; if (r->nfiles <= fileid) { WT_RET(__wt_realloc_def( r->session, &r->file_alloc, fileid + 1, &r->files)); r->nfiles = fileid + 1; } WT_RET(__wt_strdup(r->session, uri, &r->files[fileid].uri)); WT_RET( __wt_config_getones(r->session, config, "checkpoint_lsn", &cval)); /* If there is checkpoint logged for the file, apply everything. */ if (cval.type != WT_CONFIG_ITEM_STRUCT) INIT_LSN(&lsn); else if (sscanf(cval.str, "(%" PRIu32 ",%" PRIdMAX ")", &lsn.file, (intmax_t*)&lsn.offset) != 2) WT_RET_MSG(r->session, EINVAL, "Failed to parse checkpoint LSN '%.*s'", (int)cval.len, cval.str); r->files[fileid].ckpt_lsn = lsn; WT_RET(__wt_verbose(r->session, WT_VERB_RECOVERY, "Recovering %s with id %u @ (%" PRIu32 ", %" PRIu64 ")", uri, fileid, lsn.file, lsn.offset)); return (0); }