summaryrefslogtreecommitdiff
path: root/test/recovery/random-abort.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/recovery/random-abort.c')
-rw-r--r--test/recovery/random-abort.c82
1 files changed, 66 insertions, 16 deletions
diff --git a/test/recovery/random-abort.c b/test/recovery/random-abort.c
index 03e67e2f723..21460646017 100644
--- a/test/recovery/random-abort.c
+++ b/test/recovery/random-abort.c
@@ -34,6 +34,7 @@
static char home[512]; /* Program working dir */
static const char *progname; /* Program name */
static const char * const uri = "table:main";
+bool inmem;
#define MAX_TH 12
#define MIN_TH 5
@@ -41,7 +42,9 @@ static const char * const uri = "table:main";
#define MIN_TIME 10
#define RECORDS_FILE "records-%" PRIu32
-#define ENV_CONFIG \
+#define ENV_CONFIG_DEF \
+ "create,log=(file_max=10M,archive=false,enabled)"
+#define ENV_CONFIG_TXNSYNC \
"create,log=(file_max=10M,archive=false,enabled)," \
"transaction_sync=(enabled,method=none)"
#define ENV_CONFIG_REC "log=(recover=on)"
@@ -73,11 +76,15 @@ thread_run(void *arg)
WT_THREAD_DATA *td;
uint64_t i;
int ret;
- char buf[MAX_VAL], kname[64];
+ size_t lsize;
+ char buf[MAX_VAL], kname[64], lgbuf[8];
+ char large[128*1024];
__wt_random_init(&rnd);
memset(buf, 0, sizeof(buf));
memset(kname, 0, sizeof(kname));
+ lsize = sizeof(large);
+ memset(large, 0, lsize);
td = (WT_THREAD_DATA *)arg;
/*
@@ -85,6 +92,13 @@ thread_run(void *arg)
*/
snprintf(buf, sizeof(buf), RECORDS_FILE, td->id);
/*
+ * Set up a large value putting our id in it. Write it in there a
+ * bunch of times, but the rest of the buffer can just be zero.
+ */
+ snprintf(lgbuf, sizeof(lgbuf), "th-%" PRIu32, td->id);
+ for (i = 0; i < 128; i += strlen(lgbuf))
+ snprintf(&large[i], lsize - i, "%s", lgbuf);
+ /*
* Keep a separate file with the records we wrote for checking.
*/
(void)unlink(buf);
@@ -107,8 +121,18 @@ thread_run(void *arg)
*/
for (i = td->start; ; ++i) {
snprintf(kname, sizeof(kname), "%" PRIu64, i);
- data.size = __wt_random(&rnd) % MAX_VAL;
cursor->set_key(cursor, kname);
+ /*
+ * Every 30th record write a very large record that exceeds the
+ * log buffer size. This forces us to use the unbuffered path.
+ */
+ if (i % 30 == 0) {
+ data.size = 128 * 1024;
+ data.data = large;
+ } else {
+ data.size = __wt_random(&rnd) % MAX_VAL;
+ data.data = buf;
+ }
cursor->set_value(cursor, &data);
if ((ret = cursor->insert(cursor)) != 0)
testutil_die(ret, "WT_CURSOR.insert");
@@ -136,12 +160,17 @@ fill_db(uint32_t nth)
WT_THREAD_DATA *td;
uint32_t i;
int ret;
+ const char *envconf;
thr = dcalloc(nth, sizeof(pthread_t));
td = dcalloc(nth, sizeof(WT_THREAD_DATA));
if (chdir(home) != 0)
testutil_die(errno, "Child chdir: %s", home);
- if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG, &conn)) != 0)
+ if (inmem)
+ envconf = ENV_CONFIG_DEF;
+ else
+ envconf = ENV_CONFIG_TXNSYNC;
+ if ((ret = wiredtiger_open(NULL, NULL, envconf, &conn)) != 0)
testutil_die(ret, "wiredtiger_open");
if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
testutil_die(ret, "WT_CONNECTION:open_session");
@@ -187,11 +216,11 @@ main(int argc, char *argv[])
WT_CURSOR *cursor;
WT_SESSION *session;
WT_RAND_STATE rnd;
- uint64_t key, last_key;
- uint32_t absent, count, i, nth, timeout;
+ uint64_t absent, count, key, last_key, middle;
+ uint32_t i, nth, timeout;
int ch, status, ret;
pid_t pid;
- bool rand_th, rand_time, verify_only;
+ bool fatal, rand_th, rand_time, verify_only;
const char *working_dir;
char fname[64], kname[64];
@@ -200,17 +229,21 @@ main(int argc, char *argv[])
else
++progname;
+ inmem = false;
nth = MIN_TH;
rand_th = rand_time = true;
timeout = MIN_TIME;
verify_only = false;
working_dir = "WT_TEST.random-abort";
- while ((ch = __wt_getopt(progname, argc, argv, "h:T:t:v")) != EOF)
+ while ((ch = __wt_getopt(progname, argc, argv, "h:mT:t:v")) != EOF)
switch (ch) {
case 'h':
working_dir = __wt_optarg;
break;
+ case 'm':
+ inmem = true;
+ break;
case 'T':
rand_th = false;
nth = (uint32_t)atoi(__wt_optarg);
@@ -303,7 +336,9 @@ main(int argc, char *argv[])
testutil_die(ret, "WT_SESSION.open_cursor: %s", uri);
absent = count = 0;
+ fatal = false;
for (i = 0; i < nth; ++i) {
+ middle = 0;
snprintf(fname, sizeof(fname), RECORDS_FILE, i);
if ((fp = fopen(fname, "r")) == NULL) {
fprintf(stderr,
@@ -313,8 +348,10 @@ main(int argc, char *argv[])
/*
* 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.
+ * 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 "\n", &key);
@@ -338,9 +375,20 @@ main(int argc, char *argv[])
if ((ret = cursor->search(cursor)) != 0) {
if (ret != WT_NOTFOUND)
testutil_die(ret, "search");
- printf("%s: no record with key %" PRIu64 "\n",
- fname, key);
- ++absent;
+ if (!inmem)
+ printf("%s: no record with key %"
+ PRIu64 "\n", fname, key);
+ absent++;
+ middle = key;
+ } else if (middle != 0) {
+ /*
+ * We should never find an existing key after
+ * we have detected one missing.
+ */
+ printf("%s: after absent record at %" PRIu64
+ " key %" PRIu64 " exists\n",
+ fname, middle, key);
+ fatal = true;
}
}
if (fclose(fp) != 0)
@@ -348,11 +396,13 @@ main(int argc, char *argv[])
}
if ((ret = conn->close(conn, NULL)) != 0)
testutil_die(ret, "WT_CONNECTION:close");
- if (absent) {
- printf("%" PRIu32 " record(s) absent from %" PRIu32 "\n",
+ if (fatal)
+ return (EXIT_FAILURE);
+ if (!inmem && absent) {
+ printf("%" PRIu64 " record(s) absent from %" PRIu64 "\n",
absent, count);
return (EXIT_FAILURE);
}
- printf("%" PRIu32 " records verified\n", count);
+ printf("%" PRIu64 " records verified\n", count);
return (EXIT_SUCCESS);
}