Implement existence constraints
Reviewers: teon.banek, mferencevic Reviewed By: teon.banek, mferencevic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2307
This commit is contained in:
parent
b8e964a82d
commit
1ab0b8e0ff
75
src/storage/v2/constraints.hpp
Normal file
75
src/storage/v2/constraints.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/vertex.hpp"
|
||||
#include "utils/result.hpp"
|
||||
#include "utils/skip_list.hpp"
|
||||
|
||||
namespace storage {
|
||||
|
||||
struct Constraints {
|
||||
std::vector<std::pair<LabelId, PropertyId>> existence_constraints;
|
||||
};
|
||||
|
||||
struct ExistenceConstraintViolation {
|
||||
LabelId label;
|
||||
PropertyId property;
|
||||
};
|
||||
|
||||
/// Adds a unique constraint to `constraints`. Returns true if the constraint
|
||||
/// was successfuly added, false if it already exists and an
|
||||
/// `ExistenceConstraintViolation` if there is an existing vertex violating the
|
||||
/// constraint.
|
||||
///
|
||||
/// @throw std::bad_alloc
|
||||
/// @throw std::length_error
|
||||
inline utils::BasicResult<ExistenceConstraintViolation, bool>
|
||||
CreateExistenceConstraint(Constraints *constraints, LabelId label,
|
||||
PropertyId property,
|
||||
utils::SkipList<Vertex>::Accessor vertices) {
|
||||
if (utils::Contains(constraints->existence_constraints,
|
||||
std::make_pair(label, property))) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &vertex : vertices) {
|
||||
if (!vertex.deleted && utils::Contains(vertex.labels, label) &&
|
||||
vertex.properties.find(property) == vertex.properties.end()) {
|
||||
return ExistenceConstraintViolation{label, property};
|
||||
}
|
||||
}
|
||||
constraints->existence_constraints.emplace_back(label, property);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Removes a unique constraint from `constraints`. Returns true if the
|
||||
/// constraint was removed, and false if it doesn't exist.
|
||||
inline bool DropExistenceConstraint(Constraints *constraints, LabelId label,
|
||||
PropertyId property) {
|
||||
auto it = std::find(constraints->existence_constraints.begin(),
|
||||
constraints->existence_constraints.end(),
|
||||
std::make_pair(label, property));
|
||||
if (it == constraints->existence_constraints.end()) {
|
||||
return false;
|
||||
}
|
||||
constraints->existence_constraints.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Verifies that the given vertex satisfies all existence constraints. Returns
|
||||
/// nullopt if all checks pass, and `ExistenceConstraintViolation` describing
|
||||
/// the violated constraint otherwise.
|
||||
[[nodiscard]] inline std::optional<ExistenceConstraintViolation>
|
||||
ValidateExistenceConstraints(Vertex *vertex, Constraints *constraints) {
|
||||
for (const auto &[label, property] : constraints->existence_constraints) {
|
||||
if (!vertex->deleted && utils::Contains(vertex->labels, label) &&
|
||||
vertex->properties.find(property) == vertex->properties.end()) {
|
||||
return ExistenceConstraintViolation{label, property};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace storage
|
@ -580,7 +580,8 @@ EdgeTypeId Storage::Accessor::NameToEdgeType(const std::string &name) {
|
||||
|
||||
void Storage::Accessor::AdvanceCommand() { ++transaction_.command_id; }
|
||||
|
||||
void Storage::Accessor::Commit() {
|
||||
[[nodiscard]] std::optional<ExistenceConstraintViolation>
|
||||
Storage::Accessor::Commit() {
|
||||
CHECK(is_transaction_active_) << "The transaction is already terminated!";
|
||||
CHECK(!transaction_.must_abort) << "The transaction can't be committed!";
|
||||
|
||||
@ -589,6 +590,23 @@ void Storage::Accessor::Commit() {
|
||||
// it.
|
||||
storage_->commit_log_.MarkFinished(transaction_.start_timestamp);
|
||||
} else {
|
||||
// Validate that existence constraints are satisfied for all modified
|
||||
// vertices.
|
||||
for (const auto &delta : transaction_.deltas) {
|
||||
auto prev = delta.prev.Get();
|
||||
if (prev.type != PreviousPtr::Type::VERTEX) {
|
||||
continue;
|
||||
}
|
||||
// No need to take any locks here because we modified this vertex and no
|
||||
// one else can touch it until we commit.
|
||||
auto validation_result =
|
||||
ValidateExistenceConstraints(prev.vertex, &storage_->constraints_);
|
||||
if (validation_result) {
|
||||
Abort();
|
||||
return *validation_result;
|
||||
}
|
||||
}
|
||||
|
||||
// Save these so we can mark them used in the commit log.
|
||||
uint64_t start_timestamp = transaction_.start_timestamp;
|
||||
uint64_t commit_timestamp;
|
||||
@ -622,6 +640,8 @@ void Storage::Accessor::Commit() {
|
||||
if (storage_->gc_config_.type == StorageGcConfig::Type::ON_FINISH) {
|
||||
storage_->CollectGarbage();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Storage::Accessor::Abort() {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "storage/v2/commit_log.hpp"
|
||||
#include "storage/v2/constraints.hpp"
|
||||
#include "storage/v2/edge.hpp"
|
||||
#include "storage/v2/edge_accessor.hpp"
|
||||
#include "storage/v2/indices.hpp"
|
||||
@ -215,7 +216,10 @@ class Storage final {
|
||||
|
||||
void AdvanceCommand();
|
||||
|
||||
void Commit();
|
||||
/// Commit returns `ExistenceConstraintViolation` if the changes made by
|
||||
/// this transaction violate an existence constraint. In that case the
|
||||
/// transaction is automatically aborted. Otherwise, nullopt is returned.
|
||||
[[nodiscard]] std::optional<ExistenceConstraintViolation> Commit();
|
||||
|
||||
void Abort();
|
||||
|
||||
@ -252,15 +256,36 @@ class Storage final {
|
||||
return indices_.label_property_index.IndexExists(label, property);
|
||||
}
|
||||
|
||||
/// Creates a unique constraint`. Returns true if the constraint was
|
||||
/// successfuly added, false if it already exists and an
|
||||
/// `ExistenceConstraintViolation` if there is an existing vertex violating
|
||||
/// the constraint.
|
||||
///
|
||||
/// @throw std::bad_alloc
|
||||
/// @throw std::length_error
|
||||
utils::BasicResult<ExistenceConstraintViolation, bool>
|
||||
CreateExistenceConstraint(LabelId label, PropertyId property) {
|
||||
std::unique_lock<utils::RWLock> storage_guard(main_lock_);
|
||||
return ::storage::CreateExistenceConstraint(&constraints_, label, property,
|
||||
vertices_.access());
|
||||
}
|
||||
|
||||
/// Removes a unique constraint. Returns true if the constraint was removed,
|
||||
/// and false if it doesn't exist.
|
||||
bool DropExistenceConstraint(LabelId label, PropertyId property) {
|
||||
std::unique_lock<utils::RWLock> storage_guard(main_lock_);
|
||||
return ::storage::DropExistenceConstraint(&constraints_, label, property);
|
||||
}
|
||||
|
||||
private:
|
||||
void CollectGarbage();
|
||||
|
||||
// Main storage lock.
|
||||
//
|
||||
// Accessors take a shared lock when starting, so it is possible to block
|
||||
// creation of new accessors by taking a unique lock. This is used when
|
||||
// building a label-property index because it is much simpler to do when there
|
||||
// are no parallel reads and writes.
|
||||
// creation of new accessors by taking a unique lock. This is used when doing
|
||||
// operations on storage that affect the global state, for example index
|
||||
// creation.
|
||||
utils::RWLock main_lock_{utils::RWLock::Priority::WRITE};
|
||||
|
||||
// Main object storage
|
||||
@ -272,6 +297,7 @@ class Storage final {
|
||||
NameIdMapper name_id_mapper_;
|
||||
|
||||
Indices indices_;
|
||||
Constraints constraints_;
|
||||
|
||||
// Transaction engine
|
||||
utils::SpinLock engine_lock_;
|
||||
|
@ -43,7 +43,7 @@ void UpdateLabelFunc(int thread_id, storage::Storage *storage,
|
||||
<< "Vertex with GID " << gid.AsUint() << " doesn't exist";
|
||||
if (vertex->AddLabel(storage::LabelId::FromUint(label_dist(gen)))
|
||||
.HasValue()) {
|
||||
acc.Commit();
|
||||
CHECK(acc.Commit() == std::nullopt);
|
||||
} else {
|
||||
acc.Abort();
|
||||
}
|
||||
@ -61,7 +61,7 @@ int main(int argc, char *argv[]) {
|
||||
for (int i = 0; i < FLAGS_num_vertices; ++i) {
|
||||
vertices.push_back(acc.CreateVertex().Gid());
|
||||
}
|
||||
acc.Commit();
|
||||
CHECK(acc.Commit() == std::nullopt);
|
||||
}
|
||||
|
||||
utils::Timer timer;
|
||||
|
@ -310,6 +310,9 @@ target_link_libraries(${test_prefix}auth mg-auth kvstore_lib)
|
||||
add_unit_test(property_value_v2.cpp)
|
||||
target_link_libraries(${test_prefix}property_value_v2 mg-utils)
|
||||
|
||||
add_unit_test(storage_v2_constraints.cpp)
|
||||
target_link_libraries(${test_prefix}storage_v2_constraints mg-storage-v2)
|
||||
|
||||
add_unit_test(storage_v2_edge.cpp)
|
||||
target_link_libraries(${test_prefix}storage_v2_edge mg-storage-v2)
|
||||
|
||||
|
@ -25,7 +25,7 @@ TEST(StorageV2, Commit) {
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::OLD), 0U);
|
||||
ASSERT_TRUE(acc.FindVertex(gid, storage::View::NEW).has_value());
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::NEW), 1U);
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -45,7 +45,7 @@ TEST(StorageV2, Commit) {
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::OLD), 1U);
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::NEW), 0U);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -111,7 +111,7 @@ TEST(StorageV2, AdvanceCommandCommit) {
|
||||
ASSERT_TRUE(acc.FindVertex(gid1, storage::View::OLD).has_value());
|
||||
ASSERT_TRUE(acc.FindVertex(gid1, storage::View::NEW).has_value());
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -185,7 +185,7 @@ TEST(StorageV2, SnapshotIsolation) {
|
||||
EXPECT_EQ(CountVertices(&acc1, storage::View::NEW), 1U);
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::NEW), 0U);
|
||||
|
||||
acc1.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
|
||||
ASSERT_FALSE(acc2.FindVertex(gid, storage::View::OLD).has_value());
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::OLD), 0U);
|
||||
@ -224,7 +224,7 @@ TEST(StorageV2, AccessorMove) {
|
||||
ASSERT_TRUE(moved.FindVertex(gid, storage::View::NEW).has_value());
|
||||
EXPECT_EQ(CountVertices(&moved, storage::View::NEW), 1U);
|
||||
|
||||
moved.Commit();
|
||||
ASSERT_EQ(moved.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -253,7 +253,7 @@ TEST(StorageV2, VertexDeleteCommit) {
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::OLD), 0U);
|
||||
ASSERT_TRUE(acc2.FindVertex(gid, storage::View::NEW).has_value());
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::NEW), 1U);
|
||||
acc2.Commit();
|
||||
ASSERT_EQ(acc2.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc3 = store.Access(); // read transaction
|
||||
@ -283,7 +283,7 @@ TEST(StorageV2, VertexDeleteCommit) {
|
||||
EXPECT_EQ(CountVertices(&acc4, storage::View::OLD), 1U);
|
||||
EXPECT_EQ(CountVertices(&acc4, storage::View::NEW), 0U);
|
||||
|
||||
acc4.Commit();
|
||||
ASSERT_EQ(acc4.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc5 = store.Access(); // read transaction
|
||||
@ -324,7 +324,7 @@ TEST(StorageV2, VertexDeleteAbort) {
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::OLD), 0U);
|
||||
ASSERT_TRUE(acc2.FindVertex(gid, storage::View::NEW).has_value());
|
||||
EXPECT_EQ(CountVertices(&acc2, storage::View::NEW), 1U);
|
||||
acc2.Commit();
|
||||
ASSERT_EQ(acc2.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc3 = store.Access(); // read transaction
|
||||
@ -390,7 +390,7 @@ TEST(StorageV2, VertexDeleteAbort) {
|
||||
EXPECT_EQ(CountVertices(&acc6, storage::View::OLD), 1U);
|
||||
EXPECT_EQ(CountVertices(&acc6, storage::View::NEW), 0U);
|
||||
|
||||
acc6.Commit();
|
||||
ASSERT_EQ(acc6.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc7 = store.Access(); // read transaction
|
||||
@ -420,10 +420,10 @@ TEST(StorageV2, VertexDeleteAbort) {
|
||||
EXPECT_EQ(CountVertices(&acc7, storage::View::NEW), 0U);
|
||||
|
||||
// Commit all accessors
|
||||
acc1.Commit();
|
||||
acc3.Commit();
|
||||
acc5.Commit();
|
||||
acc7.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
ASSERT_EQ(acc3.Commit(), std::nullopt);
|
||||
ASSERT_EQ(acc5.Commit(), std::nullopt);
|
||||
ASSERT_EQ(acc7.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
@ -437,7 +437,7 @@ TEST(StorageV2, VertexDeleteSerializationError) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc1 = store.Access();
|
||||
@ -481,7 +481,7 @@ TEST(StorageV2, VertexDeleteSerializationError) {
|
||||
}
|
||||
|
||||
// Finalize both accessors
|
||||
acc1.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
acc2.Abort();
|
||||
|
||||
// Check whether the vertex exists
|
||||
@ -491,7 +491,7 @@ TEST(StorageV2, VertexDeleteSerializationError) {
|
||||
ASSERT_FALSE(vertex);
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::OLD), 0U);
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::NEW), 0U);
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,7 +535,7 @@ TEST(StorageV2, VertexDeleteSpecialCases) {
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::OLD), 0U);
|
||||
EXPECT_EQ(CountVertices(&acc, storage::View::NEW), 0U);
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the vertices exist
|
||||
@ -564,7 +564,7 @@ TEST(StorageV2, VertexDeleteLabel) {
|
||||
gid = vertex.Gid();
|
||||
ASSERT_FALSE(acc.FindVertex(gid, storage::View::OLD).has_value());
|
||||
ASSERT_TRUE(acc.FindVertex(gid, storage::View::NEW).has_value());
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Add label, delete the vertex and check the label API (same command)
|
||||
@ -725,7 +725,7 @@ TEST(StorageV2, VertexDeleteProperty) {
|
||||
gid = vertex.Gid();
|
||||
ASSERT_FALSE(acc.FindVertex(gid, storage::View::OLD).has_value());
|
||||
ASSERT_TRUE(acc.FindVertex(gid, storage::View::NEW).has_value());
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Set property, delete the vertex and check the property API (same command)
|
||||
@ -743,9 +743,8 @@ TEST(StorageV2, VertexDeleteProperty) {
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
// Set property 5 to "nandare"
|
||||
ASSERT_TRUE(
|
||||
vertex->SetProperty(property, storage::PropertyValue("nandare"))
|
||||
.GetValue());
|
||||
ASSERT_TRUE(vertex->SetProperty(property, storage::PropertyValue("nandare"))
|
||||
.GetValue());
|
||||
|
||||
// Check whether property 5 exists
|
||||
ASSERT_TRUE(vertex->GetProperty(property, storage::View::OLD)->IsNull());
|
||||
@ -796,9 +795,8 @@ TEST(StorageV2, VertexDeleteProperty) {
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
// Set property 5 to "nandare"
|
||||
ASSERT_TRUE(
|
||||
vertex->SetProperty(property, storage::PropertyValue("nandare"))
|
||||
.GetValue());
|
||||
ASSERT_TRUE(vertex->SetProperty(property, storage::PropertyValue("nandare"))
|
||||
.GetValue());
|
||||
|
||||
// Check whether property 5 exists
|
||||
ASSERT_TRUE(vertex->GetProperty(property, storage::View::OLD)->IsNull());
|
||||
@ -905,7 +903,7 @@ TEST(StorageV2, VertexLabelCommit) {
|
||||
ASSERT_FALSE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -964,7 +962,7 @@ TEST(StorageV2, VertexLabelCommit) {
|
||||
ASSERT_FALSE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -998,7 +996,7 @@ TEST(StorageV2, VertexLabelAbort) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Add label 5, but abort the transaction.
|
||||
@ -1085,7 +1083,7 @@ TEST(StorageV2, VertexLabelAbort) {
|
||||
ASSERT_FALSE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that label 5 exists.
|
||||
@ -1211,7 +1209,7 @@ TEST(StorageV2, VertexLabelAbort) {
|
||||
ASSERT_FALSE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that label 5 doesn't exist.
|
||||
@ -1245,7 +1243,7 @@ TEST(StorageV2, VertexLabelSerializationError) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc1 = store.Access();
|
||||
@ -1313,7 +1311,7 @@ TEST(StorageV2, VertexLabelSerializationError) {
|
||||
}
|
||||
|
||||
// Finalize both accessors.
|
||||
acc1.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
acc2.Abort();
|
||||
|
||||
// Check which labels exist.
|
||||
@ -1390,7 +1388,7 @@ TEST(StorageV2, VertexPropertyCommit) {
|
||||
ASSERT_EQ(properties[property].ValueString(), "nandare");
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -1454,7 +1452,7 @@ TEST(StorageV2, VertexPropertyCommit) {
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -1490,7 +1488,7 @@ TEST(StorageV2, VertexPropertyAbort) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Set property 5 to "nandare", but abort the transaction.
|
||||
@ -1601,7 +1599,7 @@ TEST(StorageV2, VertexPropertyAbort) {
|
||||
ASSERT_EQ(properties[property].ValueString(), "nandare");
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that property 5 is "nandare".
|
||||
@ -1757,7 +1755,7 @@ TEST(StorageV2, VertexPropertyAbort) {
|
||||
ASSERT_TRUE(vertex->GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that property 5 is null.
|
||||
@ -1793,7 +1791,7 @@ TEST(StorageV2, VertexPropertySerializationError) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc1 = store.Access();
|
||||
@ -1857,7 +1855,7 @@ TEST(StorageV2, VertexPropertySerializationError) {
|
||||
}
|
||||
|
||||
// Finalize both accessors.
|
||||
acc1.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
acc2.Abort();
|
||||
|
||||
// Check which properties exist.
|
||||
@ -1942,7 +1940,7 @@ TEST(StorageV2, VertexLabelPropertyMixed) {
|
||||
|
||||
// Set property 5 to "nandare"
|
||||
ASSERT_TRUE(vertex.SetProperty(property, storage::PropertyValue("nandare"))
|
||||
.GetValue());
|
||||
.GetValue());
|
||||
|
||||
// Check whether label 5 and property 5 exist
|
||||
ASSERT_TRUE(vertex.HasLabel(label, storage::View::OLD).GetValue());
|
||||
@ -2000,7 +1998,7 @@ TEST(StorageV2, VertexLabelPropertyMixed) {
|
||||
|
||||
// Set property 5 to "haihai"
|
||||
ASSERT_FALSE(vertex.SetProperty(property, storage::PropertyValue("haihai"))
|
||||
.GetValue());
|
||||
.GetValue());
|
||||
|
||||
// Check whether label 5 and property 5 exist
|
||||
ASSERT_TRUE(vertex.HasLabel(label, storage::View::OLD).GetValue());
|
||||
@ -2143,5 +2141,5 @@ TEST(StorageV2, VertexLabelPropertyMixed) {
|
||||
ASSERT_EQ(vertex.Properties(storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
166
tests/unit/storage_v2_constraints.cpp
Normal file
166
tests/unit/storage_v2_constraints.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace storage;
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define ASSERT_NO_ERROR(result) ASSERT_FALSE((result).HasError())
|
||||
|
||||
bool operator==(const ExistenceConstraintViolation &lhs,
|
||||
const ExistenceConstraintViolation &rhs) {
|
||||
return lhs.label == rhs.label && lhs.property == rhs.property;
|
||||
}
|
||||
|
||||
class ConstraintsTest : public testing::Test {
|
||||
protected:
|
||||
ConstraintsTest()
|
||||
: prop1(storage.NameToProperty("prop1")),
|
||||
prop2(storage.NameToProperty("prop2")),
|
||||
label1(storage.NameToLabel("label1")),
|
||||
label2(storage.NameToLabel("label2")) {}
|
||||
|
||||
Storage storage;
|
||||
PropertyId prop1;
|
||||
PropertyId prop2;
|
||||
LabelId label1;
|
||||
LabelId label2;
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(ConstraintsTest, CreateAndDrop) {
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && !res.GetValue());
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label2, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
EXPECT_TRUE(storage.DropExistenceConstraint(label1, prop1));
|
||||
EXPECT_FALSE(storage.DropExistenceConstraint(label1, prop1));
|
||||
EXPECT_TRUE(storage.DropExistenceConstraint(label2, prop1));
|
||||
EXPECT_FALSE(storage.DropExistenceConstraint(label2, prop2));
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label2, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(ConstraintsTest, CreateFailure1) {
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
ASSERT_NO_ERROR(vertex.AddLabel(label1));
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(
|
||||
res.HasError() &&
|
||||
(res.GetError() == ExistenceConstraintViolation{label1, prop1}));
|
||||
}
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
for (auto vertex : acc.Vertices(View::OLD)) {
|
||||
ASSERT_NO_ERROR(acc.DeleteVertex(&vertex));
|
||||
}
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(ConstraintsTest, CreateFailure2) {
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
ASSERT_NO_ERROR(vertex.AddLabel(label1));
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(
|
||||
res.HasError() &&
|
||||
(res.GetError() == ExistenceConstraintViolation{label1, prop1}));
|
||||
}
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
for (auto vertex : acc.Vertices(View::OLD)) {
|
||||
ASSERT_NO_ERROR(vertex.SetProperty(prop1, PropertyValue(1)));
|
||||
}
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
EXPECT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(ConstraintsTest, ViolationOnCommit) {
|
||||
{
|
||||
auto res = storage.CreateExistenceConstraint(label1, prop1);
|
||||
ASSERT_TRUE(res.HasValue() && res.GetValue());
|
||||
}
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
ASSERT_NO_ERROR(vertex.AddLabel(label1));
|
||||
|
||||
auto res = acc.Commit();
|
||||
EXPECT_TRUE(res.has_value() &&
|
||||
(*res == ExistenceConstraintViolation{label1, prop1}));
|
||||
}
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
ASSERT_NO_ERROR(vertex.AddLabel(label1));
|
||||
ASSERT_NO_ERROR(vertex.SetProperty(prop1, PropertyValue(1)));
|
||||
EXPECT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
for (auto vertex : acc.Vertices(View::OLD)) {
|
||||
ASSERT_NO_ERROR(vertex.SetProperty(prop1, PropertyValue()));
|
||||
}
|
||||
|
||||
auto res = acc.Commit();
|
||||
EXPECT_TRUE(res.has_value() &&
|
||||
(*res == ExistenceConstraintViolation{label1, prop1}));
|
||||
}
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
for (auto vertex : acc.Vertices(View::OLD)) {
|
||||
ASSERT_NO_ERROR(vertex.SetProperty(prop1, PropertyValue()));
|
||||
}
|
||||
for (auto vertex : acc.Vertices(View::OLD)) {
|
||||
ASSERT_NO_ERROR(acc.DeleteVertex(&vertex));
|
||||
}
|
||||
|
||||
EXPECT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(storage.DropExistenceConstraint(label1, prop1));
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
ASSERT_NO_ERROR(vertex.AddLabel(label1));
|
||||
EXPECT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ TEST(StorageV2, EdgeCreateFromSmallerCommit) {
|
||||
auto vertex_to = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -77,7 +77,7 @@ TEST(StorageV2, EdgeCreateFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -152,7 +152,7 @@ TEST(StorageV2, EdgeCreateFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ TEST(StorageV2, EdgeCreateFromLargerCommit) {
|
||||
auto vertex_from = acc.CreateVertex();
|
||||
gid_to = vertex_to.Gid();
|
||||
gid_from = vertex_from.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -229,7 +229,7 @@ TEST(StorageV2, EdgeCreateFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -304,7 +304,7 @@ TEST(StorageV2, EdgeCreateFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ TEST(StorageV2, EdgeCreateFromSameCommit) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid_vertex = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -369,7 +369,7 @@ TEST(StorageV2, EdgeCreateFromSameCommit) {
|
||||
ASSERT_EQ(vertex->InEdges({other_et}, storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex->InEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -434,7 +434,7 @@ TEST(StorageV2, EdgeCreateFromSameCommit) {
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,7 +453,7 @@ TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
auto vertex_to = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge, but abort the transaction
|
||||
@ -532,7 +532,7 @@ TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -590,7 +590,7 @@ TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -665,7 +665,7 @@ TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -684,7 +684,7 @@ TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
auto vertex_from = acc.CreateVertex();
|
||||
gid_to = vertex_to.Gid();
|
||||
gid_from = vertex_from.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge, but abort the transaction
|
||||
@ -763,7 +763,7 @@ TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -821,7 +821,7 @@ TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -896,7 +896,7 @@ TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,7 +911,7 @@ TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid_vertex = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge, but abort the transaction
|
||||
@ -976,7 +976,7 @@ TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -1026,7 +1026,7 @@ TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
ASSERT_EQ(vertex->InEdges({other_et}, storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex->InEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1091,7 +1091,7 @@ TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1110,7 +1110,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
auto vertex_to = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -1168,7 +1168,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1243,7 +1243,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete edge
|
||||
@ -1300,7 +1300,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::OLD)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1321,7 +1321,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1340,7 +1340,7 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
auto vertex_from = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -1398,7 +1398,7 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1473,7 +1473,7 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete edge
|
||||
@ -1530,7 +1530,7 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::OLD)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1551,7 +1551,7 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1566,7 +1566,7 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid_vertex = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -1616,7 +1616,7 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
ASSERT_EQ(vertex->InEdges({other_et}, storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex->InEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1681,7 +1681,7 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete edge
|
||||
@ -1730,7 +1730,7 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
ASSERT_EQ(vertex->OutEdges({other_et}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1745,7 +1745,7 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1764,7 +1764,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
auto vertex_to = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -1822,7 +1822,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -1897,7 +1897,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge, but abort the transaction
|
||||
@ -2029,7 +2029,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge
|
||||
@ -2086,7 +2086,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::OLD)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -2107,7 +2107,7 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2126,7 +2126,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
auto vertex_to = acc.CreateVertex();
|
||||
gid_from = vertex_from.Gid();
|
||||
gid_to = vertex_to.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -2184,7 +2184,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -2259,7 +2259,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge, but abort the transaction
|
||||
@ -2391,7 +2391,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::NEW)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge
|
||||
@ -2448,7 +2448,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->InEdges({et, other_et}, storage::View::OLD)->size(),
|
||||
1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -2469,7 +2469,7 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2484,7 +2484,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid_vertex = vertex.Gid();
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Create edge
|
||||
@ -2534,7 +2534,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
ASSERT_EQ(vertex->InEdges({other_et}, storage::View::NEW)->size(), 0);
|
||||
ASSERT_EQ(vertex->InEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -2599,7 +2599,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge, but abort the transaction
|
||||
@ -2713,7 +2713,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::NEW)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Delete the edge
|
||||
@ -2762,7 +2762,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({other_et}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex->OutEdges({et, other_et}, storage::View::OLD)->size(), 1);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check whether the edge exists
|
||||
@ -2777,7 +2777,7 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2831,7 +2831,7 @@ TEST(StorageV2, VertexDetachDeleteSingleCommit) {
|
||||
}
|
||||
ASSERT_EQ(vertex_to.OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex
|
||||
@ -2888,7 +2888,7 @@ TEST(StorageV2, VertexDetachDeleteSingleCommit) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check dataset
|
||||
@ -3043,7 +3043,7 @@ TEST(StorageV2, VertexDetachDeleteMultipleCommit) {
|
||||
}
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex
|
||||
@ -3183,7 +3183,7 @@ TEST(StorageV2, VertexDetachDeleteMultipleCommit) {
|
||||
ASSERT_EQ(e.ToVertex(), *vertex2);
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check dataset
|
||||
@ -3290,7 +3290,7 @@ TEST(StorageV2, VertexDetachDeleteSingleAbort) {
|
||||
}
|
||||
ASSERT_EQ(vertex_to.OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex, but abort the transaction
|
||||
@ -3384,7 +3384,7 @@ TEST(StorageV2, VertexDetachDeleteSingleAbort) {
|
||||
}
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex
|
||||
@ -3441,7 +3441,7 @@ TEST(StorageV2, VertexDetachDeleteSingleAbort) {
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::OLD)->size(), 0);
|
||||
ASSERT_EQ(vertex_to->OutEdges({}, storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check dataset
|
||||
@ -3596,7 +3596,7 @@ TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
|
||||
}
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex, but abort the transaction
|
||||
@ -3922,7 +3922,7 @@ TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
|
||||
}
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Detach delete vertex
|
||||
@ -4062,7 +4062,7 @@ TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
|
||||
ASSERT_EQ(e.ToVertex(), *vertex2);
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check dataset
|
||||
@ -4168,7 +4168,7 @@ TEST(StorageV2, EdgePropertyCommit) {
|
||||
ASSERT_EQ(properties[property].ValueString(), "nandare");
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -4232,7 +4232,7 @@ TEST(StorageV2, EdgePropertyCommit) {
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -4272,7 +4272,7 @@ TEST(StorageV2, EdgePropertyAbort) {
|
||||
ASSERT_EQ(edge.EdgeType(), et);
|
||||
ASSERT_EQ(edge.FromVertex(), vertex);
|
||||
ASSERT_EQ(edge.ToVertex(), vertex);
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Set property 5 to "nandare", but abort the transaction.
|
||||
@ -4382,7 +4382,7 @@ TEST(StorageV2, EdgePropertyAbort) {
|
||||
ASSERT_EQ(properties[property].ValueString(), "nandare");
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that property 5 is "nandare".
|
||||
@ -4538,7 +4538,7 @@ TEST(StorageV2, EdgePropertyAbort) {
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Check that property 5 is null.
|
||||
@ -4578,7 +4578,7 @@ TEST(StorageV2, EdgePropertySerializationError) {
|
||||
ASSERT_EQ(edge.EdgeType(), et);
|
||||
ASSERT_EQ(edge.FromVertex(), vertex);
|
||||
ASSERT_EQ(edge.ToVertex(), vertex);
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
auto acc1 = store.Access();
|
||||
@ -4642,7 +4642,7 @@ TEST(StorageV2, EdgePropertySerializationError) {
|
||||
}
|
||||
|
||||
// Finalize both accessors.
|
||||
acc1.Commit();
|
||||
ASSERT_EQ(acc1.Commit(), std::nullopt);
|
||||
acc2.Abort();
|
||||
|
||||
// Check which properties exist.
|
||||
|
@ -47,7 +47,7 @@ TEST(StorageV2Gc, Sanity) {
|
||||
EXPECT_EQ(vertex_new.has_value(), i % 5 != 0);
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Verify existing vertices and add labels to some of them.
|
||||
@ -90,7 +90,7 @@ TEST(StorageV2Gc, Sanity) {
|
||||
}
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
|
||||
// Add and remove some edges.
|
||||
@ -148,7 +148,7 @@ TEST(StorageV2Gc, Sanity) {
|
||||
}
|
||||
}
|
||||
|
||||
acc.Commit();
|
||||
ASSERT_EQ(acc.Commit(), std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ TEST(StorageV2Gc, Indices) {
|
||||
auto vertex = acc0.CreateVertex();
|
||||
ASSERT_TRUE(*vertex.AddLabel(acc0.NameToLabel("label")));
|
||||
}
|
||||
acc0.Commit();
|
||||
ASSERT_EQ(acc0.Commit(), std::nullopt);
|
||||
}
|
||||
{
|
||||
auto acc1 = storage.Access();
|
||||
@ -180,7 +180,7 @@ TEST(StorageV2Gc, Indices) {
|
||||
for (auto vertex : acc2.Vertices(storage::View::OLD)) {
|
||||
ASSERT_TRUE(*vertex.RemoveLabel(acc2.NameToLabel("label")));
|
||||
}
|
||||
acc2.Commit();
|
||||
ASSERT_EQ(acc2.Commit(), std::nullopt);
|
||||
|
||||
// Wait for GC.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
|
Loading…
Reference in New Issue
Block a user