Implemented mvcc tests as discused with flor(two different transactions operations)

Reviewers: florijan, buda, dgleich

Reviewed By: florijan, buda

Subscribers: dtomicevic, teon.banek, buda, pullbot

Differential Revision: https://phabricator.memgraph.io/D359
This commit is contained in:
matej.gradicek 2017-05-16 10:22:28 +00:00
parent 15d7226515
commit f74ba586b2
4 changed files with 470 additions and 50 deletions

View File

@ -12,7 +12,7 @@
namespace mvcc {
class SerializationError : public utils::BasicException {
static constexpr const char* default_message =
static constexpr const char *default_message =
"Can't serialize due to\
concurrent operation(s)";
@ -194,20 +194,20 @@ class VersionList {
auto record = find(t);
// check if we found any visible records
if (!record) return nullptr;
permanent_assert(record != nullptr, "Updating nullptr record");
return update(record, t);
}
bool remove(tx::Transaction &t) {
void remove(tx::Transaction &t) {
debug_assert(head != nullptr, "Head is nullptr on removal.");
auto record = find(t);
if (!record) return false;
permanent_assert(record != nullptr, "Removing nullptr record");
// TODO: Is this lock and validate necessary
lock_and_validate(record, t);
return remove(record, t), true;
remove(record, t);
}
// TODO(flor): This should also be private but can't be right now because of

View File

@ -15,10 +15,22 @@ bool operator==(const Id &left, const int right) {
}
class TestClass : public mvcc::Record<TestClass> {
public:
// constructs first version, size should be 0
TestClass(int &version_list_size) : version_list_size_(version_list_size) {
++version_list_size_;
}
// version constructed in version list update
TestClass(TestClass &other) : version_list_size_(other.version_list_size_) {
version_list_size_++;
}
friend std::ostream &operator<<(std::ostream &stream, TestClass &test_class) {
stream << test_class.tx.cre() << " " << test_class.tx.exp();
return stream;
}
// reference to variable version_list_size in test SetUp, increases when new
// TestClass is created
int &version_list_size_;
};
/**
@ -41,17 +53,22 @@ class TestClass : public mvcc::Record<TestClass> {
class Mvcc : public ::testing::Test {
protected:
virtual void SetUp() {
id0 = Id{0};
t1 = &engine.advance(t1->id);
id1 = t1->id;
v1 = version_list.find(*t1);
t1->commit();
t2 = engine.begin();
id2 = t2->id;
}
// variable where number of versions is stored
int version_list_size = 0;
tx::Engine engine;
tx::Transaction *t1 = engine.begin();
mvcc::VersionList<TestClass> version_list{*t1};
mvcc::VersionList<TestClass> version_list{*t1, version_list_size};
TestClass *v1 = nullptr;
tx::Transaction *t2 = nullptr;
int id0, id1, id2;
};
// helper macros. important:
@ -65,11 +82,13 @@ class Mvcc : public ::testing::Test {
#define T3_COMMIT t3->commit();
#define T2_ABORT t2->abort();
#define T3_ABORT t3->abort();
#define T3_BEGIN auto t3 = engine.begin();
#define T3_BEGIN auto t3 = engine.begin(); __attribute__((unused)) int id3 = t3->id
#define T2_REMOVE version_list.remove(*t2)
#define T3_REMOVE version_list.remove(*t3)
#define EXPECT_CRE(record, expected) EXPECT_EQ(record->tx.cre(), expected)
#define EXPECT_EXP(record, expected) EXPECT_EQ(record->tx.exp(), expected)
#define EXPECT_CRE(record, expected) EXPECT_EQ(record->tx.cre(), id##expected)
#define EXPECT_EXP(record, expected) EXPECT_EQ(record->tx.exp(), id##expected)
#define EXPECT_NXT(v1, v2) EXPECT_EQ(v1->next(), v2)
#define EXPECT_SIZE(n) EXPECT_EQ(version_list_size, n)
// test the fixture
TEST_F(Mvcc, Fixture) {

View File

@ -91,7 +91,7 @@ TEST(GarbageCollector, GcClean) {
t1->commit();
auto t2 = engine.begin();
EXPECT_EQ(vl->remove(*t2), true);
vl->remove(*t2);
t2->commit();
gc.Run(Id(3), engine);

View File

@ -1,88 +1,489 @@
#include "mvcc_find_update_common.hpp"
// TODO Gradicek: rename all existing cases
// TODO Gradicek: check validity of all existing cases
// TODO Gradicek: add all other cases (48 in total, discuss with Flor)
// TODO Gradicek: what about command advance testing,
// as opposed to transaction commit/abort?
TEST_F(Mvcc, Case1_InsertWithUpdates) {
// ****************************************************************
// * CASE 1: T3 starts after T2 ends.
// *
// * T2: START---OP---END
// *
// * T3: START---OP---END
// *
// ****************************************************************
TEST_F(Mvcc, UpdCmtUpdCmt1) {
T2_UPDATE;
T2_COMMIT;
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v2);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdCmtRemCmt1) {
T2_UPDATE;
T2_COMMIT;
T3_BEGIN;
T3_REMOVE;
T3_COMMIT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 3);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemoveUpdatedRecord) {
TEST_F(Mvcc, RemCmtUpdCmt1) {
T2_REMOVE;
T2_COMMIT;
T3_BEGIN;
EXPECT_DEATH(T3_UPDATE, ".*nullptr.*");
}
TEST_F(Mvcc, RemCmtRemCmt1) {
T2_REMOVE;
T2_COMMIT;
T3_BEGIN;
EXPECT_DEATH(T3_REMOVE, ".*nullptr.*");
}
TEST_F(Mvcc, UpdCmtUpdAbt1) {
T2_UPDATE;
T2_COMMIT;
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v2, v1);
EXPECT_NXT(v3, v2);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdCmtRemAbt1) {
T2_UPDATE;
T2_COMMIT;
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 3);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemCmtUpdAbt1) {
T2_REMOVE;
T2_COMMIT;
T3_BEGIN;
EXPECT_DEATH(T3_UPDATE, ".*nullptr.*");
}
TEST_F(Mvcc, RemCmtRemAbt1) {
T2_REMOVE;
T2_COMMIT;
T3_BEGIN;
EXPECT_DEATH(T3_REMOVE, ".*nullptr.*");
}
TEST_F(Mvcc, UpdAbtUpdCmt1) {
T2_UPDATE;
T2_ABORT;
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v2);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdAbtRemCmt1) {
T2_UPDATE;
T2_ABORT;
T3_BEGIN;
T3_REMOVE;
T3_COMMIT;
EXPECT_NXT(v2, v1);
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtUpdCmt1) {
T2_REMOVE;
T2_ABORT;
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtRemCmt1) {
T2_REMOVE;
T2_ABORT;
T3_BEGIN;
T3_REMOVE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_SIZE(1);
}
TEST_F(Mvcc, UpdAbtUpdAbt1) {
T2_UPDATE;
T2_ABORT;
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v2, v1);
EXPECT_NXT(v3, v2);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdAbtRemAbt1) {
T2_UPDATE;
T2_ABORT;
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
EXPECT_NXT(v2, v1);
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtUpdAbt1) {
T2_REMOVE;
T2_ABORT;
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtRemAbt1) {
T2_REMOVE;
T2_ABORT;
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_SIZE(1);
}
// ****************************************************************
// * CASE 2: T3 starts before T2 ends.
// *
// * T2: START---OP---END
// *
// * T3: START---------OP---END
// *
// ****************************************************************
// ****************************
// COVERS 8 cases!
TEST_F(Mvcc, UpdCmtUpd2) {
T2_UPDATE;
T3_BEGIN;
T2_COMMIT;
EXPECT_THROW(T3_UPDATE, mvcc::SerializationError);
}
TEST_F(Mvcc, UpdCmtRem2) {
T2_UPDATE;
T3_BEGIN;
T2_COMMIT;
EXPECT_THROW(T3_REMOVE, mvcc::SerializationError);
}
TEST_F(Mvcc, RemCmtUpd2) {
T2_REMOVE;
T3_BEGIN;
T2_COMMIT;
EXPECT_THROW(T3_UPDATE, mvcc::SerializationError);
}
TEST_F(Mvcc, RemCmtRem2) {
T2_REMOVE;
T3_BEGIN;
T2_COMMIT;
EXPECT_THROW(T3_REMOVE, mvcc::SerializationError);
}
// **************************
TEST_F(Mvcc, UpdAbtUpdCmt2) {
T2_UPDATE;
T3_BEGIN;
T2_ABORT;
T3_UPDATE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v2);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdAbtRemCmt2) {
T2_UPDATE;
T3_BEGIN;
T2_ABORT;
T3_REMOVE;
T3_COMMIT;
EXPECT_NXT(v2, v1);
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtUpdCmt2) {
T2_REMOVE;
T3_BEGIN;
T2_ABORT;
T3_UPDATE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtRemCmt2) {
T2_REMOVE;
T3_BEGIN;
T2_ABORT;
T3_REMOVE;
T3_COMMIT;
EXPECT_EXP(v1, 3);
EXPECT_SIZE(1);
}
TEST_F(Mvcc, UpdAbtUpdAbt2) {
T2_UPDATE;
T3_BEGIN;
T2_ABORT;
T3_UPDATE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v2, 0);
EXPECT_NXT(v2, v1);
EXPECT_NXT(v3, v2);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdAbtRemAbt2) {
T2_UPDATE;
T3_BEGIN;
T2_ABORT;
T3_REMOVE;
T3_ABORT;
EXPECT_NXT(v2, v1);
EXPECT_EXP(v1, 3);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtUpdAbt2) {
T2_REMOVE;
T3_BEGIN;
T2_ABORT;
T3_UPDATE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtRemAbt2) {
T2_REMOVE;
T3_BEGIN;
T2_ABORT;
T3_REMOVE;
T3_ABORT;
EXPECT_EXP(v1, 3);
EXPECT_SIZE(1);
}
// ****************************************************************
// * CASE 3: T3 ends before T2 starts executing operations.
// *
// * T2: START--------------------OP---END
// *
// * T3: START---OP---END
// *
// ****************************************************************
// ****************************
// COVERS 8 cases!
TEST_F(Mvcc, UpdUpdCmt3) {
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_THROW(T2_UPDATE, mvcc::SerializationError);
}
TEST_F(Mvcc, UpdRemCmt3) {
T3_BEGIN;
T3_REMOVE;
T3_COMMIT;
EXPECT_THROW(T2_UPDATE, mvcc::SerializationError);
}
TEST_F(Mvcc, RemUpdCmt3) {
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_THROW(T2_REMOVE, mvcc::SerializationError);
}
TEST_F(Mvcc, UpdateUpdatedRecord) {
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_THROW(version_list.update(*t2), mvcc::SerializationError);
}
TEST_F(Mvcc, Case2_AbortUpdate_Remove_T10) {
T2_UPDATE;
T2_ABORT;
TEST_F(Mvcc, RemRemCmt3) {
T3_BEGIN;
T3_REMOVE;
T3_COMMIT;
EXPECT_THROW(T2_REMOVE, mvcc::SerializationError);
}
// **************************
EXPECT_CRE(v1, 1);
EXPECT_EXP(v1, 3);
TEST_F(Mvcc, UpdCmtUpdAbt3) {
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
T2_UPDATE;
T2_COMMIT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_NXT(v2, v3);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, Case2_AbortUpdate_Remove_T7) {
TEST_F(Mvcc, UpdCmtRemAbt3) {
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
T2_UPDATE;
T2_COMMIT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_NXT(v2, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemCmtUpdAbt3) {
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
T2_REMOVE;
T2_COMMIT;
EXPECT_CRE(v1, 1);
EXPECT_EXP(v1, 2);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, Case2_AbortUpdate_Update_T10) {
T2_UPDATE;
T2_ABORT;
TEST_F(Mvcc, RemCmtRemAbt3) {
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_CRE(v1, 1);
EXPECT_EXP(v1, 3);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
T3_REMOVE;
T3_ABORT;
T2_REMOVE;
T2_COMMIT;
EXPECT_EXP(v1, 2);
EXPECT_SIZE(1);
}
TEST_F(Mvcc, Case2_AbortUpdate_Update_T7) {
TEST_F(Mvcc, UpdAbtUpdAbt3) {
T3_BEGIN;
T3_UPDATE;
T3_ABORT;
T2_UPDATE;
T2_COMMIT;
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
T2_ABORT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_NXT(v2, v3);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, Case1Test3) {
TEST_F(Mvcc, UpdAbtRemAbt3) {
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
T2_UPDATE;
T2_ABORT;
EXPECT_NXT(v2, v1);
EXPECT_EXP(v1, 2);
EXPECT_CRE(v2, 2);
EXPECT_EXP(v2, 0);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtUpdAbt3) {
T3_BEGIN;
T3_UPDATE;
T3_COMMIT;
EXPECT_THROW(T2_REMOVE, mvcc::SerializationError);
T3_ABORT;
T2_REMOVE;
T2_ABORT;
EXPECT_EXP(v1, 2);
EXPECT_CRE(v3, 3);
EXPECT_EXP(v3, 0);
EXPECT_NXT(v3, v1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemAbtRemAbt3) {
T3_BEGIN;
T3_REMOVE;
T3_ABORT;
T2_REMOVE;
T2_ABORT;
EXPECT_EXP(v1, 2);
EXPECT_SIZE(1);
}