range_del_aggregator_bench.cc 9.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
//  Copyright (c) 2018-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).

#ifndef GFLAGS
#include <cstdio>
int main() {
  fprintf(stderr, "Please install gflags to run rocksdb tools\n");
  return 1;
}
#else

#include <iostream>
#include <iomanip>
#include <memory>
#include <random>
#include <set>
#include <string>
#include <vector>

#include "db/range_del_aggregator.h"
23 24
#include "db/range_del_aggregator_v2.h"
#include "db/range_tombstone_fragmenter.h"
25 26 27 28 29 30 31 32 33 34 35 36 37
#include "rocksdb/comparator.h"
#include "rocksdb/env.h"
#include "util/coding.h"
#include "util/random.h"
#include "util/stop_watch.h"
#include "util/testutil.h"

#include "util/gflags_compat.h"

using GFLAGS_NAMESPACE::ParseCommandLineFlags;

DEFINE_int32(num_range_tombstones, 1000, "number of range tombstones created");

38
DEFINE_int32(num_runs, 1000, "number of test runs");
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

DEFINE_int32(tombstone_start_upper_bound, 1000,
             "exclusive upper bound on range tombstone start keys");

DEFINE_int32(should_delete_upper_bound, 1000,
             "exclusive upper bound on keys passed to ShouldDelete");

DEFINE_double(tombstone_width_mean, 100.0, "average range tombstone width");

DEFINE_double(tombstone_width_stddev, 0.0,
              "standard deviation of range tombstone width");

DEFINE_bool(use_collapsed, true, "use the collapsed range tombstone map");

DEFINE_int32(seed, 0, "random number generator seed");

DEFINE_int32(should_deletes_per_run, 1, "number of ShouldDelete calls per run");

57 58 59
DEFINE_int32(add_tombstones_per_run, 1,
             "number of AddTombstones calls per run");

60 61
DEFINE_bool(use_v2_aggregator, false, "benchmark RangeDelAggregatorV2");

62 63 64 65 66 67 68 69 70 71 72 73 74
namespace {

struct Stats {
  uint64_t time_add_tombstones = 0;
  uint64_t time_first_should_delete = 0;
  uint64_t time_rest_should_delete = 0;
};

std::ostream& operator<<(std::ostream& os, const Stats& s) {
  std::ios fmt_holder(nullptr);
  fmt_holder.copyfmt(os);

  os << std::left;
75 76 77
  os << std::setw(25) << "AddTombstones: "
     << s.time_add_tombstones /
            (FLAGS_add_tombstones_per_run * FLAGS_num_runs * 1.0e3)
78 79 80 81 82 83 84 85 86 87 88 89 90 91
     << " us\n";
  os << std::setw(25) << "ShouldDelete (first): "
     << s.time_first_should_delete / (FLAGS_num_runs * 1.0e3) << " us\n";
  if (FLAGS_should_deletes_per_run > 1) {
    os << std::setw(25) << "ShouldDelete (rest): "
       << s.time_rest_should_delete /
              ((FLAGS_should_deletes_per_run - 1) * FLAGS_num_runs * 1.0e3)
       << " us\n";
  }

  os.copyfmt(fmt_holder);
  return os;
}

92 93
auto icmp = rocksdb::InternalKeyComparator(rocksdb::BytewiseComparator());

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
}  // anonymous namespace

namespace rocksdb {

namespace {

// A wrapper around RangeTombstones and the underlying data of its start and end
// keys.
struct PersistentRangeTombstone {
  std::string start_key;
  std::string end_key;
  RangeTombstone tombstone;

  PersistentRangeTombstone(std::string start, std::string end,
                           SequenceNumber seq)
      : start_key(std::move(start)), end_key(std::move(end)) {
    tombstone = RangeTombstone(start_key, end_key, seq);
  }

  PersistentRangeTombstone() = default;

  PersistentRangeTombstone(const PersistentRangeTombstone& t) { *this = t; }

  PersistentRangeTombstone& operator=(const PersistentRangeTombstone& t) {
    start_key = t.start_key;
    end_key = t.end_key;
    tombstone = RangeTombstone(start_key, end_key, t.tombstone.seq_);

    return *this;
  }

  PersistentRangeTombstone(PersistentRangeTombstone&& t) noexcept { *this = t; }

  PersistentRangeTombstone& operator=(PersistentRangeTombstone&& t) {
    start_key = std::move(t.start_key);
    end_key = std::move(t.end_key);
    tombstone = RangeTombstone(start_key, end_key, t.tombstone.seq_);

    return *this;
  }
};

struct TombstoneStartKeyComparator {
  explicit TombstoneStartKeyComparator(const Comparator* c) : cmp(c) {}

  bool operator()(const RangeTombstone& a, const RangeTombstone& b) const {
    return cmp->Compare(a.start_key_, b.start_key_) < 0;
  }

  const Comparator* cmp;
};

146 147
std::unique_ptr<InternalIterator> MakeRangeDelIterator(
    const std::vector<PersistentRangeTombstone>& range_dels) {
148 149 150 151 152 153
  std::vector<std::string> keys, values;
  for (const auto& range_del : range_dels) {
    auto key_and_value = range_del.tombstone.Serialize();
    keys.push_back(key_and_value.first.Encode().ToString());
    values.push_back(key_and_value.second.ToString());
  }
154
  return std::unique_ptr<test::VectorIterator>(
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
      new test::VectorIterator(keys, values));
}

// convert long to a big-endian slice key
static std::string Key(int64_t val) {
  std::string little_endian_key;
  std::string big_endian_key;
  PutFixed64(&little_endian_key, val);
  assert(little_endian_key.size() == sizeof(val));
  big_endian_key.resize(sizeof(val));
  for (size_t i = 0; i < sizeof(val); ++i) {
    big_endian_key[i] = little_endian_key[sizeof(val) - 1 - i];
  }
  return big_endian_key;
}

}  // anonymous namespace

}  // namespace rocksdb

int main(int argc, char** argv) {
  ParseCommandLineFlags(&argc, &argv, true);

  Stats stats;
  rocksdb::Random64 rnd(FLAGS_seed);
  std::default_random_engine random_gen(FLAGS_seed);
  std::normal_distribution<double> normal_dist(FLAGS_tombstone_width_mean,
                                               FLAGS_tombstone_width_stddev);
183 184 185 186 187 188 189 190 191 192
  std::vector<std::vector<rocksdb::PersistentRangeTombstone> >
      all_persistent_range_tombstones(FLAGS_add_tombstones_per_run);
  for (int i = 0; i < FLAGS_add_tombstones_per_run; i++) {
    all_persistent_range_tombstones[i] =
        std::vector<rocksdb::PersistentRangeTombstone>(
            FLAGS_num_range_tombstones);
  }
  auto mode = FLAGS_use_collapsed
                  ? rocksdb::RangeDelPositioningMode::kForwardTraversal
                  : rocksdb::RangeDelPositioningMode::kFullScan;
193 194 195 196

  for (int i = 0; i < FLAGS_num_runs; i++) {
    rocksdb::RangeDelAggregator range_del_agg(icmp, {} /* snapshots */,
                                              FLAGS_use_collapsed);
197
    rocksdb::ReadRangeDelAggregatorV2 range_del_agg_v2(
198 199 200 201
        &icmp, rocksdb::kMaxSequenceNumber /* upper_bound */);

    std::vector<std::unique_ptr<rocksdb::FragmentedRangeTombstoneList> >
        fragmented_range_tombstone_lists(FLAGS_add_tombstones_per_run);
202

203 204 205 206 207 208 209 210 211 212
    for (auto& persistent_range_tombstones : all_persistent_range_tombstones) {
      // TODO(abhimadan): consider whether creating the range tombstones right
      // before AddTombstones is artificially warming the cache compared to
      // real workloads.
      for (int j = 0; j < FLAGS_num_range_tombstones; j++) {
        uint64_t start = rnd.Uniform(FLAGS_tombstone_start_upper_bound);
        uint64_t end = start + std::max(1.0, normal_dist(random_gen));
        persistent_range_tombstones[j] = rocksdb::PersistentRangeTombstone(
            rocksdb::Key(start), rocksdb::Key(end), j);
      }
213

214 215
      auto range_del_iter =
          rocksdb::MakeRangeDelIterator(persistent_range_tombstones);
216 217
      fragmented_range_tombstone_lists.emplace_back(
          new rocksdb::FragmentedRangeTombstoneList(
218 219
              rocksdb::MakeRangeDelIterator(persistent_range_tombstones),
              icmp));
220 221 222
      std::unique_ptr<rocksdb::FragmentedRangeTombstoneIterator>
          fragmented_range_del_iter(
              new rocksdb::FragmentedRangeTombstoneIterator(
223 224
                  fragmented_range_tombstone_lists.back().get(), icmp,
                  rocksdb::kMaxSequenceNumber));
225 226 227 228 229 230 231 232 233 234 235 236

      if (FLAGS_use_v2_aggregator) {
        rocksdb::StopWatchNano stop_watch_add_tombstones(
            rocksdb::Env::Default(), true /* auto_start */);
        range_del_agg_v2.AddTombstones(std::move(fragmented_range_del_iter));
        stats.time_add_tombstones += stop_watch_add_tombstones.ElapsedNanos();
      } else {
        rocksdb::StopWatchNano stop_watch_add_tombstones(
            rocksdb::Env::Default(), true /* auto_start */);
        range_del_agg.AddTombstones(std::move(range_del_iter));
        stats.time_add_tombstones += stop_watch_add_tombstones.ElapsedNanos();
      }
237
    }
238 239 240 241 242 243 244 245 246 247 248 249

    rocksdb::ParsedInternalKey parsed_key;
    parsed_key.sequence = FLAGS_num_range_tombstones / 2;
    parsed_key.type = rocksdb::kTypeValue;

    uint64_t first_key = rnd.Uniform(FLAGS_should_delete_upper_bound -
                                     FLAGS_should_deletes_per_run + 1);

    for (int j = 0; j < FLAGS_should_deletes_per_run; j++) {
      std::string key_string = rocksdb::Key(first_key + j);
      parsed_key.user_key = key_string;

250 251 252 253 254 255 256 257 258 259 260 261
      uint64_t call_time;
      if (FLAGS_use_v2_aggregator) {
        rocksdb::StopWatchNano stop_watch_should_delete(rocksdb::Env::Default(),
                                                        true /* auto_start */);
        range_del_agg_v2.ShouldDelete(parsed_key, mode);
        call_time = stop_watch_should_delete.ElapsedNanos();
      } else {
        rocksdb::StopWatchNano stop_watch_should_delete(rocksdb::Env::Default(),
                                                        true /* auto_start */);
        range_del_agg.ShouldDelete(parsed_key, mode);
        call_time = stop_watch_should_delete.ElapsedNanos();
      }
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

      if (j == 0) {
        stats.time_first_should_delete += call_time;
      } else {
        stats.time_rest_should_delete += call_time;
      }
    }
  }

  std::cout << "=========================\n"
            << "Results:\n"
            << "=========================\n"
            << stats;

  return 0;
}

#endif  // GFLAGS