int util_load(WT_SESSION *session, int argc, char *argv[]) { int ch; const char *filename; uint32_t flags; flags = 0; filename = "<stdin>"; while ((ch = __wt_getopt(progname, argc, argv, "af:jnr:")) != EOF) switch (ch) { case 'a': /* append (ignore record number keys) */ append = 1; break; case 'f': /* input file */ if (freopen(__wt_optarg, "r", stdin) == NULL) return ( util_err(errno, "%s: reopen", __wt_optarg)); else filename = __wt_optarg; break; case 'j': /* input is JSON */ json = 1; break; case 'n': /* don't overwrite existing data */ no_overwrite = 1; break; case 'r': /* rename */ cmdname = __wt_optarg; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* -a and -o are mutually exclusive. */ if (append == 1 && no_overwrite == 1) return (util_err(EINVAL, "the -a (append) and -n (no-overwrite) flags are mutually " "exclusive")); /* The remaining arguments are configuration uri/string pairs. */ if (argc != 0) { if (argc % 2 != 0) return (usage()); cmdconfig = argv; } if (json) { if (append) flags |= LOAD_JSON_APPEND; if (no_overwrite) flags |= LOAD_JSON_NO_OVERWRITE; return (util_load_json(session, filename, flags)); } else return (load_dump(session)); }
int util_create(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; const char *config, *uri; config = NULL; while ((ch = __wt_getopt(progname, argc, argv, "c:")) != EOF) switch (ch) { case 'c': /* command-line configuration */ config = __wt_optarg; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining argument is the uri. */ if (argc != 1) return (usage()); if ((uri = util_name(*argv, "table")) == NULL) return (1); if ((ret = session->create(session, uri, config)) != 0) return (util_err(ret, "%s: session.create", uri)); return (0); }
int util_drop(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; char *name; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining argument is the uri. */ if (argc != 1) return (usage()); if ((name = util_name(session, *argv, "table")) == NULL) return (1); ret = session->drop(session, name, "force"); free(name); return (ret); }
int util_alter(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; char **configp; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining arguments are uri/string pairs. */ if (argc % 2 != 0) return (usage()); for (configp = argv; *configp != NULL; configp += 2) if ((ret = session->alter( session, configp[0], configp[1])) != 0) { (void)util_err(session, ret, "session.alter: %s, %s", configp[0], configp[1]); return (1); } return (0); }
int util_downgrade(WT_SESSION *session, WT_CONNECTION *conn, int argc, char *argv[]) { WT_DECL_RET; int ch; char config_str[128], *release; release = NULL; while ((ch = __wt_getopt(progname, argc, argv, "V:")) != EOF) switch (ch) { case 'V': release = __wt_optarg; break; case '?': default: return (usage()); } argc -= __wt_optind; /* * The release argument is required. * There should not be any more arguments. */ if (argc != 0 || release == NULL) return (usage()); if ((ret = __wt_snprintf(config_str, sizeof(config_str), "compatibility=(release=%s)", release)) != 0) return (util_err(session, ret, NULL)); if ((ret = conn->reconfigure(conn, config_str)) != 0) return (util_err(session, ret, "conn.downgrade")); return (0); }
int util_backup(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; int ch; char *config; const char *directory, *name; config = NULL; while ((ch = __wt_getopt(progname, argc, argv, "t:")) != EOF) switch (ch) { case 't': if (append_target(session, __wt_optarg, &config)) return (1); break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; if (argc != 1) { (void)usage(); goto err; } directory = *argv; if ((ret = session->open_cursor( session, "backup:", NULL, config, &cursor)) != 0) { fprintf(stderr, "%s: cursor open(backup:) failed: %s\n", progname, session->strerror(session, ret)); goto err; } /* Copy the files. */ while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_key(cursor, &name)) == 0) if ((ret = copy(name, directory)) != 0) goto err; if (ret == WT_NOTFOUND) ret = 0; if (ret != 0) { fprintf(stderr, "%s: cursor next(backup:) failed: %s\n", progname, session->strerror(session, ret)); goto err; } err: if (config != NULL) free(config); if (cbuf != NULL) free(cbuf); return (ret); }
int main(int argc, char *argv[]) { CONFIG *cp; size_t len, *lp; int ch, small; char *working_dir; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; small = 0; working_dir = NULL; while ((ch = __wt_getopt(progname, argc, argv, "h:s")) != EOF) switch (ch) { case 'h': working_dir = __wt_optarg; break; case 's': /* Gigabytes */ small = 1; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); testutil_work_dir_from_path(home, 512, working_dir); /* Allocate a buffer to use. */ len = small ? ((size_t)SMALL_MAX) : ((size_t)4 * GIGABYTE); if ((big = malloc(len)) == NULL) testutil_die(errno, ""); memset(big, 'a', len); /* Make sure the configurations all work. */ for (lp = lengths; *lp != 0; ++lp) { if (small && *lp > SMALL_MAX) break; for (cp = config; cp->uri != NULL; ++cp) { if (!cp->recno) /* Big key on row-store */ run(cp, 1, *lp); run(cp, 0, *lp); /* Big value */ } } free(big); testutil_clean_work_dir(home); return (EXIT_SUCCESS); }
int main(int argc, char *argv[]) { u_int ptype; int ch, r; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; r = 0; ptype = 0; while ((ch = __wt_getopt(progname, argc, argv, "r:t:v")) != EOF) switch (ch) { case 'r': r = atoi(__wt_optarg); if (r == 0) return (usage()); break; case 't': if (strcmp(__wt_optarg, "fix") == 0) ptype = WT_PAGE_COL_FIX; else if (strcmp(__wt_optarg, "var") == 0) ptype = WT_PAGE_COL_VAR; else if (strcmp(__wt_optarg, "row") == 0) ptype = WT_PAGE_ROW_LEAF; else return (usage()); break; case 'v': verbose = 1; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) return (usage()); printf("salvage test run started\n"); t(r, ptype, 1); t(r, ptype, 0); printf("salvage test run completed\n"); return (EXIT_SUCCESS); }
int main(int argc, char *argv[]) { int ch; if ((g.progname = strrchr(argv[0], DIR_DELIM)) == NULL) g.progname = argv[0]; else ++g.progname; /* Set default configuration values. */ g.c_cache = 10; g.c_ops = 100000; g.c_key_max = 100; g.c_k = 8; g.c_factor = 16; g.c_srand = 3233456; /* Set values from the command line. */ while ((ch = __wt_getopt(g.progname, argc, argv, "c:f:k:o:s:")) != EOF) switch (ch) { case 'c': /* Cache size */ g.c_cache = (u_int)atoi(__wt_optarg); break; case 'f': /* Factor */ g.c_factor = (u_int)atoi(__wt_optarg); break; case 'k': /* Number of hash functions */ g.c_k = (u_int)atoi(__wt_optarg); break; case 'o': /* Number of ops */ g.c_ops = (u_int)atoi(__wt_optarg); break; case 's': /* Number of ops */ g.c_srand = (u_int)atoi(__wt_optarg); break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; setup(); run(); cleanup(); return (EXIT_SUCCESS); }
int util_printlog(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; bool printable; printable = false; while ((ch = __wt_getopt(progname, argc, argv, "f:p")) != EOF) switch (ch) { case 'f': /* output file */ if (freopen(__wt_optarg, "w", stdout) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", progname, __wt_optarg, strerror(errno)); return (1); } break; case 'p': printable = true; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* There should not be any more arguments. */ if (argc != 0) return (usage()); WT_UNUSED(printable); ret = __wt_txn_printlog(session, stdout); if (ret != 0) { fprintf(stderr, "%s: printlog failed: %s\n", progname, session->strerror(session, ret)); goto err; } if (0) { err: ret = 1; } return (ret); }
int util_list(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int cflag, ch, vflag; char *name; cflag = vflag = 0; name = NULL; while ((ch = __wt_getopt(progname, argc, argv, "cv")) != EOF) switch (ch) { case 'c': cflag = 1; break; case 'v': vflag = 1; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; switch (argc) { case 0: break; case 1: if ((name = util_name(*argv, "table")) == NULL) return (1); break; default: return (usage()); } ret = list_print(session, name, cflag, vflag); if (name != NULL) free(name); return (ret); }
int util_salvage(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; const char *force; char *uri; force = NULL; uri = NULL; while ((ch = __wt_getopt(progname, argc, argv, "F")) != EOF) switch (ch) { case 'F': force = "force"; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining argument is the file name. */ if (argc != 1) return (usage()); if ((uri = util_uri(session, *argv, "file")) == NULL) return (1); if ((ret = session->salvage(session, uri, force)) != 0) (void)util_err(session, ret, "session.salvage: %s", uri); else { /* * Verbose configures a progress counter, move to the next * line. */ if (verbose) printf("\n"); } free(uri); return (ret); }
int util_rebalance(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; char *name; name = NULL; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining argument is the table name. */ if (argc != 1) return (usage()); if ((name = util_name(session, *argv, "table")) == NULL) return (1); if ((ret = session->rebalance(session, name, NULL)) != 0) { fprintf(stderr, "%s: rebalance(%s): %s\n", progname, name, session->strerror(session, ret)); goto err; } /* Verbose configures a progress counter, move to the next line. */ if (verbose) printf("\n"); if (0) { err: ret = 1; } free(name); return (ret); }
int util_rename(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; char *uri, *newuri; uri = NULL; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining arguments are the object uri and new name. */ if (argc != 2) return (usage()); if ((uri = util_name(*argv, "table")) == NULL) return (1); newuri = argv[1]; if ((ret = session->rename(session, uri, newuri, NULL)) != 0) { fprintf(stderr, "%s: rename %s to %s: %s\n", progname, uri, newuri, wiredtiger_strerror(ret)); goto err; } if (0) { err: ret = 1; } if (uri != NULL) free(uri); return (ret); }
int util_compact(WT_SESSION *session, int argc, char *argv[]) { WT_DECL_RET; int ch; char *uri; uri = NULL; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining argument is the table name. */ if (argc != 1) return (usage()); if ((uri = util_name(session, *argv, "table")) == NULL) return (1); if ((ret = session->compact(session, uri, NULL)) != 0) { fprintf(stderr, "%s: compact(%s): %s\n", progname, uri, session->strerror(session, ret)); goto err; } if (0) { err: ret = 1; } if (uri != NULL) free(uri); return (ret); }
int main(int argc, char *argv[]) { time_t start; int ch, onerun, reps; const char *config, *home; config = NULL; #ifdef _WIN32 g.progname = "t_format.exe"; #else if ((g.progname = strrchr(argv[0], DIR_DELIM)) == NULL) g.progname = argv[0]; else ++g.progname; #endif #if 0 /* Configure the GNU malloc for debugging. */ (void)setenv("MALLOC_CHECK_", "2", 1); #endif #if 0 /* Configure the FreeBSD malloc for debugging. */ (void)setenv("MALLOC_OPTIONS", "AJ", 1); #endif /* Track progress unless we're re-directing output to a file. */ g.c_quiet = isatty(1) ? 0 : 1; /* Set values from the command line. */ home = NULL; onerun = 0; while ((ch = __wt_getopt( g.progname, argc, argv, "1C:c:H:h:Llqrt:")) != EOF) switch (ch) { case '1': /* One run */ onerun = 1; break; case 'C': /* wiredtiger_open config */ g.config_open = __wt_optarg; break; case 'c': /* Configuration from a file */ config = __wt_optarg; break; case 'H': g.helium_mount = __wt_optarg; break; case 'h': home = __wt_optarg; break; case 'L': /* Re-direct output to a log */ /* * The -l option is a superset of -L, ignore -L if we * have already configured logging for operations. */ if (g.logging == 0) g.logging = LOG_FILE; break; case 'l': /* Turn on operation logging */ g.logging = LOG_OPS; break; case 'q': /* Quiet */ g.c_quiet = 1; break; case 'r': /* Replay a run */ g.replay = 1; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; /* Initialize the global RNG. */ testutil_check(__wt_random_init_seed(NULL, &g.rnd)); /* Set up paths. */ path_setup(home); /* If it's a replay, use the home directory's CONFIG file. */ if (g.replay) { if (config != NULL) testutil_die(EINVAL, "-c incompatible with -r"); if (access(g.home_config, R_OK) != 0) testutil_die(ENOENT, "%s", g.home_config); config = g.home_config; } /* * If we weren't given a configuration file, set values from "CONFIG", * if it exists. * * Small hack to ignore any CONFIG file named ".", that just makes it * possible to ignore any local CONFIG file, used when running checks. */ if (config == NULL && access("CONFIG", R_OK) == 0) config = "CONFIG"; if (config != NULL && strcmp(config, ".") != 0) config_file(config); /* * The rest of the arguments are individual configurations that modify * the base configuration. */ for (; *argv != NULL; ++argv) config_single(*argv, 1); /* * Multithreaded runs can be replayed: it's useful and we'll get the * configuration correct. Obviously the order of operations changes, * warn the user. */ if (g.replay && !SINGLETHREADED) printf("Warning: replaying a threaded run\n"); /* * Single-threaded runs historically exited after a single replay, which * makes sense when you're debugging, leave that semantic in place. */ if (g.replay && SINGLETHREADED) g.c_runs = 1; /* * Let the command line -1 flag override runs configured from other * sources. */ if (onerun) g.c_runs = 1; /* * Initialize locks to single-thread named checkpoints and backups, last * last-record updates, and failures. */ testutil_check(pthread_rwlock_init(&g.append_lock, NULL)); testutil_check(pthread_rwlock_init(&g.backup_lock, NULL)); testutil_check(pthread_rwlock_init(&g.checkpoint_lock, NULL)); testutil_check(pthread_rwlock_init(&g.death_lock, NULL)); printf("%s: process %" PRIdMAX "\n", g.progname, (intmax_t)getpid()); while (++g.run_cnt <= g.c_runs || g.c_runs == 0 ) { startup(); /* Start a run */ config_setup(); /* Run configuration */ config_print(0); /* Dump run configuration */ key_len_setup(); /* Setup keys */ start = time(NULL); track("starting up", 0ULL, NULL); #ifdef HAVE_BERKELEY_DB if (SINGLETHREADED) bdb_open(); /* Initial file config */ #endif wts_open(g.home, true, &g.wts_conn); wts_init(); wts_load(); /* Load initial records */ wts_verify("post-bulk verify"); /* Verify */ /* * If we're not doing any operations, scan the bulk-load, copy * the statistics and we're done. Otherwise, loop reading and * operations, with a verify after each set. */ if (g.c_timer == 0 && g.c_ops == 0) { wts_read_scan(); /* Read scan */ wts_stats(); /* Statistics */ } else for (reps = 1; reps <= FORMAT_OPERATION_REPS; ++reps) { wts_read_scan(); /* Read scan */ /* Operations */ wts_ops(reps == FORMAT_OPERATION_REPS); /* * Copy out the run's statistics after the last * set of operations. * * XXX * Verify closes the underlying handle and * discards the statistics, read them first. */ if (reps == FORMAT_OPERATION_REPS) wts_stats(); /* Verify */ wts_verify("post-ops verify"); } track("shutting down", 0ULL, NULL); #ifdef HAVE_BERKELEY_DB if (SINGLETHREADED) bdb_close(); #endif wts_close(); /* * Rebalance testing. */ wts_rebalance(); /* * If single-threaded, we can dump and compare the WiredTiger * and Berkeley DB data sets. */ if (SINGLETHREADED) wts_dump("standard", 1); /* * Salvage testing. */ wts_salvage(); /* Overwrite the progress line with a completion line. */ if (!g.c_quiet) printf("\r%78s\r", " "); printf("%4d: %s, %s (%.0f seconds)\n", g.run_cnt, g.c_data_source, g.c_file_type, difftime(time(NULL), start)); fflush(stdout); } /* Flush/close any logging information. */ fclose_and_clear(&g.logfp); fclose_and_clear(&g.randfp); config_print(0); testutil_check(pthread_rwlock_destroy(&g.append_lock)); testutil_check(pthread_rwlock_destroy(&g.backup_lock)); testutil_check(pthread_rwlock_destroy(&g.checkpoint_lock)); testutil_check(pthread_rwlock_destroy(&g.death_lock)); config_clear(); return (EXIT_SUCCESS); }
int util_dump(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; size_t len; int ch, i; bool hex, json, reverse; char *checkpoint, *config, *name; hex = json = reverse = false; checkpoint = config = name = NULL; while ((ch = __wt_getopt(progname, argc, argv, "c:f:jrx")) != EOF) switch (ch) { case 'c': checkpoint = __wt_optarg; break; case 'f': /* output file */ if (freopen(__wt_optarg, "w", stdout) == NULL) return (util_err( session, errno, "%s: reopen", __wt_optarg)); break; case 'j': json = true; break; case 'r': reverse = true; break; case 'x': hex = true; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* -j and -x are incompatible. */ if (hex && json) { fprintf(stderr, "%s: the -j and -x dump options are incompatible\n", progname); goto err; } /* The remaining argument is the uri. */ if (argc < 1 || (argc != 1 && !json)) return (usage()); if (json && ((ret = dump_json_begin(session)) != 0 || (ret = dump_prefix(session, hex, json)) != 0)) goto err; for (i = 0; i < argc; i++) { if (json && i > 0) if ((ret = dump_json_separator(session)) != 0) goto err; free(name); name = NULL; if ((name = util_name(session, argv[i], "table")) == NULL) goto err; if (dump_config(session, name, hex, json) != 0) goto err; len = checkpoint == NULL ? 0 : strlen("checkpoint=") + strlen(checkpoint) + 1; len += strlen(json ? "dump=json" : (hex ? "dump=hex" : "dump=print")); if ((config = malloc(len + 10)) == NULL) goto err; if (checkpoint == NULL) config[0] = '\0'; else { (void)strcpy(config, "checkpoint="); (void)strcat(config, checkpoint); (void)strcat(config, ","); } (void)strcat(config, json ? "dump=json" : (hex ? "dump=hex" : "dump=print")); if ((ret = session->open_cursor( session, name, NULL, config, &cursor)) != 0) { fprintf(stderr, "%s: cursor open(%s) failed: %s\n", progname, name, session->strerror(session, ret)); goto err; } if ((ret = dump_record(cursor, reverse, json)) != 0) goto err; if (json && (ret = dump_json_table_end(session)) != 0) goto err; } if (json && ((ret = dump_json_end(session)) != 0)) goto err; if (0) { err: ret = 1; } free(config); free(name); return (ret); }
int main(int argc, char *argv[]) { struct stat sb; FILE *fp; WT_CONNECTION *conn; WT_CURSOR *cur_coll, *cur_local, *cur_oplog, *cur_stable; WT_RAND_STATE rnd; WT_SESSION *session; pid_t pid; uint64_t absent_coll, absent_local, absent_oplog, count, key, last_key; uint64_t first_miss, middle_coll, middle_local, middle_oplog; uint64_t stable_fp, stable_val, val[MAX_TH+1]; uint32_t i, nth, timeout; int ch, status, ret; const char *working_dir; char buf[512], fname[64], kname[64], statname[1024]; bool fatal, rand_th, rand_time, verify_only; (void)testutil_set_progname(argv); compat = inmem = false; use_ts = true; nth = MIN_TH; rand_th = rand_time = true; timeout = MIN_TIME; verify_only = false; working_dir = "WT_TEST.timestamp-abort"; while ((ch = __wt_getopt(progname, argc, argv, "Ch:mT:t:vz")) != EOF) switch (ch) { case 'C': compat = true; break; case 'h': working_dir = __wt_optarg; break; case 'm': inmem = true; break; case 'T': rand_th = false; nth = (uint32_t)atoi(__wt_optarg); break; case 't': rand_time = false; timeout = (uint32_t)atoi(__wt_optarg); break; case 'v': verify_only = true; break; case 'z': use_ts = false; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); testutil_work_dir_from_path(home, sizeof(home), working_dir); /* * If the user wants to verify they need to tell us how many threads * there were so we can find the old record files. */ if (verify_only && rand_th) { fprintf(stderr, "Verify option requires specifying number of threads\n"); exit (EXIT_FAILURE); } if (!verify_only) { testutil_make_work_dir(home); __wt_random_init_seed(NULL, &rnd); if (rand_time) { timeout = __wt_random(&rnd) % MAX_TIME; if (timeout < MIN_TIME) timeout = MIN_TIME; } if (rand_th) { nth = __wt_random(&rnd) % MAX_TH; if (nth < MIN_TH) nth = MIN_TH; } printf("Parent: compatibility: %s, " "in-mem log sync: %s, timestamp in use: %s\n", compat ? "true" : "false", inmem ? "true" : "false", use_ts ? "true" : "false"); printf("Parent: Create %" PRIu32 " threads; sleep %" PRIu32 " seconds\n", nth, timeout); /* * Fork a child to insert as many items. We will then randomly * kill the child, run recovery and make sure all items we wrote * exist after recovery runs. */ testutil_checksys((pid = fork()) < 0); if (pid == 0) { /* child */ run_workload(nth); return (EXIT_SUCCESS); } /* parent */ /* * Sleep for the configured amount of time before killing * the child. Start the timeout from the time we notice that * the file has been created. That allows the test to run * correctly on really slow machines. Verify the process ID * still exists in case the child aborts for some reason we * don't stay in this loop forever. */ testutil_check(__wt_snprintf( statname, sizeof(statname), "%s/%s", home, ckpt_file)); while (stat(statname, &sb) != 0 && kill(pid, 0) == 0) sleep(1); sleep(timeout); /* * !!! It should be plenty long enough to make sure more than * one log file exists. If wanted, that check would be added * here. */ printf("Kill child\n"); testutil_checksys(kill(pid, SIGKILL) != 0); testutil_checksys(waitpid(pid, &status, 0) == -1); } /* * !!! If we wanted to take a copy of the directory before recovery, * this is the place to do it. */ if (chdir(home) != 0) testutil_die(errno, "parent chdir: %s", home); testutil_check(__wt_snprintf(buf, sizeof(buf), "rm -rf ../%s.SAVE && mkdir ../%s.SAVE && " "cp -p WiredTigerLog.* ../%s.SAVE", home, home, home)); (void)system(buf); printf("Open database, run recovery and verify content\n"); /* * Open the connection which forces recovery to be run. */ if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG_REC, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); /* * Open a cursor on all the tables. */ if ((ret = session->open_cursor(session, uri_collection, NULL, NULL, &cur_coll)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_collection); if ((ret = session->open_cursor(session, uri_local, NULL, NULL, &cur_local)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_local); if ((ret = session->open_cursor(session, uri_oplog, NULL, NULL, &cur_oplog)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri_oplog); if ((ret = session->open_cursor(session, stable_store, NULL, NULL, &cur_stable)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", stable_store); /* * Find the biggest stable timestamp value that was saved. */ stable_val = 0; memset(val, 0, sizeof(val)); while (cur_stable->next(cur_stable) == 0) { cur_stable->get_key(cur_stable, &key); cur_stable->get_value(cur_stable, &val[key]); if (val[key] > stable_val) stable_val = val[key]; if (use_ts) printf("Stable: key %" PRIu64 " value %" PRIu64 "\n", key, val[key]); } if (use_ts) printf("Got stable_val %" PRIu64 "\n", stable_val); count = 0; absent_coll = absent_local = absent_oplog = 0; fatal = false; for (i = 1; i <= nth; ++i) { first_miss = middle_coll = middle_local = middle_oplog = 0; testutil_check(__wt_snprintf( fname, sizeof(fname), RECORDS_FILE, i)); if ((fp = fopen(fname, "r")) == NULL) testutil_die(errno, "fopen: %s", fname); /* * For every key in the saved file, verify that the key exists * in the table after recovery. If we're doing in-memory * log buffering we never expect a record missing in the middle, * but records may be missing at the end. If we did * write-no-sync, we expect every key to have been recovered. */ for (last_key = UINT64_MAX;; ++count, last_key = key) { ret = fscanf(fp, "%" SCNu64 "%" SCNu64 "\n", &stable_fp, &key); if (ret != EOF && ret != 2) { /* * If we find a partial line, consider it * like an EOF. */ if (ret == 1 || ret == 0) break; testutil_die(errno, "fscanf"); } if (ret == EOF) break; /* * If we're unlucky, the last line may be a partially * written key at the end that can result in a false * negative error for a missing record. Detect it. */ if (last_key != UINT64_MAX && key != last_key + 1) { printf("%s: Ignore partial record %" PRIu64 " last valid key %" PRIu64 "\n", fname, key, last_key); break; } testutil_check(__wt_snprintf( kname, sizeof(kname), "%" PRIu64, key)); cur_coll->set_key(cur_coll, kname); cur_local->set_key(cur_local, kname); cur_oplog->set_key(cur_oplog, kname); /* * The collection table should always only have the * data as of the checkpoint. */ if ((ret = cur_coll->search(cur_coll)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); /* * If we don't find a record, the stable * timestamp written to our file better be * larger than the saved one. */ if (!inmem && stable_fp != 0 && stable_fp <= val[i]) { printf("%s: COLLECTION no record with " "key %" PRIu64 " record ts %" PRIu64 " <= stable ts %" PRIu64 "\n", fname, key, stable_fp, val[i]); absent_coll++; } if (middle_coll == 0) first_miss = key; middle_coll = key; } else if (middle_coll != 0) { /* * We should never find an existing key after * we have detected one missing. */ printf("%s: COLLECTION after absent records %" PRIu64 "-%" PRIu64 " key %" PRIu64 " exists\n", fname, first_miss, middle_coll, key); fatal = true; } /* * The local table should always have all data. */ if ((ret = cur_local->search(cur_local)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); if (!inmem) printf("%s: LOCAL no record with key %" PRIu64 "\n", fname, key); absent_local++; middle_local = key; } else if (middle_local != 0) { /* * We should never find an existing key after * we have detected one missing. */ printf("%s: LOCAL after absent record at %" PRIu64 " key %" PRIu64 " exists\n", fname, middle_local, key); fatal = true; } /* * The oplog table should always have all data. */ if ((ret = cur_oplog->search(cur_oplog)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); if (!inmem) printf("%s: OPLOG no record with key %" PRIu64 "\n", fname, key); absent_oplog++; middle_oplog = key; } else if (middle_oplog != 0) { /* * We should never find an existing key after * we have detected one missing. */ printf("%s: OPLOG after absent record at %" PRIu64 " key %" PRIu64 " exists\n", fname, middle_oplog, key); fatal = true; } } testutil_checksys(fclose(fp) != 0); } if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if (fatal) return (EXIT_FAILURE); if (!inmem && absent_coll) { printf("COLLECTION: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_coll, count); fatal = true; } if (!inmem && absent_local) { printf("LOCAL: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_local, count); fatal = true; } if (!inmem && absent_oplog) { printf("OPLOG: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_oplog, count); fatal = true; } if (fatal) return (EXIT_FAILURE); printf("%" PRIu64 " records verified\n", count); return (EXIT_SUCCESS); }
int main(int argc, char *argv[]) { table_type ttype; int ch, cnt, ret, runs; char *working_dir; const char *config_open; if ((g.progname = strrchr(argv[0], DIR_DELIM)) == NULL) g.progname = argv[0]; else ++g.progname; config_open = NULL; ret = 0; working_dir = NULL; ttype = MIX; g.checkpoint_name = "WiredTigerCheckpoint"; if ((g.home = malloc(512)) == NULL) testutil_die(ENOMEM, "Unable to allocate memory"); g.nkeys = 10000; g.nops = 100000; g.ntables = 3; g.nworkers = 1; runs = 1; while ((ch = __wt_getopt( g.progname, argc, argv, "c:C:h:k:l:n:r:t:T:W:")) != EOF) switch (ch) { case 'c': g.checkpoint_name = __wt_optarg; break; case 'C': /* wiredtiger_open config */ config_open = __wt_optarg; break; case 'h': /* wiredtiger_open config */ working_dir = __wt_optarg; break; case 'k': /* rows */ g.nkeys = (u_int)atoi(__wt_optarg); break; case 'l': /* log */ if ((g.logfp = fopen(__wt_optarg, "w")) == NULL) { fprintf(stderr, "%s: %s\n", __wt_optarg, strerror(errno)); return (EXIT_FAILURE); } break; case 'n': /* operations */ g.nops = (u_int)atoi(__wt_optarg); break; case 'r': /* runs */ runs = atoi(__wt_optarg); break; case 't': switch (__wt_optarg[0]) { case 'c': ttype = COL; break; case 'l': ttype = LSM; break; case 'm': ttype = MIX; break; case 'r': ttype = ROW; break; default: return (usage()); } break; case 'T': g.ntables = atoi(__wt_optarg); break; case 'W': g.nworkers = atoi(__wt_optarg); break; default: return (usage()); } argc -= __wt_optind; if (argc != 0) return (usage()); /* Clean up on signal. */ (void)signal(SIGINT, onint); testutil_work_dir_from_path(g.home, 512, working_dir); printf("%s: process %" PRIu64 "\n", g.progname, (uint64_t)getpid()); for (cnt = 1; (runs == 0 || cnt <= runs) && g.status == 0; ++cnt) { printf(" %d: %u workers, %u tables\n", cnt, g.nworkers, g.ntables); (void)cleanup(); /* Clean up previous runs */ /* Setup a fresh set of cookies in the global array. */ if ((g.cookies = calloc( (size_t)(g.ntables), sizeof(COOKIE))) == NULL) { (void)log_print_err("No memory", ENOMEM, 1); break; } g.running = 1; if ((ret = wt_connect(config_open)) != 0) { (void)log_print_err("Connection failed", ret, 1); break; } if ((ret = start_checkpoints()) != 0) { (void)log_print_err("Start checkpoints failed", ret, 1); break; } if ((ret = start_workers(ttype)) != 0) { (void)log_print_err("Start workers failed", ret, 1); break; } g.running = 0; if ((ret = end_checkpoints()) != 0) { (void)log_print_err("Start workers failed", ret, 1); break; } free(g.cookies); g.cookies = NULL; if ((ret = wt_shutdown()) != 0) { (void)log_print_err("Start workers failed", ret, 1); break; } } if (g.logfp != NULL) (void)fclose(g.logfp); /* Ensure that cleanup is done on error. */ (void)wt_shutdown(); free(g.cookies); return (g.status); }
int util_stat(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; size_t urilen; int ch; bool objname_free; const char *config, *pval, *desc; char *objname, *uri; objname_free = false; objname = uri = NULL; config = NULL; while ((ch = __wt_getopt(progname, argc, argv, "af")) != EOF) switch (ch) { case 'a': /* * Historically, the -a option meant include all of the * statistics; because we are opening the database with * statistics=(all), that is now the default, allow the * option for compatibility. */ config = NULL; break; case 'f': config = "statistics=(fast)"; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* * If there are no arguments, the statistics cursor operates on the * connection, otherwise, the optional remaining argument is a file * or LSM name. */ switch (argc) { case 0: objname = (char *)""; break; case 1: if ((objname = util_name(session, *argv, "table")) == NULL) return (1); objname_free = true; break; default: return (usage()); } urilen = strlen("statistics:") + strlen(objname) + 1; if ((uri = calloc(urilen, 1)) == NULL) { fprintf(stderr, "%s: %s\n", progname, strerror(errno)); goto err; } snprintf(uri, urilen, "statistics:%s", objname); if ((ret = session->open_cursor(session, uri, NULL, config, &cursor)) != 0) { fprintf(stderr, "%s: cursor open(%s) failed: %s\n", progname, uri, session->strerror(session, ret)); goto err; } /* List the statistics. */ while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pval, NULL)) == 0) if (printf("%s=%s\n", desc, pval) < 0) { ret = errno; break; } if (ret == WT_NOTFOUND) ret = 0; if (ret != 0) { fprintf(stderr, "%s: cursor get(%s) failed: %s\n", progname, objname, session->strerror(session, ret)); goto err; } if (0) { err: ret = 1; } if (objname_free) free(objname); free(uri); return (ret); }
int main(int argc, char *argv[]) { struct sigaction sa; struct stat sb; FILE *fp; REPORT c_rep[MAX_TH], l_rep[MAX_TH], o_rep[MAX_TH]; WT_CONNECTION *conn; WT_CURSOR *cur_coll, *cur_local, *cur_oplog; WT_RAND_STATE rnd; WT_SESSION *session; pid_t pid; uint64_t absent_coll, absent_local, absent_oplog, count, key, last_key; uint64_t stable_fp, stable_val; uint32_t i, nth, timeout; int ch, status, ret; const char *working_dir; char buf[512], fname[64], kname[64], statname[1024]; char ts_string[WT_TS_HEX_STRING_SIZE]; bool fatal, rand_th, rand_time, verify_only; (void)testutil_set_progname(argv); compat = inmem = false; use_ts = true; nth = MIN_TH; rand_th = rand_time = true; timeout = MIN_TIME; verify_only = false; working_dir = "WT_TEST.timestamp-abort"; while ((ch = __wt_getopt(progname, argc, argv, "Ch:LmT:t:vz")) != EOF) switch (ch) { case 'C': compat = true; break; case 'h': working_dir = __wt_optarg; break; case 'L': table_pfx = "lsm"; break; case 'm': inmem = true; break; case 'T': rand_th = false; nth = (uint32_t)atoi(__wt_optarg); if (nth > MAX_TH) { fprintf(stderr, "Number of threads is larger than the" " maximum %" PRId32 "\n", MAX_TH); return (EXIT_FAILURE); } break; case 't': rand_time = false; timeout = (uint32_t)atoi(__wt_optarg); break; case 'v': verify_only = true; break; case 'z': use_ts = false; break; default: usage(); } argc -= __wt_optind; if (argc != 0) usage(); testutil_work_dir_from_path(home, sizeof(home), working_dir); testutil_check(pthread_rwlock_init(&ts_lock, NULL)); /* * If the user wants to verify they need to tell us how many threads * there were so we can find the old record files. */ if (verify_only && rand_th) { fprintf(stderr, "Verify option requires specifying number of threads\n"); exit (EXIT_FAILURE); } if (!verify_only) { testutil_make_work_dir(home); __wt_random_init_seed(NULL, &rnd); if (rand_time) { timeout = __wt_random(&rnd) % MAX_TIME; if (timeout < MIN_TIME) timeout = MIN_TIME; } if (rand_th) { nth = __wt_random(&rnd) % MAX_TH; if (nth < MIN_TH) nth = MIN_TH; } printf("Parent: compatibility: %s, " "in-mem log sync: %s, timestamp in use: %s\n", compat ? "true" : "false", inmem ? "true" : "false", use_ts ? "true" : "false"); printf("Parent: Create %" PRIu32 " threads; sleep %" PRIu32 " seconds\n", nth, timeout); printf("CONFIG: %s%s%s%s -h %s -T %" PRIu32 " -t %" PRIu32 "\n", progname, compat ? " -C" : "", inmem ? " -m" : "", !use_ts ? " -z" : "", working_dir, nth, timeout); /* * Fork a child to insert as many items. We will then randomly * kill the child, run recovery and make sure all items we wrote * exist after recovery runs. */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; testutil_checksys(sigaction(SIGCHLD, &sa, NULL)); testutil_checksys((pid = fork()) < 0); if (pid == 0) { /* child */ run_workload(nth); return (EXIT_SUCCESS); } /* parent */ /* * Sleep for the configured amount of time before killing * the child. Start the timeout from the time we notice that * the file has been created. That allows the test to run * correctly on really slow machines. */ testutil_check(__wt_snprintf( statname, sizeof(statname), "%s/%s", home, ckpt_file)); while (stat(statname, &sb) != 0) testutil_sleep_wait(1, pid); sleep(timeout); sa.sa_handler = SIG_DFL; testutil_checksys(sigaction(SIGCHLD, &sa, NULL)); /* * !!! It should be plenty long enough to make sure more than * one log file exists. If wanted, that check would be added * here. */ printf("Kill child\n"); testutil_checksys(kill(pid, SIGKILL) != 0); testutil_checksys(waitpid(pid, &status, 0) == -1); } /* * !!! If we wanted to take a copy of the directory before recovery, * this is the place to do it. Don't do it all the time because * it can use a lot of disk space, which can cause test machine * issues. */ if (chdir(home) != 0) testutil_die(errno, "parent chdir: %s", home); /* * The tables can get very large, so while we'd ideally like to * copy the entire database, we only copy the log files for now. * Otherwise it can take far too long to run the test, particularly * in automated testing. */ testutil_check(__wt_snprintf(buf, sizeof(buf), "rm -rf ../%s.SAVE && mkdir ../%s.SAVE && " "cp -p * ../%s.SAVE", home, home, home)); if ((status = system(buf)) < 0) testutil_die(status, "system: %s", buf); printf("Open database, run recovery and verify content\n"); /* * Open the connection which forces recovery to be run. */ testutil_check(wiredtiger_open(NULL, NULL, ENV_CONFIG_REC, &conn)); testutil_check(conn->open_session(conn, NULL, NULL, &session)); /* * Open a cursor on all the tables. */ testutil_check(__wt_snprintf( buf, sizeof(buf), "%s:%s", table_pfx, uri_collection)); testutil_check(session->open_cursor(session, buf, NULL, NULL, &cur_coll)); testutil_check(__wt_snprintf( buf, sizeof(buf), "%s:%s", table_pfx, uri_local)); testutil_check(session->open_cursor(session, buf, NULL, NULL, &cur_local)); testutil_check(__wt_snprintf( buf, sizeof(buf), "%s:%s", table_pfx, uri_oplog)); testutil_check(session->open_cursor(session, buf, NULL, NULL, &cur_oplog)); /* * Find the biggest stable timestamp value that was saved. */ stable_val = 0; if (use_ts) { testutil_check( conn->query_timestamp(conn, ts_string, "get=recovery")); testutil_assert( sscanf(ts_string, "%" SCNx64, &stable_val) == 1); printf("Got stable_val %" PRIu64 "\n", stable_val); } count = 0; absent_coll = absent_local = absent_oplog = 0; fatal = false; for (i = 0; i < nth; ++i) { initialize_rep(&c_rep[i]); initialize_rep(&l_rep[i]); initialize_rep(&o_rep[i]); testutil_check(__wt_snprintf( fname, sizeof(fname), RECORDS_FILE, i)); if ((fp = fopen(fname, "r")) == NULL) testutil_die(errno, "fopen: %s", fname); /* * For every key in the saved file, verify that the key exists * in the table after recovery. If we're doing in-memory * log buffering we never expect a record missing in the middle, * but records may be missing at the end. If we did * write-no-sync, we expect every key to have been recovered. */ for (last_key = INVALID_KEY;; ++count, last_key = key) { ret = fscanf(fp, "%" SCNu64 "%" SCNu64 "\n", &stable_fp, &key); if (last_key == INVALID_KEY) { c_rep[i].first_key = key; l_rep[i].first_key = key; o_rep[i].first_key = key; } if (ret != EOF && ret != 2) { /* * If we find a partial line, consider it * like an EOF. */ if (ret == 1 || ret == 0) break; testutil_die(errno, "fscanf"); } if (ret == EOF) break; /* * If we're unlucky, the last line may be a partially * written key at the end that can result in a false * negative error for a missing record. Detect it. */ if (last_key != INVALID_KEY && key != last_key + 1) { printf("%s: Ignore partial record %" PRIu64 " last valid key %" PRIu64 "\n", fname, key, last_key); break; } testutil_check(__wt_snprintf( kname, sizeof(kname), "%" PRIu64, key)); cur_coll->set_key(cur_coll, kname); cur_local->set_key(cur_local, kname); cur_oplog->set_key(cur_oplog, kname); /* * The collection table should always only have the * data as of the checkpoint. */ if ((ret = cur_coll->search(cur_coll)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); /* * If we don't find a record, the stable * timestamp written to our file better be * larger than the saved one. */ if (!inmem && stable_fp != 0 && stable_fp <= stable_val) { printf("%s: COLLECTION no record with " "key %" PRIu64 " record ts %" PRIu64 " <= stable ts %" PRIu64 "\n", fname, key, stable_fp, stable_val); absent_coll++; } if (c_rep[i].first_miss == INVALID_KEY) c_rep[i].first_miss = key; c_rep[i].absent_key = key; } else if (c_rep[i].absent_key != INVALID_KEY && c_rep[i].exist_key == INVALID_KEY) { /* * If we get here we found a record that exists * after absent records, a hole in our data. */ c_rep[i].exist_key = key; fatal = true; } else if (!inmem && stable_fp != 0 && stable_fp > stable_val) { /* * If we found a record, the stable timestamp * written to our file better be no larger * than the checkpoint one. */ printf("%s: COLLECTION record with " "key %" PRIu64 " record ts %" PRIu64 " > stable ts %" PRIu64 "\n", fname, key, stable_fp, stable_val); fatal = true; } /* * The local table should always have all data. */ if ((ret = cur_local->search(cur_local)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); if (!inmem) printf("%s: LOCAL no record with key %" PRIu64 "\n", fname, key); absent_local++; if (l_rep[i].first_miss == INVALID_KEY) l_rep[i].first_miss = key; l_rep[i].absent_key = key; } else if (l_rep[i].absent_key != INVALID_KEY && l_rep[i].exist_key == INVALID_KEY) { /* * We should never find an existing key after * we have detected one missing. */ l_rep[i].exist_key = key; fatal = true; } /* * The oplog table should always have all data. */ if ((ret = cur_oplog->search(cur_oplog)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); if (!inmem) printf("%s: OPLOG no record with key %" PRIu64 "\n", fname, key); absent_oplog++; if (o_rep[i].first_miss == INVALID_KEY) o_rep[i].first_miss = key; o_rep[i].absent_key = key; } else if (o_rep[i].absent_key != INVALID_KEY && o_rep[i].exist_key == INVALID_KEY) { /* * We should never find an existing key after * we have detected one missing. */ o_rep[i].exist_key = key; fatal = true; } } c_rep[i].last_key = last_key; l_rep[i].last_key = last_key; o_rep[i].last_key = last_key; testutil_checksys(fclose(fp) != 0); print_missing(&c_rep[i], fname, "COLLECTION"); print_missing(&l_rep[i], fname, "LOCAL"); print_missing(&o_rep[i], fname, "OPLOG"); } testutil_check(conn->close(conn, NULL)); if (!inmem && absent_coll) { printf("COLLECTION: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_coll, count); fatal = true; } if (!inmem && absent_local) { printf("LOCAL: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_local, count); fatal = true; } if (!inmem && absent_oplog) { printf("OPLOG: %" PRIu64 " record(s) absent from %" PRIu64 "\n", absent_oplog, count); fatal = true; } testutil_check(pthread_rwlock_destroy(&ts_lock)); if (fatal) return (EXIT_FAILURE); printf("%" PRIu64 " records verified\n", count); return (EXIT_SUCCESS); }
int main(int argc, char *argv[]) { FILE *fp; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; WT_RAND_STATE rnd; uint64_t key; uint32_t absent, count, timeout; int ch, status, ret; pid_t pid; char *working_dir; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; working_dir = NULL; timeout = 10; while ((ch = __wt_getopt(progname, argc, argv, "h:t:")) != EOF) switch (ch) { case 'h': working_dir = __wt_optarg; break; case 't': timeout = (uint32_t)atoi(__wt_optarg); break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); testutil_work_dir_from_path(home, 512, working_dir); testutil_make_work_dir(home); /* * Fork a child to insert as many items. We will then randomly * kill the child, run recovery and make sure all items we wrote * exist after recovery runs. */ if ((pid = fork()) < 0) testutil_die(errno, "fork"); if (pid == 0) { /* child */ fill_db(); return (EXIT_SUCCESS); } /* parent */ __wt_random_init(&rnd); /* Sleep for the configured amount of time before killing the child. */ printf("Parent: sleep %" PRIu32 " seconds, then kill child\n", timeout); sleep(timeout); /* * !!! It should be plenty long enough to make sure more than one * log file exists. If wanted, that check would be added here. */ printf("Kill child\n"); if (kill(pid, SIGKILL) != 0) testutil_die(errno, "kill"); waitpid(pid, &status, 0); /* * !!! If we wanted to take a copy of the directory before recovery, * this is the place to do it. */ chdir(home); printf("Open database, run recovery and verify content\n"); if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG_REC, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri); if ((fp = fopen(RECORDS_FILE, "r")) == NULL) testutil_die(errno, "fopen"); /* * For every key in the saved file, verify that the key exists * in the table after recovery. Since we did write-no-sync, we * expect every key to have been recovered. */ for (absent = count = 0;; ++count) { ret = fscanf(fp, "%" SCNu64 "\n", &key); if (ret != EOF && ret != 1) testutil_die(errno, "fscanf"); if (ret == EOF) break; cursor->set_key(cursor, key); if ((ret = cursor->search(cursor)) != 0) { if (ret != WT_NOTFOUND) testutil_die(ret, "search"); printf("no record with key %" PRIu64 "\n", key); ++absent; } } fclose(fp); if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if (absent) { printf("%u record(s) absent from %u\n", absent, count); return (EXIT_FAILURE); } printf("%u records verified\n", count); return (EXIT_SUCCESS); }
int util_write(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; uint64_t recno; int append, ch, overwrite, rkey; const char *uri; char config[100]; append = overwrite = 0; while ((ch = __wt_getopt(progname, argc, argv, "ao")) != EOF) switch (ch) { case 'a': append = 1; break; case 'o': overwrite = 1; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* * The remaining arguments are a uri followed by a list of values (if * append is set), or key/value pairs (if append is not set). */ if (append) { if (argc < 2) return (usage()); } else if (argc < 3 || ((argc - 1) % 2 != 0)) return (usage()); if ((uri = util_name(session, *argv, "table")) == NULL) return (1); /* Open the object. */ (void)snprintf(config, sizeof(config), "%s,%s", append ? "append=true" : "", overwrite ? "overwrite=true" : ""); if ((ret = session->open_cursor( session, uri, NULL, config, &cursor)) != 0) return (util_err(session, ret, "%s: session.open", uri)); /* * A simple search only makes sense if the key format is a string or a * record number, and the value format is a single string. */ if (strcmp(cursor->key_format, "r") != 0 && strcmp(cursor->key_format, "S") != 0) { fprintf(stderr, "%s: write command only possible when the key format is " "a record number or string\n", progname); return (1); } rkey = strcmp(cursor->key_format, "r") == 0 ? 1 : 0; if (strcmp(cursor->value_format, "S") != 0) { fprintf(stderr, "%s: write command only possible when the value format is " "a string\n", progname); return (1); } /* Run through the values or key/value pairs. */ while (*++argv != NULL) { if (!append) { if (rkey) { if (util_str2recno(session, *argv, &recno)) return (1); cursor->set_key(cursor, recno); } else cursor->set_key(cursor, *argv); ++argv; } cursor->set_value(cursor, *argv); if ((ret = cursor->insert(cursor)) != 0) return (util_cerr(cursor, "search", ret)); } return (0); }
int main(int argc, char *argv[]) { FILE *fp; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; uint64_t new_offset, offset; uint32_t count, max_key; int ch, status, ret; pid_t pid; const char *working_dir; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; working_dir = "WT_TEST.truncated-log"; while ((ch = __wt_getopt(progname, argc, argv, "h:")) != EOF) switch (ch) { case 'h': working_dir = __wt_optarg; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); testutil_work_dir_from_path(home, 512, working_dir); testutil_make_work_dir(home); /* * Fork a child to insert as many items. We will then randomly * kill the child, run recovery and make sure all items we wrote * exist after recovery runs. */ if ((pid = fork()) < 0) testutil_die(errno, "fork"); if (pid == 0) { /* child */ fill_db(); return (EXIT_SUCCESS); } /* parent */ /* Wait for child to kill itself. */ if (waitpid(pid, &status, 0) == -1) testutil_die(errno, "waitpid"); /* * !!! If we wanted to take a copy of the directory before recovery, * this is the place to do it. */ if (chdir(home) != 0) testutil_die(errno, "chdir: %s", home); printf("Open database, run recovery and verify content\n"); if ((fp = fopen(RECORDS_FILE, "r")) == NULL) testutil_die(errno, "fopen"); ret = fscanf(fp, "%" SCNu64 " %" SCNu32 "\n", &offset, &max_key); if (ret != 2) testutil_die(errno, "fscanf"); if (fclose(fp) != 0) testutil_die(errno, "fclose"); /* * The offset is the beginning of the last record. Truncate to * the middle of that last record (i.e. ahead of that offset). */ if (offset > UINT64_MAX - V_SIZE) testutil_die(ERANGE, "offset"); new_offset = offset + V_SIZE; printf("Parent: Truncate to %" PRIu64 "\n", new_offset); if ((ret = truncate(LOG_FILE_1, (wt_off_t)new_offset)) != 0) testutil_die(errno, "truncate"); if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG_REC, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri); /* * For every key in the saved file, verify that the key exists * in the table after recovery. Since we did write-no-sync, we * expect every key to have been recovered. */ count = 0; while ((ret = cursor->next(cursor)) == 0) ++count; if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if (count > max_key) { printf("expected %" PRIu32 " records found %" PRIu32 "\n", max_key, count); return (EXIT_FAILURE); } printf("%" PRIu32 " records verified\n", count); return (EXIT_SUCCESS); }
int main(int argc, char *argv[]) { u_int readers, writers; int ch, cnt, runs; char *config_open, *working_dir; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; config_open = NULL; working_dir = NULL; ftype = ROW; log_print = 0; multiple_files = 0; nkeys = 1000; max_nops = 10000; readers = 10; runs = 1; session_per_op = 0; vary_nops = 0; writers = 10; while ((ch = __wt_getopt( progname, argc, argv, "C:Fk:h:Ll:n:R:r:St:vW:")) != EOF) switch (ch) { case 'C': /* wiredtiger_open config */ config_open = __wt_optarg; break; case 'F': /* multiple files */ multiple_files = 1; break; case 'h': working_dir = __wt_optarg; break; case 'k': /* rows */ nkeys = (u_int)atoi(__wt_optarg); break; case 'L': /* log print per operation */ log_print = 1; break; case 'l': /* log */ if ((logfp = fopen(__wt_optarg, "w")) == NULL) { fprintf(stderr, "%s: %s\n", __wt_optarg, strerror(errno)); return (EXIT_FAILURE); } break; case 'n': /* operations */ max_nops = (u_int)atoi(__wt_optarg); break; case 'R': readers = (u_int)atoi(__wt_optarg); break; case 'r': /* runs */ runs = atoi(__wt_optarg); break; case 'S': /* new session per operation */ session_per_op = 1; break; case 't': switch (__wt_optarg[0]) { case 'f': ftype = FIX; break; case 'r': ftype = ROW; break; case 'v': ftype = VAR; break; default: return (usage()); } break; case 'v': /* vary operation count */ vary_nops = 1; break; case 'W': writers = (u_int)atoi(__wt_optarg); break; default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) return (usage()); testutil_work_dir_from_path(home, 512, working_dir); if (vary_nops && !multiple_files) { fprintf(stderr, "Variable op counts only supported with multiple tables\n"); return (usage()); } /* Clean up on signal. */ (void)signal(SIGINT, onint); printf("%s: process %" PRIu64 "\n", progname, (uint64_t)getpid()); for (cnt = 1; runs == 0 || cnt <= runs; ++cnt) { printf( " %d: %u readers, %u writers\n", cnt, readers, writers); shutdown(); /* Clean up previous runs */ wt_connect(config_open); /* WiredTiger connection */ if (rw_start(readers, writers)) /* Loop operations */ return (EXIT_FAILURE); stats(); /* Statistics */ wt_shutdown(); /* WiredTiger shut down */ } return (0); }
int util_read(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; uint64_t recno; int ch; bool rkey, rval; char *uri, *value; uri = NULL; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining arguments are a uri followed by a list of keys. */ if (argc < 2) return (usage()); if ((uri = util_uri(session, *argv, "table")) == NULL) return (1); /* * Open the object; free allocated memory immediately to simplify * future error handling. */ if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) (void)util_err(session, ret, "%s: session.open_cursor", uri); free(uri); if (ret != 0) return (ret); /* * A simple search only makes sense if the key format is a string or a * record number, and the value format is a single string. */ if (strcmp(cursor->key_format, "r") != 0 && strcmp(cursor->key_format, "S") != 0) { fprintf(stderr, "%s: read command only possible when the key format is " "a record number or string\n", progname); return (1); } rkey = strcmp(cursor->key_format, "r") == 0; if (strcmp(cursor->value_format, "S") != 0) { fprintf(stderr, "%s: read command only possible when the value format is " "a string\n", progname); return (1); } /* * Run through the keys, returning non-zero on error or if any requested * key isn't found. */ for (rval = false; *++argv != NULL;) { if (rkey) { if (util_str2recno(session, *argv, &recno)) return (1); cursor->set_key(cursor, recno); } else cursor->set_key(cursor, *argv); switch (ret = cursor->search(cursor)) { case 0: if ((ret = cursor->get_value(cursor, &value)) != 0) return (util_cerr(cursor, "get_value", ret)); if (printf("%s\n", value) < 0) return (util_err(session, EIO, NULL)); break; case WT_NOTFOUND: (void)util_err(session, 0, "%s: not found", *argv); rval = true; break; default: return (util_cerr(cursor, "search", ret)); } } return (rval ? 1 : 0); }
int main(int argc, char *argv[]) { SHARED_CONFIG _cfg, *cfg; int ch, cnt, runs; char *config_open, *working_dir; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; cfg = &_cfg; config_open = NULL; working_dir = NULL; runs = 1; /* * Explicitly initialize the shared configuration object before * parsing command line options. */ cfg->append_inserters = 1; cfg->conn = NULL; cfg->ftype = ROW; cfg->max_nops = 1000000; cfg->multiple_files = false; cfg->nkeys = 1000; cfg->reverse_scanners = 5; cfg->reverse_scan_ops = 10; cfg->thread_finish = false; cfg->vary_nops = false; while ((ch = __wt_getopt( progname, argc, argv, "C:Fk:h:l:n:R:r:t:vw:W:")) != EOF) switch (ch) { case 'C': /* wiredtiger_open config */ config_open = __wt_optarg; break; case 'F': /* multiple files */ cfg->multiple_files = true; break; case 'h': working_dir = __wt_optarg; break; case 'k': /* rows */ cfg->nkeys = (uint64_t)atol(__wt_optarg); break; case 'l': /* log */ if ((logfp = fopen(__wt_optarg, "w")) == NULL) { fprintf(stderr, "%s: %s\n", __wt_optarg, strerror(errno)); return (EXIT_FAILURE); } break; case 'n': /* operations */ cfg->max_nops = (uint64_t)atol(__wt_optarg); break; case 'R': cfg->reverse_scanners = (uint64_t)atol(__wt_optarg); break; case 'r': /* runs */ runs = atoi(__wt_optarg); break; case 't': switch (__wt_optarg[0]) { case 'f': cfg->ftype = FIX; break; case 'r': cfg->ftype = ROW; break; case 'v': cfg->ftype = VAR; break; default: return (usage()); } break; case 'v': /* vary operation count */ cfg->vary_nops = true; break; case 'w': cfg->reverse_scan_ops = (uint64_t)atol(__wt_optarg); break; case 'W': cfg->append_inserters = (uint64_t)atol(__wt_optarg); break; default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) return (usage()); testutil_work_dir_from_path(home, 512, working_dir); if (cfg->vary_nops && !cfg->multiple_files) { fprintf(stderr, "Variable op counts only supported with multiple tables\n"); return (usage()); } /* Clean up on signal. */ (void)signal(SIGINT, onint); printf("%s: process %" PRIu64 "\n", progname, (uint64_t)getpid()); for (cnt = 1; runs == 0 || cnt <= runs; ++cnt) { printf( " %d: %" PRIu64 " reverse scanners, %" PRIu64 " writers\n", cnt, cfg->reverse_scanners, cfg->append_inserters); shutdown(); /* Clean up previous runs */ wt_connect(cfg, config_open); /* WiredTiger connection */ if (ops_start(cfg)) return (EXIT_FAILURE); wt_shutdown(cfg); /* WiredTiger shut down */ } return (0); }
int main(int argc, char *argv[]) { WT_CONNECTION *conn; WT_DECL_RET; WT_SESSION *session; size_t len; int ch, major_v, minor_v, tret, (*func)(WT_SESSION *, int, char *[]); const char *cmd_config, *config, *p1, *p2, *p3, *rec_config; char *p, *secretkey; bool logoff, recover, salvage; conn = NULL; p = NULL; /* Get the program name. */ if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else ++progname; command = ""; /* Check the version against the library build. */ (void)wiredtiger_version(&major_v, & minor_v, NULL); if (major_v != WIREDTIGER_VERSION_MAJOR || minor_v != WIREDTIGER_VERSION_MINOR) { fprintf(stderr, "%s: program build version %d.%d does not match " "library build version %d.%d\n", progname, WIREDTIGER_VERSION_MAJOR, WIREDTIGER_VERSION_MINOR, major_v, minor_v); return (EXIT_FAILURE); } cmd_config = config = secretkey = NULL; /* * We default to returning an error if recovery needs to be run. * Generally we expect this to be run after a clean shutdown. * The printlog command disables logging entirely. If recovery is * needed, the user can specify -R to run recovery. */ rec_config = REC_ERROR; logoff = recover = salvage = false; /* Check for standard options. */ while ((ch = __wt_getopt(progname, argc, argv, "C:E:h:LRSVv")) != EOF) switch (ch) { case 'C': /* wiredtiger_open config */ cmd_config = __wt_optarg; break; case 'E': /* secret key */ free(secretkey); /* lint: set more than once */ if ((secretkey = strdup(__wt_optarg)) == NULL) { (void)util_err(NULL, errno, NULL); goto err; } memset(__wt_optarg, 0, strlen(__wt_optarg)); break; case 'h': /* home directory */ home = __wt_optarg; break; case 'L': /* no logging */ rec_config = REC_LOGOFF; logoff = true; break; case 'R': /* recovery */ rec_config = REC_RECOVER; recover = true; break; case 'S': /* salvage */ rec_config = REC_SALVAGE; salvage = true; break; case 'V': /* version */ printf("%s\n", wiredtiger_version(NULL, NULL, NULL)); goto done; case 'v': /* verbose */ verbose = true; break; case '?': default: usage(); goto err; } if ((logoff && recover) || (logoff && salvage) || (recover && salvage)) { fprintf(stderr, "Only one of -L, -R, and -S is allowed.\n"); goto err; } argc -= __wt_optind; argv += __wt_optind; /* The next argument is the command name. */ if (argc < 1) { usage(); goto err; } command = argv[0]; /* Reset getopt. */ __wt_optreset = __wt_optind = 1; func = NULL; switch (command[0]) { case 'a': if (strcmp(command, "alter") == 0) func = util_alter; break; case 'b': if (strcmp(command, "backup") == 0) func = util_backup; break; case 'c': if (strcmp(command, "compact") == 0) func = util_compact; else if (strcmp(command, "copyright") == 0) { util_copyright(); goto done; } else if (strcmp(command, "create") == 0) { func = util_create; config = "create"; } break; case 'd': if (strcmp(command, "downgrade") == 0) func = util_downgrade; else if (strcmp(command, "drop") == 0) func = util_drop; else if (strcmp(command, "dump") == 0) func = util_dump; break; case 'l': if (strcmp(command, "list") == 0) func = util_list; else if (strcmp(command, "load") == 0) { func = util_load; config = "create"; } else if (strcmp(command, "loadtext") == 0) { func = util_loadtext; config = "create"; } break; case 'p': if (strcmp(command, "printlog") == 0) { func = util_printlog; rec_config = REC_LOGOFF; } break; case 'r': if (strcmp(command, "read") == 0) func = util_read; else if (strcmp(command, "rebalance") == 0) func = util_rebalance; else if (strcmp(command, "rename") == 0) func = util_rename; break; case 's': if (strcmp(command, "salvage") == 0) func = util_salvage; else if (strcmp(command, "stat") == 0) { func = util_stat; config = "statistics=(all)"; } break; case 't' : if (strcmp(command, "truncate") == 0) func = util_truncate; break; case 'u': if (strcmp(command, "upgrade") == 0) func = util_upgrade; break; case 'v': if (strcmp(command, "verify") == 0) func = util_verify; break; case 'w': if (strcmp(command, "write") == 0) func = util_write; break; default: break; } if (func == NULL) { usage(); goto err; } /* Build the configuration string. */ len = 10; /* some slop */ p1 = p2 = p3 = ""; len += strlen("error_prefix=wt"); if (config != NULL) len += strlen(config); if (cmd_config != NULL) len += strlen(cmd_config); if (secretkey != NULL) { len += strlen(secretkey) + 30; p1 = ",encryption=(secretkey="; p2 = secretkey; p3 = ")"; } len += strlen(rec_config); if ((p = malloc(len)) == NULL) { (void)util_err(NULL, errno, NULL); goto err; } if ((ret = __wt_snprintf(p, len, "error_prefix=wt,%s,%s,%s%s%s%s", config == NULL ? "" : config, cmd_config == NULL ? "" : cmd_config, rec_config, p1, p2, p3)) != 0) { (void)util_err(NULL, ret, NULL); goto err; } config = p; /* Open the database and a session. */ if ((ret = wiredtiger_open(home, verbose ? verbose_handler : NULL, config, &conn)) != 0) { (void)util_err(NULL, ret, NULL); goto err; } if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { (void)util_err(NULL, ret, NULL); goto err; } /* Call the function. */ ret = func(session, argc, argv); if (0) { err: ret = 1; } done: /* Close the database. */ if (conn != NULL && (tret = conn->close(conn, NULL)) != 0 && ret == 0) ret = tret; free(p); free(secretkey); return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
/* * testutil_parse_opts -- * Parse command line options for a test case. */ int testutil_parse_opts(int argc, char * const *argv, TEST_OPTS *opts) { int ch; size_t len; opts->preserve = false; opts->running = true; opts->verbose = false; if ((opts->progname = strrchr(argv[0], '/')) == NULL) opts->progname = argv[0]; else ++opts->progname; while ((ch = __wt_getopt(opts->progname, argc, argv, "A:h:n:o:pR:T:t:vW:")) != EOF) switch (ch) { case 'A': /* Number of append threads */ opts->n_append_threads = (uint64_t)atoll(__wt_optarg); break; case 'h': /* Home directory */ opts->home = __wt_optarg; break; case 'n': /* Number of records */ opts->nrecords = (uint64_t)atoll(__wt_optarg); break; case 'o': /* Number of operations */ opts->nops = (uint64_t)atoll(__wt_optarg); break; case 'p': /* Preserve directory contents */ opts->preserve = true; break; case 'R': /* Number of reader threads */ opts->n_read_threads = (uint64_t)atoll(__wt_optarg); break; case 'T': /* Number of threads */ opts->nthreads = (uint64_t)atoll(__wt_optarg); break; case 't': /* Table type */ switch (__wt_optarg[0]) { case 'C': case 'c': opts->table_type = TABLE_COL; break; case 'F': case 'f': opts->table_type = TABLE_FIX; break; case 'R': case 'r': opts->table_type = TABLE_ROW; break; } break; case 'v': opts->verbose = true; break; case 'W': /* Number of writer threads */ opts->n_write_threads = (uint64_t)atoll(__wt_optarg); break; case '?': default: (void)fprintf(stderr, "usage: %s " "[-A append thread count] " "[-h home] " "[-n record count] " "[-o op count] " "[-p] " "[-R read thread count] " "[-T thread count] " "[-t c|f|r table type] " "[-v] " "[-W write thread count] ", opts->progname); return (1); } /* * Setup the home directory. It needs to be unique for every test * or the auto make parallel tester gets upset. */ len = strlen("WT_TEST.") + strlen(opts->progname) + 10; opts->home = dmalloc(len); snprintf(opts->home, len, "WT_TEST.%s", opts->progname); /* Setup the default URI string */ len = strlen("table:") + strlen(opts->progname) + 10; opts->uri = dmalloc(len); snprintf(opts->uri, len, "table:%s", opts->progname); return (0); }
int main(int argc, char *argv[]) { WT_CONNECTION *conn, *conn2, *conn3, *conn4; WT_CURSOR *cursor; WT_ITEM data; WT_SESSION *session; uint64_t i; int ch, status, op, ret; bool child; const char *working_dir; char cmd[512]; uint8_t buf[MAX_VAL]; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; /* * Needed unaltered for system command later. */ saved_argv0 = argv[0]; working_dir = "WT_RD"; child = false; op = OP_READ; while ((ch = __wt_getopt(progname, argc, argv, "Rh:W")) != EOF) switch (ch) { case 'R': child = true; op = OP_READ; break; case 'W': child = true; op = OP_WRITE; break; case 'h': working_dir = __wt_optarg; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); /* * Set up all the directory names. */ testutil_work_dir_from_path(home, sizeof(home), working_dir); (void)snprintf(home_wr, sizeof(home_wr), "%s%s", home, HOME_WR_SUFFIX); (void)snprintf(home_rd, sizeof(home_rd), "%s%s", home, HOME_RD_SUFFIX); (void)snprintf( home_rd2, sizeof(home_rd2), "%s%s", home, HOME_RD2_SUFFIX); if (!child) { testutil_make_work_dir(home); testutil_make_work_dir(home_wr); testutil_make_work_dir(home_rd); testutil_make_work_dir(home_rd2); } else /* * We are a child process, we just want to call * the open_dbs with the directories we have. * The child function will exit. */ open_dbs(op, home, home_wr, home_rd, home_rd2); /* * Parent creates a database and table. Then cleanly shuts down. * Then copy database to read-only directory and chmod. * Also copy database to read-only directory and remove the lock * file. One read-only database will have a lock file in the * file system and the other will not. * Parent opens all databases with read-only configuration flag. * Parent forks off child who tries to also open all databases * with the read-only flag. It should error on the writeable * directory, but allow it on the read-only directories. * The child then confirms it can read all the data. */ /* * Run in the home directory and create the table. */ if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); if ((ret = session->create(session, uri, "key_format=Q,value_format=u")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri); if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri); /* * Write data into the table and then cleanly shut down connection. */ memset(buf, 0, sizeof(buf)); data.data = buf; data.size = MAX_VAL; for (i = 0; i < MAX_KV; ++i) { cursor->set_key(cursor, i); cursor->set_value(cursor, &data); if ((ret = cursor->insert(cursor)) != 0) testutil_die(ret, "WT_CURSOR.insert"); } if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); /* * Copy the database. Remove any lock file from one copy * and chmod the copies to be read-only permissions. */ (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; rm -f %s/WiredTiger.lock", home, home_wr, home_wr); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; chmod 0555 %s; chmod -R 0444 %s/*", home, home_rd, home_rd, home_rd); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; rm -f %s/WiredTiger.lock; " "chmod 0555 %s; chmod -R 0444 %s/*", home, home_rd2, home_rd2, home_rd2, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); /* * Run four scenarios. Sometimes expect errors, sometimes success. * The writable database directories should always fail to allow the * child to open due to the lock file. The read-only ones will only * succeed when the child attempts read-only. * * 1. Parent has read-only handle to all databases. Child opens * read-only also. * 2. Parent has read-only handle to all databases. Child opens * read-write. * 3. Parent has read-write handle to writable databases and * read-only to read-only databases. Child opens read-only. * 4. Parent has read-write handle to writable databases and * read-only to read-only databases. Child opens read-write. */ /* * Open a connection handle to all databases. */ fprintf(stderr, " *** Expect several error messages from WT ***\n"); /* * Scenario 1. */ if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG_RD, &conn)) != 0) testutil_die(ret, "wiredtiger_open original home"); if ((ret = wiredtiger_open(home_wr, NULL, ENV_CONFIG_RD, &conn2)) != 0) testutil_die(ret, "wiredtiger_open write nolock"); if ((ret = wiredtiger_open(home_rd, NULL, ENV_CONFIG_RD, &conn3)) != 0) testutil_die(ret, "wiredtiger_open readonly"); if ((ret = wiredtiger_open(home_rd2, NULL, ENV_CONFIG_RD, &conn4)) != 0) testutil_die(ret, "wiredtiger_open readonly nolock"); /* * Create a child to also open a connection handle to the databases. * We cannot use fork here because using fork the child inherits the * same memory image. Therefore the WT process structure is set in * the child even though it should not be. So use 'system' to spawn * an entirely new process. * * The child will exit with success if its test passes. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -R", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Scenario 2. Run child with writable config. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -W", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Reopen the two writable directories and rerun the child. */ if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn2->close(conn2, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG_RD, &conn)) != 0) testutil_die(ret, "wiredtiger_open original home"); if ((ret = wiredtiger_open(home_wr, NULL, ENV_CONFIG_RD, &conn2)) != 0) testutil_die(ret, "wiredtiger_open write nolock"); /* * Scenario 3. Child read-only. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -R", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Scenario 4. Run child with writable config. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -W", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Clean-up. */ if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn2->close(conn2, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn3->close(conn3, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn4->close(conn4, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); /* * We need to chmod the read-only databases back so that they can * be removed by scripts. */ (void)snprintf(cmd, sizeof(cmd), "chmod 0777 %s %s", home_rd, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "chmod -R 0666 %s/* %s/*", home_rd, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); printf(" *** Readonly test successful ***\n"); return (EXIT_SUCCESS); }