diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/third_party/wiredtiger/dist/s_string.ok | 8 | ||||
-rw-r--r-- | src/third_party/wiredtiger/import.data | 2 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/docs/command-line.dox | 5 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/docs/spell.ok | 2 | ||||
-rwxr-xr-x | src/third_party/wiredtiger/src/utilities/util_dump.c | 473 |
5 files changed, 459 insertions, 31 deletions
diff --git a/src/third_party/wiredtiger/dist/s_string.ok b/src/third_party/wiredtiger/dist/s_string.ok index bb96e2fe3b4..7381406c91d 100644 --- a/src/third_party/wiredtiger/dist/s_string.ok +++ b/src/third_party/wiredtiger/dist/s_string.ok @@ -465,6 +465,7 @@ basecfg bbb bbuilddir bcr +bd beginthreadex bigram binutils @@ -486,6 +487,7 @@ booleans boption br breakpoint +bs bstorage bswap btcur @@ -660,6 +662,7 @@ dup dv eee eg +ejnprx el emp encodings @@ -835,7 +838,6 @@ isrc isspace iter jjj -jnprx js json kB @@ -900,6 +902,7 @@ lsn lt lte lu +luc lwsync lz madvise @@ -1072,6 +1075,7 @@ rN rS rbrace rbracket +rc rdlock rdtsc rduppo @@ -1100,6 +1104,7 @@ retp revint rf risc +rl rle rmw rng @@ -1138,6 +1143,7 @@ skiplist skiplists skipp slvg +sn snaplen snapsort snprintf diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data index 41a5132c636..7d327e4f1a9 100644 --- a/src/third_party/wiredtiger/import.data +++ b/src/third_party/wiredtiger/import.data @@ -2,5 +2,5 @@ "vendor": "wiredtiger", "github": "wiredtiger/wiredtiger.git", "branch": "mongodb-master", - "commit": "83f2b1b94c08e5d7c5b97a0fd77880cbb8989b82" + "commit": "47a84526899070f48875f1c89a3091508f5d6bd2" } diff --git a/src/third_party/wiredtiger/src/docs/command-line.dox b/src/third_party/wiredtiger/src/docs/command-line.dox index 91c4f72df62..668516d28f0 100644 --- a/src/third_party/wiredtiger/src/docs/command-line.dox +++ b/src/third_party/wiredtiger/src/docs/command-line.dox @@ -184,7 +184,7 @@ which can be re-loaded into a new table using the \c load command. See @subpage dump_formats for details of the dump file formats. @subsection util_dump_synopsis Synopsis -`wt [-BLmRrSVv] [-C config] [-E secretkey ] [-h directory] dump [-jnprx] [-c checkpoint] [-f output] [-l lower bound] [-t timestamp] [-u upper bound] uri` +`wt [-BLmRrSVv] [-C config] [-E secretkey ] [-h directory] dump [-ejnprx] [-c checkpoint] [-f output] [-l lower bound] [-t timestamp] [-u upper bound] [-w window] uri` @subsection util_dump_options Options The following are command-specific options for the \c dump command: @@ -194,6 +194,9 @@ By default, the \c dump command opens the most recent version of the data source; the \c -c option changes the \c dump command to dump as of the named checkpoint. +@par \c -e +Start the explore mode to dump the file interactively. + @par \c -f By default, the \c dump command output is written to the standard output; the \c -f option re-directs the output to the specified file. diff --git a/src/third_party/wiredtiger/src/docs/spell.ok b/src/third_party/wiredtiger/src/docs/spell.ok index e1b8c3626bd..cb5b7f51163 100644 --- a/src/third_party/wiredtiger/src/docs/spell.ok +++ b/src/third_party/wiredtiger/src/docs/spell.ok @@ -305,6 +305,7 @@ dumpfile dup dups ebusy +ejnprx encrypt encryptor encryptor's @@ -410,7 +411,6 @@ je jemalloc jitter jni -jnprx jrx json jxf diff --git a/src/third_party/wiredtiger/src/utilities/util_dump.c b/src/third_party/wiredtiger/src/utilities/util_dump.c index 00fc228ceb6..e3665024618 100755 --- a/src/third_party/wiredtiger/src/utilities/util_dump.c +++ b/src/third_party/wiredtiger/src/utilities/util_dump.c @@ -9,11 +9,19 @@ #include "util.h" #include "util_dump.h" +#define ARG_BUF_SIZE 256 +#define MAX_ARGS 20 +#define MAX_BOOKMARKS 20 #define STRING_MATCH_CONFIG(s, item) \ (strncmp(s, (item).str, (item).len) == 0 && (s)[(item).len] == '\0') static int dump_all_records(WT_CURSOR *, bool, bool); static int dump_config(WT_SESSION *, const char *, WT_CURSOR *, bool, bool, bool); +static int dump_explore(WT_CURSOR *, const char *, bool, bool, bool, bool); +static void dump_explore_bookmark_delete_key(WT_CURSOR *, char **, const char *); +static int dump_explore_bookmark_save(WT_CURSOR *, char **); +static int dump_explore_bookmark_select(WT_CURSOR *, char **, uint64_t); +static void dump_explore_bookmarks_list(char **); static int dump_json_begin(WT_SESSION *); static int dump_json_end(WT_SESSION *); static int dump_json_separator(WT_SESSION *); @@ -37,7 +45,10 @@ static int usage(void) { static const char *options[] = {"-c checkpoint", - "dump as of the named checkpoint (the default is the most recent version of the data)", + "dump as of the named checkpoint (the default is the most recent version of the data)", "-e", + "explore a file in an interactive fashion, everything is redirected to stdout, hence " + "incompatible with " + "the -f option", "-f output", "dump to the specified file (the default is stdout)", "-j", "dump in JSON format", "-k", "specify a key too look for", "-l lower bound", "lower bound of the key range to dump", "-n", @@ -55,12 +66,31 @@ usage(void) "-?", "show this message", NULL, NULL}; util_usage( - "dump [-jnprx] [-c checkpoint] [-f output-file] [-k key] [-l lower bound] [-t timestamp] [-u " + "dump [-ejnprx] [-c checkpoint] [-f output-file] [-k key] [-l lower bound] [-t timestamp] " + "[-u " "upper bound] [-w window] uri", "options:", options); return (1); } +/* + * explore_usage -- + * Display a usage message for the explore functionality. + */ +static void +explore_usage(void) +{ + static const char *options[] = {"a", "show the current cursor's position", "b", + "list bookmarks", "b bookmark", "jump to bookmark", "bd bookmark", "delete bookmark", + "bs [key]", "save cursor's position to bookmarks or the given key", "c", "reset the cursor", + "d key", "delete the given key", "h", "show this message", "i key value", + "insert the key/value pair", "m", "dump the config", "n", "call cursor next", "p", + "call cursor prev", "q", "exit", "rl", "set the lower bound", "ru", "set the upper bound", + "s key", "search for a key", "sn key", "search for a key using search_near", "u key value", + "update the key/value pair", "w value", "set the windowing to the given value", NULL, NULL}; + util_usage(NULL, NULL, options); +} + static FILE *fp; /* @@ -79,7 +109,7 @@ util_dump(WT_SESSION *session, int argc, char *argv[]) int ch, format_specifiers, i; char *checkpoint, *ofile, *p, *simpleuri, *timestamp, *uri; const char *end_key, *key, *start_key; - bool hex, json, pretty, reverse, search_near; + bool explore, hex, json, pretty, reverse, search_near; session_impl = (WT_SESSION_IMPL *)session; window = 0; @@ -87,16 +117,19 @@ util_dump(WT_SESSION *session, int argc, char *argv[]) hs_dump_cursor = NULL; key = NULL; checkpoint = ofile = simpleuri = uri = timestamp = NULL; - hex = json = pretty = reverse = search_near = false; + explore = hex = json = pretty = reverse = search_near = false; end_key = NULL; key = NULL; start_key = NULL; - while ((ch = __wt_getopt(progname, argc, argv, "c:f:k:l:t:u:w:jnprx?")) != EOF) + while ((ch = __wt_getopt(progname, argc, argv, "c:f:k:l:t:u:w:ejnprx?")) != EOF) switch (ch) { case 'c': checkpoint = __wt_optarg; break; + case 'e': + explore = true; + break; case 'f': ofile = __wt_optarg; break; @@ -165,10 +198,14 @@ util_dump(WT_SESSION *session, int argc, char *argv[]) /* Open any optional output file. */ if (ofile == NULL) fp = stdout; - else if ((fp = fopen(ofile, "w")) == NULL) + else if (explore) { + fprintf(stderr, "%s: the options -e and -f are incompatible\n", progname); + return (usage()); + } else if ((fp = fopen(ofile, "w")) == NULL) return (util_err(session, errno, "%s: open", ofile)); - if (json && (dump_json_begin(session) != 0 || dump_prefix(session, pretty, hex, json) != 0)) + if (!explore && json && + (dump_json_begin(session) != 0 || dump_prefix(session, pretty, hex, json) != 0)) goto err; WT_RET(__wt_scr_alloc(session_impl, 0, &tmp)); @@ -221,27 +258,32 @@ util_dump(WT_SESSION *session, int argc, char *argv[]) F_SET(hs_dump_cursor->child, WT_CURSTD_IGNORE_TOMBSTONE); } - if (dump_config(session, simpleuri, cursor, pretty, hex, json) != 0) - goto err; + if (explore) { + if (dump_explore(cursor, simpleuri, reverse, pretty, hex, json) != 0) + goto err; + } else { + if (dump_config(session, simpleuri, cursor, pretty, hex, json) != 0) + goto err; - if (key == NULL) { - if (start_key != NULL) { - cursor->set_key(cursor, start_key); - if (cursor->bound(cursor, "action=set,bound=lower") != 0) + if (key == NULL) { + if (start_key != NULL) { + cursor->set_key(cursor, start_key); + if (cursor->bound(cursor, "action=set,bound=lower") != 0) + goto err; + } + if (end_key != NULL) { + cursor->set_key(cursor, end_key); + if (cursor->bound(cursor, "action=set,bound=upper") != 0) + goto err; + } + if (dump_all_records(cursor, reverse, json) != 0) goto err; - } - if (end_key != NULL) { - cursor->set_key(cursor, end_key); - if (cursor->bound(cursor, "action=set,bound=upper") != 0) + if ((start_key != NULL || end_key != NULL) && + cursor->bound(cursor, "action=clear") != 0) goto err; - } - if (dump_all_records(cursor, reverse, json) != 0) - goto err; - if ((start_key != NULL || end_key != NULL) && - cursor->bound(cursor, "action=clear") != 0) + } else if (dump_record(cursor, key, reverse, search_near, json, window) != 0) goto err; - } else if (dump_record(cursor, key, reverse, search_near, json, window) != 0) - goto err; + } if (json && dump_json_table_end(session) != 0) goto err; @@ -745,7 +787,7 @@ dump_record( return (WT_NOTFOUND); if (window == 0) - ret = print_record(cursor, json); + WT_RET(print_record(cursor, json)); else { fwd = (reverse) ? cursor->prev : cursor->next; bck = (reverse) ? cursor->next : cursor->prev; @@ -773,7 +815,7 @@ dump_record( if (fputc(',', fp) == EOF) return (util_err(session, EIO, NULL)); } - print_record(cursor, json); + WT_RET(print_record(cursor, json)); if ((ret = fwd(cursor)) != 0) { if (ret == WT_NOTFOUND) break; @@ -807,16 +849,393 @@ dump_all_records(WT_CURSOR *cursor, bool reverse, bool json) if (fputc(',', fp) == EOF) return (util_err(session, EIO, NULL)); } - print_record(cursor, json); + WT_RET(print_record(cursor, json)); once = true; } + if (ret != WT_NOTFOUND) + return (util_err(session, ret, reverse ? "WT_CURSOR.prev" : "WT_CURSOR.next")); + if (json && once && fprintf(fp, "\n") < 0) return (util_err(session, EIO, NULL)); return (0); } /* + * dump_explore_bookmark_delete_key -- + * Delete the bookmark associated with the key. + */ +static void +dump_explore_bookmark_delete_key(WT_CURSOR *cursor, char **bookmarks, const char *key) +{ + uint64_t i; + + for (i = 0; i < MAX_BOOKMARKS; ++i) { + if (bookmarks[i] != NULL && strcmp(bookmarks[i], key) == 0) { + __wt_free((WT_SESSION_IMPL *)cursor->session, bookmarks[i]); + printf("Bookmark %" PRIu64 " deleted.\n", i); + break; + } + } +} + +/* + * dump_explore_bookmark_save -- + * Save the cursor's position to bookmarks. + */ +static int +dump_explore_bookmark_save(WT_CURSOR *cursor, char **bookmarks) +{ + WT_DECL_RET; + WT_SESSION *session; + uint64_t i; + const char *key; + + session = cursor->session; + + ret = cursor->get_key(cursor, &key); + if (ret != 0 && ret != EINVAL) + return (util_cerr(cursor, "get_key", ret)); + if (ret == EINVAL) { + printf("Error: the cursor needs to be positioned to create a bookmark.\n"); + return (0); + } + + for (i = 0; i < MAX_BOOKMARKS; ++i) { + if (bookmarks[i] != NULL) + continue; + if ((bookmarks[i] = malloc(strlen(key))) == NULL) + return (util_err(session, errno, NULL)); + strcpy(bookmarks[i], key); + printf("Added bookmark %" PRIu64 ": %s.\n", i, key); + break; + } + if (i >= MAX_BOOKMARKS) + printf("Error: bookmark list full.\n"); + return (ret); +} + +/* + * dump_explore_bookmark_select -- + * Set the cursor to the bookmark. + */ +static int +dump_explore_bookmark_select(WT_CURSOR *cursor, char **bookmarks, uint64_t index) +{ + WT_DECL_RET; + const char *key; + + if (index >= MAX_BOOKMARKS) { + printf("Error: please indicate a value between 0 and %d\n", MAX_BOOKMARKS); + return (0); + } + + if ((key = bookmarks[index]) == NULL) { + printf("Error: no keys associated with bookmark %" PRIu64 ".\n", index); + return (0); + } + + /* Set the cursor to the bookmark. */ + cursor->set_key(cursor, key); + ret = cursor->search(cursor); + if (ret != 0 && ret != WT_NOTFOUND) + return (util_cerr(cursor, "search", ret)); + else if (ret == WT_NOTFOUND) { + printf("Error: %d\n", ret); + ret = 0; + } else + printf("Cursor positioned on key %s.\n", key); + return (ret); +} + +/* + * dump_explore_bookmarks_list -- + * List the existing bookmarks. + */ +static void +dump_explore_bookmarks_list(char **bookmarks) +{ + uint64_t i; + printf("List of bookmarks:\n"); + for (i = 0; i < MAX_BOOKMARKS; ++i) { + if (bookmarks[i] != NULL) + printf("#%" PRIu64 ": %s\n", i, bookmarks[i]); + } +} + +/* + * dump_explore -- + * Dump data in an interactive fashion. + */ +static int +dump_explore(WT_CURSOR *cursor, const char *uri, bool reverse, bool pretty, bool hex, bool json) +{ + WT_DECL_RET; + WT_SESSION *session; + WT_SESSION_IMPL *session_impl; + uint64_t bookmark_index, window; + int i, exact, num_args; + char *args[MAX_ARGS], *bookmarks[MAX_BOOKMARKS]; + char *first_arg, user_input[ARG_BUF_SIZE], *current_arg; + const char *key, *value; + bool once, search_near; + + session = cursor->session; + session_impl = (WT_SESSION_IMPL *)session; + once = search_near = false; + i = exact = num_args = 0; + bookmark_index = window = 0; + memset(args, 0, sizeof(args)); + memset(bookmarks, 0, sizeof(bookmarks)); + + printf("**************************\n"); + printf("Explore mode for %s.\n", uri); + printf("**************************\n"); + printf("Enter 'h' for help, 'q' to exit.\n\n"); + + while (ret == 0) { + i = num_args = 0; + if (fgets(user_input, MAX_ARGS, stdin) == NULL) { + if (!feof(stdin)) + continue; + goto err; + } + + /* Remove new line character. */ + user_input[strlen(user_input) - 1] = '\0'; + if (strlen(user_input) == 0 && !once) + continue; + once = true; + + /* Parse the input. */ + current_arg = strtok(user_input, " "); + if (current_arg == NULL) + continue; + while (current_arg != NULL) { + if ((args[i] = malloc(ARG_BUF_SIZE)) == NULL) + WT_ERR(util_err(session, errno, NULL)); + strcpy(args[i++], current_arg); + ++num_args; + current_arg = strtok(NULL, " "); + } + + first_arg = args[0]; + switch (first_arg[0]) { + /* Cursor info. */ + case 'a': + ret = cursor->get_key(cursor, &key); + if (ret == EINVAL) { + printf("Error: the cursor needs to be positioned.\n"); + ret = 0; + } else + /* Any other error is handled in print_record(). */ + print_record(cursor, json); + break; + /* Bookmarks. */ + case 'b': + if (strcmp(first_arg, "b") == 0) { + /* List existing bookmarks. */ + if (num_args < 2) + dump_explore_bookmarks_list(bookmarks); + /* Jump to the bookmark. */ + else if (util_str2num(session, args[1], true, &bookmark_index) == 0) + WT_ERR(dump_explore_bookmark_select(cursor, bookmarks, bookmark_index)); + } + /* Delete. */ + else if (strcmp(first_arg, "bd") == 0) { + if (num_args < 2) + printf("Error: please indicate the bookmark you want to delete.\n"); + else if (util_str2num(session, args[1], true, &bookmark_index) == 0) { + if (bookmark_index >= MAX_BOOKMARKS) + printf("Error: please indicate a value between 0 and %d\n", MAX_BOOKMARKS); + else { + __wt_free(session_impl, bookmarks[bookmark_index]); + printf("Bookmark %" PRIu64 " deleted.\n", bookmark_index); + } + } + } + /* Save. */ + else if (strcmp(first_arg, "bs") == 0) { + /* If a key is specified, save that key. */ + if (num_args >= 2) { + key = args[1]; + cursor->set_key(cursor, key); + ret = cursor->search(cursor); + if (ret != 0 && ret != WT_NOTFOUND) + WT_ERR(util_cerr(cursor, "search", ret)); + if (ret == WT_NOTFOUND) { + printf("Error: %d\n", ret); + ret = 0; + break; + } + } + WT_ERR(dump_explore_bookmark_save(cursor, bookmarks)); + } + break; + /* Cursor reset. */ + case 'c': + if ((ret = cursor->reset(cursor)) != 0) + WT_ERR(util_cerr(cursor, "reset", ret)); + printf("Cursor reset.\n"); + break; + /* Cursor delete. */ + case 'd': + if (num_args < 2) { + printf("Error: please indicate the key to delete.\n"); + break; + } + key = args[1]; + cursor->set_key(cursor, key); + ret = cursor->remove(cursor); + + if (ret != 0 && ret != WT_NOTFOUND) + WT_ERR(util_cerr(cursor, "remove", ret)); + if (ret == 0) { + printf("Removed key '%s'.\n", key); + dump_explore_bookmark_delete_key(cursor, bookmarks, key); + } else { + printf("Error: the key '%s' does not exist.\n", key); + ret = 0; + } + break; + /* Help. */ + case 'h': + explore_usage(); + break; + /* Cursor insert. */ + case 'i': + if (num_args < 3) { + printf("Error: please indicate the key/value pair to insert.\n"); + break; + } + key = args[1]; + value = args[2]; + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + if ((ret = cursor->insert(cursor)) != 0) + WT_ERR(util_cerr(cursor, "insert", ret)); + printf("Inserted key '%s' and value '%s'.\n", key, value); + break; + /* Dump metadata. */ + case 'm': + WT_ERR(dump_config(session, uri, cursor, pretty, hex, json)); + break; + /* Cursor next. */ + case 'n': + /* Cursor prev. */ + case 'p': + if (first_arg[0] == 'n') + ret = (reverse ? cursor->prev(cursor) : cursor->next(cursor)); + else + ret = (reverse ? cursor->next(cursor) : cursor->prev(cursor)); + if (ret != 0 && ret != WT_NOTFOUND) + WT_ERR(util_cerr(cursor, (reverse ? "prev" : "next"), ret)); + if (ret == WT_NOTFOUND) { + printf("Start/End of file reached.\n"); + ret = 0; + } else + WT_ERR(print_record(cursor, json)); + break; + /* Exit. */ + case 'q': + if (strcmp(first_arg, "q") == 0) + goto err; + break; + /* Range cursor. */ + case 'r': + if (strlen(first_arg) < 2 || strchr("luc", first_arg[1]) == NULL) { + printf( + "Error: use 'rl' for lower range, 'ru' for upper range and 'rc' to clear " + "range.\n"); + break; + } + + /* Clear range. */ + if (first_arg[1] == 'c') { + if (cursor->bound(cursor, "action=clear") != 0) + WT_ERR(util_cerr(cursor, "bound clear", ret)); + printf("Cursor bounds cleared.\n"); + break; + } + + if (num_args < 2) { + printf("Error: please indicate the value for the range.\n"); + break; + } + + key = args[1]; + cursor->set_key(cursor, key); + + if (first_arg[1] == 'l') + ret = cursor->bound(cursor, "action=set,bound=lower"); + else + ret = cursor->bound(cursor, "action=set,bound=upper"); + + if (ret != 0 && ret != EINVAL) + WT_ERR(util_cerr(cursor, "bound set", ret)); + if (ret == EINVAL) + ret = 0; + else + printf("%s bound set.\n", first_arg[1] == 'l' ? "Lower" : "Upper"); + break; + /* Search. */ + case 's': + if (num_args < 2) { + printf("Error: please indicate a key to look for.\n"); + break; + } + + key = args[1]; + cursor->set_key(cursor, key); + search_near = first_arg[1] == 'n'; + ret = dump_record(cursor, key, reverse, search_near, json, window); + + if (ret != 0) { + printf("Error: %d\n", ret); + if (ret == WT_NOTFOUND) + ret = 0; + else + WT_ERR(ret); + } + break; + /* Cursor update. */ + case 'u': + if (num_args < 3) { + printf("Error: please indicate the key/value pair to update.\n"); + break; + } + key = args[1]; + value = args[2]; + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + if ((ret = cursor->insert(cursor)) != 0) + WT_ERR(util_cerr(cursor, "update", ret)); + printf("Updated key '%s' to value '%s'.\n", key, value); + break; + /* Window. */ + case 'w': + if (num_args < 2) + printf("Error: please indicate the window value you want to set.\n"); + else if (util_str2num(session, args[1], true, &window) == 0) + printf("Window value: %" PRIu64 ".\n", window); + break; + default: + break; + } + + for (i = 0; i < MAX_ARGS; ++i) + __wt_free(session_impl, args[i]); + } + +err: + for (i = 0; i < MAX_BOOKMARKS; ++i) + __wt_free(session_impl, bookmarks[i]); + for (i = 0; i < MAX_ARGS; ++i) + __wt_free(session_impl, args[i]); + return (ret); +} + +/* * dump_suffix -- * Output the dump file header suffix. */ |