range_del_aggregator_bench.cc 9.6 KB

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