@@ -129,6 +129,7 @@ DEFINE_string(
129129 " compact1,"
130130 " waitforcompaction,"
131131 " multireadrandom,"
132+ " multiscan,"
132133 " mixgraph,"
133134 " readseq,"
134135 " readtorowcache,"
@@ -333,6 +334,13 @@ DEFINE_bool(use_uint64_comparator, false, "use Uint64 user comparator");
333334
334335DEFINE_int64 (batch_size, 1 , " Batch size" );
335336
337+ DEFINE_int64 (multiscan_size, 10 ,
338+ " MultiScan size - number of multiscans of size `batch_size`" );
339+
340+ DEFINE_int64 (
341+ multiscan_stride, 100 ,
342+ " The amount of keys between two successive Scan operations in multiscan" );
343+
336344static bool ValidateKeySize (const char * /* flagname*/ , int32_t /* value*/ ) {
337345 return true ;
338346}
@@ -2190,7 +2198,8 @@ enum OperationType : unsigned char {
21902198 kUncompress ,
21912199 kCrc ,
21922200 kHash ,
2193- kOthers
2201+ kOthers ,
2202+ kMultiScan
21942203};
21952204
21962205static std::unordered_map<OperationType, std::string, std::hash<unsigned char >>
@@ -2199,7 +2208,7 @@ static std::unordered_map<OperationType, std::string, std::hash<unsigned char>>
21992208 {kMerge , " merge" }, {kUpdate , " update" },
22002209 {kCompress , " compress" }, {kCompress , " uncompress" },
22012210 {kCrc , " crc" }, {kHash , " hash" },
2202- {kOthers , " op" }};
2211+ {kOthers , " op" }, { kMultiScan , " multiscan " } };
22032212
22042213class CombinedStats ;
22052214class Stats {
@@ -3641,6 +3650,12 @@ class Benchmark {
36413650 fprintf (stderr, " entries_per_batch = %" PRIi64 " \n " ,
36423651 entries_per_batch_);
36433652 method = &Benchmark::MultiReadRandom;
3653+ } else if (name == " multiscan" ) {
3654+ fprintf (stderr, " multiscan_stride = %" PRIi64 " \n " ,
3655+ FLAGS_multiscan_stride);
3656+ fprintf (stderr, " multiscan_size = %" PRIi64 " \n " , FLAGS_multiscan_size);
3657+ fprintf (stderr, " seek_nexts = %" PRIi32 " \n " , FLAGS_seek_nexts);
3658+ method = &Benchmark::MultiScan;
36443659 } else if (name == " multireadwhilewriting" ) {
36453660 fprintf (stderr, " entries_per_batch = %" PRIi64 " \n " ,
36463661 entries_per_batch_);
@@ -6369,6 +6384,71 @@ class Benchmark {
63696384 thread->stats .AddMessage (msg);
63706385 }
63716386
6387+ void MultiScan (ThreadState* thread) {
6388+ const int64_t scan_size = FLAGS_seek_nexts ? FLAGS_seek_nexts : 50 ;
6389+ const int64_t readahead =
6390+ FLAGS_readahead_size ? FLAGS_readahead_size : 1024 * 24 ;
6391+ const int64_t multiscan_size = FLAGS_multiscan_size;
6392+ auto count_hist = std::make_shared<HistogramImpl>();
6393+ ReadOptions options = read_options_;
6394+
6395+ int64_t multiscans_done = 0 ;
6396+
6397+ options.async_io = true ;
6398+ options.readahead_size = readahead;
6399+
6400+ Duration duration (FLAGS_duration, reads_);
6401+ while (!duration.Done (1 )) {
6402+ DB * db = SelectDB (thread);
6403+ std::vector<ScanOptions> opts;
6404+ std::vector<std::unique_ptr<const char []>> guards;
6405+ opts.reserve (multiscan_size);
6406+ // We create 1 random start, and then multiscan will start from that
6407+ // random start point And create a set of scans of `scan_size` in size
6408+ // with `multiscan_stride` space between each scan.
6409+ uint64_t range = static_cast <uint64_t >(FLAGS_num) -
6410+ ((scan_size + FLAGS_multiscan_stride) * multiscan_size);
6411+ uint64_t start_key = thread->rand .Uniform (range);
6412+ for (int64_t i = 0 ; i < multiscan_size; i++) {
6413+ std::unique_ptr<const char []> skey_guard;
6414+ Slice skey = AllocateKey (&skey_guard);
6415+ guards.push_back (std::move (skey_guard));
6416+ std::unique_ptr<const char []> ekey_guard;
6417+ Slice ekey = AllocateKey (&ekey_guard);
6418+ guards.push_back (std::move (ekey_guard));
6419+
6420+ GenerateKeyFromInt (start_key, FLAGS_num, &skey);
6421+ uint64_t end_key = start_key + scan_size;
6422+ GenerateKeyFromInt (end_key, FLAGS_num, &ekey);
6423+
6424+ opts.emplace_back (skey, ekey);
6425+ start_key += scan_size + FLAGS_multiscan_stride;
6426+ }
6427+
6428+ auto iter =
6429+ db->NewMultiScan (read_options_, db->DefaultColumnFamily (), opts);
6430+ for (auto rng : *iter) {
6431+ size_t keys = 0 ;
6432+ for (auto it __attribute__ ((__unused__)) : rng) {
6433+ keys++;
6434+ }
6435+ assert (keys > 0 );
6436+ }
6437+
6438+ if (thread->shared ->read_rate_limiter .get () != nullptr ) {
6439+ thread->shared ->read_rate_limiter ->Request (
6440+ 1 , Env::IO_HIGH , nullptr /* stats */ , RateLimiter::OpType::kRead );
6441+ }
6442+
6443+ thread->stats .FinishedOps (nullptr , db, 1 , kMultiScan );
6444+ multiscans_done += 1 ;
6445+ }
6446+
6447+ char msg[100 ];
6448+ snprintf (msg, sizeof (msg), " (multscans:%" PRIu64 " )" , multiscans_done);
6449+ thread->stats .AddMessage (msg);
6450+ }
6451+
63726452 void ApproximateMemtableStats (ThreadState* thread) {
63736453 const size_t batch_size = entries_per_batch_;
63746454 std::unique_ptr<const char []> skey_guard;
0 commit comments