diff options
-rw-r--r-- | src/cursor/cur_metadata.c | 158 | ||||
-rw-r--r-- | src/include/cursor.h | 1 | ||||
-rw-r--r-- | src/include/extern.h | 1 | ||||
-rw-r--r-- | src/utilities/util_dump.c | 210 |
4 files changed, 155 insertions, 215 deletions
diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c index fc63ca13f7c..863c0c2b487 100644 --- a/src/cursor/cur_metadata.c +++ b/src/cursor/cur_metadata.c @@ -31,55 +31,87 @@ } while (0) /* - * __wt_schema_create_final -- - * Create a single configuration line from a set of configuration strings, - * including all of the defaults declared for a session.create, and stripping - * any configuration strings that don't belong in a session.create. Here for - * the wt dump command utility, which reads a set of configuration strings and - * needs to add in the defaults and then collapse them into single string for - * a subsequent load. + * __schema_source_config -- + * Extract the "source" configuration key, lookup its metadata. */ -int -__wt_schema_create_final( - WT_SESSION_IMPL *session, char *cfg_arg[], char **value_ret) +static int +__schema_source_config(WT_SESSION_IMPL *session, WT_CURSOR *srch, + char *config, char **result) { + WT_CONFIG_ITEM cval; + WT_DECL_ITEM(buf); WT_DECL_RET; - u_int i; - const char **cfg; - - /* - * Count the entries in the original, - * Allocate a copy with the defaults as the first entry, - * Collapse the whole thing into a single configuration string (which - * also strips any entries that don't appear in the first entry). - */ - for (i = 0; cfg_arg[i] != NULL; ++i) - ; - WT_RET(__wt_calloc_def(session, i + 2, &cfg)); - cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_create); - for (i = 0; cfg_arg[i] != NULL; ++i) - cfg[i + 1] = cfg_arg[i]; - cfg[i + 1] = NULL; - - ret = __wt_config_collapse(session, cfg, value_ret); - - __wt_free(session, cfg); + char *v; + + WT_ERR(__wt_config_getones(session, config, "source", &cval)); + WT_ERR(__wt_scr_alloc(session, cval.len + 10, &buf)); + WT_ERR(__wt_buf_fmt(session, buf, "%.*s", (int)cval.len, cval.str)); + srch->set_key(srch, buf->data); + if ((ret = srch->search(srch)) == WT_NOTFOUND) + WT_ERR(EINVAL); + WT_ERR(ret); + WT_ERR(srch->get_value(srch, &v)); + WT_ERR(__wt_strdup(session, v, result)); + +err: __wt_scr_free(session, &buf); return (ret); } /* - * __schema_create_strip -- - * Discard any configuration information from a schema entry that is not - * applicable to an session.create call. Here for the metadata:create URI. + * __schema_create_collapse -- + * Discard any configuration information from a schema entry that is + * not applicable to an session.create call. + * + * For a table URI that contains no named column groups, fold in the + * configuration from the implicit column group and its source. For a + * named column group URI, fold in its source. */ static int -__schema_create_strip( - WT_SESSION_IMPL *session, const char *value, char **value_ret) +__schema_create_collapse(WT_SESSION_IMPL *session, WT_CURSOR_METADATA *mdc, + const char *key, char *value, char **value_ret) { - const char *cfg[] = - { WT_CONFIG_BASE(session, WT_SESSION_create), value, NULL }; - - return (__wt_config_collapse(session, cfg, value_ret)); + WT_CURSOR *c; + WT_DECL_ITEM(buf); + WT_DECL_RET; + char *_cfg[5] = {NULL, NULL, NULL, value, NULL}; + char **cfg, **firstcfg, **lastcfg, *v; + + lastcfg = cfg = &_cfg[3]; /* position on value */ + c = NULL; + if (key != NULL && WT_PREFIX_SKIP(key, "table:")) { + c = mdc->create_cursor; + WT_ERR(__wt_scr_alloc(session, 0, &buf)); + /* + * When a table is created without column groups, + * we create one without a name. + */ + WT_ERR(__wt_buf_fmt(session, buf, "colgroup:%s", key)); + c->set_key(c, buf->data); + if ((ret = c->search(c)) == 0) { + WT_ERR(c->get_value(c, &v)); + WT_ERR(__wt_strdup(session, v, --cfg)); + WT_ERR(__schema_source_config(session, c, v, --cfg)); + } else + WT_ERR_NOTFOUND_OK(ret); + } else if (key != NULL && WT_PREFIX_SKIP(key, "colgroup:")) { + if (strchr(key, ':') != NULL) { + c = mdc->create_cursor; + WT_ERR(__wt_strdup(session, value, --cfg)); + WT_ERR( + __schema_source_config(session, c, value, --cfg)); + } + } + firstcfg = cfg; + *--firstcfg = (char *)WT_CONFIG_BASE(session, WT_SESSION_create); + WT_ERR(__wt_config_collapse( + session, (const char **)firstcfg, value_ret)); + +err: for (; cfg < lastcfg; cfg++) + __wt_free(session, *cfg); + if (c != NULL) + c->reset(c); + __wt_scr_free(session, &buf); + return (ret); } /* @@ -95,17 +127,17 @@ __curmetadata_setkv(WT_CURSOR_METADATA *mdc, WT_CURSOR *fc) WT_SESSION_IMPL *session; char *value; + value = NULL; c = &mdc->iface; session = (WT_SESSION_IMPL *)c->session; c->key.data = fc->key.data; c->key.size = fc->key.size; if (F_ISSET(mdc, WT_MDC_CREATEONLY)) { - WT_RET(__schema_create_strip(session, fc->value.data, &value)); - ret = __wt_buf_set( - session, &c->value, value, strlen(value) + 1); - __wt_free(session, value); - WT_RET(ret); + WT_ERR(__schema_create_collapse(session, mdc, + (char *)fc->key.data, (char *)fc->value.data, &value)); + WT_ERR(__wt_buf_set( + session, &c->value, value, strlen(value) + 1)); } else { c->value.data = fc->value.data; c->value.size = fc->value.size; @@ -115,7 +147,8 @@ __curmetadata_setkv(WT_CURSOR_METADATA *mdc, WT_CURSOR *fc) F_CLR(mdc, WT_MDC_ONMETADATA); F_SET(mdc, WT_MDC_POSITIONED); - return (0); +err: __wt_free(session, value); + return (ret); } /* @@ -143,7 +176,8 @@ __curmetadata_metadata_search(WT_SESSION_IMPL *session, WT_CURSOR *cursor) WT_RET(__wt_metadata_search(session, WT_METAFILE_URI, &value)); if (F_ISSET(mdc, WT_MDC_CREATEONLY)) { - ret = __schema_create_strip(session, value, &stripped); + ret = __schema_create_collapse(session, mdc, NULL, value, + &stripped); __wt_free(session, value); WT_RET(ret); value = stripped; @@ -467,19 +501,20 @@ err: API_END_RET(session, ret); static int __curmetadata_close(WT_CURSOR *cursor) { - WT_CURSOR *file_cursor; + WT_CURSOR *c; WT_CURSOR_METADATA *mdc; WT_DECL_RET; WT_SESSION_IMPL *session; mdc = (WT_CURSOR_METADATA *)cursor; - file_cursor = mdc->file_cursor; - CURSOR_API_CALL(cursor, session, - close, file_cursor == NULL ? - NULL : ((WT_CURSOR_BTREE *)file_cursor)->btree); - - if (file_cursor != NULL) - ret = file_cursor->close(file_cursor); + c = mdc->file_cursor; + CURSOR_API_CALL(cursor, session, close, c == NULL ? + NULL : ((WT_CURSOR_BTREE *)c)->btree); + + if (c != NULL) + ret = c->close(c); + if ((c = mdc->create_cursor) != NULL) + WT_TRET(c->close(c)); WT_TRET(__wt_cursor_close(cursor)); err: API_END_RET(session, ret); @@ -536,11 +571,18 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, */ WT_ERR(__wt_metadata_cursor_open(session, cfg[1], &mdc->file_cursor)); - WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp)); - - /* If we are only returning create config, strip internal metadata. */ - if (WT_STREQ(uri, "metadata:create")) + /* + * If we are only returning create config, strip internal metadata. + * We'll need some extra cursors to pull out column group information + * and chase "source" entries. + */ + if (WT_STREQ(uri, "metadata:create")) { F_SET(mdc, WT_MDC_CREATEONLY); + WT_ERR(__wt_metadata_cursor_open(session, cfg[1], + &mdc->create_cursor)); + } + + WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp)); /* * Metadata cursors default to readonly; if not set to not-readonly, diff --git a/src/include/cursor.h b/src/include/cursor.h index dce24f20844..f1fa4d193ac 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -425,6 +425,7 @@ struct __wt_cursor_metadata { WT_CURSOR iface; WT_CURSOR *file_cursor; /* Queries of regular metadata */ + WT_CURSOR *create_cursor; /* Extra cursor for create option */ #define WT_MDC_CREATEONLY 0x01 #define WT_MDC_ONMETADATA 0x02 diff --git a/src/include/extern.h b/src/include/extern.h index 5a12a7f333a..a18f2b3ef8c 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -297,7 +297,6 @@ extern int __wt_json_to_item(WT_SESSION_IMPL *session, const char *jstr, const c extern ssize_t __wt_json_strlen(const char *src, size_t srclen); extern int __wt_json_strncpy(WT_SESSION *wt_session, char **pdst, size_t dstlen, const char *src, size_t srclen) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern int __wt_curlog_open(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], WT_CURSOR **cursorp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); -extern int __wt_schema_create_final( WT_SESSION_IMPL *session, char *cfg_arg[], char **value_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern int __wt_curmetadata_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern void __wt_curstat_dsrc_final(WT_CURSOR_STAT *cst); extern int __wt_curstat_init(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *curjoin, const char *cfg[], WT_CURSOR_STAT *cst) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); diff --git a/src/utilities/util_dump.c b/src/utilities/util_dump.c index 6344a90dddd..7dde13ee837 100644 --- a/src/utilities/util_dump.c +++ b/src/utilities/util_dump.c @@ -18,10 +18,10 @@ static int dump_prefix(WT_SESSION *, bool, bool); static int dump_record(WT_CURSOR *, bool, bool); static int dump_suffix(WT_SESSION *, bool); static int dump_table_config(WT_SESSION *, WT_CURSOR *, const char *, bool); -static int dump_table_config_complex( - WT_SESSION *, WT_CURSOR *, WT_CURSOR *, const char *, const char *, bool); +static int dump_table_parts_config( + WT_SESSION *, WT_CURSOR *, const char *, const char *, bool); static int dup_json_string(const char *, char **); -static int print_config(WT_SESSION *, const char *, char *[], bool, bool); +static int print_config(WT_SESSION *, const char *, const char *, bool, bool); static int usage(void); int @@ -146,9 +146,9 @@ dump_config(WT_SESSION *session, const char *uri, bool hex, bool json) /* Open a metadata cursor. */ if ((ret = session->open_cursor( - session, "metadata:", NULL, NULL, &cursor)) != 0) { + session, "metadata:create", NULL, NULL, &cursor)) != 0) { fprintf(stderr, "%s: %s: session.open_cursor: %s\n", progname, - "metadata:", session->strerror(session, ret)); + "metadata:create", session->strerror(session, ret)); return (1); } /* @@ -202,7 +202,7 @@ dump_json_end(WT_SESSION *session) /* * dump_json_begin -- - * Output the dump file header prefix. + * Output a separator between two JSON outputs in a list. */ static int dump_json_separator(WT_SESSION *session) @@ -232,18 +232,8 @@ static int dump_table_config( WT_SESSION *session, WT_CURSOR *cursor, const char *uri, bool json) { - WT_CONFIG_ITEM cval; - WT_CURSOR *srch; WT_DECL_RET; - size_t len; - int tret; - bool complex_table; const char *name, *v; - char *p, **cfg, *_cfg[4] = {NULL, NULL, NULL, NULL}; - - p = NULL; - srch = NULL; - cfg = &_cfg[3]; /* Get the table name. */ if ((name = strchr(uri, ':')) == NULL) { @@ -258,105 +248,39 @@ dump_table_config( */ cursor->set_key(cursor, uri); if ((ret = cursor->search(cursor)) != 0) - WT_ERR(util_cerr(cursor, "search", ret)); + return (util_cerr(cursor, "search", ret)); if ((ret = cursor->get_value(cursor, &v)) != 0) - WT_ERR(util_cerr(cursor, "get_value", ret)); - if ((*--cfg = strdup(v)) == NULL) - WT_ERR(util_err(session, errno, NULL)); - - /* - * Workaround for WiredTiger "simple" table handling. Simple tables - * have column-group entries, but they aren't listed in the metadata's - * table entry, and the name is different from other column-groups. - * Figure out if it's a simple table and in that case, retrieve the - * column-group's configuration value and the column-group's "source" - * entry, where the column-group entry overrides the source's. - */ - complex_table = false; - if (WT_PREFIX_MATCH(uri, "table:")) { - len = strlen("colgroup:") + strlen(name) + 1; - if ((p = malloc(len)) == NULL) - WT_ERR(util_err(session, errno, NULL)); - (void)snprintf(p, len, "colgroup:%s", name); - cursor->set_key(cursor, p); - if ((ret = cursor->search(cursor)) == 0) { - if ((ret = cursor->get_value(cursor, &v)) != 0) - WT_ERR(util_cerr(cursor, "get_value", ret)); - if ((*--cfg = strdup(v)) == NULL) - WT_ERR(util_err(session, errno, NULL)); - if ((ret =__wt_config_getones( - (WT_SESSION_IMPL *)session, - *cfg, "source", &cval)) != 0) - WT_ERR(util_err( - session, ret, "%s: source entry", p)); - free(p); - len = cval.len + 10; - if ((p = malloc(len)) == NULL) - WT_ERR(util_err(session, errno, NULL)); - (void)snprintf(p, len, "%.*s", (int)cval.len, cval.str); - cursor->set_key(cursor, p); - if ((ret = cursor->search(cursor)) != 0) - WT_ERR(util_cerr(cursor, "search", ret)); - if ((ret = cursor->get_value(cursor, &v)) != 0) - WT_ERR(util_cerr(cursor, "get_value", ret)); - if ((*--cfg = strdup(v)) == NULL) - WT_ERR(util_err(session, errno, NULL)); - } else - complex_table = true; - } - - WT_ERR(print_config(session, uri, cfg, json, true)); + return (util_cerr(cursor, "get_value", ret)); - /* - * The underlying table configuration function needs a second - * cursor: open one before calling it, it makes error handling - * hugely simpler. - */ - if ((ret = session->open_cursor( - session, "metadata:", NULL, NULL, &srch)) != 0) - WT_ERR(util_cerr(cursor, "open_cursor", ret)); - - if (complex_table) - WT_ERR(dump_table_config_complex( - session, cursor, srch, name, "colgroup:", json)); - else if (json && printf( - " \"colgroups\" : [],\n") < 0) - WT_ERR(util_cerr(cursor, NULL, EIO)); + WT_RET(print_config(session, uri, v, json, true)); - WT_ERR(dump_table_config_complex( - session, cursor, srch, name, "index:", json)); + WT_RET(dump_table_parts_config( + session, cursor, name, "colgroup:", json)); + WT_RET(dump_table_parts_config( + session, cursor, name, "index:", json)); -err: if (srch != NULL && (tret = srch->close(srch)) != 0) { - tret = util_cerr(cursor, "close", tret); - if (ret == 0) - ret = tret; - } - free(p); - free(_cfg[0]); - free(_cfg[1]); - free(_cfg[2]); - return (ret); + return (0); } /* - * dump_table_config_complex -- - * Dump the column groups or indices for a table. + * dump_table_parts_config -- + * Dump the column groups or indices parts with a table. */ static int -dump_table_config_complex(WT_SESSION *session, WT_CURSOR *cursor, - WT_CURSOR *srch, const char *name, const char *entry, bool json) +dump_table_parts_config(WT_SESSION *session, WT_CURSOR *cursor, + const char *name, const char *entry, bool json) { - WT_CONFIG_ITEM cval; WT_DECL_RET; bool multiple; const char *groupname, *key, *sep; size_t len; int exact; const char *v; - char *p, *cfg[3] = {NULL, NULL, NULL}; + char *uriprefix; multiple = false; sep = ""; + uriprefix = NULL; if (json) { if (strcmp(entry, "colgroup:") == 0) { @@ -368,82 +292,61 @@ dump_table_config_complex(WT_SESSION *session, WT_CURSOR *cursor, if (printf(" \"%s\" : [", groupname) < 0) return (util_err(session, EIO, NULL)); } + + len = strlen(entry) + strlen(name) + 1; + if ((uriprefix = malloc(len)) == NULL) + return util_err(session, errno, NULL); + + snprintf(uriprefix, len, "%s%s", entry, name); + /* * Search the file looking for column group and index key/value pairs: * for each one, look up the related source information and append it * to the base record, where the column group and index configuration * overrides the source configuration. */ - cursor->set_key(cursor, entry); - if ((ret = cursor->search_near(cursor, &exact)) != 0) { - if (ret == WT_NOTFOUND) - return (0); + cursor->set_key(cursor, uriprefix); + ret = cursor->search_near(cursor, &exact); + free(uriprefix); + if (ret == WT_NOTFOUND) + return (0); + if (ret != 0) return (util_cerr(cursor, "search_near", ret)); - } - if (exact >= 0) + + /* + * An exact match is only possible for column groups, and indicates + * there is an implicit (unnamed) column group. Any configuration + * for such a column group has already been folded into the + * configuration for the associated table, so it is not interesting. + */ + if (exact > 0) goto match; - while ((ret = cursor->next(cursor)) == 0) { + while (exact != 0 && (ret = cursor->next(cursor)) == 0) { match: if ((ret = cursor->get_key(cursor, &key)) != 0) return (util_cerr(cursor, "get_key", ret)); /* Check if we've finished the list of entries. */ - if (!WT_PREFIX_MATCH(key, entry)) + if (!WT_PREFIX_MATCH(key, entry) || + !WT_PREFIX_MATCH(key + strlen(entry), name)) break; - /* - * Check for a table name match. This test will match "simple" - * table column-groups as well as the more complex ones, but - * the previous version of the test was wrong and we're only - * in this function in the case of complex tables. - */ - if (!WT_PREFIX_MATCH(key + strlen(entry), name)) - continue; - - /* Get the value. */ if ((ret = cursor->get_value(cursor, &v)) != 0) return (util_cerr(cursor, "get_value", ret)); - if ((cfg[1] = strdup(v)) == NULL) - return (util_err(session, errno, NULL)); - - /* Crack it and get the underlying source. */ - if ((ret = __wt_config_getones( - (WT_SESSION_IMPL *)session, cfg[1], "source", &cval)) != 0) - return ( - util_err(session, ret, "%s: source entry", key)); - - /* Nul-terminate the source entry. */ - len = cval.len + 10; - if ((p = malloc(len)) == NULL) - return (util_err(session, errno, NULL)); - (void)snprintf(p, len, "%.*s", (int)cval.len, cval.str); - srch->set_key(srch, p); - if ((ret = srch->search(srch)) != 0) - ret = util_err(session, ret, "%s: %s", key, p); - free(p); - if (ret != 0) - return (1); - - /* Get the source's value. */ - if ((ret = srch->get_value(srch, &v)) != 0) - return (util_cerr(cursor, "get_value", ret)); - if ((cfg[0] = strdup(v)) == NULL) - return (util_err(session, errno, NULL)); - if (json && printf("%s\n", multiple ? "," : "") < 0) + if (json && printf("%s\n", (multiple ? "," : "")) < 0) return (util_err(session, EIO, NULL)); /* * The dumped configuration string is the original key plus the * source's configuration, where the values of the original key * override any source configurations of the same name. */ - if (print_config(session, key, cfg, json, false) != 0) + if (print_config(session, key, v, json, false) != 0) return (util_err(session, EIO, NULL)); multiple = true; } - if (json && printf("\n ]%s\n", sep) < 0) + if (json && printf("%s]%s\n", + (multiple ? "\n " : ""), sep) < 0) return (util_err(session, EIO, NULL)); - free(cfg[0]); - free(cfg[1]); if (ret == 0 || ret == WT_NOTFOUND) return (0); @@ -573,11 +476,11 @@ dup_json_string(const char *str, char **result) * Output a key/value URI pair by combining v1 and v2. */ static int -print_config( - WT_SESSION *session, const char *key, char *cfg[], bool json, bool toplevel) +print_config(WT_SESSION *session, const char *key, const char *cfg, bool json, + bool toplevel) { WT_DECL_RET; - char *jsonconfig, *value_ret; + char *jsonconfig; /* * We have all of the object configuration, but don't have the default @@ -585,13 +488,9 @@ print_config( * defaults and collapse it all into one load configuration string. */ jsonconfig = NULL; - if ((ret = __wt_schema_create_final( - (WT_SESSION_IMPL *)session, cfg, &value_ret)) != 0) - return (util_err(session, ret, NULL)); - if (json && (ret = dup_json_string(value_ret, &jsonconfig)) != 0) { - free(value_ret); + if (json && (ret = dup_json_string(cfg, &jsonconfig)) != 0) return (util_err(session, ret, NULL)); - } + if (json) { if (toplevel) ret = printf( @@ -604,8 +503,7 @@ print_config( " \"config\" : \"%s\"\n" " }", key, jsonconfig); } else - ret = printf("%s\n%s\n", key, value_ret); - free(value_ret); + ret = printf("%s\n%s\n", key, cfg); free(jsonconfig); if (ret < 0) return (util_err(session, EIO, NULL)); |