memgraph/tests/unit/graph_db_accessor.cpp
Matej Ferencevic 6525451489 Remove distributed logic from single node
Summary:
Start removing `is_remote` from `Address`
Remove `GlobalAddress`
Remove `GlobalizedAddress`
Remove bitmasks from `Address`
Remove `is_local` from `Address`
Remove `is_local` from `RecordAccessor`
Remove `worker_id` from `Address`
Remove `worker_id` from `GidGenerator`
Unfriend `IndexRpcServer` from `Storage`
Remove `LocalizedAddressIfPossible`
Make member private
Remove `worker_id` from `Storage`
Copy function to ease removal of distributed logic
Remove `worker_id` from `WriteAheadLog`
Remove `worker_id` from `GraphDb`
Remove `worker_id` from durability
Remove nonexistant function
Remove `gid` from `Address`
Remove usage of `Address`
Remove `Address`
Remove `VertexAddress` and `EdgeAddress`
Fix Id test
Remove `cypher_id` from `VersionList`
Remove `cypher_id` from durability
Remove `cypher_id` member from `VersionList`
Remove `cypher_id` from database
Fix recovery (revert D1142)
Remove unnecessary functions from `GraphDbAccessor`
Revert `InsertEdge` implementation to the way it was in/before D1142
Remove leftover `VertexAddress` from `Edge`
Remove `PostCreateIndex` and `PopulateIndexFromBuildIndex`
Split durability paths into single node and distributed
Fix `TransactionIdFromWalFilename` implementation
Fix tests
Remove `cypher_id` from `snapshooter` and `durability` test

Reviewers: msantl, teon.banek

Reviewed By: msantl

Subscribers: msantl, pullbot

Differential Revision: https://phabricator.memgraph.io/D1647
2018-10-11 13:08:22 +02:00

399 lines
12 KiB
C++

#include <experimental/optional>
#include <gtest/gtest.h>
#include "database/single_node/graph_db.hpp"
#include "database/single_node/graph_db_accessor.hpp"
#include "storage/common/types.hpp"
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
using namespace database;
using namespace storage;
template <typename TIterable>
auto Count(TIterable iterable) {
return std::distance(iterable.begin(), iterable.end());
}
TEST(GraphDbAccessorTest, InsertVertex) {
GraphDb db;
auto accessor = db.Access();
gid::Generator generator;
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
EXPECT_EQ(accessor->InsertVertex().gid(), generator.Next());
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
EXPECT_EQ(Count(accessor->Vertices(true)), 1);
accessor->AdvanceCommand();
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
EXPECT_EQ(accessor->InsertVertex().gid(), generator.Next());
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
EXPECT_EQ(Count(accessor->Vertices(true)), 2);
accessor->AdvanceCommand();
EXPECT_EQ(Count(accessor->Vertices(false)), 2);
}
TEST(GraphDbAccessorTest, UniqueVertexId) {
GraphDb db;
SkipList<int64_t> ids;
std::vector<std::thread> threads;
for (int i = 0; i < 50; i++) {
threads.emplace_back([&db, &ids]() {
auto dba = db.Access();
auto access = ids.access();
for (int i = 0; i < 200; i++) access.insert(dba->InsertVertex().gid());
});
}
for (auto &thread : threads) thread.join();
EXPECT_EQ(ids.access().size(), 50 * 200);
}
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
GraphDb db;
auto accessor = db.Access();
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
auto va1 = accessor->InsertVertex();
accessor->AdvanceCommand();
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
EXPECT_TRUE(accessor->RemoveVertex(va1));
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
EXPECT_EQ(Count(accessor->Vertices(true)), 0);
accessor->AdvanceCommand();
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
EXPECT_EQ(Count(accessor->Vertices(true)), 0);
}
TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
GraphDb db;
// first transaction creates a vertex
{
auto accessor = db.Access();
accessor->InsertVertex();
accessor->Commit();
}
// second transaction checks that it sees it, and deletes it
{
auto accessor = db.Access();
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
EXPECT_EQ(Count(accessor->Vertices(true)), 1);
for (auto vertex_accessor : accessor->Vertices(false))
accessor->RemoveVertex(vertex_accessor);
accessor->Commit();
}
// third transaction checks that it does not see the vertex
{
auto accessor = db.Access();
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
EXPECT_EQ(Count(accessor->Vertices(true)), 0);
}
}
TEST(GraphDbAccessorTest, InsertEdge) {
GraphDb db;
auto dba = db.Access();
auto va1 = dba->InsertVertex();
auto va2 = dba->InsertVertex();
dba->AdvanceCommand();
EXPECT_EQ(va1.in_degree(), 0);
EXPECT_EQ(va1.out_degree(), 0);
EXPECT_EQ(va2.in_degree(), 0);
EXPECT_EQ(va2.out_degree(), 0);
// setup (v1) - [:likes] -> (v2)
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
EXPECT_EQ(Count(dba->Edges(false)), 0);
EXPECT_EQ(Count(dba->Edges(true)), 1);
dba->AdvanceCommand();
EXPECT_EQ(Count(dba->Edges(false)), 1);
EXPECT_EQ(Count(dba->Edges(true)), 1);
EXPECT_EQ(va1.out().begin()->to(), va2);
EXPECT_EQ(va2.in().begin()->from(), va1);
EXPECT_EQ(va1.in_degree(), 0);
EXPECT_EQ(va1.out_degree(), 1);
EXPECT_EQ(va2.in_degree(), 1);
EXPECT_EQ(va2.out_degree(), 0);
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
auto va3 = dba->InsertVertex();
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
EXPECT_EQ(Count(dba->Edges(false)), 1);
EXPECT_EQ(Count(dba->Edges(true)), 2);
dba->AdvanceCommand();
EXPECT_EQ(Count(dba->Edges(false)), 2);
EXPECT_EQ(va3.out().begin()->to(), va2);
EXPECT_EQ(va1.in_degree(), 0);
EXPECT_EQ(va1.out_degree(), 1);
EXPECT_EQ(va2.in_degree(), 2);
EXPECT_EQ(va2.out_degree(), 0);
EXPECT_EQ(va3.in_degree(), 0);
EXPECT_EQ(va3.out_degree(), 1);
}
TEST(GraphDbAccessorTest, UniqueEdgeId) {
GraphDb db;
SkipList<int64_t> ids;
std::vector<std::thread> threads;
for (int i = 0; i < 50; i++) {
threads.emplace_back([&db, &ids]() {
auto dba = db.Access();
auto v1 = dba->InsertVertex();
auto v2 = dba->InsertVertex();
auto edge_type = dba->EdgeType("edge_type");
auto access = ids.access();
for (int i = 0; i < 200; i++)
access.insert(dba->InsertEdge(v1, v2, edge_type).gid());
});
}
for (auto &thread : threads) thread.join();
EXPECT_EQ(ids.access().size(), 50 * 200);
}
TEST(GraphDbAccessorTest, RemoveEdge) {
GraphDb db;
auto dba = db.Access();
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
auto va1 = dba->InsertVertex();
auto va2 = dba->InsertVertex();
auto va3 = dba->InsertVertex();
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
dba->AdvanceCommand();
EXPECT_EQ(Count(dba->Edges(false)), 2);
EXPECT_EQ(Count(dba->Edges(true)), 2);
// remove all [:hates] edges
for (auto edge : dba->Edges(false))
if (edge.EdgeType() == dba->EdgeType("hates")) dba->RemoveEdge(edge);
EXPECT_EQ(Count(dba->Edges(false)), 2);
EXPECT_EQ(Count(dba->Edges(true)), 1);
// current state: (v1) - [:likes] -> (v2), (v3)
dba->AdvanceCommand();
EXPECT_EQ(Count(dba->Edges(false)), 1);
EXPECT_EQ(Count(dba->Edges(true)), 1);
EXPECT_EQ(Count(dba->Vertices(false)), 3);
EXPECT_EQ(Count(dba->Vertices(true)), 3);
for (auto edge : dba->Edges(false)) {
EXPECT_EQ(edge.EdgeType(), dba->EdgeType("likes"));
auto v1 = edge.from();
auto v2 = edge.to();
// ensure correct connectivity for all the vertices
for (auto vertex : dba->Vertices(false)) {
if (vertex == v1) {
EXPECT_EQ(vertex.in_degree(), 0);
EXPECT_EQ(vertex.out_degree(), 1);
} else if (vertex == v2) {
EXPECT_EQ(vertex.in_degree(), 1);
EXPECT_EQ(vertex.out_degree(), 0);
} else {
EXPECT_EQ(vertex.in_degree(), 0);
EXPECT_EQ(vertex.out_degree(), 0);
}
}
}
}
TEST(GraphDbAccessorTest, DetachRemoveVertex) {
GraphDb db;
auto dba = db.Access();
// setup (v0)- []->(v1)<-[]-(v2)<-[]-(v3)
std::vector<VertexAccessor> vertices;
for (int i = 0; i < 4; ++i) vertices.emplace_back(dba->InsertVertex());
auto edge_type = dba->EdgeType("type");
dba->InsertEdge(vertices[0], vertices[1], edge_type);
dba->InsertEdge(vertices[2], vertices[1], edge_type);
dba->InsertEdge(vertices[3], vertices[2], edge_type);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
// ensure that plain remove does NOT work
EXPECT_EQ(Count(dba->Vertices(false)), 4);
EXPECT_EQ(Count(dba->Edges(false)), 3);
EXPECT_FALSE(dba->RemoveVertex(vertices[0]));
EXPECT_FALSE(dba->RemoveVertex(vertices[1]));
EXPECT_FALSE(dba->RemoveVertex(vertices[2]));
EXPECT_EQ(Count(dba->Vertices(false)), 4);
EXPECT_EQ(Count(dba->Edges(false)), 3);
dba->DetachRemoveVertex(vertices[2]);
EXPECT_EQ(Count(dba->Vertices(false)), 4);
EXPECT_EQ(Count(dba->Vertices(true)), 3);
EXPECT_EQ(Count(dba->Edges(false)), 3);
EXPECT_EQ(Count(dba->Edges(true)), 1);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), 3);
EXPECT_EQ(Count(dba->Edges(false)), 1);
EXPECT_TRUE(dba->RemoveVertex(vertices[3]));
EXPECT_EQ(Count(dba->Vertices(true)), 2);
EXPECT_EQ(Count(dba->Vertices(false)), 3);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), 2);
EXPECT_EQ(Count(dba->Edges(false)), 1);
for (auto va : dba->Vertices(false)) EXPECT_FALSE(dba->RemoveVertex(va));
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), 2);
EXPECT_EQ(Count(dba->Edges(false)), 1);
for (auto va : dba->Vertices(false)) {
EXPECT_FALSE(dba->RemoveVertex(va));
dba->DetachRemoveVertex(va);
break;
}
EXPECT_EQ(Count(dba->Vertices(true)), 1);
EXPECT_EQ(Count(dba->Vertices(false)), 2);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), 1);
EXPECT_EQ(Count(dba->Edges(false)), 0);
// remove the last vertex, it has no connections
// so that should work
for (auto va : dba->Vertices(false)) EXPECT_TRUE(dba->RemoveVertex(va));
dba->AdvanceCommand();
EXPECT_EQ(Count(dba->Vertices(false)), 0);
EXPECT_EQ(Count(dba->Edges(false)), 0);
}
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
// This test checks that we can detach remove the
// same vertex / edge multiple times
GraphDb db;
auto dba = db.Access();
// setup: make a fully connected N graph
// with cycles too!
int N = 7;
std::vector<VertexAccessor> vertices;
auto edge_type = dba->EdgeType("edge");
for (int i = 0; i < N; ++i) vertices.emplace_back(dba->InsertVertex());
for (int j = 0; j < N; ++j)
for (int k = 0; k < N; ++k)
dba->InsertEdge(vertices[j], vertices[k], edge_type);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), N);
EXPECT_EQ(Count(dba->Edges(false)), N * N);
// detach delete one edge
dba->DetachRemoveVertex(vertices[0]);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), N - 1);
EXPECT_EQ(Count(dba->Edges(false)), (N - 1) * (N - 1));
// detach delete two neighboring edges
dba->DetachRemoveVertex(vertices[1]);
dba->DetachRemoveVertex(vertices[2]);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), N - 3);
EXPECT_EQ(Count(dba->Edges(false)), (N - 3) * (N - 3));
// detach delete everything, buwahahahaha
for (int l = 3; l < N; ++l) dba->DetachRemoveVertex(vertices[l]);
dba->AdvanceCommand();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->Vertices(false)), 0);
EXPECT_EQ(Count(dba->Edges(false)), 0);
}
TEST(GraphDbAccessorTest, Labels) {
GraphDb db;
auto dba = db.Access();
Label label_friend = dba->Label("friend");
EXPECT_EQ(label_friend, dba->Label("friend"));
EXPECT_NE(label_friend, dba->Label("friend2"));
EXPECT_EQ(dba->LabelName(label_friend), "friend");
// test that getting labels through a different accessor works
EXPECT_EQ(label_friend, db.Access()->Label("friend"));
EXPECT_NE(label_friend, db.Access()->Label("friend2"));
}
TEST(GraphDbAccessorTest, EdgeTypes) {
GraphDb db;
auto dba = db.Access();
EdgeType edge_type = dba->EdgeType("likes");
EXPECT_EQ(edge_type, dba->EdgeType("likes"));
EXPECT_NE(edge_type, dba->EdgeType("hates"));
EXPECT_EQ(dba->EdgeTypeName(edge_type), "likes");
// test that getting labels through a different accessor works
EXPECT_EQ(edge_type, db.Access()->EdgeType("likes"));
EXPECT_NE(edge_type, db.Access()->EdgeType("hates"));
}
TEST(GraphDbAccessorTest, Properties) {
GraphDb db;
auto dba = db.Access();
Property prop = dba->Property("name");
EXPECT_EQ(prop, dba->Property("name"));
EXPECT_NE(prop, dba->Property("surname"));
EXPECT_EQ(dba->PropertyName(prop), "name");
// test that getting labels through a different accessor works
EXPECT_EQ(prop, db.Access()->Property("name"));
EXPECT_NE(prop, db.Access()->Property("surname"));
}
TEST(GraphDbAccessorTest, Transfer) {
GraphDb db;
auto dba1 = db.Access();
auto prop = dba1->Property("property");
VertexAccessor v1 = dba1->InsertVertex();
v1.PropsSet(prop, 1);
VertexAccessor v2 = dba1->InsertVertex();
v2.PropsSet(prop, 2);
EdgeAccessor e12 = dba1->InsertEdge(v1, v2, dba1->EdgeType("et"));
e12.PropsSet(prop, 12);
// make dba2 that has dba1 in it's snapshot, so data isn't visible
auto dba2 = db.Access();
EXPECT_EQ(dba2->Transfer(v1), std::experimental::nullopt);
EXPECT_EQ(dba2->Transfer(e12), std::experimental::nullopt);
// make dba3 that does not have dba1 in it's snapshot
dba1->Commit();
auto dba3 = db.Access();
// we can transfer accessors even though the GraphDbAccessor they
// belong to is not alive anymore
EXPECT_EQ(dba3->Transfer(v1)->PropsAt(prop).Value<int64_t>(), 1);
EXPECT_EQ(dba3->Transfer(e12)->PropsAt(prop).Value<int64_t>(), 12);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
// ::testing::GTEST_FLAG(filter) = "*.DetachRemoveVertex";
return RUN_ALL_TESTS();
}