summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2014-02-26 16:09:21 +1100
committerAlex Gorrod <alexg@wiredtiger.com>2014-02-26 16:09:21 +1100
commite95fe42a0b9509244d2e9c5ab6138ba02c416a90 (patch)
tree0f1f04a4e6e490ce63fedcd47b9c1a02631d07b6
parent6bb1d7c51208f8d99bdca4d194d661360952cb77 (diff)
parentaf1793bf189527f7bc6d6133f065a0007cdd2fb9 (diff)
downloadmongo-e95fe42a0b9509244d2e9c5ab6138ba02c416a90.tar.gz
Merge branch 'config-parse-api' into wtperf-multiple-databases
Conflicts: bench/wtperf/wtperf.c bench/wtperf/wtperf.h
-rw-r--r--bench/wtperf/config.c44
-rw-r--r--bench/wtperf/runners/test1-500m-lsm.wtperf3
-rw-r--r--bench/wtperf/runners/test2-500m-lsm.wtperf5
-rw-r--r--bench/wtperf/runners/test3-500m-lsm.wtperf3
-rw-r--r--bench/wtperf/runners/test4-500m-lsm.wtperf3
-rw-r--r--bench/wtperf/wtperf.c250
-rw-r--r--bench/wtperf/wtperf.h2
-rw-r--r--bench/wtperf/wtperf_opt.i4
-rw-r--r--dist/s_funcs.list1
-rw-r--r--dist/s_string.ok1
-rw-r--r--dist/s_symbols.list1
-rw-r--r--examples/c/Makefile.am1
-rw-r--r--examples/c/ex_config_parse.c166
-rw-r--r--examples/c/ex_data_source.c49
-rw-r--r--ext/datasources/helium/helium.c65
-rw-r--r--lang/java/java_doc.i3
-rw-r--r--src/btree/bt_discard.c4
-rw-r--r--src/btree/bt_evict.c3
-rw-r--r--src/config/config.c6
-rw-r--r--src/config/config_api.c123
-rw-r--r--src/config/config_ext.c91
-rw-r--r--src/conn/conn_api.c20
-rw-r--r--src/docs/Doxyfile1
-rw-r--r--src/docs/command-line.dox3
-rw-r--r--src/docs/custom_data.dox5
-rw-r--r--src/docs/helium.dox2
-rw-r--r--src/include/cache.h2
-rw-r--r--src/include/config.h8
-rw-r--r--src/include/extern.h21
-rw-r--r--src/include/txn.i18
-rw-r--r--src/include/wiredtiger.in154
-rw-r--r--src/include/wiredtiger_ext.h82
-rw-r--r--src/include/wt_internal.h2
-rw-r--r--src/lsm/lsm_cursor.c2
-rw-r--r--tools/wtperf_stats.py13
35 files changed, 623 insertions, 538 deletions
diff --git a/bench/wtperf/config.c b/bench/wtperf/config.c
index 63944f802bc..800c760f72d 100644
--- a/bench/wtperf/config.c
+++ b/bench/wtperf/config.c
@@ -69,8 +69,8 @@ config_assign(CONFIG *dest, const CONFIG *src)
dest->popthreads = NULL;
dest->workers = NULL;
- if (src->uri != NULL)
- dest->uri = strdup(src->uri);
+ if (src->base_uri != NULL)
+ dest->base_uri = strdup(src->base_uri);
if (src->workload != NULL) {
dest->workload = calloc(WORKLOAD_MAX, sizeof(WORKLOAD));
memcpy(dest->workload,
@@ -121,7 +121,7 @@ config_free(CONFIG *cfg)
free(cfg->ckptthreads);
free(cfg->popthreads);
- free(cfg->uri);
+ free(cfg->base_uri);
free(cfg->workers);
free(cfg->workload);
}
@@ -168,9 +168,10 @@ config_threads(CONFIG *cfg, const char *config, size_t len)
{
WORKLOAD *workp;
WT_CONFIG_ITEM groupk, groupv, k, v;
- WT_CONFIG_SCAN *group, *scan;
+ WT_CONFIG_PARSER *group, *scan;
int ret;
+ group = scan = NULL;
/* Allocate the workload array. */
if ((cfg->workload = calloc(WORKLOAD_MAX, sizeof(WORKLOAD))) == NULL)
return (enomem(cfg));
@@ -185,11 +186,10 @@ config_threads(CONFIG *cfg, const char *config, size_t len)
* returned from the original string.
*/
if ((ret =
- wiredtiger_config_scan_begin(NULL, config, len, &group)) != 0)
+ wiredtiger_config_parser_open(NULL, config, len, &group)) != 0)
goto err;
- while ((ret =
- wiredtiger_config_scan_next(NULL, group, &groupk, &groupv)) == 0) {
- if ((ret = wiredtiger_config_scan_begin(
+ while ((ret = group->next(group, &groupk, &groupv)) == 0) {
+ if ((ret = wiredtiger_config_parser_open(
NULL, groupk.str, groupk.len, &scan)) != 0)
goto err;
@@ -203,8 +203,7 @@ config_threads(CONFIG *cfg, const char *config, size_t len)
}
workp = &cfg->workload[cfg->workload_cnt++];
- while ((ret =
- wiredtiger_config_scan_next(NULL, scan, &k, &v)) == 0) {
+ while ((ret = scan->next(scan, &k, &v)) == 0) {
if (STRING_MATCH("count", k.str, k.len)) {
if ((workp->threads = v.val) <= 0)
goto err;
@@ -234,8 +233,10 @@ config_threads(CONFIG *cfg, const char *config, size_t len)
ret = 0;
if (ret != 0 )
goto err;
- if ((ret = wiredtiger_config_scan_end(NULL, scan)) != 0)
+ if ((ret = scan->close(scan)) != 0) {
+ scan = NULL;
goto err;
+ }
if (workp->insert == 0 &&
workp->read == 0 && workp->update == 0)
@@ -243,12 +244,19 @@ config_threads(CONFIG *cfg, const char *config, size_t len)
cfg->workers_cnt += (u_int)workp->threads;
}
- if ((ret = wiredtiger_config_scan_end(NULL, group)) != 0)
+ if ((ret = group->close(group)) != 0) {
+ group = NULL;
goto err;
+ }
return (0);
-err: fprintf(stderr,
+err: if (group != NULL)
+ (void)group->close(group);
+ if (scan != NULL)
+ (void)scan->close(scan);
+
+ fprintf(stderr,
"invalid thread configuration or scan error: %.*s\n",
(int)len, config);
return (EINVAL);
@@ -461,19 +469,17 @@ int
config_opt_line(CONFIG *cfg, const char *optstr)
{
WT_CONFIG_ITEM k, v;
- WT_CONFIG_SCAN *scan;
+ WT_CONFIG_PARSER *scan;
int ret, t_ret;
-
- if ((ret = wiredtiger_config_scan_begin(
+ if ((ret = wiredtiger_config_parser_open(
NULL, optstr, strlen(optstr), &scan)) != 0) {
lprintf(cfg, ret, 0, "Error in config_scan_begin");
return (ret);
}
while (ret == 0) {
- if ((ret =
- wiredtiger_config_scan_next(NULL, scan, &k, &v)) != 0) {
+ if ((ret = scan->next(scan, &k, &v)) != 0) {
/* Any parse error has already been reported. */
if (ret == WT_NOTFOUND)
ret = 0;
@@ -481,7 +487,7 @@ config_opt_line(CONFIG *cfg, const char *optstr)
}
ret = config_opt(cfg, &k, &v);
}
- if ((t_ret = wiredtiger_config_scan_end(NULL, scan)) != 0) {
+ if ((t_ret = scan->close(scan)) != 0) {
lprintf(cfg, ret, 0, "Error in config_scan_end");
if (ret == 0)
ret = t_ret;
diff --git a/bench/wtperf/runners/test1-500m-lsm.wtperf b/bench/wtperf/runners/test1-500m-lsm.wtperf
index 0e79bdddb12..7f85b8c13e5 100644
--- a/bench/wtperf/runners/test1-500m-lsm.wtperf
+++ b/bench/wtperf/runners/test1-500m-lsm.wtperf
@@ -5,8 +5,9 @@
#conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024,statistics=(fast,clear),statistics_log=(wait=60)"
conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024"
compact=true
+compression="snappy"
sess_config="isolation=snapshot"
-table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=100GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
+table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=5GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
icount=500000000
key_sz=40
value_sz=1000
diff --git a/bench/wtperf/runners/test2-500m-lsm.wtperf b/bench/wtperf/runners/test2-500m-lsm.wtperf
index f305ad621d0..db1ee9d469c 100644
--- a/bench/wtperf/runners/test2-500m-lsm.wtperf
+++ b/bench/wtperf/runners/test2-500m-lsm.wtperf
@@ -6,8 +6,9 @@
#conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024,statistics=(fast,clear),statistics_log=(wait=60)"
conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024"
create=false
-sess_config="isolation=snapshot"
-table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=100GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
+compression="snappy"
+sess_config="isolation=snapshot
+table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=5GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
key_sz=40
value_sz=1000
report_interval=10
diff --git a/bench/wtperf/runners/test3-500m-lsm.wtperf b/bench/wtperf/runners/test3-500m-lsm.wtperf
index 4960d52b869..446309c32c8 100644
--- a/bench/wtperf/runners/test3-500m-lsm.wtperf
+++ b/bench/wtperf/runners/test3-500m-lsm.wtperf
@@ -6,8 +6,9 @@
#conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024,statistics=(fast,clear),statistics_log=(wait=60)"
conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024"
create=false
+compression="snappy"
sess_config="isolation=snapshot"
-table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=100GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
+table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=5GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
key_sz=40
value_sz=1000
pareto=true
diff --git a/bench/wtperf/runners/test4-500m-lsm.wtperf b/bench/wtperf/runners/test4-500m-lsm.wtperf
index 624241bb934..a959ec9057e 100644
--- a/bench/wtperf/runners/test4-500m-lsm.wtperf
+++ b/bench/wtperf/runners/test4-500m-lsm.wtperf
@@ -6,8 +6,9 @@
#conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024,statistics=(fast,clear),statistics_log=(wait=60)"
conn_config="cache_size=21G,checkpoint_sync=false,mmap=false,session_max=1024"
create=false
+compression="snappy"
sess_config="isolation=snapshot"
-table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=100GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
+table_config="internal_page_max=128K,lsm=(bloom_config=(leaf_page_max=8MB),bloom_bit_count=28,bloom_hash_count=19,bloom_oldest=true,chunk_max=5GB,chunk_size=100MB,merge_threads=3),type=lsm,leaf_page_max=16K"
key_sz=40
value_sz=1000
report_interval=10
diff --git a/bench/wtperf/wtperf.c b/bench/wtperf/wtperf.c
index 94afcf01e85..df78bca021f 100644
--- a/bench/wtperf/wtperf.c
+++ b/bench/wtperf/wtperf.c
@@ -31,7 +31,7 @@
static const CONFIG default_cfg = {
"WT_TEST", /* home */
"WT_TEST", /* monitor dir */
- NULL, /* uri */
+ NULL, /* base_uri */
NULL, /* uris */
NULL, /* helium_mount */
NULL, /* conn */
@@ -212,28 +212,21 @@ worker(void *arg)
lprintf(cfg, ret, 0, "worker: WT_CONNECTION.open_session");
goto err;
}
- if (cfg->table_count > 1) {
- cursors = (WT_CURSOR **)calloc(
- cfg->table_count, sizeof(WT_CURSOR *));
- if (cursors == NULL) {
- lprintf(cfg, ENOMEM, 0,
- "worker: couldn't allocate cursor array");
+ cursors = (WT_CURSOR **)calloc(
+ cfg->table_count, sizeof(WT_CURSOR *));
+ if (cursors == NULL) {
+ lprintf(cfg, ENOMEM, 0,
+ "worker: couldn't allocate cursor array");
+ goto err;
+ }
+ for (i = 0; i < cfg->table_count; i++) {
+ if ((ret = session->open_cursor(session,
+ cfg->uris[i], NULL, NULL, &cursors[i])) != 0) {
+ lprintf(cfg, ret, 0,
+ "worker: WT_SESSION.open_cursor: %s",
+ cfg->uris[i]);
goto err;
}
- for (i = 0; i < cfg->table_count; i++) {
- if ((ret = session->open_cursor(session,
- cfg->uris[i], NULL, NULL, &cursors[i])) != 0) {
- lprintf(cfg, ret, 0,
- "worker: WT_SESSION.open_cursor: %s",
- cfg->uris[i]);
- goto err;
- }
- }
- } else if ((ret = session->open_cursor(
- session, cfg->uri, NULL, NULL, &cursor)) != 0) {
- lprintf(cfg,
- ret, 0, "worker: WT_SESSION.open_cursor: %s", cfg->uri);
- goto err;
}
key_buf = thread->key_buf;
@@ -243,11 +236,6 @@ worker(void *arg)
op_end = op + sizeof(thread->workload->ops);
while (!cfg->stop) {
- /* Pick a cursor if there are multiple tables. */
- if (cfg->table_count > 1)
- cursor = cursors[
- __wt_random() % (cfg->table_count - 1)];
-
/*
* Generate the next key and setup operation specific
* statistics tracking objects.
@@ -282,7 +270,18 @@ worker(void *arg)
}
sprintf(key_buf, "%0*" PRIu64, cfg->key_sz, next_val);
- measure_latency = cfg->sample_interval != 0 && (
+
+ /*
+ * Spread the data out around the multiple databases.
+ */
+ cursor = cursors[next_val % cfg->table_count];
+
+ /*
+ * Skip the first time we do an operation, when trk->ops
+ * is 0, to avoid first time latency spikes.
+ */
+ measure_latency =
+ cfg->sample_interval != 0 && trk->ops != 0 && (
trk->ops % cfg->sample_rate == 0);
if (measure_latency &&
(ret = __wt_epoch(NULL, &start)) != 0) {
@@ -529,30 +528,23 @@ populate_thread(void *arg)
/* Do bulk loads if populate is single-threaded. */
cursor_config = cfg->populate_threads == 1 ? "bulk" : NULL;
- /* Create the cursor or cursors if there are multiple tables. */
- if (cfg->table_count > 1) {
- cursors = (WT_CURSOR **)calloc(
- cfg->table_count, sizeof(WT_CURSOR *));
- if (cursors == NULL) {
- lprintf(cfg, ENOMEM, 0,
- "worker: couldn't allocate cursor array");
+ /* Create the cursors. */
+ cursors = (WT_CURSOR **)calloc(
+ cfg->table_count, sizeof(WT_CURSOR *));
+ if (cursors == NULL) {
+ lprintf(cfg, ENOMEM, 0,
+ "worker: couldn't allocate cursor array");
+ goto err;
+ }
+ for (i = 0; i < cfg->table_count; i++) {
+ if ((ret = session->open_cursor(
+ session, cfg->uris[i], NULL,
+ cursor_config, &cursors[i])) != 0) {
+ lprintf(cfg, ret, 0,
+ "populate: WT_SESSION.open_cursor: %s",
+ cfg->uris[i]);
goto err;
}
- for (i = 0; i < cfg->table_count; i++) {
- if ((ret = session->open_cursor(
- session, cfg->uris[i], NULL,
- cursor_config, &cursors[i])) != 0) {
- lprintf(cfg, ret, 0,
- "populate: WT_SESSION.open_cursor: %s",
- cfg->uris[i]);
- goto err;
- }
- }
- } else if ((ret = session->open_cursor(
- session, cfg->uri, NULL, cursor_config, &cursor)) != 0) {
- lprintf(cfg,
- ret, 0, "populate: WT_SESSION.open_cursor: %s", cfg->uri);
- goto err;
}
/* Populate the databases. */
@@ -570,38 +562,44 @@ populate_thread(void *arg)
}
intxn = 1;
}
+ /*
+ * Figure out which table this op belongs to.
+ */
+ cursor = cursors[op % cfg->table_count];
sprintf(key_buf, "%0*" PRIu64, cfg->key_sz, op);
- measure_latency = cfg->sample_interval != 0 && (
+ measure_latency =
+ cfg->sample_interval != 0 && trk->ops != 0 && (
trk->ops % cfg->sample_rate == 0);
if (measure_latency &&
(ret = __wt_epoch(NULL, &start)) != 0) {
lprintf(cfg, ret, 0, "Get time call failed");
goto err;
}
- for (i = 0; i < cfg->table_count; i++) {
- if (cfg->table_count > 1)
- cursor = cursors[i];
- cursor->set_key(cursor, key_buf);
- if (cfg->random_value)
- randomize_value(cfg, value_buf);
- cursor->set_value(cursor, value_buf);
- if ((ret = cursor->insert(cursor)) != 0) {
- lprintf(cfg, ret, 0, "Failed inserting");
+ cursor->set_key(cursor, key_buf);
+ if (cfg->random_value)
+ randomize_value(cfg, value_buf);
+ cursor->set_value(cursor, value_buf);
+ if ((ret = cursor->insert(cursor)) != 0) {
+ lprintf(cfg, ret, 0, "Failed inserting");
+ goto err;
+ }
+ /*
+ * Gather statistics.
+ * We measure the latency of inserting a single key. If there
+ * are multiple tables, it is the time for insertion into all
+ * of them.
+ */
+ if (measure_latency) {
+ if ((ret = __wt_epoch(NULL, &stop)) != 0) {
+ lprintf(cfg, ret, 0,
+ "Get time call failed");
goto err;
}
- /* Gather statistics */
- if (measure_latency) {
- if ((ret = __wt_epoch(NULL, &stop)) != 0) {
- lprintf(cfg, ret, 0,
- "Get time call failed");
- goto err;
- }
- ++trk->latency_ops;
- usecs = ns_to_us(WT_TIMEDIFF(stop, start));
- track_operation(trk, usecs);
- }
- ++thread->insert.ops; /* Same as trk->ops */
+ ++trk->latency_ops;
+ usecs = ns_to_us(WT_TIMEDIFF(stop, start));
+ track_operation(trk, usecs);
}
+ ++thread->insert.ops; /* Same as trk->ops */
if (cfg->populate_ops_per_txn != 0) {
if (++opcount < cfg->populate_ops_per_txn)
@@ -833,6 +831,7 @@ execute_populate(CONFIG *cfg)
WT_SESSION *session;
struct timespec start, stop;
double secs;
+ size_t i;
uint64_t last_ops;
uint32_t interval;
int elapsed, ret, t_ret;
@@ -927,12 +926,17 @@ execute_populate(CONFIG *cfg)
lprintf(cfg, ret, 0, "Get time failed in populate.");
goto err;
}
- if ((ret = session->compact(
- session, cfg->uri, "timeout=0")) != 0) {
- lprintf(cfg, ret, 0,
- "execute_populate: WT_SESSION.compact");
- goto err;
- }
+ /*
+ * We measure how long it takes to compact all tables for this
+ * workload.
+ */
+ for (i = 0; i < cfg->table_count; i++)
+ if ((ret = session->compact(
+ session, cfg->uris[i], "timeout=0")) != 0) {
+ lprintf(cfg, ret, 0,
+ "execute_populate: WT_SESSION.compact");
+ goto err;
+ }
if ((ret = __wt_epoch(NULL, &stop)) != 0) {
lprintf(cfg, ret, 0, "Get time failed in populate.");
goto err;
@@ -1085,47 +1089,54 @@ find_table_count(CONFIG *cfg)
WT_CURSOR *cursor;
WT_SESSION *session;
char *key;
+ uint32_t i, max_icount, table_icount;
int ret, t_ret;
conn = cfg->conn;
+ max_icount = 0;
if ((ret = conn->open_session(
conn, NULL, cfg->sess_config, &session)) != 0) {
lprintf(cfg, ret, 0,
- "open_session failed finding existing table count");
- goto err;
- }
- if ((ret = session->open_cursor(session, cfg->uri,
- NULL, NULL, &cursor)) != 0) {
- lprintf(cfg, ret, 0,
- "open_cursor failed finding existing table count");
- goto err;
- }
- if ((ret = cursor->prev(cursor)) != 0) {
- lprintf(cfg, ret, 0,
- "cursor prev failed finding existing table count");
- goto err;
- }
- if ((ret = cursor->get_key(cursor, &key)) != 0) {
- lprintf(cfg, ret, 0,
- "cursor get_key failed finding existing table count");
- goto err;
+ "find_table_count: open_session failed");
+ goto out;
}
- cfg->icount = (uint32_t)atoi(key);
+ for (i = 0; i < cfg->table_count; i++) {
+ if ((ret = session->open_cursor(session, cfg->uris[i],
+ NULL, NULL, &cursor)) != 0) {
+ lprintf(cfg, ret, 0,
+ "find_table_count: open_cursor failed");
+ goto err;
+ }
+ if ((ret = cursor->prev(cursor)) != 0) {
+ lprintf(cfg, ret, 0,
+ "find_table_count: cursor prev failed");
+ goto err;
+ }
+ if ((ret = cursor->get_key(cursor, &key)) != 0) {
+ lprintf(cfg, ret, 0,
+ "find_table_count: cursor get_key failed");
+ goto err;
+ }
+ table_icount = (uint32_t)atoi(key);
+ if (table_icount > max_icount)
+ max_icount = table_icount;
-err: if ((t_ret = session->close(session, NULL)) != 0) {
- if (ret == 0)
- ret = t_ret;
- lprintf(cfg, ret, 0,
- "session close failed finding existing table count");
+err: if ((t_ret = session->close(session, NULL)) != 0) {
+ if (ret == 0)
+ ret = t_ret;
+ lprintf(cfg, ret, 0,
+ "find_table_count: session close failed");
+ }
}
- return (ret);
+ cfg->icount = max_icount;
+out: return (ret);
}
/*
* Populate the uri array if more than one table is being used.
*/
-int
+static int
create_uris(CONFIG *cfg)
{
char *uri;
@@ -1134,12 +1145,7 @@ create_uris(CONFIG *cfg)
uint32_t i;
ret = 0;
- if (cfg->table_count < 2) {
- cfg->uris = NULL;
- return (0);
- }
-
- base_uri_len = strlen(cfg->uri);
+ base_uri_len = strlen(cfg->base_uri);
cfg->uris = (char **)calloc(cfg->table_count, sizeof(char *));
if (cfg->uris == NULL) {
ret = ENOMEM;
@@ -1151,10 +1157,15 @@ create_uris(CONFIG *cfg)
ret = ENOMEM;
goto err;
}
- memcpy(uri, cfg->uri, base_uri_len);
- uri[base_uri_len] = uri[base_uri_len + 1] = '0';
- uri[base_uri_len] = '0' + (i / 10);
- uri[base_uri_len + 1] = '0' + (i % 10);
+ memcpy(uri, cfg->base_uri, base_uri_len);
+ /*
+ * If there is only one table, just use base name.
+ */
+ if (cfg->table_count > 1) {
+ uri[base_uri_len] = uri[base_uri_len + 1] = '0';
+ uri[base_uri_len] = '0' + (i / 10);
+ uri[base_uri_len + 1] = '0' + (i % 10);
+ }
}
err: if (ret != 0 && cfg->uris != NULL) {
for (i = 0; i < cfg->table_count; i++)
@@ -1165,7 +1176,7 @@ err: if (ret != 0 && cfg->uris != NULL) {
return (ret);
}
-int
+static int
create_tables(CONFIG *cfg)
{
WT_SESSION *session;
@@ -1177,7 +1188,7 @@ create_tables(CONFIG *cfg)
if (cfg->create == 0)
return (0);
- uri = cfg->uri;
+ uri = cfg->base_uri;
if ((ret = cfg->conn->open_session(
cfg->conn, NULL, cfg->sess_config, &session)) != 0) {
lprintf(cfg, ret, 0,
@@ -1185,12 +1196,11 @@ create_tables(CONFIG *cfg)
return (ret);
}
for (i = 0; i < cfg->table_count; i++) {
- if (cfg->table_count > 1)
- uri = cfg->uris[i];
+ uri = cfg->uris[i];
if ((ret = session->create(
session, uri, cfg->table_config)) != 0) {
lprintf(cfg, ret, 0,
- "Error creating table %s", cfg->uri);
+ "Error creating table %s", cfg->uris[i]);
return (ret);
}
}
@@ -1530,11 +1540,11 @@ main(int argc, char *argv[])
/* Build the URI from the table name. */
req_len = strlen("table:") +
strlen(HELIUM_NAME) + strlen(cfg->table_name) + 2;
- if ((cfg->uri = calloc(req_len, 1)) == NULL) {
+ if ((cfg->base_uri = calloc(req_len, 1)) == NULL) {
ret = enomem(cfg);
goto err;
}
- snprintf(cfg->uri, req_len, "table:%s%s%s",
+ snprintf(cfg->base_uri, req_len, "table:%s%s%s",
cfg->helium_mount == NULL ? "" : HELIUM_NAME,
cfg->helium_mount == NULL ? "" : "/",
cfg->table_name);
diff --git a/bench/wtperf/wtperf.h b/bench/wtperf/wtperf.h
index 15d296d00a0..c94ec10d8fd 100644
--- a/bench/wtperf/wtperf.h
+++ b/bench/wtperf/wtperf.h
@@ -83,7 +83,7 @@ typedef struct {
struct __config { /* Configuration struction */
const char *home; /* WiredTiger home */
const char *monitor_dir; /* Monitor output dir */
- char *uri; /* Object URI */
+ char *base_uri; /* Object URI */
char **uris; /* URIs if multiple tables */
const char *helium_mount; /* Optional Helium mount point */
diff --git a/bench/wtperf/wtperf_opt.i b/bench/wtperf/wtperf_opt.i
index af50e7e9bf3..0fff7a14416 100644
--- a/bench/wtperf/wtperf_opt.i
+++ b/bench/wtperf/wtperf_opt.i
@@ -123,8 +123,8 @@ DEF_OPT_AS_CONFIG_STRING(table_config,
"leaf_page_max=4kb,internal_page_max=64kb,allocation_size=4kb,",
"table configuration string")
DEF_OPT_AS_UINT32(table_count, 1,
- "number of tables to run operations over. Operations are spread evenly "
- "over the tables amongst all threads. Default 1, maximum 99.")
+ "number of tables to run operations over. Keys are divided evenly "
+ "over the tables. Default 1, maximum 99.")
DEF_OPT_AS_STRING(threads, "", "workload configuration: each 'count' "
"entry is the total number of threads, and the 'insert', 'read' and "
"'update' entries are the ratios of insert, read and update operations "
diff --git a/dist/s_funcs.list b/dist/s_funcs.list
index b34564adda7..6ffb956f59e 100644
--- a/dist/s_funcs.list
+++ b/dist/s_funcs.list
@@ -22,6 +22,7 @@ __wt_log_scan
__wt_nlpo2
__wt_nlpo2_round
__wt_print_huffman_code
+wiredtiger_config_parser_open
wiredtiger_pack_int
wiredtiger_pack_item
wiredtiger_pack_str
diff --git a/dist/s_string.ok b/dist/s_string.ok
index a71cca62a8c..5f0d331e105 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -688,6 +688,7 @@ openfile
os
ovfl
packv
+parserp
patchp
pathname
pathnames
diff --git a/dist/s_symbols.list b/dist/s_symbols.list
index a66af1f8994..d3803bc3afa 100644
--- a/dist/s_symbols.list
+++ b/dist/s_symbols.list
@@ -1,4 +1,5 @@
# List of OK external symbols.
+wiredtiger_config_parser_open
wiredtiger_open
wiredtiger_pack_close
wiredtiger_pack_int
diff --git a/examples/c/Makefile.am b/examples/c/Makefile.am
index bd281df7130..5b43dcc2285 100644
--- a/examples/c/Makefile.am
+++ b/examples/c/Makefile.am
@@ -6,6 +6,7 @@ noinst_PROGRAMS = \
ex_all \
ex_call_center \
ex_config \
+ ex_config_parse \
ex_cursor \
ex_data_source \
ex_extending \
diff --git a/examples/c/ex_config_parse.c b/examples/c/ex_config_parse.c
new file mode 100644
index 00000000000..c6adc327c78
--- /dev/null
+++ b/examples/c/ex_config_parse.c
@@ -0,0 +1,166 @@
+/*-
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ex_config_parse.c
+ * This is an example demonstrating how to parse WiredTiger compatible
+ * configuration strings.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <wiredtiger.h>
+
+const char *home = NULL;
+
+int main(void)
+{
+ int ret;
+
+ /*! [Create a configuration parser] */
+ WT_CONFIG_ITEM k, v;
+ WT_CONFIG_PARSER *parser;
+ const char *config_string =
+ "path=/dev/loop,page_size=1024,log=(archive=true,file_max=20MB)";
+
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser)) != 0) {
+ fprintf(stderr, "Error creating configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+ if ((ret = parser->close(parser)) != 0) {
+ fprintf(stderr, "Error closing configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+ /*! [Create a configuration parser] */
+
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser)) != 0) {
+ fprintf(stderr, "Error creating configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+
+ {
+ /*! [get] */
+ int64_t my_page_size;
+ /*
+ * Retrieve the value of the integer configuration string "page_size".
+ */
+ if ((ret = parser->get(parser, "page_size", &v)) != 0) {
+ fprintf(stderr,
+ "page_size configuration: %s", wiredtiger_strerror(ret));
+ return (ret);
+ }
+ my_page_size = v.val;
+ /*! [get] */
+
+ ret = parser->close(parser);
+
+ (void)my_page_size;
+ }
+
+ {
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser)) != 0) {
+ fprintf(stderr, "Error creating configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+ /*! [next] */
+ /*
+ * Retrieve and print the values of the configuration strings.
+ */
+ while ((ret = parser->next(parser, &k, &v)) == 0) {
+ printf("%.*s:", (int)k.len, k.str);
+ if (v.type == WT_CONFIG_ITEM_NUM)
+ printf("%d\n", (int)v.val);
+ else
+ printf("%.*s\n", (int)v.len, v.str);
+ }
+ /*! [next] */
+ ret = parser->close(parser);
+ }
+
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser)) != 0) {
+ fprintf(stderr, "Error creating configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+
+ /*! [nested get] */
+ /*
+ * Retrieve the value of the nested log file_max configuration string
+ * using dot shorthand. Utilize the configuration parsing automatic
+ * conversion of value strings into an integer.
+ */
+ v.type = WT_CONFIG_ITEM_NUM;
+ if ((ret = parser->get(parser, "log.file_max", &v)) != 0) {
+ fprintf(stderr,
+ "log.file_max configuration: %s", wiredtiger_strerror(ret));
+ return (ret);
+ }
+ printf("log file max: %d\n", (int)v.val);
+ /*! [nested get] */
+ ret = parser->close(parser);
+
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser)) != 0) {
+ fprintf(stderr, "Error creating configuration parser: %s\n",
+ wiredtiger_strerror(ret));
+ return (ret);
+ }
+ /*! [nested traverse] */
+ {
+ WT_CONFIG_PARSER *sub_parser;
+ while ((ret = parser->next(parser, &k, &v)) == 0) {
+ if (v.type == WT_CONFIG_ITEM_STRUCT) {
+ printf("Found nested configuration: %.*s\n",
+ (int)k.len, k.str);
+ if ((ret = wiredtiger_config_parser_open(
+ NULL, v.str, v.len, &sub_parser)) != 0) {
+ fprintf(stderr,
+ "Error creating nested configuration "
+ "parser: %s\n",
+ wiredtiger_strerror(ret));
+ parser->close(parser);
+ return (ret);
+ }
+ while ((ret = sub_parser->next(
+ sub_parser, &k, &v)) == 0)
+ printf("\t%.*s\n", (int)k.len, k.str);
+ sub_parser->close(sub_parser);
+ }
+ }
+ /*! [nested traverse] */
+ parser->close(parser);
+ }
+
+ return (0);
+}
diff --git a/examples/c/ex_data_source.c b/examples/c/ex_data_source.c
index daedce04075..953bb799340 100644
--- a/examples/c/ex_data_source.c
+++ b/examples/c/ex_data_source.c
@@ -339,30 +339,6 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
}
{
- /*! [WT_EXTENSION config_strget] */
- WT_CONFIG_ITEM v;
- int64_t my_data_source_page_size;
-
- /*
- * Retrieve the value of the integer type configuration string
- * "page_size" from a local string (as opposed to the provided
- * WT_CONFIG_ARG reference).
- */
- const char *config_string = "path=/dev/loop,page_size=1024";
-
- if ((ret = wt_api->config_strget(
- wt_api, session, config_string, "page_size", &v)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "page_size configuration: %s", wiredtiger_strerror(ret));
- return (ret);
- }
- my_data_source_page_size = v.val;
- /*! [WT_EXTENSION config_strget] */
-
- (void)my_data_source_page_size;
- }
-
- {
/*! [WT_EXTENSION config_get] */
WT_CONFIG_ITEM v;
const char *my_data_source_key;
@@ -392,31 +368,6 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
}
{
- /*! [WT_EXTENSION config scan] */
- WT_CONFIG_ITEM k, v;
- WT_CONFIG_SCAN *scan;
-
- /*
- * Retrieve the value of the list type configuration string "paths".
- */
- if ((ret = wt_api->config_get(
- wt_api, session, config, "paths", &v)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "paths configuration: %s", wiredtiger_strerror(ret));
- return (ret);
- }
-
- /*
- * Step through the list of entries.
- */
- ret = wt_api->config_scan_begin(wt_api, session, v.str, v.len, &scan);
- while ((ret = wt_api->config_scan_next(wt_api, scan, &k, &v)) == 0)
- printf("%.*s\n", (int)k.len, k.str);
- ret = wt_api->config_scan_end(wt_api, scan);
- /*! [WT_EXTENSION config scan] */
- }
-
- {
/*! [WT_EXTENSION collator config] */
/*
* Configure the appropriate collator.
diff --git a/ext/datasources/helium/helium.c b/ext/datasources/helium/helium.c
index 1239c88befa..c8a6fe99bb0 100644
--- a/ext/datasources/helium/helium.c
+++ b/ext/datasources/helium/helium.c
@@ -2098,19 +2098,22 @@ helium_session_open_cursor(WT_DATA_SOURCE *wtds, WT_SESSION *session,
CURSOR *cursor;
DATA_SOURCE *ds;
WT_CONFIG_ITEM v;
+ WT_CONFIG_PARSER *config_parser;
WT_CURSOR *wtcursor;
WT_EXTENSION_API *wtext;
WT_SOURCE *ws;
- int locked, ret = 0;
+ int locked, ret, t_ret;
const char *value;
*new_cursor = NULL;
+ config_parser = NULL;
cursor = NULL;
ds = (DATA_SOURCE *)wtds;
wtext = ds->wtext;
ws = NULL;
locked = 0;
+ ret = t_ret = 0;
value = NULL;
/* Allocate and initialize a cursor. */
@@ -2164,23 +2167,28 @@ helium_session_open_cursor(WT_DATA_SOURCE *wtds, WT_SESSION *session,
if ((ret = master_uri_get(wtds, session, uri, &value)) != 0)
goto err;
- if ((ret = wtext->config_strget(
- wtext, session, value, "key_format", &v)) != 0)
+ if ((ret = wtext->config_parser_open(wtext,
+ session, value, strlen(value), &config_parser)) != 0)
+ EMSG_ERR(wtext, session, ret,
+ "Configuration string parser: %s",
+ wtext->strerror(ret));
+ if ((ret = config_parser->get(
+ config_parser, "key_format", &v)) != 0)
EMSG_ERR(wtext, session, ret,
"key_format configuration: %s",
wtext->strerror(ret));
ws->config_recno = v.len == 1 && v.str[0] == 'r';
- if ((ret = wtext->config_strget(
- wtext, session, value, "value_format", &v)) != 0)
+ if ((ret = config_parser->get(
+ config_parser, "value_format", &v)) != 0)
EMSG_ERR(wtext, session, ret,
"value_format configuration: %s",
wtext->strerror(ret));
ws->config_bitfield =
v.len == 2 && isdigit(v.str[0]) && v.str[1] == 't';
- if ((ret = wtext->config_strget(
- wtext, session, value, "helium_o_compress", &v)) != 0)
+ if ((ret = config_parser->get(
+ config_parser, "helium_o_compress", &v)) != 0)
EMSG_ERR(wtext, session, ret,
"helium_o_compress configuration: %s",
wtext->strerror(ret));
@@ -2219,6 +2227,9 @@ err: if (ws != NULL && locked)
ESET(unlock(wtext, session, &ws->lock));
cursor_destroy(cursor);
}
+ if (config_parser != NULL && (t_ret =
+ (void)config_parser->close(config_parser)) != 0 && ret == 0)
+ ret = t_ret;
free((void *)value);
return (ret);
}
@@ -2882,19 +2893,19 @@ helium_config_read(WT_EXTENSION_API *wtext, WT_CONFIG_ITEM *config,
char **devicep, HE_ENV *envp, int *env_setp, int *flagsp)
{
WT_CONFIG_ITEM k, v;
- WT_CONFIG_SCAN *scan;
+ WT_CONFIG_PARSER *config_parser;
int ret = 0, tret;
*env_setp = 0;
*flagsp = 0;
- /* Set up the scan of the configuration arguments list. */
- if ((ret = wtext->config_scan_begin(
- wtext, NULL, config->str, config->len, &scan)) != 0)
+ /* Traverse the configuration arguments list. */
+ if ((ret = wtext->config_parser_open(
+ wtext, NULL, config->str, config->len, &config_parser)) != 0)
ERET(wtext, NULL, ret,
- "WT_EXTENSION_API.config_scan_begin: %s",
+ "WT_EXTENSION_API.config_parser_open: %s",
wtext->strerror(ret));
- while ((ret = wtext->config_scan_next(wtext, scan, &k, &v)) == 0) {
+ while ((ret = config_parser->next(config_parser, &k, &v)) == 0) {
if (string_match("helium_devices", k.str, k.len)) {
if ((*devicep = calloc(1, v.len + 1)) == NULL)
return (os_errno());
@@ -2924,13 +2935,11 @@ helium_config_read(WT_EXTENSION_API *wtext, WT_CONFIG_ITEM *config,
ret = 0;
if (ret != 0)
EMSG_ERR(wtext, NULL, ret,
- "WT_EXTENSION_API.config_scan_next: %s",
- wtext->strerror(ret));
+ "WT_CONFIG_PARSER.next: %s", wtext->strerror(ret));
-err: if ((tret = wtext->config_scan_end(wtext, scan)) != 0)
+err: if ((tret = config_parser->close(config_parser)) != 0)
EMSG(wtext, NULL, tret,
- "WT_EXTENSION_API.config_scan_end: %s",
- wtext->strerror(tret));
+ "WT_CONFIG_PARSER.close: %s", wtext->strerror(tret));
return (ret);
}
@@ -3320,11 +3329,12 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
DATA_SOURCE *ds;
HELIUM_SOURCE *hs;
WT_CONFIG_ITEM k, v;
- WT_CONFIG_SCAN *scan;
+ WT_CONFIG_PARSER *config_parser;
WT_EXTENSION_API *wtext;
int vmajor, vminor, ret = 0;
const char **p;
+ config_parser = NULL;
ds = NULL;
wtext = connection->get_extension_api(connection);
@@ -3357,12 +3367,12 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
wtext->strerror(ret));
/* Step through the list of Helium sources, opening each one. */
- if ((ret =
- wtext->config_scan_begin(wtext, NULL, v.str, v.len, &scan)) != 0)
+ if ((ret = wtext->config_parser_open(
+ wtext, NULL, v.str, v.len, &config_parser)) != 0)
EMSG_ERR(wtext, NULL, ret,
- "WT_EXTENSION_API.config_scan_begin: config: %s",
+ "WT_EXTENSION_API.config_parser_open: config: %s",
wtext->strerror(ret));
- while ((ret = wtext->config_scan_next(wtext, scan, &k, &v)) == 0) {
+ while ((ret = config_parser->next(config_parser, &k, &v)) == 0) {
if (string_match("helium_verbose", k.str, k.len)) {
verbose = v.val == 0 ? 0 : 1;
continue;
@@ -3372,12 +3382,13 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
}
if (ret != WT_NOTFOUND)
EMSG_ERR(wtext, NULL, ret,
- "WT_EXTENSION_API.config_scan_next: config: %s",
+ "WT_CONFIG_PARSER.next: config: %s",
wtext->strerror(ret));
- if ((ret = wtext->config_scan_end(wtext, scan)) != 0)
+ if ((ret = config_parser->close(config_parser)) != 0)
EMSG_ERR(wtext, NULL, ret,
- "WT_EXTENSION_API.config_scan_end: config: %s",
+ "WT_CONFIG_PARSER.close: config: %s",
wtext->strerror(ret));
+ config_parser = NULL;
/* Find and open the database transaction store. */
if ((ret = helium_source_open_txn(ds)) != 0)
@@ -3414,6 +3425,8 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
err: if (ds != NULL)
ESET(helium_terminate((WT_DATA_SOURCE *)ds, NULL));
+ if (config_parser != NULL)
+ (void)config_parser->close(config_parser);
return (ret);
}
diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i
index fcb580ddbd4..83404b45508 100644
--- a/lang/java/java_doc.i
+++ b/lang/java/java_doc.i
@@ -40,3 +40,6 @@ COPYDOC(__wt_connection, WT_CONNECTION, add_data_source)
COPYDOC(__wt_connection, WT_CONNECTION, add_collator)
COPYDOC(__wt_connection, WT_CONNECTION, add_compressor)
COPYDOC(__wt_connection, WT_CONNECTION, add_extractor)
+COPYDOC(__wt_config_parser, WT_CONFIG_PARSER, close)
+COPYDOC(__wt_config_parser, WT_CONFIG_PARSER, next)
+COPYDOC(__wt_config_parser, WT_CONFIG_PARSER, get)
diff --git a/src/btree/bt_discard.c b/src/btree/bt_discard.c
index 568e07f7fd1..c0c7a245a9f 100644
--- a/src/btree/bt_discard.c
+++ b/src/btree/bt_discard.c
@@ -317,6 +317,10 @@ __free_update_list(WT_SESSION_IMPL *session, WT_UPDATE *upd)
do {
next = upd->next;
+ /* Everything we free should be visible to everyone. */
+ WT_ASSERT(session,
+ upd->txnid == WT_TXN_ABORTED ||
+ __wt_txn_visible_all(session, upd->txnid));
__wt_free(session, upd);
} while ((upd = next) != NULL);
}
diff --git a/src/btree/bt_evict.c b/src/btree/bt_evict.c
index d57162c06a9..fed52963de4 100644
--- a/src/btree/bt_evict.c
+++ b/src/btree/bt_evict.c
@@ -436,6 +436,9 @@ __wt_evict_file(WT_SESSION_IMPL *session, int syncop)
*/
__wt_evict_file_exclusive_on(session);
+ /* Make sure the oldest transaction ID is up-to-date. */
+ __wt_txn_update_oldest(session);
+
/*
* We can't evict the page just returned to us, it marks our place in
* the tree. So, always walk one page ahead of the page being evicted.
diff --git a/src/config/config.c b/src/config/config.c
index c30c816de85..c0eb672015f 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -738,10 +738,8 @@ __wt_config_subgetraw(WT_SESSION_IMPL *session,
__wt_config_subgets(WT_SESSION_IMPL *session,
WT_CONFIG_ITEM *cfg, const char *key, WT_CONFIG_ITEM *value)
{
- WT_CONFIG_ITEM key_item;
-
- key_item.str = key;
- key_item.len = strlen(key);
+ WT_CONFIG_ITEM key_item =
+ { key, strlen(key), 0, WT_CONFIG_ITEM_STRING };
return (__wt_config_subgetraw(session, cfg, &key_item, value));
}
diff --git a/src/config/config_api.c b/src/config/config_api.c
index a5781a20c61..42f4c117b81 100644
--- a/src/config/config_api.c
+++ b/src/config/config_api.c
@@ -8,89 +8,98 @@
#include "wt_internal.h"
/*
- * wiredtiger_config_get --
- * Given a NULL-terminated list of configuration strings, find the final
- * value for a given string key (external API version).
+ * __config_parser_close --
+ * WT_CONFIG_PARSER->close method.
*/
-int
-wiredtiger_config_get(WT_SESSION *wt_session,
- WT_CONFIG_ARG *cfg_arg, const char *key, WT_CONFIG_ITEM *cval)
+static int
+__config_parser_close(WT_CONFIG_PARSER *wt_config_parser)
{
- WT_SESSION_IMPL *session;
- const char **cfg;
+ WT_CONFIG_PARSER_IMPL *config_parser;
- session = (WT_SESSION_IMPL *)wt_session;
+ config_parser = (WT_CONFIG_PARSER_IMPL *)wt_config_parser;
- if ((cfg = (const char **)cfg_arg) == NULL)
- return (WT_NOTFOUND);
- return (__wt_config_gets(session, cfg, key, cval));
+ if (config_parser == NULL)
+ return (EINVAL);
+
+ __wt_free(config_parser->session, config_parser);
+ return (0);
}
/*
- * wiredtiger_config_strget --
- * Given a single configuration string, find the final value for a given
- * string key (external API version).
+ * __config_parser_get --
+ * WT_CONFIG_PARSER->search method.
*/
-int
-wiredtiger_config_strget(WT_SESSION *wt_session,
- const char *config, const char *key, WT_CONFIG_ITEM *cval)
+static int
+__config_parser_get(WT_CONFIG_PARSER *wt_config_parser,
+ const char *key, WT_CONFIG_ITEM *cval)
{
- const char *cfg_arg[] = { config, NULL };
+ WT_CONFIG_PARSER_IMPL *config_parser;
- return (wiredtiger_config_get(
- wt_session, (WT_CONFIG_ARG *)cfg_arg, key, cval));
+ config_parser = (WT_CONFIG_PARSER_IMPL *)wt_config_parser;
+
+ if (config_parser == NULL)
+ return (EINVAL);
+
+ return (__wt_config_subgets(config_parser->session,
+ &config_parser->config_item, key, cval));
}
/*
- * wiredtiger_config_scan_begin --
- * Start a scan of a config string.
+ * __config_parser_next --
+ * WT_CONFIG_PARSER->next method.
*/
-int
-wiredtiger_config_scan_begin(WT_SESSION *wt_session,
- const char *str, size_t len, WT_CONFIG_SCAN **scanp)
+static int
+__config_parser_next(WT_CONFIG_PARSER *wt_config_parser,
+ WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *cval)
{
- WT_CONFIG config, *scan;
- WT_SESSION_IMPL *session;
+ WT_CONFIG_PARSER_IMPL *config_parser;
- session = (WT_SESSION_IMPL *)wt_session;
+ config_parser = (WT_CONFIG_PARSER_IMPL *)wt_config_parser;
- /* Note: allocate memory last to avoid cleanup. */
- WT_CLEAR(config);
- WT_RET(__wt_config_initn(session, &config, str, len));
- WT_RET(__wt_calloc_def(session, 1, &scan));
- *scan = config;
- *scanp = (WT_CONFIG_SCAN *)scan;
- return (0);
+ if (config_parser == NULL)
+ return (EINVAL);
+
+ return (__wt_config_next(&config_parser->config, key, cval));
}
/*
- * wiredtiger_config_scan_end --
- * End a scan of a config string.
+ * wiredtiger_config_parser_open --
+ * Create a configuration parser.
*/
int
-wiredtiger_config_scan_end(WT_SESSION *wt_session, WT_CONFIG_SCAN *scan)
+wiredtiger_config_parser_open(WT_SESSION *wt_session,
+ const char *config, size_t len, WT_CONFIG_PARSER **config_parserp)
{
- WT_CONFIG *conf;
+ static const WT_CONFIG_PARSER stds = {
+ __config_parser_close,
+ __config_parser_next,
+ __config_parser_get
+ };
+ WT_CONFIG_ITEM config_item =
+ { config, len, 0, WT_CONFIG_ITEM_STRING };
+ WT_CONFIG_PARSER_IMPL *config_parser;
+ WT_DECL_RET;
+ WT_SESSION_IMPL *session;
- WT_UNUSED(wt_session);
+ *config_parserp = NULL;
+ session = (WT_SESSION_IMPL *)wt_session;
- conf = (WT_CONFIG *)scan;
- __wt_free(conf->session, scan);
- return (0);
-}
+ WT_RET(__wt_calloc_def(session, 1, &config_parser));
+ config_parser->iface = stds;
+ config_parser->session = session;
-/*
- * wiredtiger_config_scan_next --
- * Get the next key/value pair from a config scan.
- */
-int
-wiredtiger_config_scan_next(WT_SESSION *wt_session,
- WT_CONFIG_SCAN *scan, WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value)
-{
- WT_CONFIG *conf;
+ /*
+ * Setup a WT_CONFIG_ITEM to be used for get calls and a WT_CONFIG
+ * structure for iterations through the configuration string.
+ */
+ memcpy(&config_parser->config_item, &config_item, sizeof(config_item));
+ WT_ERR(__wt_config_initn(
+ session, &config_parser->config, config, len));
- WT_UNUSED(wt_session);
+ if (ret == 0)
+ *config_parserp = (WT_CONFIG_PARSER *)config_parser;
+ else
+err: __wt_free(session, config_parser);
- conf = (WT_CONFIG *)scan;
- return (__wt_config_next(conf, key, value));
+ return (ret);
}
diff --git a/src/config/config_ext.c b/src/config/config_ext.c
index 7dd5445cc3c..26b3799d61c 100644
--- a/src/config/config_ext.c
+++ b/src/config/config_ext.c
@@ -8,6 +8,19 @@
#include "wt_internal.h"
/*
+ * __wt_ext_config_parser_open --
+ * WT_EXTENSION_API->config_parser_open implementation
+ */
+int
+__wt_ext_config_parser_open(WT_EXTENSION_API *wt_ext, WT_SESSION *wt_session,
+ const char *config, size_t len, WT_CONFIG_PARSER **config_parserp)
+{
+ WT_UNUSED(wt_ext);
+ return (wiredtiger_config_parser_open(
+ wt_session, config, len, config_parserp));
+}
+
+/*
* __wt_ext_config_get --
* Given a NULL-terminated list of configuration strings, find the final
* value for a given string key (external API version).
@@ -29,81 +42,3 @@ __wt_ext_config_get(WT_EXTENSION_API *wt_api,
return (WT_NOTFOUND);
return (__wt_config_gets(session, cfg, key, cval));
}
-
-/*
- * __wt_ext_config_strget --
- * Given a single configuration string, find the final value for a given
- * string key (external API version).
- */
-int
-__wt_ext_config_strget(WT_EXTENSION_API *wt_api,
- WT_SESSION *wt_session, const char *config, const char *key,
- WT_CONFIG_ITEM *cval)
-{
- const char *cfg_arg[] = { config, NULL };
-
- return (__wt_ext_config_get(
- wt_api, wt_session, (WT_CONFIG_ARG *)cfg_arg, key, cval));
-}
-
-/*
- * __wt_ext_config_scan_begin --
- * Start a scan of a config string.
- * (external API only).
- */
-int
-__wt_ext_config_scan_begin(
- WT_EXTENSION_API *wt_api, WT_SESSION *wt_session,
- const char *str, size_t len, WT_CONFIG_SCAN **scanp)
-{
- WT_CONFIG config, *scan;
- WT_CONNECTION_IMPL *conn;
- WT_SESSION_IMPL *session;
-
- conn = (WT_CONNECTION_IMPL *)wt_api->conn;
- if ((session = (WT_SESSION_IMPL *)wt_session) == NULL)
- session = conn->default_session;
-
- /* Note: allocate memory last to avoid cleanup. */
- WT_CLEAR(config);
- WT_RET(__wt_config_initn(session, &config, str, len));
- WT_RET(__wt_calloc_def(session, 1, &scan));
- *scan = config;
- *scanp = (WT_CONFIG_SCAN *)scan;
- return (0);
-}
-
-/*
- * __wt_ext_config_scan_end --
- * End a scan of a config string.
- * (external API only).
- */
-int
-__wt_ext_config_scan_end(WT_EXTENSION_API *wt_api, WT_CONFIG_SCAN *scan)
-{
- WT_CONFIG *conf;
-
- WT_UNUSED(wt_api);
-
- conf = (WT_CONFIG *)scan;
- __wt_free(conf->session, scan);
- return (0);
-}
-
-/*
- * __wt_ext_config_scan_next --
- * Get the next key/value pair from a config scan.
- * (external API only).
- */
-int
-__wt_ext_config_scan_next(
- WT_EXTENSION_API *wt_api, WT_CONFIG_SCAN *scan,
- WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value)
-{
- WT_CONFIG *conf;
-
- WT_UNUSED(wt_api);
-
- conf = (WT_CONFIG *)scan;
- return (__wt_config_next(conf, key, value));
-}
diff --git a/src/conn/conn_api.c b/src/conn/conn_api.c
index 780ae6f6be5..bcbb8e3ceb8 100644
--- a/src/conn/conn_api.c
+++ b/src/conn/conn_api.c
@@ -105,11 +105,8 @@ __conn_get_extension_api(WT_CONNECTION *wt_conn)
conn->extension_api.scr_free = __wt_ext_scr_free;
conn->extension_api.collator_config = ext_collator_config;
conn->extension_api.collate = ext_collate;
+ conn->extension_api.config_parser_open = __wt_ext_config_parser_open;
conn->extension_api.config_get = __wt_ext_config_get;
- conn->extension_api.config_strget = __wt_ext_config_strget;
- conn->extension_api.config_scan_begin = __wt_ext_config_scan_begin;
- conn->extension_api.config_scan_end = __wt_ext_config_scan_end;
- conn->extension_api.config_scan_next = __wt_ext_config_scan_next;
conn->extension_api.metadata_insert = __wt_ext_metadata_insert;
conn->extension_api.metadata_remove = __wt_ext_metadata_remove;
conn->extension_api.metadata_search = __wt_ext_metadata_search;
@@ -123,6 +120,7 @@ __conn_get_extension_api(WT_CONNECTION *wt_conn)
conn->extension_api.transaction_notify = __wt_ext_transaction_notify;
conn->extension_api.transaction_oldest = __wt_ext_transaction_oldest;
conn->extension_api.transaction_visible = __wt_ext_transaction_visible;
+ conn->extension_api.version = wiredtiger_version;
return (&conn->extension_api);
}
@@ -498,6 +496,20 @@ __conn_close(WT_CONNECTION *wt_conn, const char *config)
CONNECTION_API_CALL(conn, session, close, config, cfg);
WT_UNUSED(cfg);
+ /*
+ * Rollback all running transactions.
+ * We do this as a separate pass because an active transaction in one
+ * session could cause trouble when closing a file, even if that
+ * session never referenced that file.
+ */
+ for (s = conn->sessions, i = 0; i < conn->session_cnt; ++s, ++i)
+ if (s->active && !F_ISSET(s, WT_SESSION_INTERNAL) &&
+ F_ISSET(&s->txn, TXN_RUNNING)) {
+ wt_session = &s->iface;
+ WT_TRET(wt_session->rollback_transaction(
+ wt_session, NULL));
+ }
+
/* Close open, external sessions. */
for (s = conn->sessions, i = 0; i < conn->session_cnt; ++s, ++i)
if (s->active && !F_ISSET(s, WT_SESSION_INTERNAL)) {
diff --git a/src/docs/Doxyfile b/src/docs/Doxyfile
index 5f7e5016892..d8f753b269b 100644
--- a/src/docs/Doxyfile
+++ b/src/docs/Doxyfile
@@ -1576,6 +1576,7 @@ PREDEFINED = DOXYGEN \
__wt_compressor:=WT_COMPRESSOR \
__wt_config_arg:=WT_CONFIG_ARG \
__wt_config_item:=WT_CONFIG_ITEM \
+ __wt_config_parser:=WT_CONFIG_PARSER \
__wt_config_scan:=WT_CONFIG_SCAN \
__wt_connection:=WT_CONNECTION \
__wt_cursor:=WT_CURSOR \
diff --git a/src/docs/command-line.dox b/src/docs/command-line.dox
index 52be68a1074..04daa4050cd 100644
--- a/src/docs/command-line.dox
+++ b/src/docs/command-line.dox
@@ -291,9 +291,6 @@ engine, or, if specified, for the URI on the command-line.
<code>wt [-Vv] [-C config] [-h directory] stat [-a] [uri]</code>
@subsection util_stat_options Options
-The \c stat command has no command-specific options.
-
-@subsection util_stat_options Options
The following are command-specific options for the \c stat command:
@par <code>-a</code>
diff --git a/src/docs/custom_data.dox b/src/docs/custom_data.dox
index b1ee8dfbd9e..22dd75dcc26 100644
--- a/src/docs/custom_data.dox
+++ b/src/docs/custom_data.dox
@@ -165,11 +165,6 @@ of a configuration string as follows:
@snippet ex_data_source.c WT_EXTENSION config_get
-The WT_DATA_SOURCE::open_cursor method might retrieve the list value
-of a configuration string as follows:
-
-@snippet ex_data_source.c WT_EXTENSION config scan
-
@subsection custom_ds_config_add Creating data-specific configuration strings
Applications can add their own configuration strings to WiredTiger
diff --git a/src/docs/helium.dox b/src/docs/helium.dox
index cd6b47fb968..35e3886a8d6 100644
--- a/src/docs/helium.dox
+++ b/src/docs/helium.dox
@@ -103,7 +103,7 @@ WT_SESSION *session;
/* Create and truncate the access table. */
ret = session->create(session, "table:dev1/access",
- "key_format=S,value_format=S,type=helium,helium_open_o_truncate=1");
+ "key_format=S,value_format=S,type=helium,helium_o_truncate=1");
@endcode
@section helium_notes Helium notes
diff --git a/src/include/cache.h b/src/include/cache.h
index 055041b7e6c..abbc2189f9d 100644
--- a/src/include/cache.h
+++ b/src/include/cache.h
@@ -9,7 +9,7 @@
* Tuning constants: I hesitate to call this tuning, but we want to review some
* number of pages from each file's in-memory tree for each page we evict.
*/
-#define WT_EVICT_INT_SKEW (1<<12) /* Prefer leaf pages over internal
+#define WT_EVICT_INT_SKEW (1<<20) /* Prefer leaf pages over internal
pages by this many increments of the
read generation. */
#define WT_EVICT_WALK_PER_FILE 10 /* Pages to visit per file */
diff --git a/src/include/config.h b/src/include/config.h
index d8837f0f368..c83d96c8a5e 100644
--- a/src/include/config.h
+++ b/src/include/config.h
@@ -33,6 +33,14 @@ struct __wt_config_entry {
const WT_CONFIG_CHECK *checks; /* check array */
};
+struct __wt_config_parser_impl {
+ WT_CONFIG_PARSER iface;
+
+ WT_SESSION_IMPL *session;
+ WT_CONFIG config;
+ WT_CONFIG_ITEM config_item;
+};
+
/*
* DO NOT EDIT: automatically built by dist/api_config.py.
* configuration section: BEGIN
diff --git a/src/include/extern.h b/src/include/extern.h
index d1662717345..bd24cb02d61 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -529,27 +529,16 @@ extern int __wt_config_concat( WT_SESSION_IMPL *session,
const char **config_ret);
extern int __wt_conn_config_init(WT_SESSION_IMPL *session);
extern void __wt_conn_config_discard(WT_SESSION_IMPL *session);
+extern int __wt_ext_config_parser_open(WT_EXTENSION_API *wt_ext,
+ WT_SESSION *wt_session,
+ const char *config,
+ size_t len,
+ WT_CONFIG_PARSER **config_parserp);
extern int __wt_ext_config_get(WT_EXTENSION_API *wt_api,
WT_SESSION *wt_session,
WT_CONFIG_ARG *cfg_arg,
const char *key,
WT_CONFIG_ITEM *cval);
-extern int __wt_ext_config_strget(WT_EXTENSION_API *wt_api,
- WT_SESSION *wt_session,
- const char *config,
- const char *key,
- WT_CONFIG_ITEM *cval);
-extern int __wt_ext_config_scan_begin( WT_EXTENSION_API *wt_api,
- WT_SESSION *wt_session,
- const char *str,
- size_t len,
- WT_CONFIG_SCAN **scanp);
-extern int __wt_ext_config_scan_end(WT_EXTENSION_API *wt_api,
- WT_CONFIG_SCAN *scan);
-extern int __wt_ext_config_scan_next( WT_EXTENSION_API *wt_api,
- WT_CONFIG_SCAN *scan,
- WT_CONFIG_ITEM *key,
- WT_CONFIG_ITEM *value);
extern int __wt_collator_config( WT_SESSION_IMPL *session,
const char **cfg,
WT_COLLATOR **collatorp);
diff --git a/src/include/txn.i b/src/include/txn.i
index cdfe697ee51..8ec1f52bff4 100644
--- a/src/include/txn.i
+++ b/src/include/txn.i
@@ -167,19 +167,23 @@ __wt_txn_visible(WT_SESSION_IMPL *session, uint64_t id)
/*
* __wt_txn_read_skip --
* Get the first visible update in a list (or NULL if none are visible),
- * and report whether uncommitted changes were skipped.
+ * and report whether there are an uncommitted changes in the list.
*/
static inline WT_UPDATE *
__wt_txn_read_skip(WT_SESSION_IMPL *session, WT_UPDATE *upd, int *skipp)
{
+ WT_UPDATE *first_upd;
+
*skipp = 0;
- while (upd != NULL && !__wt_txn_visible(session, upd->txnid)) {
- if (upd->txnid != WT_TXN_ABORTED)
- *skipp = 1;
- upd = upd->next;
- }
+ for (first_upd = NULL; upd != NULL; upd = upd->next)
+ if (upd->txnid != WT_TXN_ABORTED) {
+ if (!__wt_txn_visible(session, upd->txnid))
+ *skipp = 1;
+ else if (first_upd == NULL)
+ first_upd = upd;
+ }
- return (upd);
+ return (first_upd);
}
/*
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index ac776e31ecd..c08b4d37206 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -71,9 +71,9 @@ extern "C" {
*******************************************/
struct __wt_collator; typedef struct __wt_collator WT_COLLATOR;
struct __wt_compressor; typedef struct __wt_compressor WT_COMPRESSOR;
-struct __wt_config_arg; typedef struct __wt_config_arg WT_CONFIG_ARG;
struct __wt_config_item; typedef struct __wt_config_item WT_CONFIG_ITEM;
-struct __wt_config_scan; typedef struct __wt_config_scan WT_CONFIG_SCAN;
+struct __wt_config_parser;
+ typedef struct __wt_config_parser WT_CONFIG_PARSER;
struct __wt_connection; typedef struct __wt_connection WT_CONNECTION;
struct __wt_cursor; typedef struct __wt_cursor WT_CURSOR;
struct __wt_data_source; typedef struct __wt_data_source WT_DATA_SOURCE;
@@ -1910,7 +1910,7 @@ struct __wt_config_item {
* list or string), the \c str field will reference the value of the
* configuration string.
*
- * The bytes referenced by \c str are <b>not</b> be nul-terminated,
+ * The bytes referenced by \c str are <b>not</b> nul-terminated,
* use the \c len field instead of a terminating nul byte.
*/
const char *str;
@@ -1951,93 +1951,94 @@ struct __wt_config_item {
};
/*!
- * @typedef WT_CONFIG_ARG
- *
- * A configuration object passed to some extension interfaces. This is an
- * opaque type: configuration values can be queried using
- * WT_EXTENSION_API::config_get and wiredtiger_config_get.
- */
-
-/*!
- * @typedef WT_CONFIG_SCAN
- *
- * A handle for a scan through a configuration string.
- * This is an opaque type returned by WT_EXTENSION_API::config_scan_begin and
- * wiredtiger_config_scan_begin. Configuration values can be queried using
- * WT_EXTENSION_API::config_scan_next or wiredtiger_config_scan_next. Call
- * WT_EXTENSION_API::config_scan_end or wiredtiger_config_scan_end when
- * finished to release resources.
+ * Create a handle that can be used to parse or create configuration strings
+ * compatible with WiredTiger APIs.
+ * This API is outside the scope of a WiredTiger connection handle, since
+ * applications may need to generate configuration strings prior to calling
+ * ::wiredtiger_open.
+ * @param session the session handle (or NULL if none available), used for
+ * error reporting if provided
+ * @param config the configuration string being parsed. The string must
+ * remain valid for the lifetime of the parser handle.
+ * @param len the number of valid bytes in \c config
+ * @param[out] config_parserp A pointer to the newly opened handle
+ * @errors
*/
+int wiredtiger_config_parser_open(WT_SESSION *session,
+ const char *config, size_t len, WT_CONFIG_PARSER **config_parserp);
/*!
- * Return the value of a configuration string.
+ * A handle that can be used to search and traverse configuration strings
+ * compatible with WiredTiger APIs.
+ * To parse the contents of a list or nested configuration string use a new
+ * configuration parser handle based on the content of the ::WT_CONFIG_ITEM
+ * retrieved from the parent configuration string.
*
- * @param session the session handle (or NULL if none available)
- * @param key configuration key string
- * @param config the configuration information passed to an application
- * @param value the returned value
- * @errors
+ * @section config_parse_examples Configuration String Parsing examples
*
- */
-int wiredtiger_config_get(WT_SESSION *session,
- WT_CONFIG_ARG *config, const char *key, WT_CONFIG_ITEM *value);
-
-/*!
- * Return the value of a configuration string.
+ * This could be used in C to create a configuration parser as follows:
*
- * @param session the session handle (or NULL if none available)
- * @param config a configuration string
- * @param key configuration key string
- * @param value the returned value
- * @errors
+ * @snippet ex_config_parse.c Create a configuration parser
*
- */
-int wiredtiger_config_strget(WT_SESSION *session,
- const char *config, const char *key, WT_CONFIG_ITEM *value);
-
-/*!
- * Return the list entries of a configuration string value.
- * This method steps through the entries found in the last returned
- * value from wiredtiger_config_get. The last returned value
- * should be of type "list".
- *
- * @param session the session handle (or NULL if none available)
- * @param str the configuration string to scan
- * @param len the number of valid bytes in \c str
- * @param[out] scanp a handle used to scan the config string
- * @errors
+ * Once the parser has been created the content can be queried directly:
*
- */
-int wiredtiger_config_scan_begin(WT_SESSION *session,
- const char *str, size_t len, WT_CONFIG_SCAN **scanp);
-
-/*!
- * Release any resources allocated by
- * wiredtiger_config_scan_begin.
+ * @snippet ex_config_parse.c get
*
- * @param session the session handle (or NULL if none available)
- * @param scan the configuration scanner, invalid after this call
- * @errors
+ * Or the content can be traversed linearly:
*
- */
-int wiredtiger_config_scan_end(WT_SESSION *session, WT_CONFIG_SCAN *scan);
-
-/*!
- * Return the next key/value pair from a config string scan.
+ * @snippet ex_config_parse.c next
*
- * If the string contains a list of items with no assigned value, the
- * items will be returned in \c key and the \c value will be set to the
- * boolean \c "true" value.
+ * Nested configuration values can be queried using a shorthand notation:
*
- * @param session the session handle (or NULL if none available)
- * @param scan the configuration scanner
- * @param key the returned key
- * @param value the returned value
- * @errors
+ * @snippet ex_config_parse.c nested get
*
+ * Nested configuration values can be traversed using multiple
+ * ::WT_CONFIG_PARSER handles:
+ *
+ * @snippet ex_config_parse.c nested traverse
*/
-int wiredtiger_config_scan_next(WT_SESSION *session,
- WT_CONFIG_SCAN *scan, WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value);
+struct __wt_config_parser {
+
+ /*!
+ * Close the configuration scanner releasing any resources.
+ *
+ * @param config_parser the configuration parser handle
+ * @errors
+ *
+ */
+ int __F(close)(WT_CONFIG_PARSER *config_parser);
+
+ /*!
+ * Return the next key/value pair.
+ *
+ * When iteration would pass the end of the configuration string
+ * ::WT_NOTFOUND will be returned.
+ *
+ * If an item has no explicitly assigned value, the item will be
+ * returned in \c key and the \c value will be set to the boolean
+ * \c "true" value.
+ *
+ * @param config_parser the configuration parser handle
+ * @param key the returned key
+ * @param value the returned value
+ * @errors
+ *
+ */
+ int __F(next)(WT_CONFIG_PARSER *config_parser,
+ WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value);
+
+ /*!
+ * Return the value of an item in the configuration string.
+ *
+ * @param config_parser the configuration parser handle
+ * @param key configuration key string
+ * @param value the returned value
+ * @errors
+ *
+ */
+ int __F(get)(WT_CONFIG_PARSER *config_parser,
+ const char *key, WT_CONFIG_ITEM *value);
+};
#endif /* !defined(SWIG) */
/*!
@@ -2134,6 +2135,7 @@ const char *wiredtiger_version(int *majorp, int *minorp, int *patchp);
/*******************************************
* Forward structure declarations for the extension API
*******************************************/
+struct __wt_config_arg; typedef struct __wt_config_arg WT_CONFIG_ARG;
/*!
* The interface implemented by applications to provide custom ordering of
diff --git a/src/include/wiredtiger_ext.h b/src/include/wiredtiger_ext.h
index 1f66c421027..acf7efad3d9 100644
--- a/src/include/wiredtiger_ext.h
+++ b/src/include/wiredtiger_ext.h
@@ -184,6 +184,12 @@ struct __wt_extension_api {
WT_ITEM *first, WT_ITEM *second, int *cmp);
/*!
+ * @copydoc wiredtiger_config_parser_open
+ */
+ int (*config_parser_open)(WT_EXTENSION_API *wt_api, WT_SESSION *session,
+ const char *config, size_t len, WT_CONFIG_PARSER **config_parserp);
+
+ /*!
* Return the value of a configuration string.
*
* @param wt_api the extension handle
@@ -199,69 +205,6 @@ struct __wt_extension_api {
WT_CONFIG_ARG *config, const char *key, WT_CONFIG_ITEM *value);
/*!
- * Return the value of a configuration string.
- *
- * @param wt_api the extension handle
- * @param session the session handle (or NULL if none available)
- * @param config a configuration string
- * @param key configuration key string
- * @param value the returned value
- * @errors
- *
- * @snippet ex_data_source.c WT_EXTENSION config_strget
- */
- int (*config_strget)(WT_EXTENSION_API *wt_api, WT_SESSION *session,
- const char *config, const char *key, WT_CONFIG_ITEM *value);
-
- /*!
- * Return the list entries of a configuration string value.
- * This method steps through the entries found in the last returned
- * value from WT_EXTENSION_API::config_get. The last returned value
- * should be of type "list".
- *
- * @param wt_api the extension handle
- * @param session the session handle (or NULL if none available)
- * @param str the configuration string to scan
- * @param len the number of valid bytes in \c str
- * @param[out] scanp a handle used to scan the config string
- * @errors
- *
- * @snippet ex_data_source.c WT_EXTENSION config scan
- */
- int (*config_scan_begin)(WT_EXTENSION_API *wt_api, WT_SESSION *session,
- const char *str, size_t len, WT_CONFIG_SCAN **scanp);
-
- /*!
- * Release any resources allocated by
- * WT_EXTENSION_API::config_scan_begin.
- *
- * @param wt_api the extension handle
- * @param scan the configuration scanner, invalid after this call
- * @errors
- *
- * @snippet ex_data_source.c WT_EXTENSION config scan
- */
- int (*config_scan_end)(WT_EXTENSION_API *wt_api, WT_CONFIG_SCAN *scan);
-
- /*!
- * Return the next key/value pair from a config string scan.
- *
- * If the string contains a list of items with no assigned value, the
- * items will be returned in \c key and the \c value will be set to the
- * boolean \c "true" value.
- *
- * @param wt_api the extension handle
- * @param scan the configuration scanner
- * @param key the returned key
- * @param value the returned value
- * @errors
- *
- * @snippet ex_data_source.c WT_EXTENSION config scan
- */
- int (*config_scan_next)(WT_EXTENSION_API *wt_api,
- WT_CONFIG_SCAN *scan, WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value);
-
- /*!
* Insert a row into the metadata if it does not already exist.
*
* @param wt_api the extension handle
@@ -428,8 +371,21 @@ struct __wt_extension_api {
*/
int (*transaction_visible)(WT_EXTENSION_API *wt_api,
WT_SESSION *session, uint64_t transaction_id);
+
+ /*!
+ * @copydoc wiredtiger_version
+ */
+ const char *(*version)(int *majorp, int *minorp, int *patchp);
};
+/*!
+ * @typedef WT_CONFIG_ARG
+ *
+ * A configuration object passed to some extension interfaces. This is an
+ * opaque type: configuration values can be queried using
+ * WT_EXTENSION_API::config_get
+ */
+
/*! @} */
#endif /* SWIG */
diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h
index 3ae89fc211e..19a805aa25f 100644
--- a/src/include/wt_internal.h
+++ b/src/include/wt_internal.h
@@ -93,6 +93,8 @@ struct __wt_config_check;
typedef struct __wt_config_check WT_CONFIG_CHECK;
struct __wt_config_entry;
typedef struct __wt_config_entry WT_CONFIG_ENTRY;
+struct __wt_config_parser_impl;
+ typedef struct __wt_config_parser_impl WT_CONFIG_PARSER_IMPL;
struct __wt_connection_impl;
typedef struct __wt_connection_impl WT_CONNECTION_IMPL;
struct __wt_connection_stats;
diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c
index b51c9deeade..5076343bc4b 100644
--- a/src/lsm/lsm_cursor.c
+++ b/src/lsm/lsm_cursor.c
@@ -385,7 +385,7 @@ retry: if (F_ISSET(clsm, WT_CLSM_MERGE)) {
* generation number and retry if it has changed under us.
*/
if (clsm->cursors != NULL && (ngood < clsm->nchunks ||
- (F_ISSET(clsm, WT_CLSM_OPEN_READ) && nupdates > 0))) {
+ (!F_ISSET(clsm, WT_CLSM_OPEN_READ) && nupdates > 0))) {
saved_gen = lsm_tree->dsk_gen;
locked = 0;
WT_ERR(__wt_lsm_tree_unlock(session, lsm_tree));
diff --git a/tools/wtperf_stats.py b/tools/wtperf_stats.py
index 388eb9fe24b..d9743055fff 100644
--- a/tools/wtperf_stats.py
+++ b/tools/wtperf_stats.py
@@ -76,6 +76,19 @@ def munge_dict(values_dict, abstime):
next_val[title] = value
ret.append(next_val)
+ # After building the series, eliminate constants
+ d0 = ret[0]
+ for t0, v0 in d0.items():
+ skip = True
+ for d in ret:
+ v = d[t0]
+ if v != v0:
+ skip = False
+ break
+ if skip:
+ for dicts in ret:
+ del dicts[t0]
+
return ret
def addPlotsToChart(chart, graph_data, wtstat_chart = False):