mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 16:50:48 +00:00
Add more tests for RWLock.
This commit is contained in:
parent
d74f72d310
commit
fc00569db6
@ -24,6 +24,39 @@ namespace DB
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
class Events
|
||||
{
|
||||
public:
|
||||
Events() : start_time(std::chrono::steady_clock::now()) {}
|
||||
|
||||
void add(String && event)
|
||||
{
|
||||
String timepoint = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count());
|
||||
if (timepoint.length() < 5)
|
||||
timepoint.insert(0, 5 - timepoint.length(), ' ');
|
||||
std::lock_guard lock{mutex};
|
||||
std::cout << timepoint << " : " << event << std::endl;
|
||||
events.emplace_back(std::move(event));
|
||||
}
|
||||
|
||||
void check(const Strings & expected_events)
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
EXPECT_EQ(events.size(), expected_events.size());
|
||||
for (size_t i = 0; i != events.size(); ++i)
|
||||
EXPECT_EQ(events[i], (i < expected_events.size() ? expected_events[i] : ""));
|
||||
}
|
||||
|
||||
private:
|
||||
const std::chrono::time_point<std::chrono::steady_clock> start_time;
|
||||
Strings events TSA_GUARDED_BY(mutex);
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
TEST(Common, RWLock1)
|
||||
{
|
||||
/// Tests with threads require this, because otherwise
|
||||
@ -287,3 +320,200 @@ TEST(Common, RWLockNotUpgradeableWithNoQuery)
|
||||
|
||||
read_thread.join();
|
||||
}
|
||||
|
||||
|
||||
TEST(Common, RWLockWriteLockTimeoutDuringRead)
|
||||
{
|
||||
static auto rw_lock = RWLockImpl::create();
|
||||
Events events;
|
||||
|
||||
std::thread ra_thread([&] ()
|
||||
{
|
||||
events.add("Locking ra");
|
||||
auto ra = rw_lock->getLock(RWLockImpl::Read, "ra");
|
||||
events.add(ra ? "Locked ra" : "Failed to lock ra");
|
||||
EXPECT_NE(ra, nullptr);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(400));
|
||||
|
||||
events.add("Unlocking ra");
|
||||
ra.reset();
|
||||
events.add("Unlocked ra");
|
||||
});
|
||||
|
||||
std::thread wc_thread([&] ()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
events.add("Locking wc");
|
||||
auto wc = rw_lock->getLock(RWLockImpl::Write, "wc", std::chrono::milliseconds(200));
|
||||
events.add(wc ? "Locked wc" : "Failed to lock wc");
|
||||
EXPECT_EQ(wc, nullptr);
|
||||
});
|
||||
|
||||
ra_thread.join();
|
||||
wc_thread.join();
|
||||
|
||||
{
|
||||
events.add("Locking wd");
|
||||
auto wd = rw_lock->getLock(RWLockImpl::Write, "wd", std::chrono::milliseconds(1000));
|
||||
events.add(wd ? "Locked wd" : "Failed to lock wd");
|
||||
EXPECT_NE(wd, nullptr);
|
||||
events.add("Unlocking wd");
|
||||
wd.reset();
|
||||
events.add("Unlocked wd");
|
||||
}
|
||||
|
||||
events.check(
|
||||
{"Locking ra",
|
||||
"Locked ra",
|
||||
"Locking wc",
|
||||
"Failed to lock wc",
|
||||
"Unlocking ra",
|
||||
"Unlocked ra",
|
||||
"Locking wd",
|
||||
"Locked wd",
|
||||
"Unlocking wd",
|
||||
"Unlocked wd"});
|
||||
}
|
||||
|
||||
|
||||
TEST(Common, RWLockWriteLockTimeoutDuringTwoReads)
|
||||
{
|
||||
static auto rw_lock = RWLockImpl::create();
|
||||
Events events;
|
||||
|
||||
std::thread ra_thread([&] ()
|
||||
{
|
||||
events.add("Locking ra");
|
||||
auto ra = rw_lock->getLock(RWLockImpl::Read, "ra");
|
||||
events.add(ra ? "Locked ra" : "Failed to lock ra");
|
||||
EXPECT_NE(ra, nullptr);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(400));
|
||||
|
||||
events.add("Unlocking ra");
|
||||
ra.reset();
|
||||
events.add("Unlocked ra");
|
||||
});
|
||||
|
||||
std::thread rb_thread([&] ()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(200));
|
||||
events.add("Locking rb");
|
||||
|
||||
auto rb = rw_lock->getLock(RWLockImpl::Read, "rb");
|
||||
events.add(rb ? "Locked rb" : "Failed to lock rb");
|
||||
EXPECT_NE(rb, nullptr);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(200));
|
||||
events.add("Unlocking rb");
|
||||
rb.reset();
|
||||
events.add("Unlocked rb");
|
||||
});
|
||||
|
||||
std::thread wc_thread([&] ()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
events.add("Locking wc");
|
||||
auto wc = rw_lock->getLock(RWLockImpl::Write, "wc", std::chrono::milliseconds(200));
|
||||
events.add(wc ? "Locked wc" : "Failed to lock wc");
|
||||
EXPECT_EQ(wc, nullptr);
|
||||
});
|
||||
|
||||
ra_thread.join();
|
||||
rb_thread.join();
|
||||
wc_thread.join();
|
||||
|
||||
{
|
||||
events.add("Locking wd");
|
||||
auto wd = rw_lock->getLock(RWLockImpl::Write, "wd", std::chrono::milliseconds(1000));
|
||||
events.add(wd ? "Locked wd" : "Failed to lock wd");
|
||||
EXPECT_NE(wd, nullptr);
|
||||
events.add("Unlocking wd");
|
||||
wd.reset();
|
||||
events.add("Unlocked wd");
|
||||
}
|
||||
|
||||
events.check(
|
||||
{"Locking ra",
|
||||
"Locked ra",
|
||||
"Locking wc",
|
||||
"Locking rb",
|
||||
"Failed to lock wc",
|
||||
"Locked rb",
|
||||
"Unlocking ra",
|
||||
"Unlocked ra",
|
||||
"Unlocking rb",
|
||||
"Unlocked rb",
|
||||
"Locking wd",
|
||||
"Locked wd",
|
||||
"Unlocking wd",
|
||||
"Unlocked wd"});
|
||||
}
|
||||
|
||||
|
||||
TEST(Common, RWLockWriteLockTimeoutDuringWriteWithWaitingRead)
|
||||
{
|
||||
static auto rw_lock = RWLockImpl::create();
|
||||
Events events;
|
||||
|
||||
std::thread wa_thread([&] ()
|
||||
{
|
||||
events.add("Locking wa");
|
||||
auto wa = rw_lock->getLock(RWLockImpl::Write, "wa");
|
||||
events.add(wa ? "Locked wa" : "Failed to lock wa");
|
||||
EXPECT_NE(wa, nullptr);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(500));
|
||||
|
||||
events.add("Unlocking wa");
|
||||
wa.reset();
|
||||
events.add("Unlocked wa");
|
||||
});
|
||||
|
||||
std::thread wb_thread([&] ()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(100));
|
||||
events.add("Locking wb");
|
||||
auto wc = rw_lock->getLock(RWLockImpl::Write, "wc", std::chrono::milliseconds(200));
|
||||
events.add(wc ? "Locked wb" : "Failed to lock wb");
|
||||
EXPECT_EQ(wc, nullptr);
|
||||
});
|
||||
|
||||
std::thread rc_thread([&] ()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(200));
|
||||
events.add("Locking rc");
|
||||
auto rc = rw_lock->getLock(RWLockImpl::Read, "rc", std::chrono::milliseconds(200));
|
||||
events.add(rc ? "Locked rc" : "Failed to lock rc");
|
||||
EXPECT_EQ(rc, nullptr);
|
||||
});
|
||||
|
||||
wa_thread.join();
|
||||
wb_thread.join();
|
||||
rc_thread.join();
|
||||
|
||||
{
|
||||
events.add("Locking wd");
|
||||
auto wd = rw_lock->getLock(RWLockImpl::Write, "wd", std::chrono::milliseconds(1000));
|
||||
events.add(wd ? "Locked wd" : "Failed to lock wd");
|
||||
EXPECT_NE(wd, nullptr);
|
||||
events.add("Unlocking wd");
|
||||
wd.reset();
|
||||
events.add("Unlocked wd");
|
||||
}
|
||||
|
||||
events.check(
|
||||
{"Locking wa",
|
||||
"Locked wa",
|
||||
"Locking wb",
|
||||
"Locking rc",
|
||||
"Failed to lock wb",
|
||||
"Failed to lock rc",
|
||||
"Unlocking wa",
|
||||
"Unlocked wa",
|
||||
"Locking wd",
|
||||
"Locked wd",
|
||||
"Unlocking wd",
|
||||
"Unlocked wd"});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user