@@ -48,23 +48,16 @@ TEST(StorageLock, Timeout) {
48
48
}
49
49
50
50
struct LockData {
51
- std::string lock_name_;
52
- std::shared_ptr<InMemoryStore> store_;
53
- volatile uint64_t vol_;
54
- std::atomic<uint64_t > atomic_;
55
- std::atomic<bool > contended_;
51
+ std::string lock_name_ = " stress_test_lock" ;
52
+ std::shared_ptr<InMemoryStore> store_ = std::make_shared<InMemoryStore>();
53
+ volatile uint64_t vol_ { 0 };
54
+ std::atomic<uint64_t > atomic_ = { 0 };
55
+ std::atomic<bool > contended_ { false };
56
+ std::atomic<bool > timedout_ { false };
56
57
const size_t num_tests_;
57
- std::atomic<bool > timedout_;
58
-
59
- LockData (size_t num_tests) :
60
- lock_name_ (" stress_test_lock" ),
61
- store_ (std::make_shared<InMemoryStore>()),
62
- vol_ (0 ),
63
- atomic_ (0 ),
64
- contended_ (false ),
65
- num_tests_ (num_tests),
66
- timedout_ (false ){
67
- }
58
+
59
+ explicit LockData (size_t num_tests) :
60
+ num_tests_(num_tests){}
68
61
69
62
};
70
63
@@ -77,6 +70,7 @@ struct OptimisticLockTask {
77
70
78
71
folly::Future<folly::Unit> operator ()() {
79
72
StorageLock<> lock{data_->lock_name_ };
73
+ using namespace std ::chrono_literals;
80
74
81
75
for (auto i = size_t (0 ); i < data_->num_tests_ ; ++i) {
82
76
if (!lock.try_lock (data_->store_ )) {
@@ -85,6 +79,7 @@ struct OptimisticLockTask {
85
79
else {
86
80
// As of C++20, '++' expression of 'volatile'-qualified type is deprecated.
87
81
const uint64_t vol_ = data_->vol_ + 1 ;
82
+ std::this_thread::sleep_for (10ms);
88
83
data_->vol_ = vol_;
89
84
++data_->atomic_ ;
90
85
lock.unlock (data_->store_ );
@@ -370,7 +365,7 @@ class StorageLockWithSlowWrites : public ::testing::TestWithParam<std::tuple<int
370
365
protected:
371
366
void SetUp () override {
372
367
log::lock ().set_level (spdlog::level::debug);
373
- StorageFailureSimulator::instance ()-> reset ();
368
+ StorageFailureSimulator::reset ();
374
369
}
375
370
};
376
371
@@ -426,6 +421,29 @@ TEST_P(StorageLockWithSlowWrites, ConcurrentWritesWithRetrying) {
426
421
ASSERT_EQ (lock_data->atomic_ , 1 );
427
422
}
428
423
424
+ TEST (StorageLock, StressManyWriters) {
425
+
426
+ const StorageFailureSimulator::ParamActionSequence SLOW_ACTIONS = {
427
+ action_factories::slow_action (0.3 , 600 , 1100 ),
428
+ };
429
+
430
+ constexpr size_t num_writers = 50 ;
431
+ FutureExecutor<CPUThreadPoolExecutor> exec{num_writers};
432
+
433
+ StorageFailureSimulator::instance ()->configure ({{FailureType::WRITE_LOCK, SLOW_ACTIONS}});
434
+
435
+ std::vector<Future<Unit>> futures;
436
+ auto lock_data = std::make_shared<LockData>(num_writers);
437
+ lock_data->store_ = std::make_shared<InMemoryStore>();
438
+
439
+ for (size_t i = 0 ; i < num_writers; ++i) {
440
+ futures.emplace_back (exec.addFuture (OptimisticLockTask (lock_data)));
441
+ }
442
+ collect (futures).get ();
443
+
444
+ ASSERT_EQ (lock_data->atomic_ , lock_data->vol_ );
445
+ }
446
+
429
447
INSTANTIATE_TEST_SUITE_P (
430
448
DelayPairs,
431
449
StorageLockWithSlowWrites,
@@ -450,9 +468,6 @@ TEST(StorageLock, SlowWrites) {
450
468
451
469
TEST (StorageLock, DISABLED_LockSameTimestamp) { // Not yet implemented
452
470
log::lock ().set_level (spdlog::level::debug);
453
- const StorageFailureSimulator::ParamActionSequence SLOW_ON_2ND_CALL = {
454
- action_factories::slow_action (1 , 10 , 10 ), action_factories::slow_action (1 , 10 , 10 )
455
- };
456
471
constexpr size_t num_writers = 2 ;
457
472
458
473
using StorageLockType = StorageLock<util::ManualClock>;
@@ -462,7 +477,6 @@ TEST(StorageLock, DISABLED_LockSameTimestamp) { // Not yet implemented
462
477
while (locks.size () < num_writers) { locks.emplace_back (std::make_unique<StorageLockType>(" test" )); };
463
478
auto store = std::make_shared<InMemoryStore>();
464
479
folly::FutureExecutor<folly::CPUThreadPoolExecutor> exec{num_writers};
465
- StorageFailureSimulator::instance ()->configure ({{FailureType::WRITE_LOCK, SLOW_ON_2ND_CALL}});
466
480
std::vector<Future<Unit>> futures;
467
481
std::vector<bool > writer_has_lock;
468
482
writer_has_lock.resize (num_writers);
0 commit comments