range_del_aggregator_bench.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright (c) 2018-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #ifndef GFLAGS
  6. #include <cstdio>
  7. int main() {
  8. fprintf(stderr, "Please install gflags to run rocksdb tools\n");
  9. return 1;
  10. }
  11. #else
  12. #include <iostream>
  13. #include <iomanip>
  14. #include <memory>
  15. #include <random>
  16. #include <set>
  17. #include <string>
  18. #include <vector>
  19. #include "db/range_del_aggregator.h"
  20. #include "db/range_tombstone_fragmenter.h"
  21. #include "rocksdb/comparator.h"
  22. #include "rocksdb/env.h"
  23. #include "test_util/testutil.h"
  24. #include "util/coding.h"
  25. #include "util/random.h"
  26. #include "util/stop_watch.h"
  27. #include "util/gflags_compat.h"
  28. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  29. DEFINE_int32(num_range_tombstones, 1000, "number of range tombstones created");
  30. DEFINE_int32(num_runs, 1000, "number of test runs");
  31. DEFINE_int32(tombstone_start_upper_bound, 1000,
  32. "exclusive upper bound on range tombstone start keys");
  33. DEFINE_int32(should_delete_upper_bound, 1000,
  34. "exclusive upper bound on keys passed to ShouldDelete");
  35. DEFINE_double(tombstone_width_mean, 100.0, "average range tombstone width");
  36. DEFINE_double(tombstone_width_stddev, 0.0,
  37. "standard deviation of range tombstone width");
  38. DEFINE_int32(seed, 0, "random number generator seed");
  39. DEFINE_int32(should_deletes_per_run, 1, "number of ShouldDelete calls per run");
  40. DEFINE_int32(add_tombstones_per_run, 1,
  41. "number of AddTombstones calls per run");
  42. namespace {
  43. struct Stats {
  44. uint64_t time_add_tombstones = 0;
  45. uint64_t time_first_should_delete = 0;
  46. uint64_t time_rest_should_delete = 0;
  47. };
  48. std::ostream& operator<<(std::ostream& os, const Stats& s) {
  49. std::ios fmt_holder(nullptr);
  50. fmt_holder.copyfmt(os);
  51. os << std::left;
  52. os << std::setw(25) << "AddTombstones: "
  53. << s.time_add_tombstones /
  54. (FLAGS_add_tombstones_per_run * FLAGS_num_runs * 1.0e3)
  55. << " us\n";
  56. os << std::setw(25) << "ShouldDelete (first): "
  57. << s.time_first_should_delete / (FLAGS_num_runs * 1.0e3) << " us\n";
  58. if (FLAGS_should_deletes_per_run > 1) {
  59. os << std::setw(25) << "ShouldDelete (rest): "
  60. << s.time_rest_should_delete /
  61. ((FLAGS_should_deletes_per_run - 1) * FLAGS_num_runs * 1.0e3)
  62. << " us\n";
  63. }
  64. os.copyfmt(fmt_holder);
  65. return os;
  66. }
  67. auto icmp = ROCKSDB_NAMESPACE::InternalKeyComparator(
  68. ROCKSDB_NAMESPACE::BytewiseComparator());
  69. } // anonymous namespace
  70. namespace ROCKSDB_NAMESPACE {
  71. namespace {
  72. // A wrapper around RangeTombstones and the underlying data of its start and end
  73. // keys.
  74. struct PersistentRangeTombstone {
  75. std::string start_key;
  76. std::string end_key;
  77. RangeTombstone tombstone;
  78. PersistentRangeTombstone(std::string start, std::string end,
  79. SequenceNumber seq)
  80. : start_key(std::move(start)), end_key(std::move(end)) {
  81. tombstone = RangeTombstone(start_key, end_key, seq);
  82. }
  83. PersistentRangeTombstone() = default;
  84. PersistentRangeTombstone(const PersistentRangeTombstone& t) { *this = t; }
  85. PersistentRangeTombstone& operator=(const PersistentRangeTombstone& t) {
  86. start_key = t.start_key;
  87. end_key = t.end_key;
  88. tombstone = RangeTombstone(start_key, end_key, t.tombstone.seq_);
  89. return *this;
  90. }
  91. PersistentRangeTombstone(PersistentRangeTombstone&& t) noexcept { *this = t; }
  92. PersistentRangeTombstone& operator=(PersistentRangeTombstone&& t) {
  93. start_key = std::move(t.start_key);
  94. end_key = std::move(t.end_key);
  95. tombstone = RangeTombstone(start_key, end_key, t.tombstone.seq_);
  96. return *this;
  97. }
  98. };
  99. struct TombstoneStartKeyComparator {
  100. explicit TombstoneStartKeyComparator(const Comparator* c) : cmp(c) {}
  101. bool operator()(const RangeTombstone& a, const RangeTombstone& b) const {
  102. return cmp->Compare(a.start_key_, b.start_key_) < 0;
  103. }
  104. const Comparator* cmp;
  105. };
  106. std::unique_ptr<InternalIterator> MakeRangeDelIterator(
  107. const std::vector<PersistentRangeTombstone>& range_dels) {
  108. std::vector<std::string> keys, values;
  109. for (const auto& range_del : range_dels) {
  110. auto key_and_value = range_del.tombstone.Serialize();
  111. keys.push_back(key_and_value.first.Encode().ToString());
  112. values.push_back(key_and_value.second.ToString());
  113. }
  114. return std::unique_ptr<test::VectorIterator>(
  115. new test::VectorIterator(keys, values));
  116. }
  117. // convert long to a big-endian slice key
  118. static std::string Key(int64_t val) {
  119. std::string little_endian_key;
  120. std::string big_endian_key;
  121. PutFixed64(&little_endian_key, val);
  122. assert(little_endian_key.size() == sizeof(val));
  123. big_endian_key.resize(sizeof(val));
  124. for (size_t i = 0; i < sizeof(val); ++i) {
  125. big_endian_key[i] = little_endian_key[sizeof(val) - 1 - i];
  126. }
  127. return big_endian_key;
  128. }
  129. } // anonymous namespace
  130. } // namespace ROCKSDB_NAMESPACE
  131. int main(int argc, char** argv) {
  132. ParseCommandLineFlags(&argc, &argv, true);
  133. Stats stats;
  134. ROCKSDB_NAMESPACE::Random64 rnd(FLAGS_seed);
  135. std::default_random_engine random_gen(FLAGS_seed);
  136. std::normal_distribution<double> normal_dist(FLAGS_tombstone_width_mean,
  137. FLAGS_tombstone_width_stddev);
  138. std::vector<std::vector<ROCKSDB_NAMESPACE::PersistentRangeTombstone> >
  139. all_persistent_range_tombstones(FLAGS_add_tombstones_per_run);
  140. for (int i = 0; i < FLAGS_add_tombstones_per_run; i++) {
  141. all_persistent_range_tombstones[i] =
  142. std::vector<ROCKSDB_NAMESPACE::PersistentRangeTombstone>(
  143. FLAGS_num_range_tombstones);
  144. }
  145. auto mode = ROCKSDB_NAMESPACE::RangeDelPositioningMode::kForwardTraversal;
  146. for (int i = 0; i < FLAGS_num_runs; i++) {
  147. ROCKSDB_NAMESPACE::ReadRangeDelAggregator range_del_agg(
  148. &icmp, ROCKSDB_NAMESPACE::kMaxSequenceNumber /* upper_bound */);
  149. std::vector<
  150. std::unique_ptr<ROCKSDB_NAMESPACE::FragmentedRangeTombstoneList> >
  151. fragmented_range_tombstone_lists(FLAGS_add_tombstones_per_run);
  152. for (auto& persistent_range_tombstones : all_persistent_range_tombstones) {
  153. // TODO(abhimadan): consider whether creating the range tombstones right
  154. // before AddTombstones is artificially warming the cache compared to
  155. // real workloads.
  156. for (int j = 0; j < FLAGS_num_range_tombstones; j++) {
  157. uint64_t start = rnd.Uniform(FLAGS_tombstone_start_upper_bound);
  158. uint64_t end = static_cast<uint64_t>(
  159. std::round(start + std::max(1.0, normal_dist(random_gen))));
  160. persistent_range_tombstones[j] =
  161. ROCKSDB_NAMESPACE::PersistentRangeTombstone(
  162. ROCKSDB_NAMESPACE::Key(start), ROCKSDB_NAMESPACE::Key(end), j);
  163. }
  164. auto range_del_iter =
  165. ROCKSDB_NAMESPACE::MakeRangeDelIterator(persistent_range_tombstones);
  166. fragmented_range_tombstone_lists.emplace_back(
  167. new ROCKSDB_NAMESPACE::FragmentedRangeTombstoneList(
  168. ROCKSDB_NAMESPACE::MakeRangeDelIterator(
  169. persistent_range_tombstones),
  170. icmp));
  171. std::unique_ptr<ROCKSDB_NAMESPACE::FragmentedRangeTombstoneIterator>
  172. fragmented_range_del_iter(
  173. new ROCKSDB_NAMESPACE::FragmentedRangeTombstoneIterator(
  174. fragmented_range_tombstone_lists.back().get(), icmp,
  175. ROCKSDB_NAMESPACE::kMaxSequenceNumber));
  176. ROCKSDB_NAMESPACE::StopWatchNano stop_watch_add_tombstones(
  177. ROCKSDB_NAMESPACE::Env::Default(), true /* auto_start */);
  178. range_del_agg.AddTombstones(std::move(fragmented_range_del_iter));
  179. stats.time_add_tombstones += stop_watch_add_tombstones.ElapsedNanos();
  180. }
  181. ROCKSDB_NAMESPACE::ParsedInternalKey parsed_key;
  182. parsed_key.sequence = FLAGS_num_range_tombstones / 2;
  183. parsed_key.type = ROCKSDB_NAMESPACE::kTypeValue;
  184. uint64_t first_key = rnd.Uniform(FLAGS_should_delete_upper_bound -
  185. FLAGS_should_deletes_per_run + 1);
  186. for (int j = 0; j < FLAGS_should_deletes_per_run; j++) {
  187. std::string key_string = ROCKSDB_NAMESPACE::Key(first_key + j);
  188. parsed_key.user_key = key_string;
  189. ROCKSDB_NAMESPACE::StopWatchNano stop_watch_should_delete(
  190. ROCKSDB_NAMESPACE::Env::Default(), true /* auto_start */);
  191. range_del_agg.ShouldDelete(parsed_key, mode);
  192. uint64_t call_time = stop_watch_should_delete.ElapsedNanos();
  193. if (j == 0) {
  194. stats.time_first_should_delete += call_time;
  195. } else {
  196. stats.time_rest_should_delete += call_time;
  197. }
  198. }
  199. }
  200. std::cout << "=========================\n"
  201. << "Results:\n"
  202. << "=========================\n"
  203. << stats;
  204. return 0;
  205. }
  206. #endif // GFLAGS