@@ -2387,17 +2387,22 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2387
2387
2388
2388
class DeadlineRandomAccessFile : public FSRandomAccessFileWrapper {
2389
2389
public:
2390
- DeadlineRandomAccessFile (DeadlineFS& fs,
2390
+ DeadlineRandomAccessFile (DeadlineFS& fs, SpecialEnv* env,
2391
2391
std::unique_ptr<FSRandomAccessFile>& file)
2392
2392
: FSRandomAccessFileWrapper(file.get()),
2393
2393
fs_ (fs),
2394
- file_(std::move(file)) {}
2394
+ file_(std::move(file)),
2395
+ env_(env) {}
2395
2396
2396
2397
IOStatus Read (uint64_t offset, size_t len, const IOOptions& opts,
2397
2398
Slice* result, char * scratch, IODebugContext* dbg) const override {
2398
2399
int delay;
2400
+ const std::chrono::microseconds deadline = fs_.GetDeadline ();
2401
+ if (deadline.count ()) {
2402
+ AssertDeadline (deadline, opts);
2403
+ }
2399
2404
if (fs_.ShouldDelay (&delay)) {
2400
- Env::Default () ->SleepForMicroseconds (delay);
2405
+ env_ ->SleepForMicroseconds (delay);
2401
2406
}
2402
2407
return FSRandomAccessFileWrapper::Read (offset, len, opts, result, scratch,
2403
2408
dbg);
@@ -2406,22 +2411,37 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2406
2411
IOStatus MultiRead (FSReadRequest* reqs, size_t num_reqs,
2407
2412
const IOOptions& options, IODebugContext* dbg) override {
2408
2413
int delay;
2414
+ const std::chrono::microseconds deadline = fs_.GetDeadline ();
2415
+ if (deadline.count ()) {
2416
+ AssertDeadline (deadline, options);
2417
+ }
2409
2418
if (fs_.ShouldDelay (&delay)) {
2410
- Env::Default () ->SleepForMicroseconds (delay);
2419
+ env_ ->SleepForMicroseconds (delay);
2411
2420
}
2412
2421
return FSRandomAccessFileWrapper::MultiRead (reqs, num_reqs, options, dbg);
2413
2422
}
2414
2423
2415
2424
private:
2425
+ void AssertDeadline (const std::chrono::microseconds deadline,
2426
+ const IOOptions& opts) const {
2427
+ // Give a leeway of +- 10us as it can take some time for the Get/
2428
+ // MultiGet call to reach here, in order to avoid false alarms
2429
+ std::chrono::microseconds now =
2430
+ std::chrono::microseconds (env_->NowMicros ());
2431
+ ASSERT_EQ (deadline - now, opts.timeout );
2432
+ }
2416
2433
DeadlineFS& fs_;
2417
2434
std::unique_ptr<FSRandomAccessFile> file_;
2435
+ SpecialEnv* env_;
2418
2436
};
2419
2437
2420
2438
class DeadlineFS : public FileSystemWrapper {
2421
2439
public:
2422
- DeadlineFS ()
2423
- : FileSystemWrapper(FileSystem::Default()),
2424
- delay_idx_ (0 ) {}
2440
+ DeadlineFS (SpecialEnv* env)
2441
+ : FileSystemWrapper(FileSystem::Default()),
2442
+ delay_idx_ (0 ),
2443
+ deadline_(std::chrono::microseconds::zero()),
2444
+ env_(env) {}
2425
2445
~DeadlineFS () = default ;
2426
2446
2427
2447
IOStatus NewRandomAccessFile (const std::string& fname,
@@ -2432,13 +2452,14 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2432
2452
IOStatus s;
2433
2453
2434
2454
s = target ()->NewRandomAccessFile (fname, opts, &file, dbg);
2435
- result->reset (new DeadlineRandomAccessFile (*this , file));
2455
+ result->reset (new DeadlineRandomAccessFile (*this , env_, file));
2436
2456
return s;
2437
2457
}
2438
2458
2439
2459
// Set a vector of {IO counter, delay in microseconds} pairs that control
2440
2460
// when to inject a delay and duration of the delay
2441
- void SetDelaySequence (const std::vector<std::pair<int , int >>&& seq) {
2461
+ void SetDelaySequence (const std::chrono::microseconds deadline,
2462
+ const std::vector<std::pair<int , int >>&& seq) {
2442
2463
int total_delay = 0 ;
2443
2464
for (auto & seq_iter : seq) {
2444
2465
// Ensure no individual delay is > 500ms
@@ -2451,6 +2472,7 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2451
2472
delay_seq_ = seq;
2452
2473
delay_idx_ = 0 ;
2453
2474
io_count_ = 0 ;
2475
+ deadline_ = deadline;
2454
2476
}
2455
2477
2456
2478
// Increment the IO counter and return a delay in microseconds
@@ -2464,10 +2486,14 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2464
2486
return false ;
2465
2487
}
2466
2488
2489
+ const std::chrono::microseconds GetDeadline () { return deadline_; }
2490
+
2467
2491
private:
2468
2492
std::vector<std::pair<int , int >> delay_seq_;
2469
2493
size_t delay_idx_;
2470
2494
int io_count_;
2495
+ std::chrono::microseconds deadline_;
2496
+ SpecialEnv* env_;
2471
2497
};
2472
2498
2473
2499
inline void CheckStatus (std::vector<Status>& statuses, size_t num_ok) {
@@ -2483,8 +2509,10 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
2483
2509
2484
2510
TEST_F (DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2485
2511
std::shared_ptr<DBBasicTestMultiGetDeadline::DeadlineFS> fs (
2486
- new DBBasicTestMultiGetDeadline::DeadlineFS ());
2487
- std::unique_ptr<Env> env = NewCompositeEnv (fs);
2512
+ new DBBasicTestMultiGetDeadline::DeadlineFS (env_));
2513
+ std::unique_ptr<Env> env (new CompositeEnvWrapper (env_, fs));
2514
+ env_->no_slowdown_ = true ;
2515
+ env_->time_elapse_only_sleep_ .store (true );
2488
2516
Options options = CurrentOptions ();
2489
2517
2490
2518
std::shared_ptr<Cache> cache = NewLRUCache (1048576 );
@@ -2509,13 +2537,13 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2509
2537
cfs[i] = handles_[i];
2510
2538
keys[i] = Slice (key_str[i].data (), key_str[i].size ());
2511
2539
}
2512
- // Delay the first IO by 200ms
2513
- fs->SetDelaySequence ({{0 , 200000 }});
2514
2540
2515
2541
ReadOptions ro;
2516
2542
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2543
+ // Delay the first IO by 200ms
2544
+ fs->SetDelaySequence (ro.deadline , {{0 , 20000 }});
2545
+
2517
2546
std::vector<Status> statuses = dbfull ()->MultiGet (ro, cfs, keys, &values);
2518
- std::cout << " Non-batched MultiGet" ;
2519
2547
// The first key is successful because we check after the lookup, but
2520
2548
// subsequent keys fail due to deadline exceeded
2521
2549
CheckStatus (statuses, 1 );
@@ -2537,10 +2565,9 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2537
2565
cfs[i] = handles_[i / 2 ];
2538
2566
keys[i] = Slice (key_str[i].data (), key_str[i].size ());
2539
2567
}
2540
- fs->SetDelaySequence ({{1 , 200000 }});
2541
2568
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2569
+ fs->SetDelaySequence (ro.deadline , {{1 , 20000 }});
2542
2570
statuses = dbfull ()->MultiGet (ro, cfs, keys, &values);
2543
- std::cout << " Non-batched 2" ;
2544
2571
CheckStatus (statuses, 3 );
2545
2572
2546
2573
// Test batched MultiGet with an IO delay in the first data block read.
@@ -2552,11 +2579,10 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2552
2579
cache->SetCapacity (1048576 );
2553
2580
statuses.clear ();
2554
2581
statuses.resize (keys.size ());
2555
- fs->SetDelaySequence ({{0 , 200000 }});
2556
2582
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2583
+ fs->SetDelaySequence (ro.deadline , {{0 , 20000 }});
2557
2584
dbfull ()->MultiGet (ro, keys.size (), cfs.data (), keys.data (),
2558
2585
pin_values.data (), statuses.data ());
2559
- std::cout << " Batched 1" ;
2560
2586
CheckStatus (statuses, 2 );
2561
2587
2562
2588
// Similar to the previous one, but an IO delay in the third CF data block
@@ -2568,11 +2594,10 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2568
2594
cache->SetCapacity (1048576 );
2569
2595
statuses.clear ();
2570
2596
statuses.resize (keys.size ());
2571
- fs->SetDelaySequence ({{2 , 200000 }});
2572
2597
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2598
+ fs->SetDelaySequence (ro.deadline , {{2 , 20000 }});
2573
2599
dbfull ()->MultiGet (ro, keys.size (), cfs.data (), keys.data (),
2574
2600
pin_values.data (), statuses.data ());
2575
- std::cout << " Batched 2" ;
2576
2601
CheckStatus (statuses, 6 );
2577
2602
2578
2603
// Similar to the previous one, but an IO delay in the last but one CF
@@ -2583,11 +2608,10 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2583
2608
cache->SetCapacity (1048576 );
2584
2609
statuses.clear ();
2585
2610
statuses.resize (keys.size ());
2586
- fs->SetDelaySequence ({{3 , 200000 }});
2587
2611
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2612
+ fs->SetDelaySequence (ro.deadline , {{3 , 20000 }});
2588
2613
dbfull ()->MultiGet (ro, keys.size (), cfs.data (), keys.data (),
2589
2614
pin_values.data (), statuses.data ());
2590
- std::cout << " Batched 3" ;
2591
2615
CheckStatus (statuses, 8 );
2592
2616
2593
2617
// Test batched MultiGet with single CF and lots of keys. Inject delay
@@ -2610,11 +2634,10 @@ TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
2610
2634
}
2611
2635
statuses.clear ();
2612
2636
statuses.resize (keys.size ());
2613
- fs->SetDelaySequence ({{1 , 200000 }});
2614
2637
ro.deadline = std::chrono::microseconds{env->NowMicros () + 10000 };
2638
+ fs->SetDelaySequence (ro.deadline , {{1 , 20000 }});
2615
2639
dbfull ()->MultiGet (ro, handles_[0 ], keys.size (), keys.data (),
2616
2640
pin_values.data (), statuses.data ());
2617
- std::cout << " Batched single CF" ;
2618
2641
CheckStatus (statuses, 64 );
2619
2642
Close ();
2620
2643
}
0 commit comments