/* * __wt_schema_truncate -- * WT_SESSION::truncate without a range. */ int __wt_schema_truncate( WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *tablename; tablename = uri; if (WT_PREFIX_MATCH(uri, "file:")) { ret = __truncate_file(session, uri); } else if (WT_PREFIX_MATCH(uri, "lsm:")) ret = __wt_lsm_tree_truncate(session, uri, cfg); else if (WT_PREFIX_SKIP(tablename, "table:")) ret = __truncate_table(session, tablename, cfg); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) ret = dsrc->truncate == NULL ? __truncate_dsrc(session, uri) : dsrc->truncate( dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg); else ret = __wt_bad_object_type(session, uri); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __session_open_cursor -- * WT_SESSION->open_cursor method. */ static int __session_open_cursor(WT_SESSION *wt_session, const char *uri, WT_CURSOR *to_dup, const char *config, WT_CURSOR **cursorp) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, open_cursor, config, cfg); if ((to_dup == NULL && uri == NULL) || (to_dup != NULL && uri != NULL)) WT_ERR_MSG(session, EINVAL, "should be passed either a URI or a cursor to duplicate, " "but not both"); if (to_dup != NULL) { uri = to_dup->uri; if (WT_PREFIX_MATCH(uri, "colgroup:") || WT_PREFIX_MATCH(uri, "index:") || WT_PREFIX_MATCH(uri, "file:") || WT_PREFIX_MATCH(uri, "lsm:") || WT_PREFIX_MATCH(uri, "table:")) ret = __wt_cursor_dup(session, to_dup, cfg, cursorp); else ret = __wt_bad_object_type(session, uri); } else ret = __wt_open_cursor(session, uri, NULL, cfg, cursorp); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __curfile_equals -- * WT_CURSOR->equals method for the btree cursor type. */ static int __curfile_equals(WT_CURSOR *a, WT_CURSOR *b, int *equalp) { WT_CURSOR_BTREE *cbt; WT_DECL_RET; WT_SESSION_IMPL *session; cbt = (WT_CURSOR_BTREE *)a; CURSOR_API_CALL(a, session, equals, cbt->btree); /* * Check both cursors are a "file:" type then call the underlying * function, it can handle cursors pointing to different objects. */ if (!WT_PREFIX_MATCH(a->internal_uri, "file:") || !WT_PREFIX_MATCH(b->internal_uri, "file:")) WT_ERR_MSG(session, EINVAL, "Cursors must reference the same object"); WT_CURSOR_CHECKKEY(a); WT_CURSOR_CHECKKEY(b); ret = __wt_btcur_equals( (WT_CURSOR_BTREE *)a, (WT_CURSOR_BTREE *)b, equalp); err: API_END_RET(session, ret); }
/* * __wt_schema_range_truncate -- * WT_SESSION::truncate with a range. */ int __wt_schema_range_truncate( WT_SESSION_IMPL *session, WT_CURSOR *start, WT_CURSOR *stop) { WT_CURSOR *cursor; WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *uri; cursor = (start != NULL) ? start : stop; uri = cursor->internal_uri; if (WT_PREFIX_MATCH(uri, "file:")) WT_WITH_BTREE(session, ((WT_CURSOR_BTREE *)cursor)->btree, ret = __wt_btcur_range_truncate( (WT_CURSOR_BTREE *)start, (WT_CURSOR_BTREE *)stop)); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __wt_table_range_truncate( (WT_CURSOR_TABLE *)start, (WT_CURSOR_TABLE *)stop); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL && dsrc->range_truncate != NULL) ret = dsrc->range_truncate(dsrc, &session->iface, start, stop); else ret = __wt_range_truncate(start, stop); return (ret); }
/* * __wt_backup_list_uri_append -- * Append a new file name to the list, allocate space as necessary. * Called via the schema_worker function. */ int __wt_backup_list_uri_append( WT_SESSION_IMPL *session, const char *name, int *skip) { WT_CURSOR_BACKUP *cb; char *value; cb = session->bkp_cursor; WT_UNUSED(skip); if (WT_PREFIX_MATCH(name, "log:")) { WT_RET(__backup_log_append(session, cb, 0)); return (0); } /* Add the metadata entry to the backup file. */ WT_RET(__wt_metadata_search(session, name, &value)); WT_RET_TEST( (fprintf(cb->bfp, "%s\n%s\n", name, value) < 0), __wt_errno()); __wt_free(session, value); /* Add file type objects to the list of files to be copied. */ if (WT_PREFIX_MATCH(name, "file:")) WT_RET(__backup_list_append(session, cb, name)); return (0); }
/*通过table的schema信息来统计lsm tree和btree的数量*/ int __wt_compact_uri_analyze(WT_SESSION_IMPL* session, const char* uri, int* skip) { if(WT_PREFIX_MATCH(uri, "lsm:")){ session->compact->lsm_count++; *skip = 1; } else if(WT_PREFIX_MATCH(uri, "file:")) session->compact->file_count++; return 0; }
/* * __wt_schema_drop -- * Process a WT_SESSION::drop operation for all supported types. */ int __wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DATA_SOURCE *dsrc; WT_DECL_RET; bool force; WT_RET(__wt_config_gets_def(session, cfg, "force", 0, &cval)); force = cval.val != 0; WT_RET(__wt_meta_track_on(session)); /* Paranoia: clear any handle from our caller. */ session->dhandle = NULL; if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __drop_colgroup(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __drop_file(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __drop_index(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "lsm:")) ret = __wt_lsm_tree_drop(session, uri, cfg); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __drop_table(session, uri, cfg); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) ret = dsrc->drop == NULL ? __wt_object_unsupported(session, uri) : dsrc->drop( dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg); else ret = __wt_bad_object_type(session, uri); /* * Map WT_NOTFOUND to ENOENT, based on the assumption WT_NOTFOUND means * there was no metadata entry. Map ENOENT to zero if force is set. */ if (ret == WT_NOTFOUND || ret == ENOENT) ret = force ? 0 : ENOENT; /* Bump the schema generation so that stale data is ignored. */ ++S2C(session)->schema_gen; WT_TRET(__wt_meta_track_off(session, true, ret != 0)); return (ret); }
/* * __compact_uri_analyze -- * Extract information relevant to deciding what work compact needs to * do from a URI that is part of a table schema. * Called via the schema_worker function. */ static int __compact_uri_analyze(WT_SESSION_IMPL *session, const char *uri, bool *skipp) { /* * Add references to schema URI objects to the list of objects to be * compacted. Skip over LSM trees or we will get false positives on * the "file:" URIs for the chunks. */ if (WT_PREFIX_MATCH(uri, "lsm:")) { session->compact->lsm_count++; *skipp = true; } else if (WT_PREFIX_MATCH(uri, "file:")) session->compact->file_count++; return (0); }
/* * __backup_list_append -- * Append a new file name to the list, allocate space as necessary. */ static int __backup_list_append( WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri) { char **p; const char *name; /* Leave a NULL at the end to mark the end of the list. */ WT_RET(__wt_realloc_def(session, &cb->list_allocated, cb->list_next + 2, &cb->list)); p = &cb->list[cb->list_next]; p[0] = p[1] = NULL; name = uri; /* * If it's a file in the database we need to remove the prefix. */ if (WT_PREFIX_MATCH(uri, "file:")) name += strlen("file:"); /* * !!! * Assumes metadata file entries map one-to-one to physical files. * To support a block manager where that's not the case, we'd need * to call into the block manager and get a list of physical files * that map to this logical "file". I'm not going to worry about * that for now, that block manager might not even support physical * copying of files by applications. */ WT_RET(__wt_strdup(session, name, p)); ++cb->list_next; return (0); }
/* * __recovery_file_scan -- * Scan the files referenced from the metadata and gather information * about them for recovery. */ static int __recovery_file_scan(WT_RECOVERY *r) { WT_CURSOR *c; WT_DECL_RET; int cmp; const char *uri, *config; /* Scan through all files in the metadata. */ c = r->files[0].c; c->set_key(c, "file:"); if ((ret = c->search_near(c, &cmp)) != 0) { /* Is the metadata empty? */ WT_RET_NOTFOUND_OK(ret); return (0); } if (cmp < 0) WT_RET_NOTFOUND_OK(c->next(c)); for (; ret == 0; ret = c->next(c)) { WT_RET(c->get_key(c, &uri)); if (!WT_PREFIX_MATCH(uri, "file:")) break; WT_RET(c->get_value(c, &config)); WT_RET(__recovery_setup_file(r, uri, config)); } WT_RET_NOTFOUND_OK(ret); return (0); }
int __wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DATA_SOURCE *dsrc; WT_DECL_RET; int force; WT_RET(__wt_config_gets_defno(session, cfg, "force", &cval)); force = (cval.val != 0); /* Disallow drops from the WiredTiger name space. */ WT_RET(__wt_schema_name_check(session, uri)); WT_RET(__wt_meta_track_on(session)); /* Be careful to ignore any btree handle in our caller. */ WT_CLEAR_BTREE_IN_SESSION(session); if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __drop_colgroup(session, uri, cfg); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __drop_file(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __drop_index(session, uri, cfg); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __drop_table(session, uri, force, cfg); else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->drop(dsrc, &session->iface, uri, cfg); /* * Map WT_NOTFOUND to ENOENT (or to 0 if "force" is set), based on the * assumption WT_NOTFOUND means there was no metadata entry. The * underlying drop functions should handle this case (we passed them * the "force" value), but better safe than sorry. */ if (ret == WT_NOTFOUND) ret = force ? 0 : ENOENT; /* Bump the schema generation so that stale data is ignored. */ ++S2C(session)->schema_gen; WT_TRET(__wt_meta_track_off(session, ret != 0)); return (ret); }
/* * __wt_schema_rename -- * WT_SESSION::rename. */ 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; /* Disallow renames to/from the WiredTiger name space. */ WT_RET(__wt_schema_name_check(session, uri)); WT_RET(__wt_schema_name_check(session, newuri)); /* The target type must match the source type. */ 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 ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->rename == NULL ? __wt_object_unsupported(session, uri) : dsrc->rename(dsrc, &session->iface, uri, newuri, (WT_CONFIG_ARG *)cfg); /* Bump the schema generation so that stale data is ignored. */ ++S2C(session)->schema_gen; WT_TRET(__wt_meta_track_off(session, ret != 0)); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __wt_open_cursor -- * Internal version of WT_SESSION::open_cursor. */ int __wt_open_cursor(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_COLGROUP *colgroup; WT_DATA_SOURCE *dsrc; WT_DECL_RET; if (WT_PREFIX_MATCH(uri, "backup:")) ret = __wt_curbackup_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "colgroup:")) { /* * Column groups are a special case: open a cursor on the * underlying data source. */ WT_RET(__wt_schema_get_colgroup(session, uri, NULL, &colgroup)); ret = __wt_open_cursor( session, colgroup->source, owner, cfg, cursorp); } else if (WT_PREFIX_MATCH(uri, "config:")) ret = __wt_curconfig_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __wt_curfile_open(session, uri, owner, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __wt_curindex_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "statistics:")) ret = __wt_curstat_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __wt_curtable_open(session, uri, cfg, cursorp); else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->open_cursor(dsrc, &session->iface, uri, owner, cfg, cursorp); return (ret); }
/* * __backup_uri -- * Backup a list of objects. */ static int __backup_uri(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *cfg[], int *foundp, int *log_only) { WT_CONFIG targetconf; WT_CONFIG_ITEM cval, k, v; WT_DECL_ITEM(tmp); WT_DECL_RET; int target_list; const char *uri; *foundp = 0; *log_only = 0; /* * If we find a non-empty target configuration string, we have a job, * otherwise it's not our problem. */ WT_RET(__wt_config_gets(session, cfg, "target", &cval)); WT_RET(__wt_config_subinit(session, &targetconf, &cval)); for (cb->list_next = 0, target_list = 0; (ret = __wt_config_next(&targetconf, &k, &v)) == 0; ++target_list) { /* If it is our first time through, allocate. */ if (target_list == 0) { *foundp = 1; WT_ERR(__wt_scr_alloc(session, 512, &tmp)); } WT_ERR(__wt_buf_fmt(session, tmp, "%.*s", (int)k.len, k.str)); uri = tmp->data; if (v.len != 0) WT_ERR_MSG(session, EINVAL, "%s: invalid backup target: URIs may need quoting", uri); /* * Handle log targets. We do not need to go through the * schema worker, just call the function to append them. * Set log_only only if it is our only URI target. */ if (WT_PREFIX_MATCH(uri, "log:")) { if (target_list == 0) *log_only = 1; else *log_only = 0; WT_ERR(__wt_backup_list_uri_append( session, uri, NULL)); } else WT_ERR(__wt_schema_worker(session, uri, NULL, __wt_backup_list_uri_append, cfg, 0)); } WT_ERR_NOTFOUND_OK(ret); err: __wt_scr_free(session, &tmp); return (ret); }
/* * __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; uint32_t flags; bool bitmap, bulk; bitmap = bulk = false; flags = 0; WT_RET(__wt_config_gets_def(session, cfg, "bulk", 0, &cval)); if (cval.type == WT_CONFIG_ITEM_BOOL || (cval.type == WT_CONFIG_ITEM_NUM && (cval.val == 0 || cval.val == 1))) { bitmap = false; bulk = cval.val != 0; } else if (WT_STRING_MATCH("bitmap", cval.str, cval.len)) bitmap = bulk = true; 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_DHANDLE_EXCLUSIVE); /* Get the handle and lock it while the cursor is using it. */ if (WT_PREFIX_MATCH(uri, "file:")) { /* * If we are opening a bulk cursor, get the handle while * holding the checkpoint lock. This prevents a bulk cursor * open failing with EBUSY due to a database-wide checkpoint. */ if (bulk) __wt_spin_lock( session, &S2C(session)->checkpoint_lock); ret = __wt_session_get_btree_ckpt(session, uri, cfg, flags); if (bulk) __wt_spin_unlock( session, &S2C(session)->checkpoint_lock); WT_RET(ret); } else WT_RET(__wt_bad_object_type(session, uri)); WT_ERR(__wt_curfile_create(session, owner, cfg, bulk, bitmap, cursorp)); /* Increment the data-source's in-use counter. */ __wt_cursor_dhandle_incr_use(session); return (0); err: /* If the cursor could not be opened, release the handle. */ WT_TRET(__wt_session_release_btree(session)); return (ret); }
/* * __meta_btree_apply -- * Apply a function to all files listed in the metadata, apart from the * metadata file. */ static inline int __meta_btree_apply(WT_SESSION_IMPL *session, WT_CURSOR *cursor, int (*file_func)(WT_SESSION_IMPL *, const char *[]), int (*name_func)(WT_SESSION_IMPL *, const char *, bool *), const char *cfg[]) { WT_DECL_RET; int t_ret; const char *uri; bool skip; /* * Accumulate errors but continue through to the end of the metadata. */ while ((t_ret = cursor->next(cursor)) == 0) { if ((t_ret = cursor->get_key(cursor, &uri)) != 0 || strcmp(uri, WT_METAFILE_URI) == 0) { WT_TRET(t_ret); continue; } skip = false; if (name_func != NULL && (t_ret = name_func(session, uri, &skip)) != 0) { WT_TRET(t_ret); continue; } if (file_func == NULL || skip || !WT_PREFIX_MATCH(uri, "file:")) continue; /* * We need to pull the handle into the session handle cache * and make sure it's referenced to stop other internal code * dropping the handle (e.g in LSM when cleaning up obsolete * chunks). Holding the schema lock isn't enough. * * Handles that are busy are skipped without the whole * operation failing. This deals among other cases with * checkpoint encountering handles that are locked (e.g., for * bulk loads or verify operations). */ if ((t_ret = __wt_session_get_dhandle( session, uri, NULL, NULL, 0)) != 0) { WT_TRET_BUSY_OK(t_ret); continue; } WT_SAVE_DHANDLE(session, WT_TRET(file_func(session, cfg))); WT_TRET(__wt_session_release_dhandle(session)); } WT_TRET_NOTFOUND_OK(t_ret); return (ret); }
/* * util_name -- * Build a name. */ char * util_name(const char *s, const char *type, u_int flags) { size_t len; int copy; char *name; copy = 0; if (WT_PREFIX_MATCH(s, "backup:")) { goto type_err; } else if (WT_PREFIX_MATCH(s, "colgroup:")) { if (!(flags & UTIL_COLGROUP_OK)) goto type_err; copy = 1; } else if (WT_PREFIX_MATCH(s, "config:")) { goto type_err; } else if (WT_PREFIX_MATCH(s, "file:")) { if (!(flags & UTIL_FILE_OK)) goto type_err; copy = 1; } else if (WT_PREFIX_MATCH(s, "index:")) { if (!(flags & UTIL_INDEX_OK)) goto type_err; copy = 1; } else if (WT_PREFIX_MATCH(s, "lsm:")) { if (!(flags & UTIL_LSM_OK)) goto type_err; copy = 1; } else if (WT_PREFIX_MATCH(s, "statistics:")) { goto type_err; } else if (WT_PREFIX_MATCH(s, "table:")) { if (!(flags & UTIL_TABLE_OK)) { type_err: fprintf(stderr, "%s: %s: unsupported object type: %s\n", progname, command, s); return (NULL); } copy = 1; } len = strlen(type) + strlen(s) + 2; if ((name = calloc(len, 1)) == NULL) { (void)util_err(errno, NULL); return (NULL); } if (copy) strcpy(name, s); else snprintf(name, len, "%s:%s", type, s); return (name); }
/* * __wt_schema_create -- * Process a WT_SESSION::create operation for all supported types. */ int __wt_schema_create( WT_SESSION_IMPL *session, const char *uri, const char *config) { WT_CONFIG_ITEM cval; WT_DATA_SOURCE *dsrc; WT_DECL_RET; int exclusive; exclusive = ( __wt_config_getones(session, config, "exclusive", &cval) == 0 && cval.val != 0); /* * We track create operations: if we fail in the middle of creating a * complex object, we want to back it all out. */ WT_RET(__wt_meta_track_on(session)); if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __create_colgroup(session, uri, exclusive, config); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __create_file(session, uri, exclusive, config); else if (WT_PREFIX_MATCH(uri, "lsm:")) ret = __wt_lsm_tree_create(session, uri, exclusive, config); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __create_index(session, uri, exclusive, config); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __create_table(session, uri, exclusive, config); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) ret = dsrc->create == NULL ? __wt_object_unsupported(session, uri) : __create_data_source(session, uri, config, dsrc); else ret = __wt_bad_object_type(session, uri); session->dhandle = NULL; WT_TRET(__wt_meta_track_off(session, 1, ret != 0)); return (ret); }
/* * __backup_list_append -- * Append a new file name to the list, allocate space as necessary. */ static int __backup_list_append( WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri) { WT_CURSOR_BACKUP_ENTRY *p; WT_DATA_HANDLE *old_dhandle; WT_DECL_RET; const char *name; int need_handle; /* Leave a NULL at the end to mark the end of the list. */ WT_RET(__wt_realloc_def(session, &cb->list_allocated, cb->list_next + 2, &cb->list)); p = &cb->list[cb->list_next]; p[0].name = p[1].name = NULL; p[0].handle = p[1].handle = NULL; need_handle = 0; name = uri; if (WT_PREFIX_MATCH(uri, "file:")) { need_handle = 1; name += strlen("file:"); } /* * !!! * Assumes metadata file entries map one-to-one to physical files. * To support a block manager where that's not the case, we'd need * to call into the block manager and get a list of physical files * that map to this logical "file". I'm not going to worry about * that for now, that block manager might not even support physical * copying of files by applications. */ WT_RET(__wt_strdup(session, name, &p->name)); /* * If it's a file in the database, get a handle for the underlying * object (this handle blocks schema level operations, for example * WT_SESSION.drop or an LSM file discard after level merging). */ if (need_handle) { old_dhandle = session->dhandle; if ((ret = __wt_session_get_btree(session, uri, NULL, NULL, 0)) == 0) p->handle = session->dhandle; session->dhandle = old_dhandle; WT_RET(ret); } ++cb->list_next; 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_meta_btree_apply -- * Apply a function to all files listed in the metadata, apart from the * metadata file. */ int __wt_meta_btree_apply(WT_SESSION_IMPL *session, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]) { WT_CURSOR *cursor; WT_DATA_HANDLE *saved_dhandle; WT_DECL_RET; const char *uri; int cmp, tret; saved_dhandle = session->dhandle; WT_RET(__wt_metadata_cursor(session, NULL, &cursor)); cursor->set_key(cursor, "file:"); if ((tret = cursor->search_near(cursor, &cmp)) == 0 && cmp < 0) tret = cursor->next(cursor); for (; tret == 0; tret = cursor->next(cursor)) { WT_ERR(cursor->get_key(cursor, &uri)); if (!WT_PREFIX_MATCH(uri, "file:")) break; else if (strcmp(uri, WT_METAFILE_URI) == 0) continue; /* * We need to pull the handle into the session handle cache * and make sure it's referenced to stop other internal code * dropping the handle (e.g in LSM when cleaning up obsolete * chunks). Holding the metadata lock isn't enough. */ ret = __wt_session_get_btree(session, uri, NULL, NULL, 0); if (ret == 0) { WT_SAVE_DHANDLE(session, ret = func(session, cfg)); if (WT_META_TRACKING(session)) WT_TRET( __wt_meta_track_handle_lock(session, 0)); else WT_TRET(__wt_session_release_btree(session)); } else if (ret == EBUSY) ret = __wt_conn_btree_apply_single( session, uri, NULL, func, cfg); WT_ERR(ret); } if (tret != WT_NOTFOUND) WT_TRET(tret); err: WT_TRET(cursor->close(cursor)); session->dhandle = saved_dhandle; return (ret); }
int __wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_CONFIG_ITEM cval; int force, ret; cval.val = 0; ret = __wt_config_gets(session, cfg, "force", &cval); if (ret != 0 && ret != WT_NOTFOUND) WT_RET(ret); force = cval.val == 0 ? 0 : 1; /* Disallow drops from the WiredTiger name space. */ WT_RET(__wt_schema_name_check(session, uri)); if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __drop_colgroup(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __drop_file(session, uri, force); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __drop_index(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __drop_table(session, uri, force); else return (__wt_unknown_object_type(session, uri)); /* * Map WT_NOTFOUND to ENOENT (or to 0 if "force" is set), based on the * assumption WT_NOTFOUND means there was no schema file entry. The * underlying drop functions should handle this case (we passed them * the "force" value), but better safe than sorry. */ if (ret == WT_NOTFOUND) ret = force ? 0 : ENOENT; return (ret); }
/* * config_reorder -- * For table dumps, reorder the list so tables are first. * For other dumps, make any needed checks. */ int config_reorder(char **list) { char **entry, *p; /* * Search for a table name -- if we find one, then it's table dump, * otherwise, it's a single file dump. */ for (entry = list; *entry != NULL; ++entry) if (WT_PREFIX_MATCH(*entry, "table:")) break; if (*entry == NULL) { /* * Single file dumps can only have two lines, the file name and * the configuration information. */ if ((list[0] == NULL || list[1] == NULL || list[2] != NULL) || (WT_PREFIX_MATCH(list[0], "file:") && WT_PREFIX_MATCH(list[0], "lsm:"))) return (format()); entry = list; } /* * Make sure the table key/value pair comes first, then we can just * run through the array in order. (We already checked that we had * a multiple of 2 entries, so this is safe.) */ if (entry != list) { p = list[0]; list[0] = entry[0]; entry[0] = p; p = list[1]; list[1] = entry[1]; entry[1] = p; } return (0); }
/* * util_uri -- * Build a name. */ char * util_uri(WT_SESSION *session, const char *s, const char *type) { WT_DECL_RET; size_t len; char *name; if (WT_PREFIX_MATCH(s, "backup:") || WT_PREFIX_MATCH(s, "config:") || WT_PREFIX_MATCH(s, "statistics:")) { fprintf(stderr, "%s: %s: unsupported object type: %s\n", progname, command, s); return (NULL); } len = strlen(type) + strlen(s) + 2; if ((name = calloc(len, 1)) == NULL) { (void)util_err(session, errno, NULL); return (NULL); } /* * If the string has a URI prefix, use it verbatim, otherwise prepend * the default type for the operation. */ if (strchr(s, ':') != NULL) WT_ERR(__wt_snprintf(name, len, "%s", s)); else WT_ERR(__wt_snprintf(name, len, "%s:%s", type, s)); return (name); err: free(name); (void)util_err(session, ret, NULL); return (NULL); }
/* * __wt_lsm_compact -- * Compact an LSM tree called via __wt_schema_worker. */ int __wt_lsm_compact(WT_SESSION_IMPL *session, const char *name, int *skip) { WT_DECL_RET; WT_LSM_TREE *lsm_tree; uint64_t last_merge_progressing; time_t begin, end; /* * This function is applied to all matching sources: ignore anything * that is not an LSM tree. */ if (!WT_PREFIX_MATCH(name, "lsm:")) return (0); /* Tell __wt_schema_worker not to look inside the LSM tree. */ *skip = 1; WT_RET(__wt_lsm_tree_get(session, name, 0, &lsm_tree)); if (!F_ISSET(S2C(session), WT_CONN_LSM_MERGE) || lsm_tree->merge_threads == 0) WT_RET_MSG(session, EINVAL, "LSM compaction requires active merge threads"); WT_RET(__wt_seconds(session, &begin)); F_SET(lsm_tree, WT_LSM_TREE_COMPACTING); /* Wake up the merge threads. */ WT_RET(__wt_cond_signal(session, lsm_tree->work_cond)); /* Now wait for merge activity to stop. */ do { last_merge_progressing = lsm_tree->merge_progressing; __wt_sleep(1, 0); WT_RET(__wt_seconds(session, &end)); if (session->compact->max_time > 0 && session->compact->max_time < (uint64_t)(end - begin)) WT_ERR(ETIMEDOUT); } while (lsm_tree->merge_progressing != last_merge_progressing && lsm_tree->nchunks > 1); err: F_CLR(lsm_tree, WT_LSM_TREE_COMPACTING); return (ret); }
/* * __backup_list_uri_append -- * Append a new file name to the list, allocate space as necessary. * Called via the schema_worker function. */ static int __backup_list_uri_append( WT_SESSION_IMPL *session, const char *name, bool *skip) { WT_CURSOR_BACKUP *cb; char *value; cb = session->bkp_cursor; WT_UNUSED(skip); /* * While reading the metadata file, check there are no data sources * that can't support hot backup. This checks for a data source that's * non-standard, which can't be backed up, but is also sanity checking: * if there's an entry backed by anything other than a file or lsm * entry, we're confused. */ if (WT_PREFIX_MATCH(name, "log:")) { WT_RET(__backup_log_append(session, cb, false)); return (0); } if (!WT_PREFIX_MATCH(name, "file:") && !WT_PREFIX_MATCH(name, "colgroup:") && !WT_PREFIX_MATCH(name, "index:") && !WT_PREFIX_MATCH(name, "lsm:") && !WT_PREFIX_MATCH(name, "table:")) WT_RET_MSG(session, ENOTSUP, "hot backup is not supported for objects of type %s", name); /* Ignore the lookaside table. */ if (strcmp(name, WT_LAS_URI) == 0) return (0); /* Add the metadata entry to the backup file. */ WT_RET(__wt_metadata_search(session, name, &value)); WT_RET(__wt_fprintf(cb->bfp, "%s\n%s\n", name, value)); __wt_free(session, value); /* Add file type objects to the list of files to be copied. */ if (WT_PREFIX_MATCH(name, "file:")) WT_RET(__backup_list_append(session, cb, name)); return (0); }
/* * __wt_schema_truncate -- * WT_SESSION::truncate. */ int __wt_schema_truncate( WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *tablename; WT_UNUSED(cfg); tablename = uri; if (WT_PREFIX_MATCH(uri, "file:")) ret = __truncate_file(session, uri); else if (WT_PREFIX_SKIP(tablename, "table:")) ret = __truncate_table(session, tablename); else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->truncate(dsrc, &session->iface, uri, cfg); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __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); }
/* * __meta_btree_apply -- * Apply a function to all files listed in the metadata, apart from the * metadata file. */ static inline int __meta_btree_apply(WT_SESSION_IMPL *session, WT_CURSOR *cursor, int (*file_func)(WT_SESSION_IMPL *, const char *[]), int (*name_func)(WT_SESSION_IMPL *, const char *, bool *), const char *cfg[]) { WT_DECL_RET; const char *uri; bool skip; while ((ret = cursor->next(cursor)) == 0) { WT_RET(cursor->get_key(cursor, &uri)); if (strcmp(uri, WT_METAFILE_URI) == 0) continue; skip = false; if (name_func != NULL) WT_RET(name_func(session, uri, &skip)); if (file_func == NULL || skip || !WT_PREFIX_MATCH(uri, "file:")) continue; /* * We need to pull the handle into the session handle cache * and make sure it's referenced to stop other internal code * dropping the handle (e.g in LSM when cleaning up obsolete * chunks). Holding the metadata lock isn't enough. */ if ((ret = __wt_session_get_btree( session, uri, NULL, NULL, 0)) != 0) return (ret == EBUSY ? 0 : ret); WT_SAVE_DHANDLE(session, ret = file_func(session, cfg)); WT_TRET(__wt_session_release_btree(session)); WT_RET(ret); } WT_RET_NOTFOUND_OK(ret); 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; uint32_t flags; /* * Bulk and no cache handles are exclusive and may not be used by more * than a single thread. * Additionally set the discard flag on no cache handles so they are * destroyed on close. */ flags = 0; WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval)); if (cval.val != 0) LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_BULK); WT_RET(__wt_config_gets_defno(session, cfg, "no_cache", &cval)); if (cval.val != 0) LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_NO_CACHE); /* 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, cursorp)); return (0); err: /* If the cursor could not be opened, release the handle. */ (void)__wt_session_release_btree(session); return (ret); }