afbec0a26e
Summary: Tests the skiplist GC. Reviewers: florijan, mferencevic, buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D145
106 lines
2.8 KiB
C++
106 lines
2.8 KiB
C++
#include "gtest/gtest.h"
|
|
|
|
#include <chrono>
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
#include "data_structures/concurrent/skiplist.hpp"
|
|
#include "logging/streams/stderr.hpp"
|
|
|
|
/**
|
|
* FakeItem class which increments a variable in the destructor.
|
|
* Used to keep track of the number of destroyed elements in GC.
|
|
*/
|
|
class FakeItem {
|
|
public:
|
|
FakeItem(std::atomic<int> &count, int value) : count(count), value(value) {}
|
|
~FakeItem() { count.fetch_add(1); }
|
|
|
|
bool operator<(const FakeItem &item) const {
|
|
return this->value < item.value;
|
|
}
|
|
bool operator>(const FakeItem &item) const {
|
|
return this->value > item.value;
|
|
}
|
|
|
|
private:
|
|
std::atomic<int> &count;
|
|
int value;
|
|
};
|
|
|
|
TEST(SkipListGC, TripleScopeGC) {
|
|
SkipList<FakeItem> skiplist;
|
|
std::atomic<int> count{0};
|
|
auto item = FakeItem(count, 1);
|
|
{
|
|
auto access_1 = skiplist.access();
|
|
{
|
|
auto access_2 = skiplist.access();
|
|
{
|
|
auto access_3 = skiplist.access();
|
|
access_1.insert(item); // add with 1
|
|
access_2.remove(item); // remove with 2
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
EXPECT_EQ(count, 0);
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
EXPECT_EQ(count, 0);
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
EXPECT_EQ(count, 0);
|
|
} // scope end - GC called
|
|
for (int i = 0; i < 10; ++i) {
|
|
if (count != 0) break;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
EXPECT_EQ(count, 1);
|
|
}
|
|
|
|
TEST(SkipListGC, BlockedGCNoGC) {
|
|
SkipList<FakeItem> skiplist;
|
|
std::atomic<int> count{0};
|
|
auto item = FakeItem(count, 1);
|
|
auto blocking_access = skiplist.access();
|
|
{
|
|
auto access = skiplist.access();
|
|
access.insert(item);
|
|
access.remove(item);
|
|
} // scope end - GC still isn't called because of blocking_access
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
EXPECT_EQ(count, 0);
|
|
}
|
|
|
|
TEST(SkipListGC, NotInScopeGC) {
|
|
SkipList<FakeItem> skiplist;
|
|
std::atomic<int> count{0};
|
|
auto item = FakeItem(count, 1);
|
|
{
|
|
auto access = skiplist.access();
|
|
access.insert(item);
|
|
access.remove(item);
|
|
} // scope end - GC called
|
|
for (int i = 0; i < 10; ++i) {
|
|
if (count != 0) break;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
EXPECT_EQ(count, 1);
|
|
}
|
|
|
|
TEST(SkipListGC, StillInScopeNoGC) {
|
|
SkipList<FakeItem> skiplist;
|
|
std::atomic<int> count{0};
|
|
auto item = FakeItem(count, 1);
|
|
auto access = skiplist.access();
|
|
access.insert(item);
|
|
access.remove(item);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
EXPECT_EQ(count, 0);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
logging::init_sync();
|
|
logging::log->pipe(std::make_unique<Stderr>());
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|