Added mvcc tests with one transaction and modified version list update function

Summary: Modified version list update, added mvcc tests for one transaction

Reviewers: dgleich, florijan

Reviewed By: dgleich, florijan

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D360
This commit is contained in:
matej.gradicek 2017-06-02 07:19:23 +00:00
parent 4d63f8b44e
commit 29041eb4d1
4 changed files with 141 additions and 9 deletions

View File

@ -85,7 +85,6 @@ class VersionList {
* visible anymore. If none exists to_delete will point to nullptr.
*/
std::pair<bool, T *> GcDeleted(const Id &id, tx::Engine &engine) {
// nullptr
// |
// [v1] ... all of this gets deleted!
@ -102,8 +101,8 @@ class VersionList {
T *oldest_visible_record = nullptr;
while (current) {
if (!current->is_not_visible_from(id, engine))
oldest_visible_record = current;
current = current->next();
oldest_visible_record = current;
current = current->next();
}
if (oldest_visible_record)
head_of_deletable_records = oldest_visible_record->next();
@ -131,7 +130,8 @@ class VersionList {
// further than this record and
// that's why it's safe to set
// next to nullptr.
// Calling destructor of head_of_deletable_records will clean everything older
// Calling destructor of head_of_deletable_records will clean everything
// older
// than this record since they are called recursively.
return std::make_pair(false, head_of_deletable_records);
}
@ -192,14 +192,29 @@ class VersionList {
}
}
/**
* Looks for the first visible record seen by this transaction. If the current
* transaction has already created new record in the current command then that
* record is returned, else first older visible record is updated. New record
* becomes head of the version list and it is returned. There should always be
* older visible record when this update is called.
*
* @param t The transaction
*/
T *update(tx::Transaction &t) {
debug_assert(head != nullptr, "Head is nullptr on update.");
auto record = find(t);
T *old_record = nullptr;
T *new_record = nullptr;
find_set_old_new(t, old_record, new_record);
// check if current transaction in current cmd has
// already updated version list
if (new_record) return new_record;
// check if we found any visible records
permanent_assert(record != nullptr, "Updating nullptr record");
permanent_assert(old_record != nullptr, "Updating nullptr record");
return update(record, t);
return update(old_record, t);
}
void remove(tx::Transaction &t) {

View File

@ -76,7 +76,7 @@ class Mvcc : public ::testing::Test {
// - TX_BEGIN sets the transaction variable tX
#define T2_FIND __attribute__((unused)) auto v2 = version_list.find(*t2)
#define T3_FIND __attribute__((unused)) auto v3 = version_list.find(*t3)
#define T4_FIND version_list.find(*t4)
#define T4_FIND __attribute__((unused)) auto v4 = version_list.find(*t4)
#define T2_UPDATE __attribute__((unused)) auto v2 = version_list.update(*t2)
#define T3_UPDATE __attribute__((unused)) auto v3 = version_list.update(*t3)
#define T2_COMMIT t2->commit();

View File

@ -0,0 +1,110 @@
#include "mvcc_find_update_common.hpp"
#undef T2_FIND
#define T2_FIND version_list.find(*t2)
#undef EXPECT_CRE
#undef EXPECT_EXP
#define EXPECT_CRE(record, transaction, command) \
EXPECT_EQ(record->tx.cre(), id##transaction); \
EXPECT_EQ(record->cmd.cre(), command)
#define EXPECT_EXP(record, transaction, command) \
EXPECT_EQ(record->tx.exp(), id##transaction); \
EXPECT_EQ(record->cmd.exp(), command)
// IMPORTANT: look definiton of EXPECT_CRE and EXPECT_EXP macros in
// tests/mvcc_find_update_common.hpp. Numbers in those macros represent
// transaction ids when transactions where created.
TEST_F(Mvcc, UpdateNotAdvanceUpdate) {
T2_UPDATE;
EXPECT_EQ(T2_FIND, v1);
auto v2_2 = version_list.update(*t2);
EXPECT_NXT(v2, v1);
EXPECT_EQ(v2, v2_2);
EXPECT_CRE(v2, 2, 1);
EXPECT_EXP(v2, 0, 0);
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, UpdateNotAdvanceRemove) {
T2_UPDATE;
EXPECT_EQ(T2_FIND, v1);
T2_REMOVE;
EXPECT_NXT(v2, v1);
EXPECT_CRE(v2, 2, 1);
EXPECT_EXP(v2, 0, 0);
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemoveNotAdvanceUpdate) {
T2_REMOVE;
EXPECT_EQ(T2_FIND, v1);
T2_UPDATE;
EXPECT_NXT(v2, v1);
EXPECT_CRE(v2, 2, 1);
EXPECT_EXP(v2, 0, 0);
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemoveNotAdvanceRemove) {
T2_REMOVE;
EXPECT_EQ(T2_FIND, v1);
T2_REMOVE;
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(1);
}
TEST_F(Mvcc, UpdateAdvanceUpdate) {
T2_UPDATE;
EXPECT_EQ(T2_FIND, v1);
engine.advance(t2->id);
EXPECT_EQ(T2_FIND, v2);
auto v2_2 = version_list.update(*t2);
EXPECT_NXT(v2, v1);
EXPECT_NXT(v2_2, v2);
EXPECT_CRE(v2, 2, 1);
EXPECT_EXP(v2, 2, 2);
EXPECT_CRE(v2_2, 2, 2);
EXPECT_EXP(v2_2, 0, 0);
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(3);
}
TEST_F(Mvcc, UpdateAdvanceRemove) {
T2_UPDATE;
EXPECT_EQ(T2_FIND, v1);
engine.advance(t2->id);
EXPECT_EQ(T2_FIND, v2);
T2_REMOVE;
EXPECT_NXT(v2, v1);
EXPECT_CRE(v2, 2, 1);
EXPECT_EXP(v2, 2, 2);
EXPECT_CRE(v1, 1, 1);
EXPECT_EXP(v1, 2, 1);
EXPECT_SIZE(2);
}
TEST_F(Mvcc, RemoveAdvanceUpdate) {
T2_REMOVE;
EXPECT_EQ(T2_FIND, v1);
engine.advance(t2->id);
EXPECT_EQ(T2_FIND, nullptr);
EXPECT_DEATH(T2_UPDATE, ".*nullptr.*");
}
TEST_F(Mvcc, RemoveAdvanceRemove) {
T2_REMOVE;
EXPECT_EQ(T2_FIND, v1);
engine.advance(t2->id);
EXPECT_EQ(T2_FIND, nullptr);
EXPECT_DEATH(T2_REMOVE, ".*nullptr.*");
}

View File

@ -1,5 +1,12 @@
#include "mvcc_find_update_common.hpp"
#undef T4_FIND
#define T4_FIND version_list.find(*t4)
// IMPORTANT: look definiton of EXPECT_CRE and EXPECT_EXP macros in
// tests/mvcc_find_update_common.hpp. Numbers in those macros represent
// transaction ids when transactions where created.
// ****************************************************************
// * CASE 1: T3 starts after T2 ends.