summaryrefslogtreecommitdiff
path: root/bench/wtperf/wtperf_truncate.c
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2015-07-24 17:21:00 +1000
committerAlex Gorrod <alexg@wiredtiger.com>2015-07-24 17:21:00 +1000
commit10c5a4c4eec49666d79e4069a72f6a7ab19757b3 (patch)
treea38e571eb94d7c5fed62bfcbdbf0c4c03ffb9343 /bench/wtperf/wtperf_truncate.c
parent6cdd3625de3678b6f48ea0ba182430b0ae3e756e (diff)
downloadmongo-10c5a4c4eec49666d79e4069a72f6a7ab19757b3.tar.gz
Review feedback for wtperf truncate.
Diffstat (limited to 'bench/wtperf/wtperf_truncate.c')
-rw-r--r--bench/wtperf/wtperf_truncate.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/bench/wtperf/wtperf_truncate.c b/bench/wtperf/wtperf_truncate.c
new file mode 100644
index 00000000000..9c4e0387a90
--- /dev/null
+++ b/bench/wtperf/wtperf_truncate.c
@@ -0,0 +1,201 @@
+/*-
+ * Public Domain 2014-2015 MongoDB, Inc.
+ * 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.
+ */
+
+#include "wtperf.h"
+
+int
+setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) {
+
+ TRUNCATE_CONFIG *trunc_cfg;
+ TRUNCATE_QUEUE_ENTRY *truncate_item;
+ WORKLOAD *workload;
+ WT_CURSOR *cursor;
+ char *key, *truncate_key;
+ int ret;
+ size_t i;
+ uint64_t end_point, final_stone_gap, start_point;
+
+ end_point = final_stone_gap = start_point = 0;
+ trunc_cfg = &thread->trunc_cfg;
+ workload = thread->workload;
+
+ /* We are limited to only one table when running truncate. */
+ if ((ret = session->open_cursor(
+ session, cfg->uris[0], NULL, NULL, &cursor)) != 0)
+ goto err;
+
+ /* Truncation percentage value. eg 10% is 0.1. */
+ trunc_cfg->truncation_percentage = (double)workload->truncate_pct / 100;
+ /* How many entries between each stone. */
+ trunc_cfg->truncate_stone_gap =
+ workload->truncate_count * trunc_cfg->truncation_percentage;
+ /* How many stones we need. */
+ trunc_cfg->needed_stones =
+ workload->truncate_count / trunc_cfg->truncate_stone_gap;
+
+ final_stone_gap = trunc_cfg->truncate_stone_gap;
+
+ /* Reset this value for use again. */
+ trunc_cfg->truncate_stone_gap = 0;
+
+ /*
+ * Here we check if there is data in the collection. If there is
+ * data available, then we need to setup some initial truncation
+ * stones.
+ */
+ if ((ret = cursor->next(cursor)) != 0 ||
+ (ret = cursor->get_key(cursor, &key)) != 0) {
+ lprintf(cfg, ret, 0, "truncate setup start: failed");
+ goto err;
+ }
+
+ start_point = decode_key(key);
+ if ((cursor->reset(cursor)) != 0 || (ret = cursor->prev(cursor)) != 0 ||
+ (ret = cursor->get_key(cursor, &key)) != 0) {
+ lprintf(cfg, ret, 0, "truncate setup end: failed");
+ goto err;
+ }
+ end_point = decode_key(key);
+
+ /* Assign stones if there are enough documents. */
+ if (start_point + trunc_cfg->needed_stones > end_point)
+ trunc_cfg->truncate_stone_gap = 0;
+ else
+ trunc_cfg->truncate_stone_gap =
+ (end_point - start_point) / trunc_cfg->needed_stones;
+
+ /* If we have enough data allocate some stones. */
+ if (trunc_cfg->truncate_stone_gap != 0) {
+ trunc_cfg->expected_total = (end_point - start_point);
+ for (i = 0; i < trunc_cfg->needed_stones; i++) {
+ truncate_key = calloc(cfg->key_sz, 1);
+ truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1);
+ if (truncate_item == NULL) {
+ ret = enomem(cfg);
+ goto err;
+ }
+ generate_key(cfg, truncate_key,
+ trunc_cfg->truncate_stone_gap * (i+1));
+ truncate_item->key = truncate_key;
+ truncate_item->diff =
+ (trunc_cfg->truncate_stone_gap * (i+1)) -
+ trunc_cfg->last_key;
+ STAILQ_INSERT_TAIL( &cfg->truncate_stone_head,
+ truncate_item, q);
+ trunc_cfg->last_key =
+ trunc_cfg->truncate_stone_gap * (i+1);
+ trunc_cfg->num_stones++;
+ }
+ }
+ trunc_cfg->truncate_stone_gap = final_stone_gap;
+
+err: cursor->close(cursor);
+ return (ret);
+}
+
+int
+run_truncate(CONFIG *cfg, CONFIG_THREAD *thread,
+ TRACK **trk, WT_CURSOR *cursor, WT_SESSION *session) {
+
+ TRUNCATE_CONFIG *trunc_cfg;
+ TRUNCATE_QUEUE_ENTRY *truncate_item;
+ char *truncate_key;
+ int ret;
+
+ ret = 0;
+ trunc_cfg = &thread->trunc_cfg;
+
+ /* Update the total inserts */
+ trunc_cfg->total_inserts = sum_insert_ops(cfg);
+ trunc_cfg->expected_total +=
+ (trunc_cfg->total_inserts - trunc_cfg->last_total_inserts);
+ trunc_cfg->last_total_inserts = trunc_cfg->total_inserts;
+
+ /* We are done if there isn't enough data to trigger a new milestone. */
+ if (trunc_cfg->expected_total <= trunc_cfg->needed_stones) {
+ (void)usleep(1000);
+ *trk = &thread->truncate_sleep;
+ return (0);
+ }
+
+ while (trunc_cfg->num_stones < trunc_cfg->needed_stones) {
+ trunc_cfg->last_key += trunc_cfg->truncate_stone_gap;
+ truncate_key = calloc(cfg->key_sz, 1);
+ truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1);
+ if (truncate_item == NULL) {
+ lprintf(cfg, ENOMEM, 0,
+ "worker: couldn't allocate cursor array");
+ return (ENOMEM);
+ }
+ generate_key(cfg, truncate_key, trunc_cfg->last_key);
+ truncate_item->key = truncate_key;
+ truncate_item->diff = trunc_cfg->truncate_stone_gap;
+ STAILQ_INSERT_TAIL(&cfg->truncate_stone_head, truncate_item, q);
+ trunc_cfg->num_stones++;
+ }
+
+ /* We are done if there isn't enough data to trigger a truncate. */
+ if (trunc_cfg->num_stones == 0 ||
+ trunc_cfg->expected_total <= thread->workload->truncate_count) {
+ (void)usleep(1000);
+ *trk = &thread->truncate_sleep;
+ return (0);
+ }
+
+ truncate_item = STAILQ_FIRST(&cfg->truncate_stone_head);
+ trunc_cfg->num_stones--;
+ STAILQ_REMOVE_HEAD(&cfg->truncate_stone_head, q);
+ cursor->set_key(cursor,truncate_item->key);
+ if ((ret = cursor->search(cursor)) != 0) {
+ lprintf(cfg, ret, 0, "Truncate search: failed");
+ return (ret);
+ }
+
+ if ((ret = session->truncate(session, NULL, NULL, cursor, NULL)) != 0) {
+ lprintf(cfg, ret, 0, "Truncate: failed");
+ return (ret);
+ }
+ trunc_cfg->expected_total -= truncate_item->diff;
+ free(truncate_item->key);
+ free(truncate_item);
+ truncate_item = NULL;
+
+ return (ret);
+}
+
+void
+cleanup_truncate_config(CONFIG *cfg) {
+ TRUNCATE_QUEUE_ENTRY *truncate_item;
+
+ while (!STAILQ_EMPTY(&cfg->truncate_stone_head)) {
+ truncate_item = STAILQ_FIRST(&cfg->truncate_stone_head);
+ STAILQ_REMOVE_HEAD(&cfg->truncate_stone_head, q);
+ free(truncate_item->key);
+ free(truncate_item);
+ }
+}