summaryrefslogtreecommitdiff
path: root/test/format
diff options
context:
space:
mode:
Diffstat (limited to 'test/format')
-rw-r--r--test/format/backup.c4
-rw-r--r--test/format/config.c188
-rw-r--r--test/format/config.h20
-rw-r--r--test/format/format.h3
-rw-r--r--test/format/ops.c388
-rw-r--r--test/format/rebalance.c16
-rw-r--r--test/format/salvage.c25
-rw-r--r--test/format/t.c15
-rw-r--r--test/format/util.c51
-rw-r--r--test/format/wts.c145
10 files changed, 532 insertions, 323 deletions
diff --git a/test/format/backup.c b/test/format/backup.c
index 69fdf771de9..8aa614fa970 100644
--- a/test/format/backup.c
+++ b/test/format/backup.c
@@ -63,7 +63,7 @@ copy_file(WT_SESSION *session, const char *name)
len = strlen("BACKUP") + strlen(name) + 10;
first = dmalloc(len);
- (void)snprintf(first, len, "BACKUP/%s", name);
+ testutil_check(__wt_snprintf(first, len, "BACKUP/%s", name));
testutil_check(__wt_copy_and_sync(session, name, first));
/*
@@ -72,7 +72,7 @@ copy_file(WT_SESSION *session, const char *name)
*/
len = strlen("BACKUP_COPY") + strlen(name) + 10;
second = dmalloc(len);
- (void)snprintf(second, len, "BACKUP_COPY/%s", name);
+ testutil_check(__wt_snprintf(second, len, "BACKUP_COPY/%s", name));
testutil_check(__wt_copy_and_sync(session, first, second));
free(first);
diff --git a/test/format/config.c b/test/format/config.c
index cf922b5db04..22b40f7164d 100644
--- a/test/format/config.c
+++ b/test/format/config.c
@@ -44,6 +44,7 @@ static void config_map_compression(const char *, u_int *);
static void config_map_encryption(const char *, u_int *);
static void config_map_file_type(const char *, u_int *);
static void config_map_isolation(const char *, u_int *);
+static void config_pct(void);
static void config_reset(void);
/*
@@ -62,39 +63,42 @@ config_setup(void)
config_in_memory();
/*
- * Choose a data source type and a file type: they're interrelated (LSM
- * trees are only compatible with row-store) and other items depend on
- * them.
+ * Choose a file format and a data source: they're interrelated (LSM is
+ * only compatible with row-store) and other items depend on them.
*/
+ if (!config_is_perm("file_type")) {
+ if (config_is_perm("data_source") && DATASOURCE("lsm"))
+ config_single("file_type=row", 0);
+ else
+ switch (mmrand(NULL, 1, 10)) {
+ case 1: /* 10% */
+ config_single("file_type=fix", 0);
+ break;
+ case 2: case 3: case 4: /* 30% */
+ config_single("file_type=var", 0);
+ break; /* 60% */
+ case 5: case 6: case 7: case 8: case 9: case 10:
+ config_single("file_type=row", 0);
+ break;
+ }
+ }
+ config_map_file_type(g.c_file_type, &g.type);
+
if (!config_is_perm("data_source"))
switch (mmrand(NULL, 1, 3)) {
case 1:
config_single("data_source=file", 0);
break;
case 2:
- if (!g.c_in_memory) {
- config_single("data_source=lsm", 0);
- break;
- }
- /* FALLTHROUGH */
- case 3:
config_single("data_source=table", 0);
break;
- }
-
- if (!config_is_perm("file_type"))
- switch (DATASOURCE("lsm") ? 5 : mmrand(NULL, 1, 10)) {
- case 1:
- config_single("file_type=fix", 0);
- break;
- case 2: case 3: case 4:
- config_single("file_type=var", 0);
- break;
- case 5: case 6: case 7: case 8: case 9: case 10:
- config_single("file_type=row", 0);
+ case 3:
+ if (g.c_in_memory || g.type != ROW)
+ config_single("data_source=table", 0);
+ else
+ config_single("data_source=lsm", 0);
break;
}
- config_map_file_type(g.c_file_type, &g.type);
/*
* If data_source and file_type were both "permanent", we may still
@@ -103,7 +107,7 @@ config_setup(void)
if (DATASOURCE("lsm") && g.type != ROW) {
fprintf(stderr,
"%s: lsm data_source is only compatible with row file_type\n",
- g.progname);
+ progname);
exit(EXIT_FAILURE);
}
@@ -159,31 +163,19 @@ config_setup(void)
config_encryption();
config_isolation();
config_lrt();
+ config_pct();
/*
- * Periodically, set the delete percentage to 0 so salvage gets run,
- * as long as the delete percentage isn't nailed down.
- * Don't do it on the first run, all our smoke tests would hit it.
- */
- if (!g.replay && g.run_cnt % 10 == 9 && !config_is_perm("delete_pct"))
- config_single("delete_pct=0", 0);
-
- /*
- * If this is an LSM run, set the cache size and crank up the insert
- * percentage.
+ * If this is an LSM run, ensure cache size sanity.
+ * Ensure there is at least 1MB of cache per thread.
*/
- if (DATASOURCE("lsm")) {
- if (!config_is_perm("cache"))
+ if (!config_is_perm("cache")) {
+ if (DATASOURCE("lsm"))
g.c_cache = 30 * g.c_chunk_size;
-
- if (!config_is_perm("insert_pct"))
- g.c_insert_pct = mmrand(NULL, 50, 85);
+ if (g.c_cache < g.c_threads)
+ g.c_cache = g.c_threads;
}
- /* Ensure there is at least 1MB of cache per thread. */
- if (!config_is_perm("cache") && g.c_cache < g.c_threads)
- g.c_cache = g.c_threads;
-
/* Give in-memory configuration a final review. */
config_in_memory_check();
@@ -265,8 +257,8 @@ config_compression(const char *conf_name)
*/
cstr = "none";
if (strcmp(conf_name, "logging_compression") == 0 && g.c_logging == 0) {
- (void)snprintf(
- confbuf, sizeof(confbuf), "%s=%s", conf_name, cstr);
+ testutil_check(__wt_snprintf(
+ confbuf, sizeof(confbuf), "%s=%s", conf_name, cstr));
config_single(confbuf, 0);
return;
}
@@ -310,7 +302,8 @@ config_compression(const char *conf_name)
break;
}
- (void)snprintf(confbuf, sizeof(confbuf), "%s=%s", conf_name, cstr);
+ testutil_check(__wt_snprintf(
+ confbuf, sizeof(confbuf), "%s=%s", conf_name, cstr));
config_single(confbuf, 0);
}
@@ -473,7 +466,7 @@ config_lrt(void)
* stores.
*/
if (g.type == FIX) {
- if (config_is_perm("long_running_txn"))
+ if (config_is_perm("long_running_txn") && g.c_long_running_txn)
testutil_die(EINVAL,
"long_running_txn not supported with fixed-length "
"column store");
@@ -482,6 +475,83 @@ config_lrt(void)
}
/*
+ * config_pct --
+ * Configure operation percentages.
+ */
+static void
+config_pct(void)
+{
+ static struct {
+ const char *name; /* Operation */
+ uint32_t *vp; /* Value store */
+ u_int order; /* Order of assignment */
+ } list[] = {
+#define CONFIG_DELETE_ENTRY 0
+ { "delete_pct", &g.c_delete_pct, 0 },
+ { "insert_pct", &g.c_insert_pct, 0 },
+ { "read_pct", &g.c_read_pct, 0 },
+ { "write_pct", &g.c_write_pct, 0 },
+ };
+ u_int i, max_order, max_slot, n, pct;
+
+ /*
+ * Walk the list of operations, checking for an illegal configuration
+ * and creating a random order in the list.
+ */
+ pct = 0;
+ for (i = 0; i < WT_ELEMENTS(list); ++i)
+ if (config_is_perm(list[i].name))
+ pct += *list[i].vp;
+ else
+ list[i].order = mmrand(NULL, 1, 1000);
+ if (pct > 100)
+ testutil_die(EINVAL,
+ "operation percentages total to more than 100%%");
+
+ /*
+ * If the delete percentage isn't nailed down, periodically set it to
+ * 0 so salvage gets run. Don't do it on the first run, all our smoke
+ * tests would hit it.
+ */
+ if (!config_is_perm("delete_pct") && !g.replay && g.run_cnt % 10 == 9) {
+ list[CONFIG_DELETE_ENTRY].order = 0;
+ *list[CONFIG_DELETE_ENTRY].vp = 0;
+ }
+
+ /*
+ * Walk the list, allocating random numbers of operations in a random
+ * order.
+ *
+ * If the "order" field is non-zero, we need to create a value for this
+ * operation. Find the largest order field in the array; if one non-zero
+ * order field is found, it's the last entry and gets the remainder of
+ * the operations.
+ */
+ for (pct = 100 - pct;;) {
+ for (i = n =
+ max_order = max_slot = 0; i < WT_ELEMENTS(list); ++i) {
+ if (list[i].order != 0)
+ ++n;
+ if (list[i].order > max_order) {
+ max_order = list[i].order;
+ max_slot = i;
+ }
+ }
+ if (n == 0)
+ break;
+ if (n == 1) {
+ *list[max_slot].vp = pct;
+ break;
+ }
+ *list[max_slot].vp = mmrand(NULL, 0, pct);
+ list[max_slot].order = 0;
+ pct -= *list[max_slot].vp;
+ }
+ testutil_assert(g.c_delete_pct +
+ g.c_insert_pct + g.c_read_pct + g.c_write_pct == 100);
+}
+
+/*
* config_error --
* Display configuration information on error.
*/
@@ -609,13 +679,14 @@ void
config_single(const char *s, int perm)
{
CONFIG *cp;
- long v;
+ long vlong;
+ uint32_t v;
char *p;
const char *ep;
if ((ep = strchr(s, '=')) == NULL) {
fprintf(stderr,
- "%s: %s: illegal configuration value\n", g.progname, s);
+ "%s: %s: illegal configuration value\n", progname, s);
exit(EXIT_FAILURE);
}
@@ -674,34 +745,35 @@ config_single(const char *s, int perm)
return;
}
- v = -1;
+ vlong = -1;
if (F_ISSET(cp, C_BOOL)) {
if (strncmp(ep, "off", strlen("off")) == 0)
- v = 0;
+ vlong = 0;
else if (strncmp(ep, "on", strlen("on")) == 0)
- v = 1;
+ vlong = 1;
}
- if (v == -1) {
- v = strtol(ep, &p, 10);
+ if (vlong == -1) {
+ vlong = strtol(ep, &p, 10);
if (*p != '\0') {
fprintf(stderr, "%s: %s: illegal numeric value\n",
- g.progname, s);
+ progname, s);
exit(EXIT_FAILURE);
}
}
+ v = (uint32_t)vlong;
if (F_ISSET(cp, C_BOOL)) {
if (v != 0 && v != 1) {
fprintf(stderr, "%s: %s: value of boolean not 0 or 1\n",
- g.progname, s);
+ progname, s);
exit(EXIT_FAILURE);
}
} else if (v < cp->min || v > cp->maxset) {
fprintf(stderr, "%s: %s: value outside min/max values of %"
PRIu32 "-%" PRIu32 "\n",
- g.progname, s, cp->min, cp->maxset);
+ progname, s, cp->min, cp->maxset);
exit(EXIT_FAILURE);
}
- *cp->v = (uint32_t)v;
+ *cp->v = v;
}
/*
@@ -817,7 +889,7 @@ config_find(const char *s, size_t len)
return (cp);
fprintf(stderr,
- "%s: %s: unknown configuration keyword\n", g.progname, s);
+ "%s: %s: unknown configuration keyword\n", progname, s);
config_error();
exit(EXIT_FAILURE);
}
diff --git a/test/format/config.h b/test/format/config.h
index e4f7af2e1b2..b5feb7a5321 100644
--- a/test/format/config.h
+++ b/test/format/config.h
@@ -131,7 +131,7 @@ static CONFIG c[] = {
{ "delete_pct",
"percent operations that are deletes",
- 0x0, 0, 45, 90, &g.c_delete_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_delete_pct, NULL },
{ "dictionary",
"if values are dictionary compressed", /* 20% */
@@ -171,7 +171,7 @@ static CONFIG c[] = {
{ "insert_pct",
"percent operations that are inserts",
- 0x0, 0, 45, 90, &g.c_insert_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_insert_pct, NULL },
{ "internal_key_truncation",
"if internal keys are truncated", /* 95% */
@@ -254,6 +254,14 @@ static CONFIG c[] = {
"quiet run (same as -q)",
C_IGNORE|C_BOOL, 0, 0, 0, &g.c_quiet, NULL },
+ { "read_pct",
+ "percent operations that are reads",
+ C_IGNORE, 0, 0, 100, &g.c_read_pct, NULL },
+
+ { "rebalance",
+ "rebalance testing", /* 100% */
+ C_BOOL, 100, 1, 0, &g.c_rebalance, NULL },
+
{ "repeat_data_pct",
"percent duplicate values in row- or var-length column-stores",
0x0, 0, 90, 90, &g.c_repeat_data_pct, NULL },
@@ -270,17 +278,13 @@ static CONFIG c[] = {
"the number of runs",
C_IGNORE, 0, UINT_MAX, UINT_MAX, &g.c_runs, NULL },
- { "rebalance",
- "rebalance testing", /* 100% */
- C_BOOL, 100, 1, 0, &g.c_rebalance, NULL },
-
{ "salvage",
"salvage testing", /* 100% */
C_BOOL, 100, 1, 0, &g.c_salvage, NULL },
{ "split_pct",
"page split size as a percentage of the maximum page size",
- 0x0, 40, 85, 85, &g.c_split_pct, NULL },
+ 0x0, 50, 100, 100, &g.c_split_pct, NULL },
{ "statistics",
"maintain statistics", /* 20% */
@@ -320,7 +324,7 @@ static CONFIG c[] = {
{ "write_pct",
"percent operations that are writes",
- 0x0, 0, 90, 90, &g.c_write_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_write_pct, NULL },
{ NULL, NULL, 0x0, 0, 0, 0, NULL, NULL }
};
diff --git a/test/format/format.h b/test/format/format.h
index c1f4875dbb2..41cc48c4278 100644
--- a/test/format/format.h
+++ b/test/format/format.h
@@ -79,8 +79,6 @@
#define FORMAT_OPERATION_REPS 3 /* 3 thread operations sets */
typedef struct {
- char *progname; /* Program name */
-
char *home; /* Home directory */
char *home_backup; /* Hot-backup directory */
char *home_backup_init; /* Initialize backup command */
@@ -192,6 +190,7 @@ typedef struct {
uint32_t c_reverse;
uint32_t c_rows;
uint32_t c_runs;
+ uint32_t c_read_pct;
uint32_t c_rebalance;
uint32_t c_salvage;
uint32_t c_split_pct;
diff --git a/test/format/ops.c b/test/format/ops.c
index 940318c87a9..72e885bd0d6 100644
--- a/test/format/ops.c
+++ b/test/format/ops.c
@@ -28,14 +28,17 @@
#include "format.h"
-static int col_insert(WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t *);
-static int col_remove(WT_CURSOR *, WT_ITEM *, uint64_t);
-static int col_update(WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t);
+static int col_insert(TINFO *, WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t *);
+static int col_remove(WT_CURSOR *, WT_ITEM *, uint64_t, bool);
+static int col_update(
+ TINFO *, WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t, bool);
static int nextprev(WT_CURSOR *, int);
static void *ops(void *);
-static int row_insert(WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t);
-static int row_remove(WT_CURSOR *, WT_ITEM *, uint64_t);
-static int row_update(WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t);
+static int row_insert(
+ TINFO *, WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t, bool);
+static int row_remove(WT_CURSOR *, WT_ITEM *, uint64_t, bool);
+static int row_update(
+ TINFO *, WT_CURSOR *, WT_ITEM *, WT_ITEM *, uint64_t, bool);
static void table_append_init(void);
#ifdef HAVE_BERKELEY_DB
@@ -243,6 +246,9 @@ typedef struct {
bool insert; /* Insert operation */
} SNAP_OPS;
+#define SNAP_TRACK \
+ (snap != NULL && (size_t)(snap - snap_list) < WT_ELEMENTS(snap_list))
+
/*
* snap_track --
* Add a single snapshot isolation returned value to the list.
@@ -395,15 +401,16 @@ snap_check(WT_CURSOR *cursor,
static void *
ops(void *arg)
{
+ enum { INSERT, READ, REMOVE, UPDATE } op;
SNAP_OPS *snap, snap_list[64];
TINFO *tinfo;
WT_CONNECTION *conn;
- WT_CURSOR *cursor, *cursor_insert;
+ WT_CURSOR *cursor;
WT_DECL_RET;
WT_ITEM *key, _key, *value, _value;
WT_SESSION *session;
uint64_t keyno, ckpt_op, reset_op, session_op;
- uint32_t op, rnd;
+ uint32_t rnd;
u_int i;
int dir;
char *ckpt_config, ckpt_name[64];
@@ -429,9 +436,9 @@ ops(void *arg)
val_gen_setup(&tinfo->rnd, value);
/* Set the first operation where we'll create sessions and cursors. */
- session_op = 0;
+ cursor = NULL;
session = NULL;
- cursor = cursor_insert = NULL;
+ session_op = 0;
/* Set the first operation where we'll perform checkpoint operations. */
ckpt_op = g.c_checkpoints ? mmrand(&tinfo->rnd, 100, 10000) : 0;
@@ -485,24 +492,11 @@ ops(void *arg)
readonly = true;
} else {
/*
- * Open two cursors: one for overwriting and one
- * for append (if it's a column-store).
- *
- * The reason is when testing with existing
- * records, we don't track if a record was
- * deleted or not, which means we must use
- * cursor->insert with overwriting configured.
- * But, in column-store files where we're
- * testing with new, appended records, we don't
- * want to have to specify the record number,
- * which requires an append configuration.
+ * Configure "append", in the case of column
+ * stores, we append when inserting new rows.
*/
- testutil_check(session->open_cursor(session,
- g.uri, NULL, "overwrite", &cursor));
- if (g.type == FIX || g.type == VAR)
- testutil_check(session->open_cursor(
- session, g.uri,
- NULL, "append", &cursor_insert));
+ testutil_check(session->open_cursor(
+ session, g.uri, NULL, "append", &cursor));
/* Pick the next session/cursor close/open. */
session_op += mmrand(&tinfo->rnd, 100, 5000);
@@ -536,8 +530,9 @@ ops(void *arg)
pthread_rwlock_trywrlock(&g.backup_lock) == EBUSY)
ckpt_config = NULL;
else {
- (void)snprintf(ckpt_name, sizeof(ckpt_name),
- "name=thread-%d", tinfo->id);
+ testutil_check(__wt_snprintf(
+ ckpt_name, sizeof(ckpt_name),
+ "name=thread-%d", tinfo->id));
ckpt_config = ckpt_name;
}
@@ -563,8 +558,9 @@ ops(void *arg)
strcpy(ckpt_name,
"checkpoint=WiredTigerCheckpoint");
else
- (void)snprintf(ckpt_name, sizeof(ckpt_name),
- "checkpoint=thread-%d", tinfo->id);
+ testutil_check(__wt_snprintf(
+ ckpt_name, sizeof(ckpt_name),
+ "checkpoint=thread-%d", tinfo->id));
ckpt_available = true;
skip_checkpoint: /* Pick the next checkpoint operation. */
@@ -600,111 +596,174 @@ skip_checkpoint: /* Pick the next checkpoint operation. */
intxn = true;
}
+ /* Select a row. */
keyno = mmrand(&tinfo->rnd, 1, (u_int)g.rows);
positioned = false;
+ /* Select an operation. */
+ op = READ;
+ if (!readonly) {
+ i = mmrand(&tinfo->rnd, 1, 100);
+ if (i < g.c_delete_pct)
+ op = REMOVE;
+ else if (i < g.c_delete_pct + g.c_insert_pct)
+ op = INSERT;
+ else if (i <
+ g.c_delete_pct + g.c_insert_pct + g.c_write_pct)
+ op = UPDATE;
+ else
+ op = READ;
+ }
+
/*
- * Perform some number of operations: the percentage of deletes,
- * inserts and writes are specified, reads are the rest. The
- * percentages don't have to add up to 100, a high percentage
- * of deletes will mean fewer inserts and writes. Modifications
- * are always followed by a read to confirm it worked.
+ * Inserts, removes and updates can be done following a cursor
+ * set-key, or based on a cursor position taken from a previous
+ * search. If not already doing a read, position the cursor at
+ * an existing point in the tree 20% of the time.
*/
- op = readonly ? UINT32_MAX : mmrand(&tinfo->rnd, 1, 100);
- if (op < g.c_delete_pct) {
- ++tinfo->remove;
+ positioned = false;
+ if (op != READ && mmrand(&tinfo->rnd, 1, 5) == 1) {
+ ++tinfo->search;
+ ret = read_row(cursor, key, value, keyno);
+ if (ret == 0) {
+ positioned = true;
+ if (SNAP_TRACK)
+ snap_track(snap++, keyno, NULL, value);
+ } else {
+ positioned = false;
+ if (ret == WT_ROLLBACK && intxn)
+ goto deadlock;
+ testutil_assert(ret == WT_NOTFOUND);
+ }
+ }
+#if 0
+ /* Optionally reserve a row. */
+ if (!readonly && intxn && mmrand(&tinfo->rnd, 0, 20) == 1) {
switch (g.type) {
case ROW:
- ret = row_remove(cursor, key, keyno);
+ ret =
+ row_reserve(cursor, key, keyno, positioned);
break;
case FIX:
case VAR:
- ret = col_remove(cursor, key, keyno);
+ ret = col_reserve(cursor, keyno, positioned);
break;
}
if (ret == 0) {
positioned = true;
- if (snap != NULL && (size_t)
- (snap - snap_list) < WT_ELEMENTS(snap_list))
- snap_track(snap++, keyno, NULL, NULL);
+ __wt_yield();
} else {
positioned = false;
if (ret == WT_ROLLBACK && intxn)
goto deadlock;
+ testutil_assert(ret == WT_NOTFOUND);
}
- } else if (op < g.c_delete_pct + g.c_insert_pct) {
- ++tinfo->insert;
+ }
+#endif
+ /* Perform the operation. */
+ switch (op) {
+ case INSERT:
switch (g.type) {
case ROW:
- key_gen_insert(&tinfo->rnd, key, keyno);
- val_gen(&tinfo->rnd, value, keyno);
- ret = row_insert(cursor, key, value, keyno);
+ ret = row_insert(tinfo,
+ cursor, key, value, keyno, positioned);
break;
case FIX:
case VAR:
/*
- * We can only append so many new records, if
- * we've reached that limit, update a record
- * instead of doing an insert.
+ * We can only append so many new records, once
+ * we reach that limit, update a record instead
+ * of inserting.
*/
if (g.append_cnt >= g.append_max)
- goto skip_insert;
+ goto update_instead_of_insert;
- /* Insert, then reset the insert cursor. */
- val_gen(&tinfo->rnd, value, g.rows + 1);
ret = col_insert(
- cursor_insert, key, value, &keyno);
- testutil_check(
- cursor_insert->reset(cursor_insert));
+ tinfo, cursor, key, value, &keyno);
break;
}
+
+ /* Insert never leaves the cursor positioned. */
positioned = false;
if (ret == 0) {
- if (snap != NULL && (size_t)
- (snap - snap_list) < WT_ELEMENTS(snap_list))
+ ++tinfo->insert;
+ if (SNAP_TRACK)
snap_track(snap++, keyno,
g.type == ROW ? key : NULL, value);
- } else
+ } else {
if (ret == WT_ROLLBACK && intxn)
goto deadlock;
- } else if (
- op < g.c_delete_pct + g.c_insert_pct + g.c_write_pct) {
- ++tinfo->update;
+ testutil_assert(ret == 0 || ret == WT_ROLLBACK);
+ }
+ break;
+ case READ:
+ ++tinfo->search;
+ ret = read_row(cursor, key, value, keyno);
+ if (ret == 0) {
+ positioned = true;
+ if (SNAP_TRACK)
+ snap_track(snap++, keyno, NULL, value);
+ } else {
+ positioned = false;
+ if (ret == WT_ROLLBACK && intxn)
+ goto deadlock;
+ testutil_assert(ret == WT_NOTFOUND);
+ }
+ break;
+ case REMOVE:
switch (g.type) {
case ROW:
- key_gen(key, keyno);
- val_gen(&tinfo->rnd, value, keyno);
- ret = row_update(cursor, key, value, keyno);
+ ret =
+ row_remove(cursor, key, keyno, positioned);
break;
case FIX:
case VAR:
-skip_insert: val_gen(&tinfo->rnd, value, keyno);
- ret = col_update(cursor, key, value, keyno);
+ ret =
+ col_remove(cursor, key, keyno, positioned);
break;
}
if (ret == 0) {
- positioned = true;
- if (snap != NULL && (size_t)
- (snap - snap_list) < WT_ELEMENTS(snap_list))
- snap_track(snap++, keyno, NULL, value);
+ ++tinfo->remove;
+ /*
+ * Don't set positioned: it's unchanged from the
+ * previous state, but not necessarily set.
+ */
+ if (SNAP_TRACK)
+ snap_track(snap++, keyno, NULL, NULL);
} else {
positioned = false;
if (ret == WT_ROLLBACK && intxn)
goto deadlock;
+ testutil_assert(ret == WT_NOTFOUND);
+ }
+ break;
+ case UPDATE:
+update_instead_of_insert:
+ ++tinfo->update;
+
+ /* Update the row. */
+ switch (g.type) {
+ case ROW:
+ ret = row_update(tinfo,
+ cursor, key, value, keyno, positioned);
+ break;
+ case FIX:
+ case VAR:
+ ret = col_update(tinfo,
+ cursor, key, value, keyno, positioned);
+ break;
}
- } else {
- ++tinfo->search;
- ret = read_row(cursor, key, value, keyno);
if (ret == 0) {
positioned = true;
- if (snap != NULL && (size_t)
- (snap - snap_list) < WT_ELEMENTS(snap_list))
+ if (SNAP_TRACK)
snap_track(snap++, keyno, NULL, value);
} else {
positioned = false;
if (ret == WT_ROLLBACK && intxn)
goto deadlock;
+ testutil_assert(ret == 0 || ret == WT_ROLLBACK);
}
+ break;
}
/*
@@ -727,8 +786,8 @@ skip_insert: val_gen(&tinfo->rnd, value, keyno);
testutil_check(cursor->reset(cursor));
/*
- * If we're in a transaction, commit 40% of the time and
- * rollback 10% of the time.
+ * Continue if not in a transaction, else add more operations
+ * to the transaction half the time.
*/
if (!intxn || (rnd = mmrand(&tinfo->rnd, 1, 10)) > 5)
continue;
@@ -741,6 +800,10 @@ skip_insert: val_gen(&tinfo->rnd, value, keyno);
cursor, snap_list, snap, key, value)) == WT_ROLLBACK)
goto deadlock;
+ /*
+ * If we're in a transaction, commit 40% of the time and
+ * rollback 10% of the time.
+ */
switch (rnd) {
case 1: case 2: case 3: case 4: /* 40% */
testutil_check(
@@ -1040,27 +1103,94 @@ nextprev(WT_CURSOR *cursor, int next)
return (ret);
}
+#if 0
+/*
+ * row_reserve --
+ * Reserve a row in a row-store file.
+ */
+static int
+row_reserve(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, bool positioned)
+{
+ WT_DECL_RET;
+
+ if (!positioned) {
+ key_gen(key, keyno);
+ cursor->set_key(cursor, key);
+ }
+
+ if (g.logging == LOG_OPS)
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
+ "%-10s{%.*s}", "reserve", (int)key->size, key->data);
+
+ switch (ret = cursor->reserve(cursor)) {
+ case 0:
+ break;
+ case WT_CACHE_FULL:
+ case WT_ROLLBACK:
+ return (WT_ROLLBACK);
+ case WT_NOTFOUND:
+ return (WT_NOTFOUND);
+ default:
+ testutil_die(ret,
+ "row_reserve: reserve row %" PRIu64 " by key", keyno);
+ }
+ return (0);
+}
+
+/*
+ * col_reserve --
+ * Reserve a row in a column-store file.
+ */
+static int
+col_reserve(WT_CURSOR *cursor, uint64_t keyno, bool positioned)
+{
+ WT_DECL_RET;
+
+ if (!positioned)
+ cursor->set_key(cursor, keyno);
+
+ if (g.logging == LOG_OPS)
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
+ "%-10s%" PRIu64, "reserve", keyno);
+
+ switch (ret = cursor->reserve(cursor)) {
+ case 0:
+ break;
+ case WT_CACHE_FULL:
+ case WT_ROLLBACK:
+ return (WT_ROLLBACK);
+ case WT_NOTFOUND:
+ return (WT_NOTFOUND);
+ default:
+ testutil_die(ret, "col_reserve: %" PRIu64, keyno);
+ }
+ return (0);
+}
+#endif
+
/*
* row_update --
* Update a row in a row-store file.
*/
static int
-row_update(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
+row_update(TINFO *tinfo, WT_CURSOR *cursor,
+ WT_ITEM *key, WT_ITEM *value, uint64_t keyno, bool positioned)
{
WT_DECL_RET;
- WT_SESSION *session;
- session = cursor->session;
+ if (!positioned) {
+ key_gen(key, keyno);
+ cursor->set_key(cursor, key);
+ }
+ val_gen(&tinfo->rnd, value, keyno);
+ cursor->set_value(cursor, value);
- /* Log the operation */
if (g.logging == LOG_OPS)
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s{%.*s}, {%.*s}",
"put",
(int)key->size, key->data, (int)value->size, value->data);
- cursor->set_key(cursor, key);
- cursor->set_value(cursor, value);
switch (ret = cursor->update(cursor)) {
case 0:
break;
@@ -1086,32 +1216,32 @@ row_update(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
* Update a row in a column-store file.
*/
static int
-col_update(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
+col_update(TINFO *tinfo, WT_CURSOR *cursor,
+ WT_ITEM *key, WT_ITEM *value, uint64_t keyno, bool positioned)
{
WT_DECL_RET;
- WT_SESSION *session;
- session = cursor->session;
+ if (!positioned)
+ cursor->set_key(cursor, keyno);
+ val_gen(&tinfo->rnd, value, keyno);
+ if (g.type == FIX)
+ cursor->set_value(cursor, *(uint8_t *)value->data);
+ else
+ cursor->set_value(cursor, value);
- /* Log the operation */
if (g.logging == LOG_OPS) {
if (g.type == FIX)
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s%" PRIu64 " {0x%02" PRIx8 "}",
"update", keyno,
((uint8_t *)value->data)[0]);
else
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s%" PRIu64 " {%.*s}",
"update", keyno,
(int)value->size, (char *)value->data);
}
- cursor->set_key(cursor, keyno);
- if (g.type == FIX)
- cursor->set_value(cursor, *(uint8_t *)value->data);
- else
- cursor->set_value(cursor, value);
switch (ret = cursor->update(cursor)) {
case 0:
break;
@@ -1238,22 +1368,29 @@ table_append(uint64_t keyno)
* Insert a row in a row-store file.
*/
static int
-row_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
+row_insert(TINFO *tinfo, WT_CURSOR *cursor,
+ WT_ITEM *key, WT_ITEM *value, uint64_t keyno, bool positioned)
{
WT_DECL_RET;
- WT_SESSION *session;
- session = cursor->session;
+ /*
+ * If we positioned the cursor already, it's a test of an update using
+ * the insert method. Otherwise, generate a unique key and insert.
+ */
+ if (!positioned) {
+ key_gen_insert(&tinfo->rnd, key, keyno);
+ cursor->set_key(cursor, key);
+ }
+ val_gen(&tinfo->rnd, value, keyno);
+ cursor->set_value(cursor, value);
/* Log the operation */
if (g.logging == LOG_OPS)
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s{%.*s}, {%.*s}",
"insert",
(int)key->size, key->data, (int)value->size, value->data);
- cursor->set_key(cursor, key);
- cursor->set_value(cursor, value);
switch (ret = cursor->insert(cursor)) {
case 0:
break;
@@ -1279,14 +1416,13 @@ row_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
* Insert an element in a column-store file.
*/
static int
-col_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop)
+col_insert(TINFO *tinfo,
+ WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop)
{
WT_DECL_RET;
- WT_SESSION *session;
uint64_t keyno;
- session = cursor->session;
-
+ val_gen(&tinfo->rnd, value, g.rows + 1);
if (g.type == FIX)
cursor->set_value(cursor, *(uint8_t *)value->data);
else
@@ -1307,12 +1443,12 @@ col_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop)
if (g.logging == LOG_OPS) {
if (g.type == FIX)
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s%" PRIu64 " {0x%02" PRIx8 "}",
"insert", keyno,
((uint8_t *)value->data)[0]);
else
- (void)g.wt_api->msg_printf(g.wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, cursor->session,
"%-10s%" PRIu64 " {%.*s}",
"insert", keyno,
(int)value->size, (char *)value->data);
@@ -1335,21 +1471,19 @@ col_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop)
* Remove an row from a row-store file.
*/
static int
-row_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno)
+row_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, bool positioned)
{
WT_DECL_RET;
- WT_SESSION *session;
- session = cursor->session;
-
- key_gen(key, keyno);
+ if (!positioned) {
+ key_gen(key, keyno);
+ cursor->set_key(cursor, key);
+ }
- /* Log the operation */
if (g.logging == LOG_OPS)
- (void)g.wt_api->msg_printf(
- g.wt_api, session, "%-10s%" PRIu64, "remove", keyno);
+ (void)g.wt_api->msg_printf(g.wt_api,
+ cursor->session, "%-10s%" PRIu64, "remove", keyno);
- cursor->set_key(cursor, key);
/* We use the cursor in overwrite mode, check for existence. */
if ((ret = cursor->search(cursor)) == 0)
ret = cursor->remove(cursor);
@@ -1385,19 +1519,17 @@ row_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno)
* Remove a row from a column-store file.
*/
static int
-col_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno)
+col_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, bool positioned)
{
WT_DECL_RET;
- WT_SESSION *session;
- session = cursor->session;
+ if (!positioned)
+ cursor->set_key(cursor, keyno);
- /* Log the operation */
if (g.logging == LOG_OPS)
- (void)g.wt_api->msg_printf(
- g.wt_api, session, "%-10s%" PRIu64, "remove", keyno);
+ (void)g.wt_api->msg_printf(g.wt_api,
+ cursor->session, "%-10s%" PRIu64, "remove", keyno);
- cursor->set_key(cursor, keyno);
/* We use the cursor in overwrite mode, check for existence. */
if ((ret = cursor->search(cursor)) == 0)
ret = cursor->remove(cursor);
@@ -1448,7 +1580,7 @@ notfound_chk(const char *f, int wt_ret, int bdb_notfound, uint64_t keyno)
return (1);
if (bdb_notfound) {
- fprintf(stderr, "%s: %s:", g.progname, f);
+ fprintf(stderr, "%s: %s:", progname, f);
if (keyno != 0)
fprintf(stderr, " row %" PRIu64 ":", keyno);
fprintf(stderr,
@@ -1456,7 +1588,7 @@ notfound_chk(const char *f, int wt_ret, int bdb_notfound, uint64_t keyno)
testutil_die(0, NULL);
}
if (wt_ret == WT_NOTFOUND) {
- fprintf(stderr, "%s: %s:", g.progname, f);
+ fprintf(stderr, "%s: %s:", progname, f);
if (keyno != 0)
fprintf(stderr, " row %" PRIu64 ":", keyno);
fprintf(stderr,
diff --git a/test/format/rebalance.c b/test/format/rebalance.c
index 9849b7df82b..e35c62e7255 100644
--- a/test/format/rebalance.c
+++ b/test/format/rebalance.c
@@ -41,10 +41,10 @@ wts_rebalance(void)
track("rebalance", 0ULL, NULL);
/* Dump the current object. */
- (void)snprintf(cmd, sizeof(cmd),
+ testutil_check(__wt_snprintf(cmd, sizeof(cmd),
".." DIR_DELIM_STR ".." DIR_DELIM_STR "wt"
" -h %s dump -f %s/rebalance.orig %s",
- g.home, g.home, g.uri);
+ g.home, g.home, g.uri));
testutil_checkfmt(system(cmd), "command failed: %s", cmd);
/* Rebalance, then verify the object. */
@@ -66,21 +66,21 @@ wts_rebalance(void)
wts_verify("post-rebalance verify");
wts_close();
- (void)snprintf(cmd, sizeof(cmd),
+ testutil_check(__wt_snprintf(cmd, sizeof(cmd),
".." DIR_DELIM_STR ".." DIR_DELIM_STR "wt"
" -h %s dump -f %s/rebalance.new %s",
- g.home, g.home, g.uri);
+ g.home, g.home, g.uri));
testutil_checkfmt(system(cmd), "command failed: %s", cmd);
/* Compare the old/new versions of the object. */
#ifdef _WIN32
- (void)snprintf(cmd, sizeof(cmd),
+ testutil_check(__wt_snprintf(cmd, sizeof(cmd),
"fc /b %s\\rebalance.orig %s\\rebalance.new > NUL",
- g.home, g.home);
+ g.home, g.home));
#else
- (void)snprintf(cmd, sizeof(cmd),
+ testutil_check(__wt_snprintf(cmd, sizeof(cmd),
"cmp %s/rebalance.orig %s/rebalance.new > /dev/null",
- g.home, g.home);
+ g.home, g.home));
#endif
testutil_checkfmt(system(cmd), "command failed: %s", cmd);
}
diff --git a/test/format/salvage.c b/test/format/salvage.c
index 69805fb1018..f82dc34dd5f 100644
--- a/test/format/salvage.c
+++ b/test/format/salvage.c
@@ -70,29 +70,31 @@ corrupt(void)
* It's a little tricky: if the data source is a file, we're looking
* for "wt", if the data source is a table, we're looking for "wt.wt".
*/
- (void)snprintf(buf, sizeof(buf), "%s/%s", g.home, WT_NAME);
+ testutil_check(__wt_snprintf(
+ buf, sizeof(buf), "%s/%s", g.home, WT_NAME));
if ((fd = open(buf, O_RDWR)) != -1) {
#ifdef _WIN32
- (void)snprintf(copycmd, sizeof(copycmd),
+ testutil_check(__wt_snprintf(copycmd, sizeof(copycmd),
"copy %s\\%s %s\\slvg.copy\\%s.corrupted",
- g.home, WT_NAME, g.home, WT_NAME);
+ g.home, WT_NAME, g.home, WT_NAME));
#else
- (void)snprintf(copycmd, sizeof(copycmd),
+ testutil_check(__wt_snprintf(copycmd, sizeof(copycmd),
"cp %s/%s %s/slvg.copy/%s.corrupted",
- g.home, WT_NAME, g.home, WT_NAME);
+ g.home, WT_NAME, g.home, WT_NAME));
#endif
goto found;
}
- (void)snprintf(buf, sizeof(buf), "%s/%s.wt", g.home, WT_NAME);
+ testutil_check(__wt_snprintf(
+ buf, sizeof(buf), "%s/%s.wt", g.home, WT_NAME));
if ((fd = open(buf, O_RDWR)) != -1) {
#ifdef _WIN32
- (void)snprintf(copycmd, sizeof(copycmd),
+ testutil_check(__wt_snprintf(copycmd, sizeof(copycmd),
"copy %s\\%s.wt %s\\slvg.copy\\%s.wt.corrupted",
- g.home, WT_NAME, g.home, WT_NAME);
+ g.home, WT_NAME, g.home, WT_NAME));
#else
- (void)snprintf(copycmd, sizeof(copycmd),
+ testutil_check(__wt_snprintf(copycmd, sizeof(copycmd),
"cp %s/%s.wt %s/slvg.copy/%s.wt.corrupted",
- g.home, WT_NAME, g.home, WT_NAME);
+ g.home, WT_NAME, g.home, WT_NAME));
#endif
goto found;
}
@@ -103,7 +105,8 @@ found: if (fstat(fd, &sb) == -1)
offset = mmrand(NULL, 0, (u_int)sb.st_size);
len = (size_t)(20 + (sb.st_size / 100) * 2);
- (void)snprintf(buf, sizeof(buf), "%s/slvg.corrupt", g.home);
+ testutil_check(__wt_snprintf(
+ buf, sizeof(buf), "%s/slvg.corrupt", g.home));
if ((fp = fopen(buf, "w")) == NULL)
testutil_die(errno, "salvage-corrupt: open: %s", buf);
(void)fprintf(fp,
diff --git a/test/format/t.c b/test/format/t.c
index 7701595776c..c6686ae8b91 100644
--- a/test/format/t.c
+++ b/test/format/t.c
@@ -49,14 +49,7 @@ main(int argc, char *argv[])
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
+ (void)testutil_set_progname(argv);
#if 0
/* Configure the GNU malloc for debugging. */
@@ -74,7 +67,7 @@ main(int argc, char *argv[])
home = NULL;
onerun = 0;
while ((ch = __wt_getopt(
- g.progname, argc, argv, "1C:c:H:h:Llqrt:")) != EOF)
+ progname, argc, argv, "1C:c:H:h:Llqrt:")) != EOF)
switch (ch) {
case '1': /* One run */
onerun = 1;
@@ -179,7 +172,7 @@ main(int argc, char *argv[])
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());
+ printf("%s: process %" PRIdMAX "\n", progname, (intmax_t)getpid());
while (++g.run_cnt <= g.c_runs || g.c_runs == 0 ) {
startup(); /* Start a run */
@@ -344,7 +337,7 @@ usage(void)
"usage: %s [-1Llqr] [-C wiredtiger-config]\n "
"[-c config-file] [-H mount] [-h home] "
"[name=value ...]\n",
- g.progname);
+ progname);
fprintf(stderr, "%s",
"\t-1 run once\n"
"\t-C specify wiredtiger_open configuration arguments\n"
diff --git a/test/format/util.c b/test/format/util.c
index b9788f1ac75..983d03e2525 100644
--- a/test/format/util.c
+++ b/test/format/util.c
@@ -241,20 +241,23 @@ val_gen(WT_RAND_STATE *rnd, WT_ITEM *value, uint64_t keyno)
void
track(const char *tag, uint64_t cnt, TINFO *tinfo)
{
- static int lastlen = 0;
- int len;
+ static size_t lastlen = 0;
+ size_t len;
char msg[128];
if (g.c_quiet || tag == NULL)
return;
if (tinfo == NULL && cnt == 0)
- len = snprintf(msg, sizeof(msg), "%4d: %s", g.run_cnt, tag);
+ testutil_check(__wt_snprintf_len_set(
+ msg, sizeof(msg), &len, "%4d: %s", g.run_cnt, tag));
else if (tinfo == NULL)
- len = snprintf(
- msg, sizeof(msg), "%4d: %s: %" PRIu64, g.run_cnt, tag, cnt);
+ testutil_check(__wt_snprintf_len_set(
+ msg, sizeof(msg), &len,
+ "%4d: %s: %" PRIu64, g.run_cnt, tag, cnt));
else
- len = snprintf(msg, sizeof(msg),
+ testutil_check(__wt_snprintf_len_set(
+ msg, sizeof(msg), &len,
"%4d: %s: "
"search %" PRIu64 "%s, "
"insert %" PRIu64 "%s, "
@@ -268,7 +271,7 @@ track(const char *tag, uint64_t cnt, TINFO *tinfo)
tinfo->update > M(9) ? tinfo->update / M(1) : tinfo->update,
tinfo->update > M(9) ? "M" : "",
tinfo->remove > M(9) ? tinfo->remove / M(1) : tinfo->remove,
- tinfo->remove > M(9) ? "M" : "");
+ tinfo->remove > M(9) ? "M" : ""));
if (lastlen > len) {
memset(msg + len, ' ', (size_t)(lastlen - len));
@@ -297,27 +300,30 @@ path_setup(const char *home)
/* Log file. */
len = strlen(g.home) + strlen("log") + 2;
g.home_log = dmalloc(len);
- snprintf(g.home_log, len, "%s/%s", g.home, "log");
+ testutil_check(__wt_snprintf(g.home_log, len, "%s/%s", g.home, "log"));
/* RNG log file. */
len = strlen(g.home) + strlen("rand") + 2;
g.home_rand = dmalloc(len);
- snprintf(g.home_rand, len, "%s/%s", g.home, "rand");
+ testutil_check(__wt_snprintf(
+ g.home_rand, len, "%s/%s", g.home, "rand"));
/* Run file. */
len = strlen(g.home) + strlen("CONFIG") + 2;
g.home_config = dmalloc(len);
- snprintf(g.home_config, len, "%s/%s", g.home, "CONFIG");
+ testutil_check(__wt_snprintf(
+ g.home_config, len, "%s/%s", g.home, "CONFIG"));
/* Statistics file. */
len = strlen(g.home) + strlen("stats") + 2;
g.home_stats = dmalloc(len);
- snprintf(g.home_stats, len, "%s/%s", g.home, "stats");
+ testutil_check(__wt_snprintf(
+ g.home_stats, len, "%s/%s", g.home, "stats"));
/* BDB directory. */
len = strlen(g.home) + strlen("bdb") + 2;
g.home_bdb = dmalloc(len);
- snprintf(g.home_bdb, len, "%s/%s", g.home, "bdb");
+ testutil_check(__wt_snprintf(g.home_bdb, len, "%s/%s", g.home, "bdb"));
/*
* Home directory initialize command: create the directory if it doesn't
@@ -336,21 +342,23 @@ path_setup(const char *home)
"cd %s & mkdir KVS"
len = strlen(g.home) * 7 + strlen(CMD) + 1;
g.home_init = dmalloc(len);
- snprintf(g.home_init, len, CMD,
- g.home, g.home, g.home, g.home, g.home, g.home, g.home);
+ testutil_check(__wt_snprintf(g.home_init, len, CMD,
+ g.home, g.home, g.home, g.home, g.home, g.home, g.home));
#else
#define CMD "test -e %s || mkdir %s; " \
"cd %s > /dev/null && rm -rf `ls | sed /rand/d`; " \
"mkdir KVS"
len = strlen(g.home) * 3 + strlen(CMD) + 1;
g.home_init = dmalloc(len);
- snprintf(g.home_init, len, CMD, g.home, g.home, g.home);
+ testutil_check(__wt_snprintf(
+ g.home_init, len, CMD, g.home, g.home, g.home));
#endif
/* Primary backup directory. */
len = strlen(g.home) + strlen("BACKUP") + 2;
g.home_backup = dmalloc(len);
- snprintf(g.home_backup, len, "%s/%s", g.home, "BACKUP");
+ testutil_check(__wt_snprintf(
+ g.home_backup, len, "%s/%s", g.home, "BACKUP"));
/*
* Backup directory initialize command, remove and re-create the primary
@@ -365,9 +373,9 @@ path_setup(const char *home)
len = strlen(g.home) * 4 +
strlen("BACKUP") * 2 + strlen("BACKUP_COPY") * 2 + strlen(CMD) + 1;
g.home_backup_init = dmalloc(len);
- snprintf(g.home_backup_init, len, CMD,
+ testutil_check(__wt_snprintf(g.home_backup_init, len, CMD,
g.home, "BACKUP", g.home, "BACKUP_COPY",
- g.home, "BACKUP", g.home, "BACKUP_COPY");
+ g.home, "BACKUP", g.home, "BACKUP_COPY"));
/*
* Salvage command, save the interesting files so we can replay the
@@ -390,7 +398,7 @@ path_setup(const char *home)
#endif
len = strlen(g.home) + strlen(CMD) + 1;
g.home_salvage_copy = dmalloc(len);
- snprintf(g.home_salvage_copy, len, CMD, g.home);
+ testutil_check(__wt_snprintf(g.home_salvage_copy, len, CMD, g.home));
}
/*
@@ -489,8 +497,9 @@ alter(void *arg)
while (!g.workers_finished) {
period = mmrand(NULL, 1, 10);
- snprintf(buf, sizeof(buf),
- "access_pattern_hint=%s", access_value ? "random" : "none");
+ testutil_check(__wt_snprintf(buf, sizeof(buf),
+ "access_pattern_hint=%s",
+ access_value ? "random" : "none"));
access_value = !access_value;
if (session->alter(session, g.uri, buf) != 0)
break;
diff --git a/test/format/wts.c b/test/format/wts.c
index da234ce53c7..6aa4784d1c1 100644
--- a/test/format/wts.c
+++ b/test/format/wts.c
@@ -120,8 +120,15 @@ static WT_EVENT_HANDLER event_handler = {
NULL /* Close handler. */
};
-#undef REMAIN
-#define REMAIN(p, end) (size_t)((p) >= (end) ? 0 : (end) - (p))
+#define CONFIG_APPEND(p, ...) do { \
+ size_t __len; \
+ testutil_check( \
+ __wt_snprintf_len_set(p, max, &__len, __VA_ARGS__)); \
+ if (__len > max) \
+ __len = max; \
+ p += __len; \
+ max -= __len; \
+} while (0)
/*
* wts_open --
@@ -132,42 +139,42 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
{
WT_CONNECTION *conn;
WT_DECL_RET;
- char *config, *end, *p, helium_config[1024];
+ size_t max;
+ char *config, *p, helium_config[1024];
*connp = NULL;
config = p = g.wiredtiger_open_config;
- end = config + sizeof(g.wiredtiger_open_config);
+ max = sizeof(g.wiredtiger_open_config);
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
"create=true,"
"cache_size=%" PRIu32 "MB,"
"checkpoint_sync=false,"
"error_prefix=\"%s\"",
- g.c_cache, g.progname);
+ g.c_cache, progname);
/* In-memory configuration. */
if (g.c_in_memory != 0)
- p += snprintf(p, REMAIN(p, end), ",in_memory=1");
+ CONFIG_APPEND(p, ",in_memory=1");
/* LSM configuration. */
if (DATASOURCE("lsm"))
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",lsm_manager=(worker_thread_max=%" PRIu32 "),",
g.c_lsm_worker_threads);
- if (DATASOURCE("lsm") || g.c_cache < 20) {
- p += snprintf(p, REMAIN(p, end), ",eviction_dirty_trigger=95");
- }
+ if (DATASOURCE("lsm") || g.c_cache < 20)
+ CONFIG_APPEND(p, ",eviction_dirty_trigger=95");
/* Eviction worker configuration. */
if (g.c_evict_max != 0)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",eviction=(threads_max=%" PRIu32 ")", g.c_evict_max);
/* Logging configuration. */
if (g.c_logging)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",log=(enabled=true,archive=%d,prealloc=%d"
",compressor=\"%s\")",
g.c_logging_archive ? 1 : 0,
@@ -175,21 +182,21 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
compressor(g.c_logging_compression_flag));
if (g.c_encryption)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",encryption=(name=%s)", encryptor(g.c_encryption_flag));
/* Miscellaneous. */
#ifdef HAVE_POSIX_MEMALIGN
- p += snprintf(p, REMAIN(p, end), ",buffer_alignment=512");
+ CONFIG_APPEND(p, ",buffer_alignment=512");
#endif
- p += snprintf(p, REMAIN(p, end), ",mmap=%d", g.c_mmap ? 1 : 0);
+ CONFIG_APPEND(p, ",mmap=%d", g.c_mmap ? 1 : 0);
if (g.c_direct_io)
- p += snprintf(p, REMAIN(p, end), ",direct_io=(data)");
+ CONFIG_APPEND(p, ",direct_io=(data)");
if (g.c_data_extend)
- p += snprintf(p, REMAIN(p, end), ",file_extend=(data=8MB)");
+ CONFIG_APPEND(p, ",file_extend=(data=8MB)");
/*
* Run the statistics server and/or maintain statistics in the engine.
@@ -198,18 +205,18 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
if (g.c_statistics_server) {
if (mmrand(NULL, 0, 5) == 1 &&
memcmp(g.uri, "file:", strlen("file:")) == 0)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",statistics=(fast)"
",statistics_log=(wait=5,sources=(\"file:\"))");
else
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",statistics=(fast),statistics_log=(wait=5)");
} else
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",statistics=(%s)", g.c_statistics ? "fast" : "none");
/* Extensions. */
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",extensions=["
"\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"],",
g.c_reverse ? REVERSE_PATH : "",
@@ -227,11 +234,11 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
* override the standard configuration.
*/
if (g.c_config_open != NULL)
- p += snprintf(p, REMAIN(p, end), ",%s", g.c_config_open);
+ CONFIG_APPEND(p, ",%s", g.c_config_open);
if (g.config_open != NULL)
- p += snprintf(p, REMAIN(p, end), ",%s", g.config_open);
+ CONFIG_APPEND(p, ",%s", g.config_open);
- if (REMAIN(p, end) == 0)
+ if (max == 0)
testutil_die(ENOMEM,
"wiredtiger_open configuration buffer too small");
@@ -259,12 +266,13 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
if (DATASOURCE("helium")) {
if (g.helium_mount == NULL)
testutil_die(EINVAL, "no Helium mount point specified");
- (void)snprintf(helium_config, sizeof(helium_config),
+ testutil_check(
+ __wt_snprintf(helium_config, sizeof(helium_config),
"entry=wiredtiger_extension_init,config=["
"helium_verbose=0,"
"dev1=[helium_devices=\"he://./%s\","
"helium_o_volume_truncate=1]]",
- g.helium_mount);
+ g.helium_mount));
if ((ret = conn->load_extension(
conn, HELIUM_PATH, helium_config)) != 0)
testutil_die(ret,
@@ -299,13 +307,13 @@ wts_init(void)
{
WT_CONNECTION *conn;
WT_SESSION *session;
+ size_t max;
uint32_t maxintlpage, maxintlkey, maxleafpage, maxleafkey, maxleafvalue;
- char config[4096], *end, *p;
+ char config[4096], *p;
conn = g.wts_conn;
-
p = config;
- end = config + sizeof(config);
+ max = sizeof(config);
/*
* Ensure that we can service at least one operation per-thread
@@ -326,7 +334,7 @@ wts_init(void)
if (maxleafpage > 512)
maxleafpage >>= 1;
}
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
"key_format=%s,"
"allocation_size=512,%s"
"internal_page_max=%" PRIu32 ",leaf_page_max=%" PRIu32,
@@ -340,43 +348,35 @@ wts_init(void)
*/
maxintlkey = mmrand(NULL, maxintlpage / 50, maxintlpage / 40);
if (maxintlkey > 20)
- p += snprintf(p, REMAIN(p, end),
- ",internal_key_max=%" PRIu32, maxintlkey);
+ CONFIG_APPEND(p, ",internal_key_max=%" PRIu32, maxintlkey);
maxleafkey = mmrand(NULL, maxleafpage / 50, maxleafpage / 40);
if (maxleafkey > 20)
- p += snprintf(p, REMAIN(p, end),
- ",leaf_key_max=%" PRIu32, maxleafkey);
+ CONFIG_APPEND(p, ",leaf_key_max=%" PRIu32, maxleafkey);
maxleafvalue = mmrand(NULL, maxleafpage * 10, maxleafpage / 40);
if (maxleafvalue > 40 && maxleafvalue < 100 * 1024)
- p += snprintf(p, REMAIN(p, end),
- ",leaf_value_max=%" PRIu32, maxleafvalue);
+ CONFIG_APPEND(p, ",leaf_value_max=%" PRIu32, maxleafvalue);
switch (g.type) {
case FIX:
- p += snprintf(p, REMAIN(p, end),
- ",value_format=%" PRIu32 "t", g.c_bitcnt);
+ CONFIG_APPEND(p, ",value_format=%" PRIu32 "t", g.c_bitcnt);
break;
case ROW:
if (g.c_huffman_key)
- p += snprintf(p, REMAIN(p, end),
- ",huffman_key=english");
+ CONFIG_APPEND(p, ",huffman_key=english");
if (g.c_prefix_compression)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",prefix_compression_min=%" PRIu32,
g.c_prefix_compression_min);
else
- p += snprintf(p, REMAIN(p, end),
- ",prefix_compression=false");
+ CONFIG_APPEND(p, ",prefix_compression=false");
if (g.c_reverse)
- p += snprintf(p, REMAIN(p, end),
- ",collator=reverse");
+ CONFIG_APPEND(p, ",collator=reverse");
/* FALLTHROUGH */
case VAR:
if (g.c_huffman_value)
- p += snprintf(p, REMAIN(p, end),
- ",huffman_value=english");
+ CONFIG_APPEND(p, ",huffman_value=english");
if (g.c_dictionary)
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",dictionary=%" PRIu32, mmrand(NULL, 123, 517));
break;
}
@@ -384,66 +384,63 @@ wts_init(void)
/* Configure checksums. */
switch (g.c_checksum_flag) {
case CHECKSUM_OFF:
- p += snprintf(p, REMAIN(p, end), ",checksum=\"off\"");
+ CONFIG_APPEND(p, ",checksum=\"off\"");
break;
case CHECKSUM_ON:
- p += snprintf(p, REMAIN(p, end), ",checksum=\"on\"");
+ CONFIG_APPEND(p, ",checksum=\"on\"");
break;
case CHECKSUM_UNCOMPRESSED:
- p += snprintf(p, REMAIN(p, end), ",checksum=\"uncompressed\"");
+ CONFIG_APPEND(p, ",checksum=\"uncompressed\"");
break;
}
/* Configure compression. */
if (g.c_compression_flag != COMPRESS_NONE)
- p += snprintf(p, REMAIN(p, end), ",block_compressor=\"%s\"",
+ CONFIG_APPEND(p, ",block_compressor=\"%s\"",
compressor(g.c_compression_flag));
/* Configure Btree internal key truncation. */
- p += snprintf(p, REMAIN(p, end), ",internal_key_truncate=%s",
+ CONFIG_APPEND(p, ",internal_key_truncate=%s",
g.c_internal_key_truncation ? "true" : "false");
/* Configure Btree page key gap. */
- p += snprintf(p, REMAIN(p, end), ",key_gap=%" PRIu32, g.c_key_gap);
+ CONFIG_APPEND(p, ",key_gap=%" PRIu32, g.c_key_gap);
/* Configure Btree split page percentage. */
- p += snprintf(p, REMAIN(p, end), ",split_pct=%" PRIu32, g.c_split_pct);
+ CONFIG_APPEND(p, ",split_pct=%" PRIu32, g.c_split_pct);
/* Configure LSM and data-sources. */
if (DATASOURCE("helium"))
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
",type=helium,helium_o_compress=%d,helium_o_truncate=1",
g.c_compression_flag == COMPRESS_NONE ? 0 : 1);
if (DATASOURCE("kvsbdb"))
- p += snprintf(p, REMAIN(p, end), ",type=kvsbdb");
+ CONFIG_APPEND(p, ",type=kvsbdb");
if (DATASOURCE("lsm")) {
- p += snprintf(p, REMAIN(p, end), ",type=lsm,lsm=(");
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p, ",type=lsm,lsm=(");
+ CONFIG_APPEND(p,
"auto_throttle=%s,", g.c_auto_throttle ? "true" : "false");
- p += snprintf(p, REMAIN(p, end),
- "chunk_size=%" PRIu32 "MB,", g.c_chunk_size);
+ CONFIG_APPEND(p, "chunk_size=%" PRIu32 "MB,", g.c_chunk_size);
/*
* We can't set bloom_oldest without bloom, and we want to test
* with Bloom filters on most of the time anyway.
*/
if (g.c_bloom_oldest)
g.c_bloom = 1;
- p += snprintf(p, REMAIN(p, end),
- "bloom=%s,", g.c_bloom ? "true" : "false");
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p, "bloom=%s,", g.c_bloom ? "true" : "false");
+ CONFIG_APPEND(p,
"bloom_bit_count=%" PRIu32 ",", g.c_bloom_bit_count);
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
"bloom_hash_count=%" PRIu32 ",", g.c_bloom_hash_count);
- p += snprintf(p, REMAIN(p, end),
+ CONFIG_APPEND(p,
"bloom_oldest=%s,", g.c_bloom_oldest ? "true" : "false");
- p += snprintf(p, REMAIN(p, end),
- "merge_max=%" PRIu32 ",", g.c_merge_max);
- p += snprintf(p, REMAIN(p, end), ",)");
+ CONFIG_APPEND(p, "merge_max=%" PRIu32 ",", g.c_merge_max);
+ CONFIG_APPEND(p, ",)");
}
- if (REMAIN(p, end) == 0)
+ if (max == 0)
testutil_die(ENOMEM,
"WT_SESSION.create configuration buffer too small");
@@ -490,14 +487,14 @@ wts_dump(const char *tag, int dump_bdb)
len = strlen(g.home) + strlen(BERKELEY_DB_PATH) + strlen(g.uri) + 100;
cmd = dmalloc(len);
- (void)snprintf(cmd, len,
+ testutil_check(__wt_snprintf(cmd, len,
"sh s_dumpcmp -h %s %s %s %s %s %s",
g.home,
dump_bdb ? "-b " : "",
dump_bdb ? BERKELEY_DB_PATH : "",
g.type == FIX || g.type == VAR ? "-c" : "",
g.uri == NULL ? "" : "-n",
- g.uri == NULL ? "" : g.uri);
+ g.uri == NULL ? "" : g.uri));
testutil_checkfmt(system(cmd), "%s: dump comparison failed", tag);
free(cmd);
@@ -587,7 +584,7 @@ wts_stats(void)
fprintf(fp, "\n\n====== Data source statistics:\n");
len = strlen("statistics:") + strlen(g.uri) + 1;
stat_name = dmalloc(len);
- snprintf(stat_name, len, "statistics:%s", g.uri);
+ testutil_check(__wt_snprintf(stat_name, len, "statistics:%s", g.uri));
testutil_check(session->open_cursor(
session, stat_name, NULL, NULL, &cursor));
free(stat_name);