diff --git a/tools/db_bench_tool.cc b/tools/db_bench_tool.cc index d959e84bf..cffd2897f 100644 --- a/tools/db_bench_tool.cc +++ b/tools/db_bench_tool.cc @@ -446,6 +446,26 @@ DEFINE_int32(num_multi_db, 0, DEFINE_double(compression_ratio, 0.5, "Arrange to generate values that shrink" " to this fraction of their original size after compression"); +DEFINE_double( + overwrite_probability, 0.0, + "Used in 'filluniquerandom' benchmark: for each write operation, " + "we give a probability to perform an overwrite instead. The key used for " + "the overwrite is randomly chosen from the last 'overwrite_window_size' " + "keys " + "previously inserted into the DB. " + "Valid overwrite_probability values: [0.0, 1.0]."); + +DEFINE_uint32(overwrite_window_size, 1, + "Used in 'filluniquerandom' benchmark. For each write " + "operation, when " + "the overwrite_probability flag is set by the user, the key used " + "to perform " + "an overwrite is randomly chosen from the last " + "'overwrite_window_size' keys " + "previously inserted into the DB. " + "Warning: large values can affect throughput. " + "Valid overwrite_window_size values: [1, kMaxUint32]."); + DEFINE_double(read_random_exp_range, 0.0, "Read random's key will be generated using distribution of " "num * exp(-r) where r is uniform number from 0 to this value. " @@ -4807,6 +4827,36 @@ class Benchmark { Slice begin_key = AllocateKey(&begin_key_guard); std::unique_ptr end_key_guard; Slice end_key = AllocateKey(&end_key_guard); + double p = 0.0; + uint64_t num_overwrites = 0, num_unique_keys = 0; + // If user set overwrite_probability flag, + // check if value is in [0.0,1.0]. + if (FLAGS_overwrite_probability > 0.0) { + p = FLAGS_overwrite_probability > 1.0 ? 1.0 : FLAGS_overwrite_probability; + // If overwrite set by user, and UNIQUE_RANDOM mode on, + // the overwrite_window_size must be > 0. + if (write_mode == UNIQUE_RANDOM && FLAGS_overwrite_window_size == 0) { + fprintf(stderr, + "Overwrite_window_size must be strictly greater than 0.\n"); + ErrorExit(); + } + } + + // Default_random_engine provides slightly + // improved throughput over mt19937. + std::default_random_engine overwrite_gen{ + static_cast(FLAGS_seed)}; + std::bernoulli_distribution overwrite_decider(p); + + // Inserted key window is filled with the last N + // keys previously inserted into the DB (with + // N=FLAGS_overwrite_window_size). + // We use a deque struct because: + // - random access is O(1) + // - insertion/removal at beginning/end is also O(1). + std::deque inserted_key_window; + Random64 reservoir_id_gen(FLAGS_seed); + std::vector> expanded_key_guards; std::vector expanded_keys; if (FLAGS_expand_range_tombstones) { @@ -4841,7 +4891,26 @@ class Benchmark { int64_t batch_bytes = 0; for (int64_t j = 0; j < entries_per_batch_; j++) { - int64_t rand_num = key_gens[id]->Next(); + int64_t rand_num = 0; + if ((write_mode == UNIQUE_RANDOM) && (p > 0.0)) { + if ((inserted_key_window.size() > 0) && + overwrite_decider(overwrite_gen)) { + num_overwrites++; + rand_num = inserted_key_window[reservoir_id_gen.Next() % + inserted_key_window.size()]; + } else { + num_unique_keys++; + rand_num = key_gens[id]->Next(); + if (inserted_key_window.size() < FLAGS_overwrite_window_size) { + inserted_key_window.push_back(rand_num); + } else { + inserted_key_window.pop_front(); + inserted_key_window.push_back(rand_num); + } + } + } else { + rand_num = key_gens[id]->Next(); + } GenerateKeyFromInt(rand_num, FLAGS_num, &key); Slice val = gen.Generate(); if (use_blob_db_) { @@ -4969,6 +5038,12 @@ class Benchmark { ErrorExit(); } } + if ((write_mode == UNIQUE_RANDOM) && (p > 0.0)) { + fprintf(stdout, + "Number of unique keys inerted: %" PRIu64 + ".\nNumber of overwrites: %" PRIu64 "\n", + num_unique_keys, num_overwrites); + } thread->stats.AddBytes(bytes); }