Fix Jenkins hang.

Summary:
Jenkins would hang at a random time while running all the tests.
The reason for that is a bug in skiplist implementation.

Skiplist method find_or_larger was never ending and would continuously stay in the while loop because the next node (with the queried value) onto which it would try to jump would be marked as deleted and that would stop it from jumping on it, or ending on that node.

Reviewers: buda, teon.banek, mislav.bradac

Reviewed By: buda

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D334
This commit is contained in:
Dominik Gleich 2017-05-03 10:54:40 +02:00
parent 0a33a555a6
commit b6c26a1a86
2 changed files with 42 additions and 2 deletions

View File

@ -794,8 +794,11 @@ class SkipList : private Lockable<lock_t> {
int h = static_cast<int>(pred->height) - 1;
while (true) {
// try to descend down first the next key on this layer overshoots
for (; h >= 0 && less(item, node = pred->forward(h)); --h) {
// try to descend down first while the next key on this layer overshoots
// or the next key is marked for deletion
for (; h >= 0 && (less(item, node = pred->forward(h)) ||
(node && node->flags.is_marked()));
--h) {
}
// if we overshoot at every layer, item doesn't exist

View File

@ -0,0 +1,37 @@
#include "gtest/gtest.h"
#include <thread>
#include <vector>
#include "data_structures/concurrent/skiplist.hpp"
// Try to provoke find_or_larger to hang. This happened before and caused
// Jenkins to stop responding. It is hard to recreate deterministically and this
// is the best we can do without doing friend_tests or refactoring skiplist.
TEST(SkipList, HangDuringFindOrLarger) {
std::vector<std::thread> threads;
SkipList<int> skiplist;
const int num_of_threads = 8;
const int iter = 100000;
for (int i = 0; i < num_of_threads; ++i) {
threads.emplace_back([&iter, &skiplist]() {
auto accessor = skiplist.access();
for (int i = 0; i < iter; ++i) accessor.insert(rand() % 3);
});
threads.emplace_back([&iter, &skiplist]() {
auto accessor = skiplist.access();
for (int i = 0; i < iter; ++i) accessor.remove(rand() % 3);
});
threads.emplace_back([&iter, &skiplist]() {
auto accessor = skiplist.access();
for (int i = 0; i < iter; ++i)
accessor.find_or_larger<SkipList<int>::ConstIterator>(rand() % 3);
});
}
for (auto &thread : threads) thread.join();
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}