db_bench.cc 76.7 KB
Newer Older
J
jorlow@chromium.org 已提交
1 2 3 4
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

5
#include <cstddef>
J
jorlow@chromium.org 已提交
6 7 8 9 10
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include "db/db_impl.h"
#include "db/version_set.h"
11
#include "db/db_statistics.h"
12
#include "leveldb/options.h"
13 14 15 16
#include "leveldb/cache.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/write_batch.h"
17
#include "leveldb/statistics.h"
J
jorlow@chromium.org 已提交
18
#include "port/port.h"
19
#include "util/bit_set.h"
J
jorlow@chromium.org 已提交
20
#include "util/crc32c.h"
J
jorlow@chromium.org 已提交
21
#include "util/histogram.h"
22
#include "util/mutexlock.h"
J
jorlow@chromium.org 已提交
23
#include "util/random.h"
24
#include "util/stack_trace.h"
25
#include "util/string_util.h"
J
jorlow@chromium.org 已提交
26
#include "util/testutil.h"
27
#include "hdfs/env_hdfs.h"
J
jorlow@chromium.org 已提交
28 29 30

// Comma-separated list of operations to run in the specified order
//   Actual benchmarks:
31 32 33 34 35
//      fillseq       -- write N values in sequential key order in async mode
//      fillrandom    -- write N values in random key order in async mode
//      overwrite     -- overwrite N values in random key order in async mode
//      fillsync      -- write N/100 values in random key order in sync mode
//      fill100K      -- write N/1000 100K values in random order in async mode
S
Sanjay Ghemawat 已提交
36 37
//      deleteseq     -- delete N keys in sequential order
//      deleterandom  -- delete N keys in random order
38 39 40
//      readseq       -- read N times sequentially
//      readreverse   -- read N times in reverse order
//      readrandom    -- read N times in random order
S
Sanjay Ghemawat 已提交
41
//      readmissing   -- read N missing keys in random order
42
//      readhot       -- read N times in random order from 1% section of DB
43 44 45
//      readwhilewriting -- 1 writer, N threads doing random reads
//      readrandomwriterandom - N threads doing random-read, random-write
//      updaterandom  -- N threads doing read-modify-write for random keys
S
Sanjay Ghemawat 已提交
46
//      seekrandom    -- N random seeks
J
jorlow@chromium.org 已提交
47
//      crc32c        -- repeated crc32c of 4K of data
48
//      acquireload   -- load N*1000 times
J
jorlow@chromium.org 已提交
49 50
//   Meta operations:
//      compact     -- Compact the entire DB
51
//      stats       -- Print DB stats
52
//      levelstats  -- Print the number of files and bytes per level
S
Sanjay Ghemawat 已提交
53
//      sstables    -- Print sstable info
J
jorlow@chromium.org 已提交
54 55
//      heapprofile -- Dump a heap profile (if supported by this port)
static const char* FLAGS_benchmarks =
56
    "fillseq,"
J
jorlow@chromium.org 已提交
57
    "fillsync,"
58 59
    "fillrandom,"
    "overwrite,"
J
jorlow@chromium.org 已提交
60 61
    "readrandom,"
    "readrandom,"  // Extra run to allow previous compactions to quiesce
J
jorlow@chromium.org 已提交
62
    "readseq,"
J
jorlow@chromium.org 已提交
63
    "readreverse,"
J
jorlow@chromium.org 已提交
64
    "compact,"
J
jorlow@chromium.org 已提交
65
    "readrandom,"
J
jorlow@chromium.org 已提交
66
    "readseq,"
J
jorlow@chromium.org 已提交
67
    "readreverse,"
68
    "readwhilewriting,"
69
    "readrandomwriterandom," // mix reads and writes based on FLAGS_readwritepercent
M
Mark Callaghan 已提交
70
    "updaterandom," // read-modify-write for random keys
71
    "randomwithverify," // random reads and writes with some verification
J
jorlow@chromium.org 已提交
72 73
    "fill100K,"
    "crc32c,"
74 75
    "snappycomp,"
    "snappyuncomp,"
76
    "acquireload,"
J
jorlow@chromium.org 已提交
77
    ;
78 79
// the maximum size of key in bytes
static const int MAX_KEY_SIZE = 128;
J
jorlow@chromium.org 已提交
80
// Number of key/values to place in database
81
static long FLAGS_num = 1000000;
J
jorlow@chromium.org 已提交
82

83 84 85 86 87
// Number of distinct keys to use. Used in RandomWithVerify to read/write
// on fewer keys so that gets are more likely to find the key and puts
// are more likely to update the same key
static long FLAGS_numdistinct = 1000;

88
// Number of read operations to do.  If negative, do FLAGS_num reads.
89
static long FLAGS_reads = -1;
90

91 92 93 94 95 96
// When ==1 reads use ::Get, when >1 reads use an iterator
static long FLAGS_read_range = 1;

// Seed base for random number generators. When 0 it is deterministic.
static long FLAGS_seed = 0;

97 98 99
// Number of concurrent threads to run.
static int FLAGS_threads = 1;

M
Mark Callaghan 已提交
100 101 102 103
// Time in seconds for the random-ops tests to run. When 0 then
// FLAGS_num & FLAGS_reads determine the test duration
static int FLAGS_duration = 0;

J
jorlow@chromium.org 已提交
104 105 106
// Size of each value
static int FLAGS_value_size = 100;

107 108 109
//size of each key
static int FLAGS_key_size = 16;

J
jorlow@chromium.org 已提交
110 111
// Arrange to generate values that shrink to this fraction of
// their original size after compression
112
static double FLAGS_compression_ratio = 0.5;
J
jorlow@chromium.org 已提交
113 114 115 116 117

// Print histogram of operation timings
static bool FLAGS_histogram = false;

// Number of bytes to buffer in memtable before compacting
118 119 120
// (initialized to default value by "main")
static int FLAGS_write_buffer_size = 0;

A
Abhishek Kona 已提交
121
// The number of in-memory memtables.
122 123 124 125
// Each memtable is of size FLAGS_write_buffer_size.
// This is initialized to default value of 2 in "main" function.
static int FLAGS_max_write_buffer_number = 0;

126 127 128
// The minimum number of write buffers that will be merged together
// before writing to storage. This is cheap because it is an
// in-memory merge. If this feature is not enabled, then all these
X
Xing Jin 已提交
129
// write buffers are flushed to L0 as separate files and this increases
130
// read amplification because a get request has to check in all of these
X
Xing Jin 已提交
131
// files. Also, an in-memory merge may result in writing less
132 133 134 135
// data to storage if there are duplicate records in each of these
// individual write buffers.
static int FLAGS_min_write_buffer_number_to_merge = 0;

136 137 138 139 140
// The maximum number of concurrent background compactions
// that can occur in parallel.
// This is initialized to default value of 1 in "main" function.
static int FLAGS_max_background_compactions = 0;

141 142
// style of compaction: level-based vs universal
static leveldb::CompactionStyle FLAGS_compaction_style = leveldb::kCompactionStyleLevel;
143

X
Xing Jin 已提交
144 145
// Percentage flexibility while comparing file size
// (for universal compaction only).
146
static int FLAGS_universal_size_ratio = 1;
147

X
Xing Jin 已提交
148 149
// The minimum number of files in a single compaction run
// (for universal compaction only).
150
static int FLAGS_compaction_universal_min_merge_width = 2;
151

152 153
// Number of bytes to use as a cache of uncompressed data.
// Negative means use default settings.
D
Dhruba Borthakur 已提交
154
static long FLAGS_cache_size = -1;
J
jorlow@chromium.org 已提交
155

156 157 158
// Number of bytes in a block.
static int FLAGS_block_size = 0;

159 160 161
// Maximum number of files to keep open at the same time (use default if == 0)
static int FLAGS_open_files = 0;

S
Sanjay Ghemawat 已提交
162 163 164 165
// Bloom filter bits per key.
// Negative means use default settings.
static int FLAGS_bloom_bits = -1;

166 167 168 169 170
// If true, do not destroy the existing database.  If you set this
// flag and also specify a benchmark that wants a fresh database, that
// benchmark will fail.
static bool FLAGS_use_existing_db = false;

171
// Use the db with the following name.
172
static const char* FLAGS_db = nullptr;
173

174 175 176 177 178
// Number of shards for the block cache is 2 ** FLAGS_cache_numshardbits.
// Negative means use default settings. This is applied only
// if FLAGS_cache_size is non-negative.
static int FLAGS_cache_numshardbits = -1;

179 180 181
// Verify checksum for every block read from storage
static bool FLAGS_verify_checksum = false;

182 183
// Database statistics
static bool FLAGS_statistics = false;
A
Abhishek Kona 已提交
184
static class std::shared_ptr<leveldb::Statistics> dbstats;
185

186 187 188
// Number of write operations to do.  If negative, do FLAGS_num reads.
static long FLAGS_writes = -1;

189 190 191 192
// Per-thread rate limit on writes per second. No limit when <= 0.
// Only for the readwhilewriting test.
static int FLAGS_writes_per_second = 0;

H
heyongqiang 已提交
193 194
// These default values might change if the hardcoded

195 196 197
// Sync all writes to disk
static bool FLAGS_sync = false;

H
heyongqiang 已提交
198 199 200
// If true, do not wait until data is synced to disk.
static bool FLAGS_disable_data_sync = false;

201 202 203
// If true, issue fsync instead of fdatasync
static bool FLAGS_use_fsync = false;

H
heyongqiang 已提交
204 205 206
// If true, do not write WAL for write.
static bool FLAGS_disable_wal = false;

M
Mark Callaghan 已提交
207 208 209 210 211 212 213
// If true, create a snapshot per query when randomread benchmark is used
static bool FLAGS_use_snapshot = false;

// If true, call GetApproximateSizes per query when FLAGS_read_range is > 1
// and randomread benchmark is used
static bool FLAGS_get_approx = false;

214
// The total number of levels
215
static int FLAGS_num_levels = 7;
216

X
Xing Jin 已提交
217
// Target file size at level-1
H
heyongqiang 已提交
218 219
static int FLAGS_target_file_size_base = 2 * 1048576;

X
Xing Jin 已提交
220
// A multiplier to compute target level-N file size (N >= 2)
H
heyongqiang 已提交
221 222
static int FLAGS_target_file_size_multiplier = 1;

223
// Max bytes for level-1
224
static uint64_t FLAGS_max_bytes_for_level_base = 10 * 1048576;
H
heyongqiang 已提交
225

X
Xing Jin 已提交
226
// A multiplier to compute max bytes for level-N (N >= 2)
H
heyongqiang 已提交
227 228
static int FLAGS_max_bytes_for_level_multiplier = 10;

229 230 231
// A vector that specifies additional fanout per level
static std::vector<int> FLAGS_max_bytes_for_level_multiplier_additional;

H
heyongqiang 已提交
232 233 234
// Number of files in level-0 that will trigger put stop.
static int FLAGS_level0_stop_writes_trigger = 12;

235 236
// Number of files in level-0 that will slow down writes.
static int FLAGS_level0_slowdown_writes_trigger = 8;
H
heyongqiang 已提交
237

238 239 240
// Number of files in level-0 when compactions start
static int FLAGS_level0_file_num_compaction_trigger = 4;

X
Xing Jin 已提交
241 242 243 244
// Ratio of reads to reads/writes (expressed as percentage) for the
// ReadRandomWriteRandom workload. The default value 90 means 90% operations
// out of all reads and writes operations are reads. In other words, 9 gets
// for every 1 put.
245 246
static int FLAGS_readwritepercent = 90;

X
Xing Jin 已提交
247 248 249 250
// Percentage of deletes out of reads/writes/deletes (used in RandomWithVerify
// only). RandomWithVerify calculates writepercent as
// (100 - FLAGS_readwritepercent - FLAGS_deletepercent), so FLAGS_deletepercent
// must be smaller than (100 - FLAGS_readwritepercent)
251 252
static int FLAGS_deletepercent = 2;

X
Xing Jin 已提交
253
// Option to disable compaction triggered by read.
254 255
static int FLAGS_disable_seek_compaction = false;

256 257 258 259 260
// Option to delete obsolete files periodically
// Default: 0 which means that obsolete files are
// deleted after every compaction run.
static uint64_t FLAGS_delete_obsolete_files_period_micros = 0;

X
Xing Jin 已提交
261
// Algorithm used to compress the database
262 263 264
static enum leveldb::CompressionType FLAGS_compression_type =
    leveldb::kSnappyCompression;

X
Xing Jin 已提交
265 266 267
// If non-negative, compression starts from this level. Levels with number
// < FLAGS_min_level_to_compress are not compressed.
// Otherwise, apply FLAGS_compression_type to all levels.
268
static int FLAGS_min_level_to_compress = -1;
269

270 271
static int FLAGS_table_cache_numshardbits = 4;

272 273 274
// posix or hdfs environment
static leveldb::Env* FLAGS_env = leveldb::Env::Default();

275 276 277 278
// Stats are reported every N operations when this is greater
// than zero. When 0 the interval grows over time.
static int FLAGS_stats_interval = 0;

279 280 281 282
// Reports additional stats per interval when this is greater
// than 0.
static int FLAGS_stats_per_interval = 0;

J
Jim Paton 已提交
283 284
static double FLAGS_soft_rate_limit = 0;

285 286 287
// When not equal to 0 this make threads sleep at each stats
// reporting interval until the compaction score for all levels is
// less than or equal to this value.
J
Jim Paton 已提交
288
static double FLAGS_hard_rate_limit = 0;
289

J
Jim Paton 已提交
290 291 292
// When FLAGS_hard_rate_limit is set then this is the max time a put will be
// stalled.
static int FLAGS_rate_limit_delay_max_milliseconds = 1000;
293

294 295
// Control maximum bytes of overlaps in grandparent (i.e., level+2) before we
// stop building a single file in a level->level+1 compaction.
296
static int FLAGS_max_grandparent_overlap_factor = 10;
297

H
heyongqiang 已提交
298 299 300
// Run read only benchmarks.
static bool FLAGS_read_only = false;

301 302 303
// Do not auto trigger compactions
static bool FLAGS_disable_auto_compactions = false;

X
Xing Jin 已提交
304 305
// Cap the size of data in level-K for a compaction run
// that compacts Level-K with Level-(K+1) (for K >= 1)
306 307
static int FLAGS_source_compaction_factor = 1;

308 309 310
// Set the TTL for the WAL Files.
static uint64_t FLAGS_WAL_ttl_seconds = 0;

311 312 313 314 315 316 317 318 319
// Allow buffered io using OS buffers
static bool FLAGS_use_os_buffer;

// Allow reads to occur via mmap-ing files
static bool FLAGS_use_mmap_reads;

// Allow writes to occur via mmap-ing files
static bool FLAGS_use_mmap_writes;

320 321 322 323 324 325 326 327
// Advise random access on table file open
static bool FLAGS_advise_random_on_open =
  leveldb::Options().advise_random_on_open;

// Access pattern advice when a file is compacted
static auto FLAGS_compaction_fadvice =
  leveldb::Options().access_hint_on_compaction_start;

328 329 330 331 332 333 334 335 336 337 338
// Use multiget to access a series of keys instead of get
static bool FLAGS_use_multiget = false;

// If FLAGS_use_multiget is true, determines number of keys to group per call
// Arbitrary default. 90 is good because it agrees with FLAGS_readwritepercent
static long FLAGS_keys_per_multiget = 90;

// Print a message to user when a key is missing in a Get/MultiGet call
// TODO: Apply this flag to generic Get calls too. Currently only with Multiget
static bool FLAGS_warn_missing_keys = true;

H
Haobo Xu 已提交
339 340 341 342
// Use adaptive mutex
static auto FLAGS_use_adaptive_mutex =
  leveldb::Options().use_adaptive_mutex;

H
Haobo Xu 已提交
343 344 345 346 347 348
// Allows OS to incrementally sync files to disk while they are being
// written, in the background. Issue one request for every bytes_per_sync
// written. 0 turns it off.
static auto FLAGS_bytes_per_sync =
  leveldb::Options().bytes_per_sync;

349
// On true, deletes use bloom-filter and drop the delete if key not present
350
static bool FLAGS_filter_deletes = false;
351

J
jorlow@chromium.org 已提交
352 353
namespace leveldb {

354
// Helper for quickly generating random data.
J
jorlow@chromium.org 已提交
355 356 357
class RandomGenerator {
 private:
  std::string data_;
358
  unsigned int pos_;
J
jorlow@chromium.org 已提交
359 360 361 362 363 364 365 366

 public:
  RandomGenerator() {
    // We use a limited amount of data over and over again and ensure
    // that it is larger than the compression window (32KB), and also
    // large enough to serve all typical value sizes we want to write.
    Random rnd(301);
    std::string piece;
367
    while (data_.size() < (unsigned)std::max(1048576, FLAGS_value_size)) {
J
jorlow@chromium.org 已提交
368 369 370 371 372 373 374 375
      // Add a short fragment that is as compressible as specified
      // by FLAGS_compression_ratio.
      test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
      data_.append(piece);
    }
    pos_ = 0;
  }

376
  Slice Generate(unsigned int len) {
J
jorlow@chromium.org 已提交
377 378 379 380 381 382 383
    if (pos_ + len > data_.size()) {
      pos_ = 0;
      assert(len < data_.size());
    }
    pos_ += len;
    return Slice(data_.data() + pos_ - len, len);
  }
384
};
X
Xing Jin 已提交
385

386
static Slice TrimSpace(Slice s) {
387
  unsigned int start = 0;
388 389 390
  while (start < s.size() && isspace(s[start])) {
    start++;
  }
391
  unsigned int limit = s.size();
392 393 394 395 396 397
  while (limit > start && isspace(s[limit-1])) {
    limit--;
  }
  return Slice(s.data() + start, limit - start);
}

398 399 400 401 402 403 404 405 406 407
static void AppendWithSpace(std::string* str, Slice msg) {
  if (msg.empty()) return;
  if (!str->empty()) {
    str->push_back(' ');
  }
  str->append(msg.data(), msg.size());
}

class Stats {
 private:
408
  int id_;
409 410 411
  double start_;
  double finish_;
  double seconds_;
412
  long done_;
413
  long last_report_done_;
414 415 416
  int next_report_;
  int64_t bytes_;
  double last_op_finish_;
417
  double last_report_finish_;
418
  HistogramImpl hist_;
419
  std::string message_;
420
  bool exclude_from_merge_;
421 422

 public:
423
  Stats() { Start(-1); }
424

425 426 427
  void Start(int id) {
    id_ = id;
    next_report_ = FLAGS_stats_interval ? FLAGS_stats_interval : 100;
428 429 430
    last_op_finish_ = start_;
    hist_.Clear();
    done_ = 0;
431
    last_report_done_ = 0;
432 433
    bytes_ = 0;
    seconds_ = 0;
434
    start_ = FLAGS_env->NowMicros();
435
    finish_ = start_;
436
    last_report_finish_ = start_;
437
    message_.clear();
438 439
    // When set, stats from this thread won't be merged with others.
    exclude_from_merge_ = false;
440 441 442
  }

  void Merge(const Stats& other) {
443 444 445
    if (other.exclude_from_merge_)
      return;

446 447 448 449 450 451 452 453 454 455 456 457
    hist_.Merge(other.hist_);
    done_ += other.done_;
    bytes_ += other.bytes_;
    seconds_ += other.seconds_;
    if (other.start_ < start_) start_ = other.start_;
    if (other.finish_ > finish_) finish_ = other.finish_;

    // Just keep the messages from one thread
    if (message_.empty()) message_ = other.message_;
  }

  void Stop() {
458
    finish_ = FLAGS_env->NowMicros();
459 460 461 462 463 464 465
    seconds_ = (finish_ - start_) * 1e-6;
  }

  void AddMessage(Slice msg) {
    AppendWithSpace(&message_, msg);
  }

466
  void SetId(int id) { id_ = id; }
467
  void SetExcludeFromMerge() { exclude_from_merge_ = true; }
468

M
Mark Callaghan 已提交
469
  void FinishedSingleOp(DB* db) {
470
    if (FLAGS_histogram) {
471
      double now = FLAGS_env->NowMicros();
472 473
      double micros = now - last_op_finish_;
      hist_.Add(micros);
474
      if (micros > 20000 && !FLAGS_stats_interval) {
475 476 477 478 479 480 481 482
        fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
        fflush(stderr);
      }
      last_op_finish_ = now;
    }

    done_++;
    if (done_ >= next_report_) {
483 484 485 486 487 488 489 490 491 492 493 494 495
      if (!FLAGS_stats_interval) {
        if      (next_report_ < 1000)   next_report_ += 100;
        else if (next_report_ < 5000)   next_report_ += 500;
        else if (next_report_ < 10000)  next_report_ += 1000;
        else if (next_report_ < 50000)  next_report_ += 5000;
        else if (next_report_ < 100000) next_report_ += 10000;
        else if (next_report_ < 500000) next_report_ += 50000;
        else                            next_report_ += 100000;
        fprintf(stderr, "... finished %ld ops%30s\r", done_, "");
        fflush(stderr);
      } else {
        double now = FLAGS_env->NowMicros();
        fprintf(stderr,
496
                "%s ... thread %d: (%ld,%ld) ops and (%.1f,%.1f) ops/second in (%.6f,%.6f) seconds\n",
497
                FLAGS_env->TimeToString((uint64_t) now/1000000).c_str(),
498
                id_,
M
Mark Callaghan 已提交
499
                done_ - last_report_done_, done_,
500
                (done_ - last_report_done_) /
M
Mark Callaghan 已提交
501 502 503 504
                ((now - last_report_finish_) / 1000000.0),
                done_ / ((now - start_) / 1000000.0),
                (now - last_report_finish_) / 1000000.0,
                (now - start_) / 1000000.0);
M
Mark Callaghan 已提交
505

506 507 508
        if (FLAGS_stats_per_interval) {
          std::string stats;
          if (db && db->GetProperty("leveldb.stats", &stats))
509
            fprintf(stderr, "%s\n", stats.c_str());
510
        }
M
Mark Callaghan 已提交
511

512 513 514 515 516
        fflush(stderr);
        next_report_ += FLAGS_stats_interval;
        last_report_finish_ = now;
        last_report_done_ = done_;
      }
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
    }
  }

  void AddBytes(int64_t n) {
    bytes_ += n;
  }

  void Report(const Slice& name) {
    // Pretend at least one op was done in case we are running a benchmark
    // that does not call FinishedSingleOp().
    if (done_ < 1) done_ = 1;

    std::string extra;
    if (bytes_ > 0) {
      // Rate is computed on actual elapsed time, not the sum of per-thread
      // elapsed times.
      double elapsed = (finish_ - start_) * 1e-6;
      char rate[100];
      snprintf(rate, sizeof(rate), "%6.1f MB/s",
               (bytes_ / 1048576.0) / elapsed);
      extra = rate;
    }
    AppendWithSpace(&extra, message_);
540 541
    double elapsed = (finish_ - start_) * 1e-6;
    double throughput = (double)done_/elapsed;
542

D
Dhruba Borthakur 已提交
543
    fprintf(stdout, "%-12s : %11.3f micros/op %ld ops/sec;%s%s\n",
544
            name.ToString().c_str(),
545
            elapsed * 1e6 / done_,
D
Dhruba Borthakur 已提交
546
            (long)throughput,
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
            (extra.empty() ? "" : " "),
            extra.c_str());
    if (FLAGS_histogram) {
      fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());
    }
    fflush(stdout);
  }
};

// State shared by all concurrent executions of the same benchmark.
struct SharedState {
  port::Mutex mu;
  port::CondVar cv;
  int total;

  // Each thread goes through the following states:
  //    (1) initializing
  //    (2) waiting for others to be initialized
  //    (3) running
  //    (4) done

568 569
  long num_initialized;
  long num_done;
570 571 572 573 574 575 576 577 578 579
  bool start;

  SharedState() : cv(&mu) { }
};

// Per-thread state for concurrent executions of the same benchmark.
struct ThreadState {
  int tid;             // 0..n-1 when running in n threads
  Random rand;         // Has different seeds for different threads
  Stats stats;
580
  SharedState* shared;
581

A
Abhishek Kona 已提交
582
  /* implicit */ ThreadState(int index)
583
      : tid(index),
584
        rand((FLAGS_seed ? FLAGS_seed : 1000) + index) {
585 586 587
  }
};

M
Mark Callaghan 已提交
588 589 590 591 592 593 594 595 596 597
class Duration {
 public:
  Duration(int max_seconds, long max_ops) {
    max_seconds_ = max_seconds;
    max_ops_= max_ops;
    ops_ = 0;
    start_at_ = FLAGS_env->NowMicros();
  }

  bool Done(int increment) {
598
    if (increment <= 0) increment = 1;    // avoid Done(0) and infinite loops
M
Mark Callaghan 已提交
599 600 601
    ops_ += increment;

    if (max_seconds_) {
602 603
      // Recheck every appx 1000 ops (exact iff increment is factor of 1000)
      if ((ops_/1000) != ((ops_-increment)/1000)) {
M
Mark Callaghan 已提交
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
        double now = FLAGS_env->NowMicros();
        return ((now - start_at_) / 1000000.0) >= max_seconds_;
      } else {
        return false;
      }
    } else {
      return ops_ > max_ops_;
    }
  }

 private:
  int max_seconds_;
  long max_ops_;
  long ops_;
  double start_at_;
};

J
jorlow@chromium.org 已提交
621 622
class Benchmark {
 private:
623
  shared_ptr<Cache> cache_;
S
Sanjay Ghemawat 已提交
624
  const FilterPolicy* filter_policy_;
J
jorlow@chromium.org 已提交
625
  DB* db_;
626
  long num_;
627
  int value_size_;
628
  int key_size_;
629 630
  int entries_per_batch_;
  WriteOptions write_options_;
631
  long reads_;
632
  long writes_;
633
  long readwrites_;
J
jorlow@chromium.org 已提交
634
  int heap_counter_;
635
  char keyFormat_[100]; // this string will contain the format of key. e.g "%016d"
636 637
  void PrintHeader() {
    PrintEnvironment();
638
    fprintf(stdout, "Keys:       %d bytes each\n", FLAGS_key_size);
639 640 641
    fprintf(stdout, "Values:     %d bytes each (%d bytes after compression)\n",
            FLAGS_value_size,
            static_cast<int>(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
642
    fprintf(stdout, "Entries:    %ld\n", num_);
643
    fprintf(stdout, "RawSize:    %.1f MB (estimated)\n",
644
            ((static_cast<int64_t>(FLAGS_key_size + FLAGS_value_size) * num_)
645
             / 1048576.0));
646
    fprintf(stdout, "FileSize:   %.1f MB (estimated)\n",
647
            (((FLAGS_key_size + FLAGS_value_size * FLAGS_compression_ratio) * num_)
648
             / 1048576.0));
649
    fprintf(stdout, "Write rate limit: %d\n", FLAGS_writes_per_second);
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665

    switch (FLAGS_compression_type) {
      case leveldb::kNoCompression:
        fprintf(stdout, "Compression: none\n");
        break;
      case leveldb::kSnappyCompression:
        fprintf(stdout, "Compression: snappy\n");
        break;
      case leveldb::kZlibCompression:
        fprintf(stdout, "Compression: zlib\n");
        break;
      case leveldb::kBZip2Compression:
        fprintf(stdout, "Compression: bzip2\n");
        break;
    }

666 667 668 669 670 671 672 673 674 675 676 677 678 679
    PrintWarnings();
    fprintf(stdout, "------------------------------------------------\n");
  }

  void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
    fprintf(stdout,
            "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n"
            );
#endif
#ifndef NDEBUG
    fprintf(stdout,
            "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
680

681 682 683 684 685
    if (FLAGS_compression_type != leveldb::kNoCompression) {
      // The test string should not be too small.
      const int len = FLAGS_block_size;
      char* text = (char*) malloc(len+1);
      bool result = true;
686
      const char* name = nullptr;
687 688 689 690 691 692 693
      std::string compressed;

      memset(text, (int) 'y', len);
      text[len] = '\0';

      switch (FLAGS_compression_type) {
        case kSnappyCompression:
694 695
          result = port::Snappy_Compress(Options().compression_opts, text,
                                         strlen(text), &compressed);
696 697 698
          name = "Snappy";
          break;
        case kZlibCompression:
699 700
          result = port::Zlib_Compress(Options().compression_opts, text,
                                       strlen(text), &compressed);
701 702 703
          name = "Zlib";
          break;
        case kBZip2Compression:
704 705
          result = port::BZip2_Compress(Options().compression_opts, text,
                                        strlen(text), &compressed);
706 707
          name = "BZip2";
          break;
708 709 710
        case kNoCompression:
          assert(false); // cannot happen
          break;
711 712 713 714 715 716 717 718 719
      }

      if (!result) {
        fprintf(stdout, "WARNING: %s compression is not enabled\n", name);
      } else if (name && compressed.size() >= strlen(text)) {
        fprintf(stdout, "WARNING: %s compression is not effective\n", name);
      }

      free(text);
720
    }
721 722 723 724 725 726 727
  }

  void PrintEnvironment() {
    fprintf(stderr, "LevelDB:    version %d.%d\n",
            kMajorVersion, kMinorVersion);

#if defined(__linux)
728
    time_t now = time(nullptr);
729 730 731
    fprintf(stderr, "Date:       %s", ctime(&now));  // ctime() adds newline

    FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
732
    if (cpuinfo != nullptr) {
733 734 735 736
      char line[1000];
      int num_cpus = 0;
      std::string cpu_type;
      std::string cache_size;
737
      while (fgets(line, sizeof(line), cpuinfo) != nullptr) {
738
        const char* sep = strchr(line, ':');
739
        if (sep == nullptr) {
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
          continue;
        }
        Slice key = TrimSpace(Slice(line, sep - 1 - line));
        Slice val = TrimSpace(Slice(sep + 1));
        if (key == "model name") {
          ++num_cpus;
          cpu_type = val.ToString();
        } else if (key == "cache size") {
          cache_size = val.ToString();
        }
      }
      fclose(cpuinfo);
      fprintf(stderr, "CPU:        %d * %s\n", num_cpus, cpu_type.c_str());
      fprintf(stderr, "CPUCache:   %s\n", cache_size.c_str());
    }
#endif
  }

J
jorlow@chromium.org 已提交
758
 public:
759
  Benchmark()
760 761 762
  : cache_(FLAGS_cache_size >= 0 ?
           (FLAGS_cache_numshardbits >= 1 ?
            NewLRUCache(FLAGS_cache_size, FLAGS_cache_numshardbits) :
763
            NewLRUCache(FLAGS_cache_size)) : nullptr),
S
Sanjay Ghemawat 已提交
764 765
    filter_policy_(FLAGS_bloom_bits >= 0
                   ? NewBloomFilterPolicy(FLAGS_bloom_bits)
766 767
                   : nullptr),
    db_(nullptr),
768
    num_(FLAGS_num),
769
    value_size_(FLAGS_value_size),
770
    key_size_(FLAGS_key_size),
771
    entries_per_batch_(1),
772
    reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
773
    writes_(FLAGS_writes < 0 ? FLAGS_num : FLAGS_writes),
774
    readwrites_((FLAGS_writes < 0  && FLAGS_reads < 0)? FLAGS_num :
775
                ((FLAGS_writes > FLAGS_reads) ? FLAGS_writes : FLAGS_reads)
776
               ),
777
    heap_counter_(0) {
J
jorlow@chromium.org 已提交
778
    std::vector<std::string> files;
779
    FLAGS_env->GetChildren(FLAGS_db, &files);
780
    for (unsigned int i = 0; i < files.size(); i++) {
J
jorlow@chromium.org 已提交
781
      if (Slice(files[i]).starts_with("heap-")) {
782
        FLAGS_env->DeleteFile(std::string(FLAGS_db) + "/" + files[i]);
J
jorlow@chromium.org 已提交
783 784
      }
    }
785
    if (!FLAGS_use_existing_db) {
786
      DestroyDB(FLAGS_db, Options());
787
    }
J
jorlow@chromium.org 已提交
788 789 790 791
  }

  ~Benchmark() {
    delete db_;
S
Sanjay Ghemawat 已提交
792
    delete filter_policy_;
J
jorlow@chromium.org 已提交
793 794
  }

X
Xing Jin 已提交
795 796 797 798 799 800 801 802 803 804 805 806 807
  //this function will construct string format for key. e.g "%016d"
  void ConstructStrFormatForKey(char* str, int keySize) {
    str[0] = '%';
    str[1] = '0';
    sprintf(str+2, "%dd%s", keySize, "%s");
  }

  unique_ptr<char []> GenerateKeyFromInt(int v, const char* suffix = "") {
    unique_ptr<char []> keyInStr(new char[MAX_KEY_SIZE]);
    snprintf(keyInStr.get(), MAX_KEY_SIZE, keyFormat_, v, suffix);
    return keyInStr;
  }

J
jorlow@chromium.org 已提交
808
  void Run() {
809 810
    PrintHeader();
    Open();
J
jorlow@chromium.org 已提交
811 812

    const char* benchmarks = FLAGS_benchmarks;
813
    while (benchmarks != nullptr) {
J
jorlow@chromium.org 已提交
814 815
      const char* sep = strchr(benchmarks, ',');
      Slice name;
816
      if (sep == nullptr) {
J
jorlow@chromium.org 已提交
817
        name = benchmarks;
818
        benchmarks = nullptr;
J
jorlow@chromium.org 已提交
819 820 821 822 823
      } else {
        name = Slice(benchmarks, sep - benchmarks);
        benchmarks = sep + 1;
      }

X
Xing Jin 已提交
824
      // Sanitize parameters
825
      num_ = FLAGS_num;
826
      reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);
827
      writes_ = (FLAGS_writes < 0 ? FLAGS_num : FLAGS_writes);
828
      value_size_ = FLAGS_value_size;
829 830
      key_size_ = FLAGS_key_size;
      ConstructStrFormatForKey(keyFormat_, key_size_);
831 832
      entries_per_batch_ = 1;
      write_options_ = WriteOptions();
833 834 835
      if (FLAGS_sync) {
        write_options_.sync = true;
      }
H
heyongqiang 已提交
836 837
      write_options_.disableWAL = FLAGS_disable_wal;

838
      void (Benchmark::*method)(ThreadState*) = nullptr;
839
      bool fresh_db = false;
840
      int num_threads = FLAGS_threads;
841 842

      if (name == Slice("fillseq")) {
843 844
        fresh_db = true;
        method = &Benchmark::WriteSeq;
845
      } else if (name == Slice("fillbatch")) {
846 847 848
        fresh_db = true;
        entries_per_batch_ = 1000;
        method = &Benchmark::WriteSeq;
849
      } else if (name == Slice("fillrandom")) {
850 851
        fresh_db = true;
        method = &Benchmark::WriteRandom;
852 853 854 855 856 857 858 859
      } else if (name == Slice("filluniquerandom")) {
        fresh_db = true;
        if (num_threads > 1) {
          fprintf(stderr, "filluniquerandom multithreaded not supported"
                           " set --threads=1");
          exit(1);
        }
        method = &Benchmark::WriteUniqueRandom;
860
      } else if (name == Slice("overwrite")) {
861 862
        fresh_db = false;
        method = &Benchmark::WriteRandom;
863
      } else if (name == Slice("fillsync")) {
864 865 866 867
        fresh_db = true;
        num_ /= 1000;
        write_options_.sync = true;
        method = &Benchmark::WriteRandom;
868
      } else if (name == Slice("fill100K")) {
869 870 871 872
        fresh_db = true;
        num_ /= 1000;
        value_size_ = 100 * 1000;
        method = &Benchmark::WriteRandom;
J
jorlow@chromium.org 已提交
873
      } else if (name == Slice("readseq")) {
874
        method = &Benchmark::ReadSequential;
J
jorlow@chromium.org 已提交
875
      } else if (name == Slice("readreverse")) {
876
        method = &Benchmark::ReadReverse;
J
jorlow@chromium.org 已提交
877
      } else if (name == Slice("readrandom")) {
878
        method = &Benchmark::ReadRandom;
S
Sanjay Ghemawat 已提交
879 880 881 882
      } else if (name == Slice("readmissing")) {
        method = &Benchmark::ReadMissing;
      } else if (name == Slice("seekrandom")) {
        method = &Benchmark::SeekRandom;
883
      } else if (name == Slice("readhot")) {
884
        method = &Benchmark::ReadHot;
885
      } else if (name == Slice("readrandomsmall")) {
886
        reads_ /= 1000;
887
        method = &Benchmark::ReadRandom;
S
Sanjay Ghemawat 已提交
888 889 890 891
      } else if (name == Slice("deleteseq")) {
        method = &Benchmark::DeleteSeq;
      } else if (name == Slice("deleterandom")) {
        method = &Benchmark::DeleteRandom;
892 893 894
      } else if (name == Slice("readwhilewriting")) {
        num_threads++;  // Add extra thread for writing
        method = &Benchmark::ReadWhileWriting;
895 896
      } else if (name == Slice("readrandomwriterandom")) {
        method = &Benchmark::ReadRandomWriteRandom;
M
Mark Callaghan 已提交
897 898
      } else if (name == Slice("updaterandom")) {
        method = &Benchmark::UpdateRandom;
899 900
      } else if (name == Slice("randomwithverify")) {
        method = &Benchmark::RandomWithVerify;
J
jorlow@chromium.org 已提交
901
      } else if (name == Slice("compact")) {
902
        method = &Benchmark::Compact;
J
jorlow@chromium.org 已提交
903
      } else if (name == Slice("crc32c")) {
904
        method = &Benchmark::Crc32c;
905
      } else if (name == Slice("acquireload")) {
906
        method = &Benchmark::AcquireLoad;
907
      } else if (name == Slice("snappycomp")) {
908
        method = &Benchmark::SnappyCompress;
909
      } else if (name == Slice("snappyuncomp")) {
910
        method = &Benchmark::SnappyUncompress;
J
jorlow@chromium.org 已提交
911 912
      } else if (name == Slice("heapprofile")) {
        HeapProfile();
913
      } else if (name == Slice("stats")) {
S
Sanjay Ghemawat 已提交
914
        PrintStats("leveldb.stats");
915 916
      } else if (name == Slice("levelstats")) {
        PrintStats("leveldb.levelstats");
S
Sanjay Ghemawat 已提交
917 918
      } else if (name == Slice("sstables")) {
        PrintStats("leveldb.sstables");
J
jorlow@chromium.org 已提交
919
      } else {
920 921 922 923
        if (name != Slice()) {  // No error message for empty name
          fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());
        }
      }
924 925 926 927 928

      if (fresh_db) {
        if (FLAGS_use_existing_db) {
          fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n",
                  name.ToString().c_str());
929
          method = nullptr;
930 931
        } else {
          delete db_;
932
          db_ = nullptr;
933 934 935 936 937
          DestroyDB(FLAGS_db, Options());
          Open();
        }
      }

938
      if (method != nullptr) {
939
        fprintf(stdout, "DB path: [%s]\n", FLAGS_db);
940
        RunBenchmark(num_threads, name, method);
J
jorlow@chromium.org 已提交
941 942
      }
    }
943 944 945
    if (FLAGS_statistics) {
     fprintf(stdout, "STATISTICS:\n%s\n", dbstats->ToString().c_str());
    }
J
jorlow@chromium.org 已提交
946 947
  }

948
 private:
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
  struct ThreadArg {
    Benchmark* bm;
    SharedState* shared;
    ThreadState* thread;
    void (Benchmark::*method)(ThreadState*);
  };

  static void ThreadBody(void* v) {
    ThreadArg* arg = reinterpret_cast<ThreadArg*>(v);
    SharedState* shared = arg->shared;
    ThreadState* thread = arg->thread;
    {
      MutexLock l(&shared->mu);
      shared->num_initialized++;
      if (shared->num_initialized >= shared->total) {
        shared->cv.SignalAll();
      }
      while (!shared->start) {
        shared->cv.Wait();
      }
    }

971
    thread->stats.Start(thread->tid);
972 973 974 975 976 977 978 979 980 981 982 983
    (arg->bm->*(arg->method))(thread);
    thread->stats.Stop();

    {
      MutexLock l(&shared->mu);
      shared->num_done++;
      if (shared->num_done >= shared->total) {
        shared->cv.SignalAll();
      }
    }
  }

984 985
  void RunBenchmark(int n, Slice name,
                    void (Benchmark::*method)(ThreadState*)) {
986 987 988 989 990 991 992 993 994 995 996 997
    SharedState shared;
    shared.total = n;
    shared.num_initialized = 0;
    shared.num_done = 0;
    shared.start = false;

    ThreadArg* arg = new ThreadArg[n];
    for (int i = 0; i < n; i++) {
      arg[i].bm = this;
      arg[i].method = method;
      arg[i].shared = &shared;
      arg[i].thread = new ThreadState(i);
998
      arg[i].thread->shared = &shared;
999
      FLAGS_env->StartThread(ThreadBody, &arg[i]);
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
    }

    shared.mu.Lock();
    while (shared.num_initialized < n) {
      shared.cv.Wait();
    }

    shared.start = true;
    shared.cv.SignalAll();
    while (shared.num_done < n) {
      shared.cv.Wait();
    }
    shared.mu.Unlock();

1014 1015 1016 1017
    // Stats for some threads can be excluded.
    Stats merge_stats;
    for (int i = 0; i < n; i++) {
      merge_stats.Merge(arg[i].thread->stats);
1018
    }
1019
    merge_stats.Report(name);
1020 1021 1022 1023 1024 1025 1026 1027

    for (int i = 0; i < n; i++) {
      delete arg[i].thread;
    }
    delete[] arg;
  }

  void Crc32c(ThreadState* thread) {
J
jorlow@chromium.org 已提交
1028
    // Checksum about 500MB of data total
1029 1030
    const int size = 4096;
    const char* label = "(4K per op)";
J
jorlow@chromium.org 已提交
1031
    std::string data(size, 'x');
J
jorlow@chromium.org 已提交
1032 1033 1034 1035
    int64_t bytes = 0;
    uint32_t crc = 0;
    while (bytes < 500 * 1048576) {
      crc = crc32c::Value(data.data(), size);
1036
      thread->stats.FinishedSingleOp(nullptr);
J
jorlow@chromium.org 已提交
1037 1038 1039 1040 1041
      bytes += size;
    }
    // Print so result is not dead
    fprintf(stderr, "... crc=0x%x\r", static_cast<unsigned int>(crc));

1042 1043
    thread->stats.AddBytes(bytes);
    thread->stats.AddMessage(label);
J
jorlow@chromium.org 已提交
1044 1045
  }

1046
  void AcquireLoad(ThreadState* thread) {
1047 1048 1049
    int dummy;
    port::AtomicPointer ap(&dummy);
    int count = 0;
1050
    void *ptr = nullptr;
1051
    thread->stats.AddMessage("(each op is 1000 loads)");
1052 1053 1054 1055 1056
    while (count < 100000) {
      for (int i = 0; i < 1000; i++) {
        ptr = ap.Acquire_Load();
      }
      count++;
1057
      thread->stats.FinishedSingleOp(nullptr);
1058
    }
1059
    if (ptr == nullptr) exit(1); // Disable unused variable warning.
1060 1061
  }

1062 1063 1064
  void SnappyCompress(ThreadState* thread) {
    RandomGenerator gen;
    Slice input = gen.Generate(Options().block_size);
1065 1066 1067 1068 1069
    int64_t bytes = 0;
    int64_t produced = 0;
    bool ok = true;
    std::string compressed;
    while (ok && bytes < 1024 * 1048576) {  // Compress 1G
1070 1071
      ok = port::Snappy_Compress(Options().compression_opts, input.data(),
                                 input.size(), &compressed);
1072 1073
      produced += compressed.size();
      bytes += input.size();
1074
      thread->stats.FinishedSingleOp(nullptr);
1075 1076 1077
    }

    if (!ok) {
1078
      thread->stats.AddMessage("(snappy failure)");
1079 1080 1081 1082
    } else {
      char buf[100];
      snprintf(buf, sizeof(buf), "(output: %.1f%%)",
               (produced * 100.0) / bytes);
1083 1084
      thread->stats.AddMessage(buf);
      thread->stats.AddBytes(bytes);
1085 1086 1087
    }
  }

1088 1089 1090
  void SnappyUncompress(ThreadState* thread) {
    RandomGenerator gen;
    Slice input = gen.Generate(Options().block_size);
1091
    std::string compressed;
1092 1093
    bool ok = port::Snappy_Compress(Options().compression_opts, input.data(),
                                    input.size(), &compressed);
1094
    int64_t bytes = 0;
1095
    char* uncompressed = new char[input.size()];
1096 1097
    while (ok && bytes < 1024 * 1048576) {  // Compress 1G
      ok =  port::Snappy_Uncompress(compressed.data(), compressed.size(),
1098 1099
                                    uncompressed);
      bytes += input.size();
1100
      thread->stats.FinishedSingleOp(nullptr);
1101
    }
1102
    delete[] uncompressed;
1103 1104

    if (!ok) {
1105
      thread->stats.AddMessage("(snappy failure)");
1106
    } else {
1107
      thread->stats.AddBytes(bytes);
1108 1109 1110
    }
  }

1111
  void Open() {
1112
    assert(db_ == nullptr);
1113
    Options options;
1114
    options.create_if_missing = !FLAGS_use_existing_db;
1115
    options.block_cache = cache_;
1116
    if (cache_ == nullptr) {
1117 1118
      options.no_block_cache = true;
    }
1119
    options.write_buffer_size = FLAGS_write_buffer_size;
1120
    options.max_write_buffer_number = FLAGS_max_write_buffer_number;
1121 1122
    options.min_write_buffer_number_to_merge =
      FLAGS_min_write_buffer_number_to_merge;
1123
    options.max_background_compactions = FLAGS_max_background_compactions;
1124 1125 1126 1127
    options.compaction_style = FLAGS_compaction_style;
    options.compaction_options_universal.size_ratio = FLAGS_universal_size_ratio;
    options.compaction_options_universal.min_merge_width =
      FLAGS_compaction_universal_min_merge_width;
1128
    options.block_size = FLAGS_block_size;
S
Sanjay Ghemawat 已提交
1129
    options.filter_policy = filter_policy_;
1130 1131
    options.max_open_files = FLAGS_open_files;
    options.statistics = dbstats;
1132
    options.env = FLAGS_env;
H
heyongqiang 已提交
1133
    options.disableDataSync = FLAGS_disable_data_sync;
1134
    options.use_fsync = FLAGS_use_fsync;
1135
    options.num_levels = FLAGS_num_levels;
H
heyongqiang 已提交
1136 1137 1138 1139 1140
    options.target_file_size_base = FLAGS_target_file_size_base;
    options.target_file_size_multiplier = FLAGS_target_file_size_multiplier;
    options.max_bytes_for_level_base = FLAGS_max_bytes_for_level_base;
    options.max_bytes_for_level_multiplier =
        FLAGS_max_bytes_for_level_multiplier;
1141
    options.filter_deletes = FLAGS_filter_deletes;
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    if (FLAGS_max_bytes_for_level_multiplier_additional.size() > 0) {
      if (FLAGS_max_bytes_for_level_multiplier_additional.size() !=
          (unsigned int)FLAGS_num_levels) {
        fprintf(stderr, "Insufficient number of fanouts specified %d\n",
                (int)FLAGS_max_bytes_for_level_multiplier_additional.size());
        exit(1);
      }
      options.max_bytes_for_level_multiplier_additional =
        FLAGS_max_bytes_for_level_multiplier_additional;
    }
H
heyongqiang 已提交
1152
    options.level0_stop_writes_trigger = FLAGS_level0_stop_writes_trigger;
M
Mark Callaghan 已提交
1153
    options.level0_file_num_compaction_trigger =
1154
        FLAGS_level0_file_num_compaction_trigger;
H
heyongqiang 已提交
1155 1156
    options.level0_slowdown_writes_trigger =
      FLAGS_level0_slowdown_writes_trigger;
1157
    options.compression = FLAGS_compression_type;
1158
    options.WAL_ttl_seconds = FLAGS_WAL_ttl_seconds;
1159 1160
    if (FLAGS_min_level_to_compress >= 0) {
      assert(FLAGS_min_level_to_compress <= FLAGS_num_levels);
1161
      options.compression_per_level.resize(FLAGS_num_levels);
1162
      for (int i = 0; i < FLAGS_min_level_to_compress; i++) {
1163 1164
        options.compression_per_level[i] = kNoCompression;
      }
1165
      for (int i = FLAGS_min_level_to_compress;
1166 1167 1168 1169
           i < FLAGS_num_levels; i++) {
        options.compression_per_level[i] = FLAGS_compression_type;
      }
    }
1170
    options.disable_seek_compaction = FLAGS_disable_seek_compaction;
1171 1172
    options.delete_obsolete_files_period_micros =
      FLAGS_delete_obsolete_files_period_micros;
J
Jim Paton 已提交
1173 1174 1175 1176
    options.soft_rate_limit = FLAGS_soft_rate_limit;
    options.hard_rate_limit = FLAGS_hard_rate_limit;
    options.rate_limit_delay_max_milliseconds =
      FLAGS_rate_limit_delay_max_milliseconds;
1177
    options.table_cache_numshardbits = FLAGS_table_cache_numshardbits;
A
Abhishek Kona 已提交
1178
    options.max_grandparent_overlap_factor =
1179
      FLAGS_max_grandparent_overlap_factor;
1180
    options.disable_auto_compactions = FLAGS_disable_auto_compactions;
1181
    options.source_compaction_factor = FLAGS_source_compaction_factor;
1182 1183 1184 1185 1186

    // fill storage options
    options.allow_os_buffer = FLAGS_use_os_buffer;
    options.allow_mmap_reads = FLAGS_use_mmap_reads;
    options.allow_mmap_writes = FLAGS_use_mmap_writes;
1187 1188
    options.advise_random_on_open = FLAGS_advise_random_on_open;
    options.access_hint_on_compaction_start = FLAGS_compaction_fadvice;
H
Haobo Xu 已提交
1189 1190

    options.use_adaptive_mutex = FLAGS_use_adaptive_mutex;
H
Haobo Xu 已提交
1191
    options.bytes_per_sync = FLAGS_bytes_per_sync;
H
Haobo Xu 已提交
1192

H
heyongqiang 已提交
1193 1194 1195 1196 1197 1198
    Status s;
    if(FLAGS_read_only) {
      s = DB::OpenForReadOnly(options, FLAGS_db, &db_);
    } else {
      s = DB::Open(options, FLAGS_db, &db_);
    }
1199 1200 1201 1202
    if (!s.ok()) {
      fprintf(stderr, "open error: %s\n", s.ToString().c_str());
      exit(1);
    }
1203
    if (FLAGS_min_level_to_compress >= 0) {
1204
      options.compression_per_level.clear();
1205
    }
1206 1207
  }

1208 1209 1210 1211
  enum WriteMode {
    RANDOM, SEQUENTIAL, UNIQUE_RANDOM
  };

1212
  void WriteSeq(ThreadState* thread) {
1213
    DoWrite(thread, SEQUENTIAL);
1214
  }
1215

1216
  void WriteRandom(ThreadState* thread) {
1217
    DoWrite(thread, RANDOM);
1218 1219
  }

1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
  void WriteUniqueRandom(ThreadState* thread) {
    DoWrite(thread, UNIQUE_RANDOM);
  }

  void DoWrite(ThreadState* thread, WriteMode write_mode) {
    const int test_duration = write_mode == RANDOM ? FLAGS_duration : 0;
    const int num_ops = writes_ == 0 ? num_ : writes_ ;
    Duration duration(test_duration, num_ops);
    unique_ptr<BitSet> bit_set;

    if (write_mode == UNIQUE_RANDOM) {
      bit_set.reset(new BitSet(num_ops));
    }
M
Mark Callaghan 已提交
1233

1234
    if (num_ != FLAGS_num) {
1235
      char msg[100];
1236
      snprintf(msg, sizeof(msg), "(%ld ops)", num_);
1237
      thread->stats.AddMessage(msg);
1238 1239
    }

1240
    RandomGenerator gen;
J
jorlow@chromium.org 已提交
1241 1242
    WriteBatch batch;
    Status s;
1243
    int64_t bytes = 0;
M
Mark Callaghan 已提交
1244 1245
    int i = 0;
    while (!duration.Done(entries_per_batch_)) {
J
jorlow@chromium.org 已提交
1246
      batch.Clear();
1247
      for (int j = 0; j < entries_per_batch_; j++) {
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
        int k = 0;
        switch(write_mode) {
          case SEQUENTIAL:
            k = i +j;
            break;
          case RANDOM:
            k = thread->rand.Next() % FLAGS_num;
            break;
          case UNIQUE_RANDOM:
            {
              int t = thread->rand.Next() % FLAGS_num;
              if (!bit_set->test(t)) {
                // best case
                k = t;
              } else {
                bool found = false;
                // look forward
                for (size_t i = t + 1; i < bit_set->size(); ++i) {
                  if (!bit_set->test(i)) {
                    found = true;
                    k = i;
                    break;
                  }
                }
                if (!found) {
                  for (size_t i = t; i-- > 0;) {
                    if (!bit_set->test(i)) {
                      found = true;
                      k = i;
                      break;
                    }
                  }
                }
              }
              bit_set->set(k);
              break;
            }
        };
1286 1287 1288
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        batch.Put(key.get(), gen.Generate(value_size_));
        bytes += value_size_ + strlen(key.get());
M
Mark Callaghan 已提交
1289
        thread->stats.FinishedSingleOp(db_);
1290
      }
1291
      s = db_->Write(write_options_, &batch);
J
jorlow@chromium.org 已提交
1292 1293 1294 1295
      if (!s.ok()) {
        fprintf(stderr, "put error: %s\n", s.ToString().c_str());
        exit(1);
      }
M
Mark Callaghan 已提交
1296
      i += entries_per_batch_;
J
jorlow@chromium.org 已提交
1297
    }
1298
    thread->stats.AddBytes(bytes);
J
jorlow@chromium.org 已提交
1299 1300
  }

1301
  void ReadSequential(ThreadState* thread) {
1302
    Iterator* iter = db_->NewIterator(ReadOptions(FLAGS_verify_checksum, true));
1303
    long i = 0;
1304
    int64_t bytes = 0;
1305
    for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) {
1306
      bytes += iter->key().size() + iter->value().size();
M
Mark Callaghan 已提交
1307
      thread->stats.FinishedSingleOp(db_);
1308 1309 1310
      ++i;
    }
    delete iter;
1311
    thread->stats.AddBytes(bytes);
1312 1313
  }

1314
  void ReadReverse(ThreadState* thread) {
1315
    Iterator* iter = db_->NewIterator(ReadOptions(FLAGS_verify_checksum, true));
1316
    long i = 0;
1317
    int64_t bytes = 0;
1318
    for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) {
1319
      bytes += iter->key().size() + iter->value().size();
M
Mark Callaghan 已提交
1320
      thread->stats.FinishedSingleOp(db_);
1321 1322 1323
      ++i;
    }
    delete iter;
1324
    thread->stats.AddBytes(bytes);
1325 1326
  }

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374
  // Calls MultiGet over a list of keys from a random distribution.
  // Returns the total number of keys found.
  long MultiGetRandom(ReadOptions& options, int num_keys,
                     Random& rand, int range, const char* suffix) {
    assert(num_keys > 0);
    std::vector<Slice> keys(num_keys);
    std::vector<std::string> values(num_keys);
    std::vector<unique_ptr<char []> > gen_keys(num_keys);

    int i;
    long k;

    // Fill the keys vector
    for(i=0; i<num_keys; ++i) {
      k = rand.Next() % range;
      gen_keys[i] = GenerateKeyFromInt(k,suffix);
      keys[i] = gen_keys[i].get();
    }

    if (FLAGS_use_snapshot) {
      options.snapshot = db_->GetSnapshot();
    }

    // Apply the operation
    std::vector<Status> statuses = db_->MultiGet(options, keys, &values);
    assert((long)statuses.size() == num_keys);
    assert((long)keys.size() == num_keys);  // Should always be the case.
    assert((long)values.size() == num_keys);

    if (FLAGS_use_snapshot) {
      db_->ReleaseSnapshot(options.snapshot);
      options.snapshot = nullptr;
    }

    // Count number found
    long found = 0;
    for(i=0; i<num_keys; ++i) {
      if (statuses[i].ok()){
        ++found;
      } else if (FLAGS_warn_missing_keys == true) {
        // Key not found, or error.
        fprintf(stderr, "get error: %s\n", statuses[i].ToString().c_str());
      }
    }

    return found;
  }

1375
  void ReadRandom(ThreadState* thread) {
1376
    ReadOptions options(FLAGS_verify_checksum, true);
M
Mark Callaghan 已提交
1377
    Duration duration(FLAGS_duration, reads_);
1378

1379
    long found = 0;
M
Mark Callaghan 已提交
1380

1381 1382 1383 1384 1385 1386 1387
    if (FLAGS_use_multiget) {   // MultiGet
      const long& kpg = FLAGS_keys_per_multiget;  // keys per multiget group
      long keys_left = reads_;

      // Recalculate number of keys per group, and call MultiGet until done
      long num_keys;
      while(num_keys = std::min(keys_left, kpg), !duration.Done(num_keys)) {
X
Xing Jin 已提交
1388
        found += MultiGetRandom(options, num_keys, thread->rand, FLAGS_num, "");
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
        thread->stats.FinishedSingleOp(db_);
        keys_left -= num_keys;
      }
    } else {    // Regular case. Do one "get" at a time Get
      Iterator* iter = db_->NewIterator(options);
      std::string value;
      while (!duration.Done(1)) {
        const int k = thread->rand.Next() % FLAGS_num;
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        if (FLAGS_use_snapshot) {
          options.snapshot = db_->GetSnapshot();
1400
        }
M
Mark Callaghan 已提交
1401

1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
        if (FLAGS_read_range < 2) {
          if (db_->Get(options, key.get(), &value).ok()) {
            found++;
          }
        } else {
          Slice skey(key.get());
          int count = 1;

          if (FLAGS_get_approx) {
            unique_ptr<char []> key2 =
                GenerateKeyFromInt(k + (int) FLAGS_read_range);
            Slice skey2(key2.get());
            Range range(skey, skey2);
            uint64_t sizes;
            db_->GetApproximateSizes(&range, 1, &sizes);
          }

          for (iter->Seek(skey);
               iter->Valid() && count <= FLAGS_read_range;
               ++count, iter->Next()) {
            found++;
          }
M
Mark Callaghan 已提交
1424 1425
        }

1426 1427 1428
        if (FLAGS_use_snapshot) {
          db_->ReleaseSnapshot(options.snapshot);
          options.snapshot = nullptr;
1429 1430
        }

1431
        thread->stats.FinishedSingleOp(db_);
M
Mark Callaghan 已提交
1432 1433
      }

1434
      delete iter;
S
Sanjay Ghemawat 已提交
1435
    }
1436

S
Sanjay Ghemawat 已提交
1437
    char msg[100];
1438
    snprintf(msg, sizeof(msg), "(%ld of %ld found)", found, reads_);
S
Sanjay Ghemawat 已提交
1439 1440 1441
    thread->stats.AddMessage(msg);
  }

X
Xing Jin 已提交
1442
  void ReadMissing(ThreadState* thread) {
1443 1444
    FLAGS_warn_missing_keys = false;    // Never warn about missing keys

M
Mark Callaghan 已提交
1445
    Duration duration(FLAGS_duration, reads_);
1446
    ReadOptions options(FLAGS_verify_checksum, true);
1447 1448 1449 1450 1451 1452 1453 1454 1455

    if (FLAGS_use_multiget) {
      const long& kpg = FLAGS_keys_per_multiget;  // keys per multiget group
      long keys_left = reads_;

      // Recalculate number of keys per group, and call MultiGet until done
      long num_keys;
      long found;
      while(num_keys = std::min(keys_left, kpg), !duration.Done(num_keys)) {
X
Xing Jin 已提交
1456 1457 1458 1459 1460 1461
        found = MultiGetRandom(options, num_keys, thread->rand, FLAGS_num, ".");

        // We should not find any key since the key we try to get has a
        // different suffix
        assert(!found);

1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
        thread->stats.FinishedSingleOp(db_);
        keys_left -= num_keys;
      }
    } else {  // Regular case (not MultiGet)
      std::string value;
      Status s;
      while (!duration.Done(1)) {
        const int k = thread->rand.Next() % FLAGS_num;
        unique_ptr<char []> key = GenerateKeyFromInt(k, ".");
        s = db_->Get(options, key.get(), &value);
        assert(!s.ok() && s.IsNotFound());
        thread->stats.FinishedSingleOp(db_);
      }
J
jorlow@chromium.org 已提交
1475 1476 1477
    }
  }

1478
  void ReadHot(ThreadState* thread) {
M
Mark Callaghan 已提交
1479
    Duration duration(FLAGS_duration, reads_);
1480
    ReadOptions options(FLAGS_verify_checksum, true);
1481
    const long range = (FLAGS_num + 99) / 100;
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
    long found = 0;

    if (FLAGS_use_multiget) {
      const long& kpg = FLAGS_keys_per_multiget;  // keys per multiget group
      long keys_left = reads_;

      // Recalculate number of keys per group, and call MultiGet until done
      long num_keys;
      while(num_keys = std::min(keys_left, kpg), !duration.Done(num_keys)) {
        found += MultiGetRandom(options, num_keys, thread->rand, range, "");
        thread->stats.FinishedSingleOp(db_);
        keys_left -= num_keys;
      }
    } else {
      std::string value;
      while (!duration.Done(1)) {
        const int k = thread->rand.Next() % range;
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        if (db_->Get(options, key.get(), &value).ok()){
          ++found;
        }
        thread->stats.FinishedSingleOp(db_);
      }
1505
    }
1506 1507 1508 1509

    char msg[100];
    snprintf(msg, sizeof(msg), "(%ld of %ld found)", found, reads_);
    thread->stats.AddMessage(msg);
1510 1511
  }

S
Sanjay Ghemawat 已提交
1512
  void SeekRandom(ThreadState* thread) {
M
Mark Callaghan 已提交
1513
    Duration duration(FLAGS_duration, reads_);
1514
    ReadOptions options(FLAGS_verify_checksum, true);
S
Sanjay Ghemawat 已提交
1515
    std::string value;
1516
    long found = 0;
M
Mark Callaghan 已提交
1517
    while (!duration.Done(1)) {
S
Sanjay Ghemawat 已提交
1518 1519
      Iterator* iter = db_->NewIterator(options);
      const int k = thread->rand.Next() % FLAGS_num;
1520 1521 1522
      unique_ptr<char []> key = GenerateKeyFromInt(k);
      iter->Seek(key.get());
      if (iter->Valid() && iter->key() == key.get()) found++;
S
Sanjay Ghemawat 已提交
1523
      delete iter;
M
Mark Callaghan 已提交
1524
      thread->stats.FinishedSingleOp(db_);
S
Sanjay Ghemawat 已提交
1525 1526
    }
    char msg[100];
1527
    snprintf(msg, sizeof(msg), "(%ld of %ld found)", found, num_);
S
Sanjay Ghemawat 已提交
1528 1529 1530 1531 1532 1533
    thread->stats.AddMessage(msg);
  }

  void DoDelete(ThreadState* thread, bool seq) {
    WriteBatch batch;
    Status s;
M
Mark Callaghan 已提交
1534 1535 1536
    Duration duration(seq ? 0 : FLAGS_duration, num_);
    long i = 0;
    while (!duration.Done(entries_per_batch_)) {
S
Sanjay Ghemawat 已提交
1537 1538 1539
      batch.Clear();
      for (int j = 0; j < entries_per_batch_; j++) {
        const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num);
1540 1541
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        batch.Delete(key.get());
M
Mark Callaghan 已提交
1542
        thread->stats.FinishedSingleOp(db_);
S
Sanjay Ghemawat 已提交
1543 1544 1545 1546 1547 1548
      }
      s = db_->Write(write_options_, &batch);
      if (!s.ok()) {
        fprintf(stderr, "del error: %s\n", s.ToString().c_str());
        exit(1);
      }
M
Mark Callaghan 已提交
1549
      ++i;
S
Sanjay Ghemawat 已提交
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
    }
  }

  void DeleteSeq(ThreadState* thread) {
    DoDelete(thread, true);
  }

  void DeleteRandom(ThreadState* thread) {
    DoDelete(thread, false);
  }

1561 1562 1563 1564 1565 1566
  void ReadWhileWriting(ThreadState* thread) {
    if (thread->tid > 0) {
      ReadRandom(thread);
    } else {
      // Special thread that keeps writing until other threads are done.
      RandomGenerator gen;
1567 1568 1569 1570 1571 1572 1573 1574 1575
      double last = FLAGS_env->NowMicros();
      int writes_per_second_by_10 = 0;
      int num_writes = 0;

      // --writes_per_second rate limit is enforced per 100 milliseconds
      // intervals to avoid a burst of writes at the start of each second.

      if (FLAGS_writes_per_second > 0)
        writes_per_second_by_10 = FLAGS_writes_per_second / 10;
1576 1577 1578 1579

      // Don't merge stats from this thread with the readers.
      thread->stats.SetExcludeFromMerge();

1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
      while (true) {
        {
          MutexLock l(&thread->shared->mu);
          if (thread->shared->num_done + 1 >= thread->shared->num_initialized) {
            // Other threads have finished
            break;
          }
        }

        const int k = thread->rand.Next() % FLAGS_num;
1590 1591
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        Status s = db_->Put(write_options_, key.get(), gen.Generate(value_size_));
1592 1593 1594 1595
        if (!s.ok()) {
          fprintf(stderr, "put error: %s\n", s.ToString().c_str());
          exit(1);
        }
1596
        thread->stats.FinishedSingleOp(db_);
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610

        ++num_writes;
        if (writes_per_second_by_10 && num_writes >= writes_per_second_by_10) {
          double now = FLAGS_env->NowMicros();
          double usecs_since_last = now - last;

          num_writes = 0;
          last = now;

          if (usecs_since_last < 100000.0) {
            FLAGS_env->SleepForMicroseconds(100000.0 - usecs_since_last);
            last = FLAGS_env->NowMicros();
          }
        }
1611 1612 1613 1614
      }
    }
  }

1615
  // Given a key K and value V, this puts (K+"0", V), (K+"1", V), (K+"2", V)
1616 1617
  // in DB atomically i.e in a single batch. Also refer GetMany.
  Status PutMany(const WriteOptions& writeoptions,
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
                  const Slice& key, const Slice& value) {
    std::string suffixes[3] = {"2", "1", "0"};
    std::string keys[3];

    WriteBatch batch;
    Status s;
    for (int i = 0; i < 3; i++) {
      keys[i] = key.ToString() + suffixes[i];
      batch.Put(keys[i], value);
    }

    s = db_->Write(writeoptions, &batch);
    return s;
  }


  // Given a key K, this deletes (K+"0", V), (K+"1", V), (K+"2", V)
1635 1636
  // in DB atomically i.e in a single batch. Also refer GetMany.
  Status DeleteMany(const WriteOptions& writeoptions,
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
                  const Slice& key) {
    std::string suffixes[3] = {"1", "2", "0"};
    std::string keys[3];

    WriteBatch batch;
    Status s;
    for (int i = 0; i < 3; i++) {
      keys[i] = key.ToString() + suffixes[i];
      batch.Delete(keys[i]);
    }

    s = db_->Write(writeoptions, &batch);
    return s;
  }

  // Given a key K and value V, this gets values for K+"0", K+"1" and K+"2"
  // in the same snapshot, and verifies that all the values are identical.
1654 1655
  // ASSUMES that PutMany was used to put (K, V) into the DB.
  Status GetMany(const ReadOptions& readoptions,
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692
                  const Slice& key, std::string* value) {
    std::string suffixes[3] = {"0", "1", "2"};
    std::string keys[3];
    Slice key_slices[3];
    std::string values[3];
    ReadOptions readoptionscopy = readoptions;
    readoptionscopy.snapshot = db_->GetSnapshot();
    Status s;
    for (int i = 0; i < 3; i++) {
      keys[i] = key.ToString() + suffixes[i];
      key_slices[i] = keys[i];
      s = db_->Get(readoptionscopy, key_slices[i], value);
      if (!s.ok() && !s.IsNotFound()) {
        fprintf(stderr, "get error: %s\n", s.ToString().c_str());
        values[i] = "";
        // we continue after error rather than exiting so that we can
        // find more errors if any
      } else if (s.IsNotFound()) {
        values[i] = "";
      } else {
        values[i] = *value;
      }
    }
    db_->ReleaseSnapshot(readoptionscopy.snapshot);

    if ((values[0] != values[1]) || (values[1] != values[2])) {
      fprintf(stderr, "inconsistent values for key %s: %s, %s, %s\n",
              key.ToString().c_str(), values[0].c_str(), values[1].c_str(),
              values[2].c_str());
      // we continue after error rather than exiting so that we can
      // find more errors if any
    }

    return s;
  }

  // Differs from readrandomwriterandom in the following ways:
1693
  // (a) Uses GetMany/PutMany to read/write key values. Refer to those funcs.
1694 1695 1696 1697
  // (b) Does deletes as well (per FLAGS_deletepercent)
  // (c) In order to achieve high % of 'found' during lookups, and to do
  //     multiple writes (including puts and deletes) it uses upto
  //     FLAGS_numdistinct distinct keys instead of FLAGS_num distinct keys.
1698
  // (d) Does not have a MultiGet option.
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
  void RandomWithVerify(ThreadState* thread) {
    ReadOptions options(FLAGS_verify_checksum, true);
    RandomGenerator gen;
    std::string value;
    long found = 0;
    int get_weight = 0;
    int put_weight = 0;
    int delete_weight = 0;
    long gets_done = 0;
    long puts_done = 0;
    long deletes_done = 0;
1710

1711 1712 1713
    // the number of iterations is the larger of read_ or write_
    for (long i = 0; i < readwrites_; i++) {
      const int k = thread->rand.Next() % (FLAGS_numdistinct);
1714
      unique_ptr<char []> key = GenerateKeyFromInt(k);
1715
      if (get_weight == 0 && put_weight == 0 && delete_weight == 0) {
1716
        // one batch completed, reinitialize for next batch
1717 1718 1719 1720 1721 1722
        get_weight = FLAGS_readwritepercent;
        delete_weight = FLAGS_deletepercent;
        put_weight = 100 - get_weight - delete_weight;
      }
      if (get_weight > 0) {
        // do all the gets first
1723
        Status s = GetMany(options, key.get(), &value);
1724
        if (!s.ok() && !s.IsNotFound()) {
1725
          fprintf(stderr, "getmany error: %s\n", s.ToString().c_str());
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
          // we continue after error rather than exiting so that we can
          // find more errors if any
        } else if (!s.IsNotFound()) {
          found++;
        }
        get_weight--;
        gets_done++;
      } else if (put_weight > 0) {
        // then do all the corresponding number of puts
        // for all the gets we have done earlier
1736
        Status s = PutMany(write_options_, key.get(), gen.Generate(value_size_));
1737
        if (!s.ok()) {
1738
          fprintf(stderr, "putmany error: %s\n", s.ToString().c_str());
1739 1740 1741 1742 1743
          exit(1);
        }
        put_weight--;
        puts_done++;
      } else if (delete_weight > 0) {
1744
        Status s = DeleteMany(write_options_, key.get());
1745
        if (!s.ok()) {
1746
          fprintf(stderr, "deletemany error: %s\n", s.ToString().c_str());
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
          exit(1);
        }
        delete_weight--;
        deletes_done++;
      }

      thread->stats.FinishedSingleOp(db_);
    }
    char msg[100];
    snprintf(msg, sizeof(msg), "( get:%ld put:%ld del:%ld total:%ld found:%ld)",
             gets_done, puts_done, deletes_done, readwrites_, found);
    thread->stats.AddMessage(msg);
  }

X
Xing Jin 已提交
1761
  // This is different from ReadWhileWriting because it does not use
1762
  // an extra thread.
1763
  void ReadRandomWriteRandom(ThreadState* thread) {
1764 1765 1766 1767 1768 1769
    if (FLAGS_use_multiget){
      // Separate function for multiget (for ease of reading)
      ReadRandomWriteRandomMultiGet(thread);
      return;
    }

1770 1771 1772 1773 1774 1775 1776 1777
    ReadOptions options(FLAGS_verify_checksum, true);
    RandomGenerator gen;
    std::string value;
    long found = 0;
    int get_weight = 0;
    int put_weight = 0;
    long reads_done = 0;
    long writes_done = 0;
M
Mark Callaghan 已提交
1778 1779
    Duration duration(FLAGS_duration, readwrites_);

1780
    // the number of iterations is the larger of read_ or write_
M
Mark Callaghan 已提交
1781
    while (!duration.Done(1)) {
1782
      const int k = thread->rand.Next() % FLAGS_num;
1783
      unique_ptr<char []> key = GenerateKeyFromInt(k);
1784
      if (get_weight == 0 && put_weight == 0) {
X
Xing Jin 已提交
1785
        // one batch completed, reinitialize for next batch
1786 1787 1788 1789
        get_weight = FLAGS_readwritepercent;
        put_weight = 100 - get_weight;
      }
      if (get_weight > 0) {
M
Mark Callaghan 已提交
1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804

        if (FLAGS_use_snapshot) {
          options.snapshot = db_->GetSnapshot();
        }

        if (FLAGS_get_approx) {
          char key2[100];
          snprintf(key2, sizeof(key2), "%016d", k + 1);
          Slice skey2(key2);
          Slice skey(key2);
          Range range(skey, skey2);
          uint64_t sizes;
          db_->GetApproximateSizes(&range, 1, &sizes);
        }

1805
        // do all the gets first
1806
        Status s = db_->Get(options, key.get(), &value);
1807 1808 1809 1810 1811 1812 1813 1814
        if (!s.ok() && !s.IsNotFound()) {
          fprintf(stderr, "get error: %s\n", s.ToString().c_str());
          // we continue after error rather than exiting so that we can
          // find more errors if any
        } else if (!s.IsNotFound()) {
          found++;
        }

1815 1816
        get_weight--;
        reads_done++;
M
Mark Callaghan 已提交
1817 1818 1819 1820 1821

        if (FLAGS_use_snapshot) {
          db_->ReleaseSnapshot(options.snapshot);
        }

1822 1823 1824
      } else  if (put_weight > 0) {
        // then do all the corresponding number of puts
        // for all the gets we have done earlier
1825
        Status s = db_->Put(write_options_, key.get(), gen.Generate(value_size_));
1826 1827 1828 1829 1830 1831 1832
        if (!s.ok()) {
          fprintf(stderr, "put error: %s\n", s.ToString().c_str());
          exit(1);
        }
        put_weight--;
        writes_done++;
      }
M
Mark Callaghan 已提交
1833
      thread->stats.FinishedSingleOp(db_);
1834 1835
    }
    char msg[100];
1836 1837
    snprintf(msg, sizeof(msg), "( reads:%ld writes:%ld total:%ld found:%ld)",
             reads_done, writes_done, readwrites_, found);
1838 1839 1840
    thread->stats.AddMessage(msg);
  }

1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
  // ReadRandomWriteRandom (with multiget)
  // Does FLAGS_keys_per_multiget reads (per multiget), followed by some puts.
  // FLAGS_readwritepercent will specify the ratio of gets to puts.
  // e.g.: If FLAGS_keys_per_multiget == 100 and FLAGS_readwritepercent == 75
  // Then each block will do 100 multigets and 33 puts
  // So there are 133 operations in-total: 100 of them (75%) are gets, and 33
  // of them (25%) are puts.
  void ReadRandomWriteRandomMultiGet(ThreadState* thread) {
    ReadOptions options(FLAGS_verify_checksum, true);
    RandomGenerator gen;

    // For multiget
    const long& kpg = FLAGS_keys_per_multiget;  // keys per multiget group

    long keys_left = readwrites_;  // number of keys still left to read
    long num_keys;                  // number of keys to read in current group
    long num_put_keys;              // number of keys to put in current group

    long found = 0;
    long reads_done = 0;
    long writes_done = 0;
    long multigets_done = 0;

    // the number of iterations is the larger of read_ or write_
    Duration duration(FLAGS_duration, readwrites_);
    while(true) {
      // Read num_keys keys, then write num_put_keys keys.
      // The ratio of num_keys to num_put_keys is always FLAGS_readwritepercent
      // And num_keys is set to be FLAGS_keys_per_multiget (kpg)
      // num_put_keys is calculated accordingly (to maintain the ratio)
      // Note: On the final iteration, num_keys and num_put_keys will be smaller
      num_keys = std::min(keys_left*(FLAGS_readwritepercent + 99)/100, kpg);
      num_put_keys = num_keys * (100-FLAGS_readwritepercent)
                     / FLAGS_readwritepercent;

      // This will break the loop when duration is complete
      if (duration.Done(num_keys + num_put_keys)) {
        break;
      }

      // A quick check to make sure our formula doesn't break on edge cases
      assert(num_keys >= 1);
      assert(num_keys + num_put_keys <= keys_left);

      // Apply the MultiGet operations
X
Xing Jin 已提交
1886
      found += MultiGetRandom(options, num_keys, thread->rand, FLAGS_num, "");
1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915
      ++multigets_done;
      reads_done+=num_keys;
      thread->stats.FinishedSingleOp(db_);

      // Now do the puts
      int i;
      long k;
      for(i=0; i<num_put_keys; ++i) {
        k = thread->rand.Next() % FLAGS_num;
        unique_ptr<char []> key = GenerateKeyFromInt(k);
        Status s = db_->Put(write_options_, key.get(),
                            gen.Generate(value_size_));
        if (!s.ok()) {
          fprintf(stderr, "put error: %s\n", s.ToString().c_str());
          exit(1);
        }
        writes_done++;
        thread->stats.FinishedSingleOp(db_);
      }

      keys_left -= (num_keys + num_put_keys);
    }
    char msg[100];
    snprintf(msg, sizeof(msg),
             "( reads:%ld writes:%ld total:%ld multiget_ops:%ld found:%ld)",
             reads_done, writes_done, readwrites_, multigets_done, found);
    thread->stats.AddMessage(msg);
  }

M
Mark Callaghan 已提交
1916 1917 1918
  //
  // Read-modify-write for random keys
  //
1919
  // TODO: Implement MergeOperator tests here (Read-modify-write)
M
Mark Callaghan 已提交
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965
  void UpdateRandom(ThreadState* thread) {
    ReadOptions options(FLAGS_verify_checksum, true);
    RandomGenerator gen;
    std::string value;
    long found = 0;
    Duration duration(FLAGS_duration, readwrites_);

    // the number of iterations is the larger of read_ or write_
    while (!duration.Done(1)) {
      const int k = thread->rand.Next() % FLAGS_num;
      unique_ptr<char []> key = GenerateKeyFromInt(k);

      if (FLAGS_use_snapshot) {
        options.snapshot = db_->GetSnapshot();
      }

      if (FLAGS_get_approx) {
        char key2[100];
        snprintf(key2, sizeof(key2), "%016d", k + 1);
        Slice skey2(key2);
        Slice skey(key2);
        Range range(skey, skey2);
        uint64_t sizes;
        db_->GetApproximateSizes(&range, 1, &sizes);
      }

      if (db_->Get(options, key.get(), &value).ok()) {
        found++;
      }

      if (FLAGS_use_snapshot) {
        db_->ReleaseSnapshot(options.snapshot);
      }

      Status s = db_->Put(write_options_, key.get(), gen.Generate(value_size_));
      if (!s.ok()) {
        fprintf(stderr, "put error: %s\n", s.ToString().c_str());
        exit(1);
      }
      thread->stats.FinishedSingleOp(db_);
    }
    char msg[100];
    snprintf(msg, sizeof(msg), "( updates:%ld found:%ld)", readwrites_, found);
    thread->stats.AddMessage(msg);
  }

1966
  void Compact(ThreadState* thread) {
1967
    db_->CompactRange(nullptr, nullptr);
J
jorlow@chromium.org 已提交
1968 1969
  }

S
Sanjay Ghemawat 已提交
1970
  void PrintStats(const char* key) {
1971
    std::string stats;
S
Sanjay Ghemawat 已提交
1972
    if (!db_->GetProperty(key, &stats)) {
1973
      stats = "(failed)";
1974
    }
1975
    fprintf(stdout, "\n%s\n", stats.c_str());
1976 1977
  }

J
jorlow@chromium.org 已提交
1978 1979 1980 1981 1982 1983
  static void WriteToFile(void* arg, const char* buf, int n) {
    reinterpret_cast<WritableFile*>(arg)->Append(Slice(buf, n));
  }

  void HeapProfile() {
    char fname[100];
H
Haobo Xu 已提交
1984
    EnvOptions soptions;
1985
    snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_);
1986
    unique_ptr<WritableFile> file;
1987
    Status s = FLAGS_env->NewWritableFile(fname, &file, soptions);
J
jorlow@chromium.org 已提交
1988
    if (!s.ok()) {
1989
      fprintf(stderr, "%s\n", s.ToString().c_str());
J
jorlow@chromium.org 已提交
1990 1991
      return;
    }
1992
    bool ok = port::GetHeapProfile(WriteToFile, file.get());
J
jorlow@chromium.org 已提交
1993
    if (!ok) {
1994
      fprintf(stderr, "heap profiling not supported\n");
1995
      FLAGS_env->DeleteFile(fname);
J
jorlow@chromium.org 已提交
1996 1997 1998 1999
    }
  }
};

H
Hans Wennborg 已提交
2000
}  // namespace leveldb
J
jorlow@chromium.org 已提交
2001 2002

int main(int argc, char** argv) {
2003 2004
  leveldb::InstallStackTraceHandler();

2005
  FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;
2006
  FLAGS_max_write_buffer_number = leveldb::Options().max_write_buffer_number;
2007 2008
  FLAGS_min_write_buffer_number_to_merge =
    leveldb::Options().min_write_buffer_number_to_merge;
2009
  FLAGS_open_files = leveldb::Options().max_open_files;
A
Abhishek Kona 已提交
2010
  FLAGS_max_background_compactions =
2011
    leveldb::Options().max_background_compactions;
2012 2013 2014 2015 2016
  FLAGS_compaction_style = leveldb::Options().compaction_style;
  FLAGS_universal_size_ratio =
    leveldb::Options().compaction_options_universal.size_ratio;
  FLAGS_compaction_universal_min_merge_width =
    leveldb::Options().compaction_options_universal.min_merge_width;
2017 2018
  // Compression test code above refers to FLAGS_block_size
  FLAGS_block_size = leveldb::Options().block_size;
H
Haobo Xu 已提交
2019 2020 2021
  FLAGS_use_os_buffer = leveldb::EnvOptions().use_os_buffer;
  FLAGS_use_mmap_reads = leveldb::EnvOptions().use_mmap_reads;
  FLAGS_use_mmap_writes = leveldb::EnvOptions().use_mmap_writes;
2022

H
heyongqiang 已提交
2023
  std::string default_db_path;
2024

J
jorlow@chromium.org 已提交
2025 2026 2027
  for (int i = 1; i < argc; i++) {
    double d;
    int n;
2028
    long l;
J
jorlow@chromium.org 已提交
2029
    char junk;
2030
    char buf[2048];
2031
    char str[512];
2032

J
jorlow@chromium.org 已提交
2033 2034 2035 2036 2037 2038 2039
    if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
      FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
    } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
      FLAGS_compression_ratio = d;
    } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      FLAGS_histogram = n;
2040 2041 2042
    } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      FLAGS_use_existing_db = n;
2043 2044
    } else if (sscanf(argv[i], "--num=%ld%c", &l, &junk) == 1) {
      FLAGS_num = l;
2045 2046
    } else if (sscanf(argv[i], "--numdistinct=%ld%c", &l, &junk) == 1) {
      FLAGS_numdistinct = l;
2047 2048
    } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {
      FLAGS_reads = n;
2049 2050
    } else if (sscanf(argv[i], "--read_range=%d%c", &n, &junk) == 1) {
      FLAGS_read_range = n;
M
Mark Callaghan 已提交
2051 2052
    } else if (sscanf(argv[i], "--duration=%d%c", &n, &junk) == 1) {
      FLAGS_duration = n;
2053 2054
    } else if (sscanf(argv[i], "--seed=%ld%c", &l, &junk) == 1) {
      FLAGS_seed = l;
2055 2056
    } else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) {
      FLAGS_threads = n;
J
jorlow@chromium.org 已提交
2057 2058
    } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
      FLAGS_value_size = n;
2059 2060 2061 2062 2063 2064 2065
    } else if (sscanf(argv[i], "--key_size=%d%c", &n, &junk) == 1) {
      if (MAX_KEY_SIZE < n) {
         fprintf(stderr, "key_size should not be larger than %d\n", MAX_KEY_SIZE);
         exit(1);
      } else {
        FLAGS_key_size = n;
      }
J
jorlow@chromium.org 已提交
2066 2067
    } else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) {
      FLAGS_write_buffer_size = n;
2068 2069
    } else if (sscanf(argv[i], "--max_write_buffer_number=%d%c", &n, &junk) == 1) {
      FLAGS_max_write_buffer_number = n;
2070 2071 2072
    } else if (sscanf(argv[i], "--min_write_buffer_number_to_merge=%d%c",
               &n, &junk) == 1) {
      FLAGS_min_write_buffer_number_to_merge = n;
J
Jim Paton 已提交
2073 2074
    } else if (sscanf(argv[i], "--max_background_compactions=%d%c", &n, &junk)
               == 1) {
2075
      FLAGS_max_background_compactions = n;
2076 2077 2078 2079 2080
    } else if (sscanf(argv[i], "--compaction_style=%d%c", &n, &junk) == 1) {
      FLAGS_compaction_style = (leveldb::CompactionStyle)n;
    } else if (sscanf(argv[i], "--universal_size_ratio=%d%c", &n, &junk) == 1) {
      FLAGS_universal_size_ratio = n;
    } else if (sscanf(argv[i], "--universal_min_merge_width=%d%c",
2081
               &n, &junk) == 1) {
2082
      FLAGS_compaction_universal_min_merge_width = n;
2083 2084
    } else if (sscanf(argv[i], "--cache_size=%ld%c", &l, &junk) == 1) {
      FLAGS_cache_size = l;
2085 2086
    } else if (sscanf(argv[i], "--block_size=%d%c", &n, &junk) == 1) {
      FLAGS_block_size = n;
2087
    } else if (sscanf(argv[i], "--cache_numshardbits=%d%c", &n, &junk) == 1) {
2088 2089 2090 2091 2092 2093
      if (n < 20) {
        FLAGS_cache_numshardbits = n;
      } else {
        fprintf(stderr, "The cache cannot be sharded into 2**%d pieces\n", n);
        exit(1);
      }
2094
    } else if (sscanf(argv[i], "--table_cache_numshardbits=%d%c",
A
Abhishek Kona 已提交
2095
          &n, &junk) == 1) {
2096 2097 2098 2099 2100
      if (n <= 0 || n > 20) {
        fprintf(stderr, "The cache cannot be sharded into 2**%d pieces\n", n);
        exit(1);
      }
      FLAGS_table_cache_numshardbits = n;
S
Sanjay Ghemawat 已提交
2101 2102
    } else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) {
      FLAGS_bloom_bits = n;
2103 2104
    } else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) {
      FLAGS_open_files = n;
2105 2106
    } else if (strncmp(argv[i], "--db=", 5) == 0) {
      FLAGS_db = argv[i] + 5;
2107 2108 2109
    } else if (sscanf(argv[i], "--verify_checksum=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      FLAGS_verify_checksum = n;
2110 2111
    } else if (sscanf(argv[i], "--bufferedio=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
2112
      FLAGS_use_os_buffer = n;
2113 2114
    } else if (sscanf(argv[i], "--mmap_read=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
2115
      FLAGS_use_mmap_reads = n;
2116 2117
    } else if (sscanf(argv[i], "--mmap_write=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
2118
      FLAGS_use_mmap_writes = n;
2119 2120 2121
    } else if (sscanf(argv[i], "--statistics=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      if (n == 1) {
H
Haobo Xu 已提交
2122
        dbstats = leveldb::CreateDBStatistics();
2123 2124
        FLAGS_statistics = true;
      }
2125 2126
    } else if (sscanf(argv[i], "--writes=%d%c", &n, &junk) == 1) {
      FLAGS_writes = n;
2127 2128
    } else if (sscanf(argv[i], "--writes_per_second=%d%c", &n, &junk) == 1) {
      FLAGS_writes_per_second = n;
2129 2130 2131
    } else if (sscanf(argv[i], "--sync=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      FLAGS_sync = n;
2132
    } else if (sscanf(argv[i], "--readwritepercent=%d%c", &n, &junk) == 1 &&
2133
               n > 0 && n < 100) {
2134
      FLAGS_readwritepercent = n;
2135 2136 2137
    } else if (sscanf(argv[i], "--deletepercent=%d%c", &n, &junk) == 1 &&
               n > 0 && n < 100) {
      FLAGS_deletepercent = n;
H
heyongqiang 已提交
2138 2139 2140
    } else if (sscanf(argv[i], "--disable_data_sync=%d%c", &n, &junk) == 1 &&
        (n == 0 || n == 1)) {
      FLAGS_disable_data_sync = n;
2141 2142 2143
    } else if (sscanf(argv[i], "--use_fsync=%d%c", &n, &junk) == 1 &&
        (n == 0 || n == 1)) {
      FLAGS_use_fsync = n;
H
heyongqiang 已提交
2144
    } else if (sscanf(argv[i], "--disable_wal=%d%c", &n, &junk) == 1 &&
2145
        (n == 0 || n == 1)) {
H
heyongqiang 已提交
2146
      FLAGS_disable_wal = n;
M
Mark Callaghan 已提交
2147 2148 2149 2150 2151 2152
    } else if (sscanf(argv[i], "--use_snapshot=%d%c", &n, &junk) == 1 &&
        (n == 0 || n == 1)) {
      FLAGS_use_snapshot = n;
    } else if (sscanf(argv[i], "--get_approx=%d%c", &n, &junk) == 1 &&
        (n == 0 || n == 1)) {
      FLAGS_get_approx = n;
2153 2154
    } else if (sscanf(argv[i], "--hdfs=%s", buf) == 1) {
      FLAGS_env  = new leveldb::HdfsEnv(buf);
2155 2156 2157
    } else if (sscanf(argv[i], "--num_levels=%d%c",
        &n, &junk) == 1) {
      FLAGS_num_levels = n;
H
heyongqiang 已提交
2158 2159 2160 2161 2162 2163 2164
    } else if (sscanf(argv[i], "--target_file_size_base=%d%c",
        &n, &junk) == 1) {
      FLAGS_target_file_size_base = n;
    } else if ( sscanf(argv[i], "--target_file_size_multiplier=%d%c",
        &n, &junk) == 1) {
      FLAGS_target_file_size_multiplier = n;
    } else if (
2165 2166
        sscanf(argv[i], "--max_bytes_for_level_base=%ld%c", &l, &junk) == 1) {
      FLAGS_max_bytes_for_level_base = l;
H
heyongqiang 已提交
2167 2168 2169
    } else if (sscanf(argv[i], "--max_bytes_for_level_multiplier=%d%c",
        &n, &junk) == 1) {
      FLAGS_max_bytes_for_level_multiplier = n;
H
heyongqiang 已提交
2170 2171 2172
    } else if (sscanf(argv[i],"--level0_stop_writes_trigger=%d%c",
        &n, &junk) == 1) {
      FLAGS_level0_stop_writes_trigger = n;
2173 2174 2175 2176 2177 2178 2179 2180
    } else if (sscanf(argv[i],
                "--max_bytes_for_level_multiplier_additional=%s%c",
                str, &junk) == 1) {
      std::vector<std::string> fanout = leveldb::stringSplit(str, ',');
      for (unsigned int j= 0; j < fanout.size(); j++) {
        FLAGS_max_bytes_for_level_multiplier_additional.push_back(
          std::stoi(fanout[j]));
      }
H
heyongqiang 已提交
2181 2182 2183
    } else if (sscanf(argv[i],"--level0_slowdown_writes_trigger=%d%c",
        &n, &junk) == 1) {
      FLAGS_level0_slowdown_writes_trigger = n;
2184 2185 2186
    } else if (sscanf(argv[i],"--level0_file_num_compaction_trigger=%d%c",
        &n, &junk) == 1) {
      FLAGS_level0_file_num_compaction_trigger = n;
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
    } else if (strncmp(argv[i], "--compression_type=", 19) == 0) {
      const char* ctype = argv[i] + 19;
      if (!strcasecmp(ctype, "none"))
        FLAGS_compression_type = leveldb::kNoCompression;
      else if (!strcasecmp(ctype, "snappy"))
        FLAGS_compression_type = leveldb::kSnappyCompression;
      else if (!strcasecmp(ctype, "zlib"))
        FLAGS_compression_type = leveldb::kZlibCompression;
      else if (!strcasecmp(ctype, "bzip2"))
        FLAGS_compression_type = leveldb::kBZip2Compression;
      else {
        fprintf(stdout, "Cannot parse %s\n", argv[i]);
      }
2200 2201
    } else if (sscanf(argv[i], "--min_level_to_compress=%d%c", &n, &junk) == 1
        && n >= 0) {
2202
      FLAGS_min_level_to_compress = n;
2203 2204 2205
    } else if (sscanf(argv[i], "--disable_seek_compaction=%d%c", &n, &junk) == 1
        && (n == 0 || n == 1)) {
      FLAGS_disable_seek_compaction = n;
2206 2207
    } else if (sscanf(argv[i], "--delete_obsolete_files_period_micros=%ld%c",
                      &l, &junk) == 1) {
2208
      FLAGS_delete_obsolete_files_period_micros = l;
2209 2210 2211
    } else if (sscanf(argv[i], "--stats_interval=%d%c", &n, &junk) == 1 &&
               n >= 0 && n < 2000000000) {
      FLAGS_stats_interval = n;
2212 2213 2214
    } else if (sscanf(argv[i], "--stats_per_interval=%d%c", &n, &junk) == 1
        && (n == 0 || n == 1)) {
      FLAGS_stats_per_interval = n;
J
Jim Paton 已提交
2215 2216 2217 2218
    } else if (sscanf(argv[i], "--soft_rate_limit=%lf%c", &d, &junk) == 1 &&
               d > 0.0) {
      FLAGS_soft_rate_limit = d;
    } else if (sscanf(argv[i], "--hard_rate_limit=%lf%c", &d, &junk) == 1 &&
2219
               d > 1.0) {
J
Jim Paton 已提交
2220
      FLAGS_hard_rate_limit = d;
2221
    } else if (sscanf(argv[i],
J
Jim Paton 已提交
2222 2223 2224
               "--rate_limit_delay_max_milliseconds=%d%c", &n, &junk) == 1
        && n >= 0) {
      FLAGS_rate_limit_delay_max_milliseconds = n;
H
heyongqiang 已提交
2225 2226 2227
    } else if (sscanf(argv[i], "--readonly=%d%c", &n, &junk) == 1 &&
        (n == 0 || n ==1 )) {
      FLAGS_read_only = n;
2228 2229 2230
    } else if (sscanf(argv[i], "--max_grandparent_overlap_factor=%d%c",
               &n, &junk) == 1) {
      FLAGS_max_grandparent_overlap_factor = n;
A
Abhishek Kona 已提交
2231
    } else if (sscanf(argv[i], "--disable_auto_compactions=%d%c",
2232 2233
               &n, &junk) == 1 && (n == 0 || n ==1)) {
      FLAGS_disable_auto_compactions = n;
A
Abhishek Kona 已提交
2234
    } else if (sscanf(argv[i], "--source_compaction_factor=%d%c",
2235 2236
               &n, &junk) == 1 && n > 0) {
      FLAGS_source_compaction_factor = n;
2237 2238
    } else if (sscanf(argv[i], "--wal_ttl=%d%c", &n, &junk) == 1) {
      FLAGS_WAL_ttl_seconds = static_cast<uint64_t>(n);
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
    } else if (sscanf(argv[i], "--advise_random_on_open=%d%c", &n, &junk) == 1
               && (n == 0 || n ==1 )) {
      FLAGS_advise_random_on_open = n;
    } else if (sscanf(argv[i], "--compaction_fadvice=%s", buf) == 1) {
      if (!strcasecmp(buf, "NONE"))
        FLAGS_compaction_fadvice = leveldb::Options::NONE;
      else if (!strcasecmp(buf, "NORMAL"))
        FLAGS_compaction_fadvice = leveldb::Options::NORMAL;
      else if (!strcasecmp(buf, "SEQUENTIAL"))
        FLAGS_compaction_fadvice = leveldb::Options::SEQUENTIAL;
      else if (!strcasecmp(buf, "WILLNEED"))
        FLAGS_compaction_fadvice = leveldb::Options::WILLNEED;
      else {
        fprintf(stdout, "Unknown compaction fadvice:%s\n", buf);
      }
H
Haobo Xu 已提交
2254 2255 2256
    } else if (sscanf(argv[i], "--use_adaptive_mutex=%d%c", &n, &junk) == 1
               && (n == 0 || n ==1 )) {
      FLAGS_use_adaptive_mutex = n;
2257 2258 2259 2260 2261 2262
    } else if (sscanf(argv[i], "--use_multiget=%d%c", &n, &junk) == 1 &&
               (n == 0 || n == 1)) {
      FLAGS_use_multiget = n;
    } else if (sscanf(argv[i], "--keys_per_multiget=%d%c",
               &n, &junk) == 1) {
      FLAGS_keys_per_multiget = n;
H
Haobo Xu 已提交
2263 2264
    }  else if (sscanf(argv[i], "--bytes_per_sync=%ld%c", &l, &junk) == 1) {
      FLAGS_bytes_per_sync = l;
2265
    } else if (sscanf(argv[i], "--filter_deletes=%d%c", &n, &junk)
2266
               == 1 && (n == 0 || n ==1 )) {
2267
      FLAGS_filter_deletes = n;
2268
    } else {
J
jorlow@chromium.org 已提交
2269 2270 2271 2272 2273
      fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
      exit(1);
    }
  }

2274 2275 2276 2277
  // The number of background threads should be at least as much the
  // max number of concurrent compactions.
  FLAGS_env->SetBackgroundThreads(FLAGS_max_background_compactions);

H
heyongqiang 已提交
2278
  // Choose a location for the test database if none given with --db=<path>
2279
  if (FLAGS_db == nullptr) {
H
heyongqiang 已提交
2280 2281 2282 2283 2284
      leveldb::Env::Default()->GetTestDirectory(&default_db_path);
      default_db_path += "/dbbench";
      FLAGS_db = default_db_path.c_str();
  }

J
jorlow@chromium.org 已提交
2285 2286 2287 2288
  leveldb::Benchmark benchmark;
  benchmark.Run();
  return 0;
}