9f460914ed
Summary: GraphDbAccessor is now constructed only through GraphDb. This allows the concrete GraphDb to instantiate a concrete GraphDbAccessor. This allows us to use virtual calls, so that the implementation may be kept separate. The major downside of doing things this way is heap allocation of GraphDbAccessor. In case it turns out to be a real performance issues, another solution with pointer to static implementation may be used. InsertVertexIntoRemote is now a non-member function, which reduces coupling. It made no sense for it to be member function because it used only the public parts of GraphDbAccessor. Reviewers: msantl, mtomic, mferencevic Reviewed By: msantl Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1504
211 lines
6.5 KiB
C++
211 lines
6.5 KiB
C++
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "database/graph_db.hpp"
|
|
#include "database/graph_db_accessor.hpp"
|
|
#include "storage/types.hpp"
|
|
#include "storage/vertex.hpp"
|
|
#include "transactions/engine_single_node.hpp"
|
|
|
|
#include "mvcc_gc_common.hpp"
|
|
|
|
using testing::UnorderedElementsAreArray;
|
|
|
|
// Test index does it insert everything uniquely
|
|
TEST(LabelsIndex, UniqueInsert) {
|
|
database::KeyIndex<storage::Label, Vertex> index;
|
|
database::SingleNode db;
|
|
auto dba = db.Access();
|
|
tx::SingleNodeEngine engine;
|
|
|
|
auto t1 = engine.Begin();
|
|
mvcc::VersionList<Vertex> vlist(*t1, 0, 0);
|
|
engine.Commit(*t1);
|
|
auto t2 = engine.Begin();
|
|
|
|
vlist.find(*t2)->labels_.push_back(dba->Label("1"));
|
|
index.Update(dba->Label("1"), &vlist, vlist.find(*t2));
|
|
// Try multiple inserts
|
|
index.Update(dba->Label("1"), &vlist, vlist.find(*t2));
|
|
|
|
vlist.find(*t2)->labels_.push_back(dba->Label("2"));
|
|
index.Update(dba->Label("2"), &vlist, vlist.find(*t2));
|
|
|
|
vlist.find(*t2)->labels_.push_back(dba->Label("3"));
|
|
index.Update(dba->Label("3"), &vlist, vlist.find(*t2));
|
|
engine.Commit(*t2);
|
|
|
|
EXPECT_EQ(index.Count(dba->Label("1")), 1);
|
|
EXPECT_EQ(index.Count(dba->Label("2")), 1);
|
|
EXPECT_EQ(index.Count(dba->Label("3")), 1);
|
|
}
|
|
|
|
// Check if index filters duplicates.
|
|
TEST(LabelsIndex, UniqueFilter) {
|
|
database::SingleNode db;
|
|
database::KeyIndex<storage::Label, Vertex> index;
|
|
auto dba = db.Access();
|
|
tx::SingleNodeEngine engine;
|
|
|
|
auto t1 = engine.Begin();
|
|
mvcc::VersionList<Vertex> vlist1(*t1, 0, 0);
|
|
mvcc::VersionList<Vertex> vlist2(*t1, 1, 1);
|
|
engine.Advance(t1->id_);
|
|
auto r1v1 = vlist1.find(*t1);
|
|
auto r1v2 = vlist2.find(*t1);
|
|
EXPECT_NE(vlist1.find(*t1), nullptr);
|
|
|
|
auto label1 = dba->Label("1");
|
|
vlist1.find(*t1)->labels_.push_back(label1);
|
|
vlist2.find(*t1)->labels_.push_back(label1);
|
|
index.Update(label1, &vlist1, r1v1);
|
|
index.Update(label1, &vlist2, r1v2);
|
|
engine.Commit(*t1);
|
|
|
|
auto t2 = engine.Begin();
|
|
auto r2v1 = vlist1.update(*t2);
|
|
auto r2v2 = vlist2.update(*t2);
|
|
index.Update(label1, &vlist1, r2v1);
|
|
index.Update(label1, &vlist2, r2v2);
|
|
engine.Commit(*t2);
|
|
|
|
auto t3 = engine.Begin();
|
|
std::vector<mvcc::VersionList<Vertex> *> expected = {&vlist1, &vlist2};
|
|
sort(expected.begin(),
|
|
expected.end()); // Entries will be sorted by vlist pointers.
|
|
int cnt = 0;
|
|
for (auto vlist : index.GetVlists(label1, *t3, false)) {
|
|
EXPECT_LT(cnt, expected.size());
|
|
EXPECT_EQ(vlist, expected[cnt++]);
|
|
}
|
|
}
|
|
|
|
// Delete not anymore relevant recods from index.
|
|
TEST(LabelsIndex, Refresh) {
|
|
database::KeyIndex<storage::Label, Vertex> index;
|
|
database::SingleNode db;
|
|
auto access = db.Access();
|
|
tx::SingleNodeEngine engine;
|
|
|
|
// add two vertices to database
|
|
auto t1 = engine.Begin();
|
|
mvcc::VersionList<Vertex> vlist1(*t1, 0, 0);
|
|
mvcc::VersionList<Vertex> vlist2(*t1, 1, 1);
|
|
engine.Advance(t1->id_);
|
|
|
|
auto v1r1 = vlist1.find(*t1);
|
|
auto v2r1 = vlist2.find(*t1);
|
|
EXPECT_NE(v1r1, nullptr);
|
|
EXPECT_NE(v2r1, nullptr);
|
|
|
|
auto label = access->Label("label");
|
|
v1r1->labels_.push_back(label);
|
|
v2r1->labels_.push_back(label);
|
|
index.Update(label, &vlist1, v1r1);
|
|
index.Update(label, &vlist2, v2r1);
|
|
engine.Commit(*t1);
|
|
|
|
auto t2 = engine.Begin();
|
|
auto v1r2 = vlist1.update(*t2);
|
|
auto v2r2 = vlist2.update(*t2);
|
|
index.Update(label, &vlist1, v1r2);
|
|
index.Update(label, &vlist2, v2r2);
|
|
|
|
index.Refresh(GcSnapshot(engine, t2), engine);
|
|
EXPECT_EQ(index.Count(label), 4);
|
|
|
|
engine.Commit(*t2);
|
|
EXPECT_EQ(index.Count(label), 4);
|
|
index.Refresh(GcSnapshot(engine, nullptr), engine);
|
|
EXPECT_EQ(index.Count(label), 2);
|
|
}
|
|
|
|
// Transaction hasn't ended and so the vertex is not visible.
|
|
TEST(LabelsIndexDb, AddGetZeroLabels) {
|
|
database::SingleNode db;
|
|
auto dba = db.Access();
|
|
auto vertex = dba->InsertVertex();
|
|
vertex.add_label(dba->Label("test"));
|
|
auto collection = dba->Vertices(dba->Label("test"), false);
|
|
std::vector<VertexAccessor> collection_vector(collection.begin(),
|
|
collection.end());
|
|
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
|
}
|
|
|
|
// Test label index by adding and removing one vertex, and removing label from
|
|
// another, while the third one with an irrelevant label exists.
|
|
TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
|
database::SingleNode db;
|
|
{
|
|
auto dba = db.Access();
|
|
|
|
auto vertex1 = dba->InsertVertex();
|
|
vertex1.add_label(dba->Label("test"));
|
|
|
|
auto vertex2 = dba->InsertVertex();
|
|
vertex2.add_label(dba->Label("test2"));
|
|
|
|
auto vertex3 = dba->InsertVertex();
|
|
vertex3.add_label(dba->Label("test"));
|
|
|
|
dba->Commit();
|
|
} // Finish transaction.
|
|
{
|
|
auto dba = db.Access();
|
|
|
|
auto filtered = dba->Vertices(dba->Label("test"), false);
|
|
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
|
auto vertices = dba->Vertices(false);
|
|
|
|
std::vector<VertexAccessor> expected_collection;
|
|
for (auto vertex : vertices) {
|
|
if (vertex.has_label(dba->Label("test"))) {
|
|
expected_collection.push_back(vertex);
|
|
} else {
|
|
EXPECT_TRUE(vertex.has_label(dba->Label("test2")));
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(expected_collection.size(), collection.size());
|
|
EXPECT_TRUE(collection[0].has_label(dba->Label("test")));
|
|
EXPECT_TRUE(collection[1].has_label(dba->Label("test")));
|
|
EXPECT_FALSE(collection[0].has_label(dba->Label("test2")));
|
|
EXPECT_FALSE(collection[1].has_label(dba->Label("test2")));
|
|
dba->RemoveVertex(collection[0]); // Remove from database and test if
|
|
// index won't return it.
|
|
|
|
// Remove label from the vertex and add new label.
|
|
collection[1].remove_label(dba->Label("test"));
|
|
collection[1].add_label(dba->Label("test2"));
|
|
dba->Commit();
|
|
}
|
|
{
|
|
auto dba = db.Access();
|
|
|
|
auto filtered = dba->Vertices(dba->Label("test"), false);
|
|
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
|
auto vertices = dba->Vertices(false);
|
|
|
|
std::vector<VertexAccessor> expected_collection;
|
|
for (auto vertex : vertices) {
|
|
if (vertex.has_label(dba->Label("test"))) {
|
|
expected_collection.push_back(vertex);
|
|
} else {
|
|
EXPECT_TRUE(vertex.has_label(dba->Label("test2")));
|
|
}
|
|
}
|
|
|
|
// It should be empty since everything with an old label is either deleted
|
|
// or doesn't have that label anymore.
|
|
EXPECT_EQ(expected_collection.size(), 0);
|
|
EXPECT_EQ(collection.size(), 0);
|
|
}
|
|
}
|
|
|
|
// TODO gleich - discuss with Flor the API changes and the tests
|
|
|
|
int main(int argc, char **argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|