bplus_tree_concurrency_test.cpp 10.3 KB
Newer Older
羽飞's avatar
羽飞 已提交
1
/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

//
// Created by Wangyunlai on 2023/03/14
//
#include <inttypes.h>
#include <stdexcept>
#include <benchmark/benchmark.h>

#include "storage/index/bplus_tree.h"
羽飞's avatar
羽飞 已提交
19
#include "storage/buffer/disk_buffer_pool.h"
20
#include "common/log/log.h"
羽飞's avatar
羽飞 已提交
21
#include "integer_generator.h"
22 23 24 25 26

using namespace std;
using namespace common;
using namespace benchmark;

羽飞's avatar
羽飞 已提交
27
once_flag         init_bpm_flag;
28 29 30 31 32
BufferPoolManager bpm{512};

struct Stat
{
  int64_t insert_success_count = 0;
羽飞's avatar
羽飞 已提交
33 34
  int64_t duplicate_count      = 0;
  int64_t insert_other_count   = 0;
35 36

  int64_t delete_success_count = 0;
羽飞's avatar
羽飞 已提交
37 38
  int64_t not_exist_count      = 0;
  int64_t delete_other_count   = 0;
39

羽飞's avatar
羽飞 已提交
40
  int64_t scan_success_count     = 0;
41
  int64_t scan_open_failed_count = 0;
羽飞's avatar
羽飞 已提交
42 43
  int64_t mismatch_count         = 0;
  int64_t scan_other_count       = 0;
44 45 46 47 48
};

class BenchmarkBase : public Fixture
{
public:
羽飞's avatar
羽飞 已提交
49
  BenchmarkBase() {}
50

羽飞's avatar
羽飞 已提交
51
  virtual ~BenchmarkBase() { BufferPoolManager::set_instance(nullptr); }
52 53 54 55 56 57 58 59 60

  virtual string Name() const = 0;

  virtual void SetUp(const State &state)
  {
    if (0 != state.thread_index()) {
      return;
    }

羽飞's avatar
羽飞 已提交
61
    string log_name       = this->Name() + ".log";
62 63 64 65 66 67
    string btree_filename = this->Name() + ".btree";
    LoggerFactory::init_default(log_name.c_str(), LOG_LEVEL_TRACE);

    std::call_once(init_bpm_flag, []() { BufferPoolManager::set_instance(&bpm); });

    ::remove(btree_filename.c_str());
羽飞's avatar
羽飞 已提交
68

69
    const int internal_max_size = 200;
羽飞's avatar
羽飞 已提交
70 71 72 73 74
    const int leaf_max_size     = 200;

    const char *filename = btree_filename.c_str();

    RC rc = handler_.create(filename, INTS, sizeof(int32_t) /*attr_len*/, internal_max_size, leaf_max_size);
75 76 77
    if (rc != RC::SUCCESS) {
      throw runtime_error("failed to create btree handler");
    }
羽飞's avatar
羽飞 已提交
78 79
    LOG_INFO(
        "test %s setup done. threads=%d, thread index=%d", this->Name().c_str(), state.threads(), state.thread_index());
80 81 82 83 84 85 86 87 88
  }

  virtual void TearDown(const State &state)
  {
    if (0 != state.thread_index()) {
      return;
    }

    handler_.close();
羽飞's avatar
羽飞 已提交
89 90 91 92
    LOG_INFO("test %s teardown done. threads=%d, thread index=%d",
        this->Name().c_str(),
        state.threads(),
        state.thread_index());
93 94 95 96 97 98
  }

  void FillUp(uint32_t min, uint32_t max)
  {
    for (uint32_t value = min; value < max; ++value) {
      const char *key = reinterpret_cast<const char *>(&value);
羽飞's avatar
羽飞 已提交
99 100
      RID         rid(value, value);

羽飞's avatar
羽飞 已提交
101
      [[maybe_unused]] RC rc = handler_.insert_entry(key, &rid);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
      ASSERT(rc == RC::SUCCESS, "failed to insert entry into btree. key=%" PRIu32, value);
    }
  }

  uint32_t GetRangeMax(const State &state) const
  {
    uint32_t max = static_cast<uint32_t>(state.range(0) * 3);
    if (max <= 0) {
      max = (1 << 31);
    }
    return max;
  }

  void Insert(uint32_t value, Stat &stat)
  {
    const char *key = reinterpret_cast<const char *>(&value);
羽飞's avatar
羽飞 已提交
118 119
    RID         rid(value, value);

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    RC rc = handler_.insert_entry(key, &rid);
    switch (rc) {
      case RC::SUCCESS: {
        stat.insert_success_count++;
      } break;
      case RC::RECORD_DUPLICATE_KEY: {
        stat.duplicate_count++;
      } break;
      default: {
        stat.insert_other_count++;
      } break;
    }
  }

  void Delete(uint32_t value, Stat &stat)
  {
    const char *key = reinterpret_cast<const char *>(&value);
羽飞's avatar
羽飞 已提交
137 138
    RID         rid(value, value);

139 140 141 142 143
    RC rc = handler_.delete_entry(key, &rid);
    switch (rc) {
      case RC::SUCCESS: {
        stat.delete_success_count++;
      } break;
羽飞's avatar
羽飞 已提交
144
      case RC::RECORD_NOT_EXIST: {
145 146 147 148 149 150 151 152 153 154 155
        stat.not_exist_count++;
      } break;
      default: {
        stat.delete_other_count++;
      } break;
    }
  }

  void Scan(uint32_t begin, uint32_t end, Stat &stat)
  {
    const char *begin_key = reinterpret_cast<const char *>(&begin);
羽飞's avatar
羽飞 已提交
156
    const char *end_key   = reinterpret_cast<const char *>(&end);
157 158

    BplusTreeScanner scanner(handler_);
羽飞's avatar
羽飞 已提交
159 160 161

    RC rc =
        scanner.open(begin_key, sizeof(begin_key), true /*inclusive*/, end_key, sizeof(end_key), true /*inclusive*/);
162 163 164
    if (rc != RC::SUCCESS) {
      stat.scan_open_failed_count++;
    } else {
羽飞's avatar
羽飞 已提交
165
      RID      rid;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
      uint32_t count = 0;
      while (RC::RECORD_EOF != (rc = scanner.next_entry(rid))) {
        count++;
      }

      if (rc != RC::RECORD_EOF) {
        stat.scan_other_count++;
      } else if (count != (end - begin + 1)) {
        stat.mismatch_count++;
      } else {
        stat.scan_success_count++;
      }

      scanner.close();
    }
  }

protected:
  BplusTreeHandler handler_;
};

////////////////////////////////////////////////////////////////////////////////

struct InsertionBenchmark : public BenchmarkBase
{
  string Name() const override { return "insertion"; }
};

羽飞's avatar
羽飞 已提交
194
BENCHMARK_DEFINE_F(InsertionBenchmark, Insertion)(State &state)
195 196
{
  IntegerGenerator generator(1, 1 << 31);
羽飞's avatar
羽飞 已提交
197
  Stat             stat;
198 199 200 201 202 203

  for (auto _ : state) {
    uint32_t value = static_cast<uint32_t>(generator.next());
    Insert(value, stat);
  }

羽飞's avatar
羽飞 已提交
204
  state.counters["success"]   = Counter(stat.insert_success_count, Counter::kIsRate);
205
  state.counters["duplicate"] = Counter(stat.duplicate_count, Counter::kIsRate);
羽飞's avatar
羽飞 已提交
206
  state.counters["other"]     = Counter(stat.insert_other_count, Counter::kIsRate);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
}

BENCHMARK_REGISTER_F(InsertionBenchmark, Insertion)->Threads(10);

////////////////////////////////////////////////////////////////////////////////

class DeletionBenchmark : public BenchmarkBase
{
public:
  string Name() const override { return "deletion"; }

  void SetUp(const State &state) override
  {
    if (0 != state.thread_index()) {
      return;
    }

    BenchmarkBase::SetUp(state);

    uint32_t max = GetRangeMax(state);
    ASSERT(max > 0, "invalid argument count. %ld", state.range(0));
    FillUp(0, max);
  }
};

羽飞's avatar
羽飞 已提交
232
BENCHMARK_DEFINE_F(DeletionBenchmark, Deletion)(State &state)
233
{
羽飞's avatar
羽飞 已提交
234
  uint32_t         max = GetRangeMax(state);
235
  IntegerGenerator generator(0, max);
羽飞's avatar
羽飞 已提交
236
  Stat             stat;
237 238 239 240 241 242

  for (auto _ : state) {
    uint32_t value = static_cast<uint32_t>(generator.next());
    Delete(value, stat);
  }

羽飞's avatar
羽飞 已提交
243
  state.counters["success"]   = Counter(stat.delete_success_count, Counter::kIsRate);
244
  state.counters["not_exist"] = Counter(stat.not_exist_count, Counter::kIsRate);
羽飞's avatar
羽飞 已提交
245
  state.counters["other"]     = Counter(stat.delete_other_count, Counter::kIsRate);
246 247
}

羽飞's avatar
羽飞 已提交
248
BENCHMARK_REGISTER_F(DeletionBenchmark, Deletion)->Threads(10)->Arg(4 * 10000);
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

////////////////////////////////////////////////////////////////////////////////

class ScanBenchmark : public BenchmarkBase
{
public:
  string Name() const override { return "scan"; }

  void SetUp(const State &state) override
  {
    if (0 != state.thread_index()) {
      return;
    }

    BenchmarkBase::SetUp(state);

    uint32_t max = static_cast<uint32_t>(state.range(0)) * 3;
    ASSERT(max > 0, "invalid argument count. %ld", state.range(0));
    FillUp(0, max);
  }
};

羽飞's avatar
羽飞 已提交
271
BENCHMARK_DEFINE_F(ScanBenchmark, Scan)(State &state)
272
{
羽飞's avatar
羽飞 已提交
273 274
  int              max_range_size = 100;
  uint32_t         max            = GetRangeMax(state);
275 276
  IntegerGenerator begin_generator(1, max - max_range_size);
  IntegerGenerator range_generator(1, max_range_size);
羽飞's avatar
羽飞 已提交
277
  Stat             stat;
278 279 280 281 282 283 284

  for (auto _ : state) {
    uint32_t begin = static_cast<uint32_t>(begin_generator.next());
    uint32_t end   = begin + static_cast<uint32_t>(range_generator.next());
    Scan(begin, end, stat);
  }

羽飞's avatar
羽飞 已提交
285 286
  state.counters["success"]               = Counter(stat.scan_success_count, Counter::kIsRate);
  state.counters["open_failed_count"]     = Counter(stat.scan_open_failed_count, Counter::kIsRate);
287
  state.counters["mismatch_number_count"] = Counter(stat.mismatch_count, Counter::kIsRate);
羽飞's avatar
羽飞 已提交
288
  state.counters["other"]                 = Counter(stat.scan_other_count, Counter::kIsRate);
289 290 291 292 293 294 295 296 297 298 299
}

BENCHMARK_REGISTER_F(ScanBenchmark, Scan)->Threads(10)->Arg(4 * 10000);

////////////////////////////////////////////////////////////////////////////////

struct MixtureBenchmark : public BenchmarkBase
{
  string Name() const override { return "mixture"; }
};

羽飞's avatar
羽飞 已提交
300
BENCHMARK_DEFINE_F(MixtureBenchmark, Mixture)(State &state)
301 302 303 304 305 306 307 308 309 310 311 312 313
{
  pair<uint32_t, uint32_t> data_range{0, GetRangeMax(state)};
  pair<uint32_t, uint32_t> scan_range{1, 100};

  IntegerGenerator data_generator(data_range.first, data_range.second);
  IntegerGenerator scan_range_generator(scan_range.first, scan_range.second);
  IntegerGenerator operation_generator(0, 2);

  Stat stat;

  for (auto _ : state) {
    int64_t operation_type = operation_generator.next();
    switch (operation_type) {
羽飞's avatar
羽飞 已提交
314
      case 0: {  // insert
315 316 317
        uint32_t value = static_cast<uint32_t>(data_generator.next());
        Insert(value, stat);
      } break;
羽飞's avatar
羽飞 已提交
318
      case 1: {  // delete
319 320 321
        uint32_t value = static_cast<uint32_t>(data_generator.next());
        Delete(value, stat);
      } break;
羽飞's avatar
羽飞 已提交
322
      case 2: {  // scan
323
        uint32_t begin = static_cast<uint32_t>(data_generator.next());
羽飞's avatar
羽飞 已提交
324
        uint32_t end   = begin + static_cast<uint32_t>(scan_range_generator.next());
325 326 327 328 329 330 331 332
        Scan(begin, end, stat);
      } break;
      default: {
        ASSERT(false, "should not happen. operation=%ld", operation_type);
      }
    }
  }

羽飞's avatar
羽飞 已提交
333 334 335 336 337 338 339 340 341 342
  state.counters.insert({{"insert_success", Counter(stat.insert_success_count, Counter::kIsRate)},
      {"insert_other", Counter(stat.insert_other_count, Counter::kIsRate)},
      {"insert_duplicate", Counter(stat.duplicate_count, Counter::kIsRate)},
      {"delete_success", Counter(stat.delete_success_count, Counter::kIsRate)},
      {"delete_other", Counter(stat.delete_other_count, Counter::kIsRate)},
      {"delete_not_exist", Counter(stat.not_exist_count, Counter::kIsRate)},
      {"scan_success", Counter(stat.scan_success_count, Counter::kIsRate)},
      {"scan_other", Counter(stat.scan_other_count, Counter::kIsRate)},
      {"scan_mismatch", Counter(stat.mismatch_count, Counter::kIsRate)},
      {"scan_open_failed", Counter(stat.scan_open_failed_count, Counter::kIsRate)}});
343 344 345 346 347 348 349
}

BENCHMARK_REGISTER_F(MixtureBenchmark, Mixture)->Threads(10)->Arg(4 * 10000);

////////////////////////////////////////////////////////////////////////////////

BENCHMARK_MAIN();