Add support for disabling properties on edges
Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2447
This commit is contained in:
parent
8b6ae08682
commit
9ad49698e9
@ -106,6 +106,7 @@ void DumpVertex(std::ostream *os, query::DbAccessor *dba,
|
||||
"Trying to get labels from a deleted node.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw query::QueryRuntimeException(
|
||||
"Unexpected error when getting labels.");
|
||||
}
|
||||
@ -122,6 +123,7 @@ void DumpVertex(std::ostream *os, query::DbAccessor *dba,
|
||||
"Trying to get properties from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw query::QueryRuntimeException(
|
||||
"Unexpected error when getting properties.");
|
||||
}
|
||||
@ -150,6 +152,7 @@ void DumpEdge(std::ostream *os, query::DbAccessor *dba,
|
||||
"Trying to get properties from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw query::QueryRuntimeException(
|
||||
"Unexpected error when getting properties.");
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ std::map<std::string, communication::bolt::Value> BoltSession::PullAll(
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw communication::bolt::ClientError(
|
||||
"Unexpected storage error when streaming summary.");
|
||||
}
|
||||
@ -150,6 +151,7 @@ void BoltSession::TypedValueResultStream::Result(
|
||||
"Returning a deleted object as a result.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw communication::bolt::ClientError(
|
||||
"Unexpected storage error when streaming results.");
|
||||
}
|
||||
|
@ -85,6 +85,9 @@ void PropsSetChecked(TRecordAccessor *record, const storage::Property &key,
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
throw QueryRuntimeException(
|
||||
"Trying to set properties on a deleted object.");
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Can't set property because properties are disabled.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when setting a property.");
|
||||
|
@ -374,6 +374,7 @@ TypedValue Properties(const TypedValue *args, int64_t nargs,
|
||||
"Trying to get properties from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting properties.");
|
||||
}
|
||||
@ -438,6 +439,7 @@ size_t UnwrapDegreeResult(storage::Result<size_t> maybe_degree) {
|
||||
throw QueryRuntimeException("Trying to get degree of a deleted node.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting node degree.");
|
||||
}
|
||||
@ -575,6 +577,7 @@ TypedValue Keys(const TypedValue *args, int64_t nargs,
|
||||
"Trying to get keys from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Unexpected error when getting keys.");
|
||||
}
|
||||
}
|
||||
@ -609,6 +612,7 @@ TypedValue Labels(const TypedValue *args, int64_t nargs,
|
||||
"Trying to get labels from a deleted node.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Unexpected error when getting labels.");
|
||||
}
|
||||
}
|
||||
|
@ -317,6 +317,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
"Trying to access labels on a deleted node.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when accessing labels.");
|
||||
}
|
||||
@ -554,6 +555,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
"Trying to get a property from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting a property.");
|
||||
}
|
||||
@ -573,6 +575,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
"Trying to get a property from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting a property.");
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info,
|
||||
throw QueryRuntimeException(
|
||||
"Trying to set a label on a deleted node.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Unexpected error when setting a label.");
|
||||
}
|
||||
}
|
||||
@ -231,6 +232,7 @@ void CreateEdge(const EdgeCreationInfo &edge_info, DbAccessor *dba,
|
||||
throw QueryRuntimeException(
|
||||
"Trying to create an edge on a deleted node.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Unexpected error when creating an edge.");
|
||||
}
|
||||
}
|
||||
@ -490,6 +492,7 @@ auto UnwrapEdgesResult(storage::Result<TEdges> &&result) {
|
||||
"Trying to get relationships of a deleted node.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when accessing relationships.");
|
||||
}
|
||||
@ -695,6 +698,7 @@ size_t UnwrapDegreeResult(storage::Result<size_t> maybe_degree) {
|
||||
throw QueryRuntimeException("Trying to get degree of a deleted node.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting node degree.");
|
||||
}
|
||||
@ -1903,6 +1907,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
"Can't serialize due to concurrent operations.");
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when deleting an edge.");
|
||||
}
|
||||
@ -1925,6 +1930,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
"Can't serialize due to concurrent operations.");
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when deleting a node.");
|
||||
}
|
||||
@ -1939,6 +1945,7 @@ bool Delete::DeleteCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
throw RemoveAttachedVertexException();
|
||||
case storage::Error::DELETED_OBJECT:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when deleting a node.");
|
||||
}
|
||||
@ -2063,6 +2070,9 @@ void SetPropertiesOnRecord(DbAccessor *dba, TRecordAccessor *record,
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
throw QueryRuntimeException(
|
||||
"Can't serialize due to concurrent operations.");
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Can't set property because properties are disabled.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when setting properties.");
|
||||
@ -2079,6 +2089,7 @@ void SetPropertiesOnRecord(DbAccessor *dba, TRecordAccessor *record,
|
||||
"Trying to get properties from a deleted object.");
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when getting properties.");
|
||||
}
|
||||
@ -2097,6 +2108,9 @@ void SetPropertiesOnRecord(DbAccessor *dba, TRecordAccessor *record,
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
throw QueryRuntimeException(
|
||||
"Can't serialize due to concurrent operations.");
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Can't set property because properties are disabled.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when setting properties.");
|
||||
@ -2205,6 +2219,7 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
throw QueryRuntimeException(
|
||||
"Trying to set a label on a deleted node.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException("Unexpected error when setting a label.");
|
||||
}
|
||||
}
|
||||
@ -2258,6 +2273,9 @@ bool RemoveProperty::RemovePropertyCursor::Pull(Frame &frame,
|
||||
case storage::Error::SERIALIZATION_ERROR:
|
||||
throw QueryRuntimeException(
|
||||
"Can't serialize due to concurrent operations.");
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Can't remove property because properties are disabled.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when removing property.");
|
||||
@ -2330,6 +2348,7 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame,
|
||||
throw QueryRuntimeException(
|
||||
"Trying to remove labels from a deleted node.");
|
||||
case storage::Error::VERTEX_HAS_EDGES:
|
||||
case storage::Error::PROPERTIES_DISABLED:
|
||||
throw QueryRuntimeException(
|
||||
"Unexpected error when removing labels from a node.");
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ struct Config {
|
||||
Type type{Type::PERIODIC};
|
||||
std::chrono::milliseconds interval{std::chrono::milliseconds(1000)};
|
||||
} gc;
|
||||
|
||||
struct Items {
|
||||
bool properties_on_edges{true};
|
||||
} items;
|
||||
};
|
||||
|
||||
} // namespace storage
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "storage/v2/edge_ref.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/property_value.hpp"
|
||||
|
||||
@ -150,28 +151,28 @@ struct Delta {
|
||||
command_id(command_id),
|
||||
property({key, value}) {}
|
||||
|
||||
Delta(AddInEdgeTag, EdgeTypeId edge_type, Vertex *vertex, Edge *edge,
|
||||
Delta(AddInEdgeTag, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge,
|
||||
std::atomic<uint64_t> *timestamp, uint64_t command_id)
|
||||
: action(Action::ADD_IN_EDGE),
|
||||
timestamp(timestamp),
|
||||
command_id(command_id),
|
||||
vertex_edge({edge_type, vertex, edge}) {}
|
||||
|
||||
Delta(AddOutEdgeTag, EdgeTypeId edge_type, Vertex *vertex, Edge *edge,
|
||||
Delta(AddOutEdgeTag, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge,
|
||||
std::atomic<uint64_t> *timestamp, uint64_t command_id)
|
||||
: action(Action::ADD_OUT_EDGE),
|
||||
timestamp(timestamp),
|
||||
command_id(command_id),
|
||||
vertex_edge({edge_type, vertex, edge}) {}
|
||||
|
||||
Delta(RemoveInEdgeTag, EdgeTypeId edge_type, Vertex *vertex, Edge *edge,
|
||||
Delta(RemoveInEdgeTag, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge,
|
||||
std::atomic<uint64_t> *timestamp, uint64_t command_id)
|
||||
: action(Action::REMOVE_IN_EDGE),
|
||||
timestamp(timestamp),
|
||||
command_id(command_id),
|
||||
vertex_edge({edge_type, vertex, edge}) {}
|
||||
|
||||
Delta(RemoveOutEdgeTag, EdgeTypeId edge_type, Vertex *vertex, Edge *edge,
|
||||
Delta(RemoveOutEdgeTag, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge,
|
||||
std::atomic<uint64_t> *timestamp, uint64_t command_id)
|
||||
: action(Action::REMOVE_OUT_EDGE),
|
||||
timestamp(timestamp),
|
||||
@ -232,7 +233,7 @@ struct Delta {
|
||||
struct {
|
||||
EdgeTypeId edge_type;
|
||||
Vertex *vertex;
|
||||
Edge *edge;
|
||||
EdgeRef edge;
|
||||
} vertex_edge;
|
||||
};
|
||||
|
||||
|
@ -8,45 +8,47 @@
|
||||
namespace storage {
|
||||
|
||||
VertexAccessor EdgeAccessor::FromVertex() const {
|
||||
return VertexAccessor{from_vertex_, transaction_, indices_};
|
||||
return VertexAccessor{from_vertex_, transaction_, indices_, config_};
|
||||
}
|
||||
|
||||
VertexAccessor EdgeAccessor::ToVertex() const {
|
||||
return VertexAccessor{to_vertex_, transaction_, indices_};
|
||||
return VertexAccessor{to_vertex_, transaction_, indices_, config_};
|
||||
}
|
||||
|
||||
Result<bool> EdgeAccessor::SetProperty(PropertyId property,
|
||||
const PropertyValue &value) {
|
||||
std::lock_guard<utils::SpinLock> guard(edge_->lock);
|
||||
if (!config_.properties_on_edges) return Error::PROPERTIES_DISABLED;
|
||||
|
||||
if (!PrepareForWrite(transaction_, edge_))
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
|
||||
if (!PrepareForWrite(transaction_, edge_.ptr))
|
||||
return Error::SERIALIZATION_ERROR;
|
||||
|
||||
if (edge_->deleted) return Error::DELETED_OBJECT;
|
||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
auto it = edge_->properties.find(property);
|
||||
bool existed = it != edge_->properties.end();
|
||||
auto it = edge_.ptr->properties.find(property);
|
||||
bool existed = it != edge_.ptr->properties.end();
|
||||
// We could skip setting the value if the previous one is the same to the new
|
||||
// one. This would save some memory as a delta would not be created as well as
|
||||
// avoid copying the value. The reason we are not doing that is because the
|
||||
// current code always follows the logical pattern of "create a delta" and
|
||||
// "modify in-place". Additionally, the created delta will make other
|
||||
// transactions get a SERIALIZATION_ERROR.
|
||||
if (it != edge_->properties.end()) {
|
||||
CreateAndLinkDelta(transaction_, edge_, Delta::SetPropertyTag(), property,
|
||||
it->second);
|
||||
if (it != edge_.ptr->properties.end()) {
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property, it->second);
|
||||
if (value.IsNull()) {
|
||||
// remove the property
|
||||
edge_->properties.erase(it);
|
||||
edge_.ptr->properties.erase(it);
|
||||
} else {
|
||||
// set the value
|
||||
it->second = value;
|
||||
}
|
||||
} else {
|
||||
CreateAndLinkDelta(transaction_, edge_, Delta::SetPropertyTag(), property,
|
||||
PropertyValue());
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property, PropertyValue());
|
||||
if (!value.IsNull()) {
|
||||
edge_->properties.emplace(property, value);
|
||||
edge_.ptr->properties.emplace(property, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,17 +57,18 @@ Result<bool> EdgeAccessor::SetProperty(PropertyId property,
|
||||
|
||||
Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property,
|
||||
View view) const {
|
||||
if (!config_.properties_on_edges) return PropertyValue();
|
||||
bool deleted = false;
|
||||
PropertyValue value;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(edge_->lock);
|
||||
deleted = edge_->deleted;
|
||||
auto it = edge_->properties.find(property);
|
||||
if (it != edge_->properties.end()) {
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
deleted = edge_.ptr->deleted;
|
||||
auto it = edge_.ptr->properties.find(property);
|
||||
if (it != edge_.ptr->properties.end()) {
|
||||
value = it->second;
|
||||
}
|
||||
delta = edge_->delta;
|
||||
delta = edge_.ptr->delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view,
|
||||
[&deleted, &value, property](const Delta &delta) {
|
||||
@ -99,14 +102,16 @@ Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property,
|
||||
|
||||
Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(
|
||||
View view) const {
|
||||
if (!config_.properties_on_edges)
|
||||
return std::map<PropertyId, PropertyValue>{};
|
||||
std::map<PropertyId, PropertyValue> properties;
|
||||
bool deleted = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(edge_->lock);
|
||||
deleted = edge_->deleted;
|
||||
properties = edge_->properties;
|
||||
delta = edge_->delta;
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
deleted = edge_.ptr->deleted;
|
||||
properties = edge_.ptr->properties;
|
||||
delta = edge_.ptr->delta;
|
||||
}
|
||||
ApplyDeltasForRead(
|
||||
transaction_, delta, view, [&deleted, &properties](const Delta &delta) {
|
||||
|
@ -3,7 +3,9 @@
|
||||
#include <optional>
|
||||
|
||||
#include "storage/v2/edge.hpp"
|
||||
#include "storage/v2/edge_ref.hpp"
|
||||
|
||||
#include "storage/v2/config.hpp"
|
||||
#include "storage/v2/result.hpp"
|
||||
#include "storage/v2/transaction.hpp"
|
||||
#include "storage/v2/view.hpp"
|
||||
@ -19,14 +21,16 @@ class EdgeAccessor final {
|
||||
friend class Storage;
|
||||
|
||||
public:
|
||||
EdgeAccessor(Edge *edge, EdgeTypeId edge_type, Vertex *from_vertex,
|
||||
Vertex *to_vertex, Transaction *transaction, Indices *indices)
|
||||
EdgeAccessor(EdgeRef edge, EdgeTypeId edge_type, Vertex *from_vertex,
|
||||
Vertex *to_vertex, Transaction *transaction, Indices *indices,
|
||||
Config::Items config)
|
||||
: edge_(edge),
|
||||
edge_type_(edge_type),
|
||||
from_vertex_(from_vertex),
|
||||
to_vertex_(to_vertex),
|
||||
transaction_(transaction),
|
||||
indices_(indices) {}
|
||||
indices_(indices),
|
||||
config_(config) {}
|
||||
|
||||
VertexAccessor FromVertex() const;
|
||||
|
||||
@ -45,7 +49,13 @@ class EdgeAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
Gid Gid() const { return edge_->gid; }
|
||||
Gid Gid() const {
|
||||
if (config_.properties_on_edges) {
|
||||
return edge_.ptr->gid;
|
||||
} else {
|
||||
return edge_.gid;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCycle() const { return from_vertex_ == to_vertex_; }
|
||||
|
||||
@ -55,12 +65,13 @@ class EdgeAccessor final {
|
||||
bool operator!=(const EdgeAccessor &other) const { return !(*this == other); }
|
||||
|
||||
private:
|
||||
Edge *edge_;
|
||||
EdgeRef edge_;
|
||||
EdgeTypeId edge_type_;
|
||||
Vertex *from_vertex_;
|
||||
Vertex *to_vertex_;
|
||||
Transaction *transaction_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
} // namespace storage
|
||||
|
39
src/storage/v2/edge_ref.hpp
Normal file
39
src/storage/v2/edge_ref.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "storage/v2/id_types.hpp"
|
||||
|
||||
namespace storage {
|
||||
|
||||
// Forward declaration because we only store a pointer here.
|
||||
struct Edge;
|
||||
|
||||
struct EdgeRef {
|
||||
explicit EdgeRef(Gid gid) : gid(gid) {}
|
||||
explicit EdgeRef(Edge *ptr) : ptr(ptr) {}
|
||||
|
||||
union {
|
||||
Gid gid;
|
||||
Edge *ptr;
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(Gid) == sizeof(Edge *),
|
||||
"The Gid should be the same size as an Edge *!");
|
||||
static_assert(std::is_standard_layout_v<Gid>,
|
||||
"The Gid must have a standard layout!");
|
||||
static_assert(std::is_standard_layout_v<Edge *>,
|
||||
"The Edge * must have a standard layout!");
|
||||
static_assert(std::is_standard_layout_v<EdgeRef>,
|
||||
"The EdgeRef must have a standard layout!");
|
||||
|
||||
inline bool operator==(const EdgeRef &a, const EdgeRef &b) {
|
||||
return a.gid == b.gid;
|
||||
}
|
||||
|
||||
inline bool operator!=(const EdgeRef &a, const EdgeRef &b) {
|
||||
return a.gid != b.gid;
|
||||
}
|
||||
|
||||
} // namespace storage
|
@ -355,7 +355,7 @@ LabelIndex::Iterable::Iterator::Iterator(
|
||||
Iterable *self, utils::SkipList<Entry>::Iterator index_iterator)
|
||||
: self_(self),
|
||||
index_iterator_(index_iterator),
|
||||
current_vertex_accessor_(nullptr, nullptr, nullptr),
|
||||
current_vertex_accessor_(nullptr, nullptr, nullptr, self_->config_),
|
||||
current_vertex_(nullptr) {
|
||||
AdvanceUntilValid();
|
||||
}
|
||||
@ -375,7 +375,8 @@ void LabelIndex::Iterable::Iterator::AdvanceUntilValid() {
|
||||
self_->transaction_, self_->view_)) {
|
||||
current_vertex_ = index_iterator_->vertex;
|
||||
current_vertex_accessor_ =
|
||||
VertexAccessor{current_vertex_, self_->transaction_, self_->indices_};
|
||||
VertexAccessor{current_vertex_, self_->transaction_, self_->indices_,
|
||||
self_->config_};
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -383,12 +384,14 @@ void LabelIndex::Iterable::Iterator::AdvanceUntilValid() {
|
||||
|
||||
LabelIndex::Iterable::Iterable(utils::SkipList<Entry>::Accessor index_accessor,
|
||||
LabelId label, View view,
|
||||
Transaction *transaction, Indices *indices)
|
||||
Transaction *transaction, Indices *indices,
|
||||
Config::Items config)
|
||||
: index_accessor_(std::move(index_accessor)),
|
||||
label_(label),
|
||||
view_(view),
|
||||
transaction_(transaction),
|
||||
indices_(indices) {}
|
||||
indices_(indices),
|
||||
config_(config) {}
|
||||
|
||||
bool LabelPropertyIndex::Entry::operator<(const Entry &rhs) {
|
||||
if (PropertyValueLess(value, rhs.value)) {
|
||||
@ -519,7 +522,7 @@ LabelPropertyIndex::Iterable::Iterator::Iterator(
|
||||
Iterable *self, utils::SkipList<Entry>::Iterator index_iterator)
|
||||
: self_(self),
|
||||
index_iterator_(index_iterator),
|
||||
current_vertex_accessor_(nullptr, nullptr, nullptr),
|
||||
current_vertex_accessor_(nullptr, nullptr, nullptr, self_->config_),
|
||||
current_vertex_(nullptr) {
|
||||
AdvanceUntilValid();
|
||||
}
|
||||
@ -567,7 +570,8 @@ void LabelPropertyIndex::Iterable::Iterator::AdvanceUntilValid() {
|
||||
self_->transaction_, self_->view_)) {
|
||||
current_vertex_ = index_iterator_->vertex;
|
||||
current_vertex_accessor_ =
|
||||
VertexAccessor(current_vertex_, self_->transaction_, self_->indices_);
|
||||
VertexAccessor(current_vertex_, self_->transaction_, self_->indices_,
|
||||
self_->config_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -578,7 +582,7 @@ LabelPropertyIndex::Iterable::Iterable(
|
||||
PropertyId property,
|
||||
const std::optional<utils::Bound<PropertyValue>> &lower_bound,
|
||||
const std::optional<utils::Bound<PropertyValue>> &upper_bound, View view,
|
||||
Transaction *transaction, Indices *indices)
|
||||
Transaction *transaction, Indices *indices, Config::Items config)
|
||||
: index_accessor_(std::move(index_accessor)),
|
||||
label_(label),
|
||||
property_(property),
|
||||
@ -586,7 +590,8 @@ LabelPropertyIndex::Iterable::Iterable(
|
||||
upper_bound_(upper_bound),
|
||||
view_(view),
|
||||
transaction_(transaction),
|
||||
indices_(indices) {}
|
||||
indices_(indices),
|
||||
config_(config) {}
|
||||
|
||||
LabelPropertyIndex::Iterable::Iterator LabelPropertyIndex::Iterable::begin() {
|
||||
auto index_iterator = index_accessor_.begin();
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "storage/v2/config.hpp"
|
||||
#include "storage/v2/property_value.hpp"
|
||||
#include "storage/v2/transaction.hpp"
|
||||
#include "storage/v2/vertex_accessor.hpp"
|
||||
@ -40,7 +41,8 @@ class LabelIndex {
|
||||
};
|
||||
|
||||
public:
|
||||
explicit LabelIndex(Indices *indices) : indices_(indices) {}
|
||||
LabelIndex(Indices *indices, Config::Items config)
|
||||
: indices_(indices), config_(config) {}
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx);
|
||||
@ -61,7 +63,8 @@ class LabelIndex {
|
||||
class Iterable {
|
||||
public:
|
||||
Iterable(utils::SkipList<Entry>::Accessor index_accessor, LabelId label,
|
||||
View view, Transaction *transaction, Indices *indices);
|
||||
View view, Transaction *transaction, Indices *indices,
|
||||
Config::Items config);
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
@ -96,6 +99,7 @@ class LabelIndex {
|
||||
View view_;
|
||||
Transaction *transaction_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
/// Returns an self with vertices visible from the given transaction.
|
||||
@ -103,7 +107,8 @@ class LabelIndex {
|
||||
auto it = index_.find(label);
|
||||
CHECK(it != index_.end())
|
||||
<< "Index for label " << label.AsUint() << " doesn't exist";
|
||||
return Iterable(it->second.access(), label, view, transaction, indices_);
|
||||
return Iterable(it->second.access(), label, view, transaction, indices_,
|
||||
config_);
|
||||
}
|
||||
|
||||
int64_t ApproximateVertexCount(LabelId label) {
|
||||
@ -114,8 +119,9 @@ class LabelIndex {
|
||||
}
|
||||
|
||||
private:
|
||||
Indices *indices_;
|
||||
std::map<LabelId, utils::SkipList<Entry>> index_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
class LabelPropertyIndex {
|
||||
@ -133,7 +139,8 @@ class LabelPropertyIndex {
|
||||
};
|
||||
|
||||
public:
|
||||
explicit LabelPropertyIndex(Indices *indices) : indices_(indices) {}
|
||||
LabelPropertyIndex(Indices *indices, Config::Items config)
|
||||
: indices_(indices), config_(config) {}
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx);
|
||||
@ -166,7 +173,8 @@ class LabelPropertyIndex {
|
||||
PropertyId property,
|
||||
const std::optional<utils::Bound<PropertyValue>> &lower_bound,
|
||||
const std::optional<utils::Bound<PropertyValue>> &upper_bound,
|
||||
View view, Transaction *transaction, Indices *indices);
|
||||
View view, Transaction *transaction, Indices *indices,
|
||||
Config::Items config);
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
@ -207,6 +215,7 @@ class LabelPropertyIndex {
|
||||
View view_;
|
||||
Transaction *transaction_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
/// @throw std::bad_alloc if unable to copy a PropertyValue
|
||||
@ -220,7 +229,7 @@ class LabelPropertyIndex {
|
||||
<< "Index for label " << label.AsUint() << " and property "
|
||||
<< property.AsUint() << " doesn't exist";
|
||||
return Iterable(it->second.access(), label, property, lower_bound,
|
||||
upper_bound, view, transaction, indices_);
|
||||
upper_bound, view, transaction, indices_, config_);
|
||||
}
|
||||
|
||||
int64_t ApproximateVertexCount(LabelId label, PropertyId property) const {
|
||||
@ -240,12 +249,14 @@ class LabelPropertyIndex {
|
||||
const std::optional<utils::Bound<PropertyValue>> &upper) const;
|
||||
|
||||
private:
|
||||
Indices *indices_;
|
||||
std::map<std::pair<LabelId, PropertyId>, utils::SkipList<Entry>> index_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
struct Indices {
|
||||
Indices() : label_index(this), label_property_index(this) {}
|
||||
explicit Indices(Config::Items config)
|
||||
: label_index(this, config), label_property_index(this, config) {}
|
||||
|
||||
// Disable copy and move because members hold pointer to `this`.
|
||||
Indices(const Indices &) = delete;
|
||||
|
@ -12,6 +12,7 @@ enum class Error : uint8_t {
|
||||
SERIALIZATION_ERROR,
|
||||
DELETED_OBJECT,
|
||||
VERTEX_HAS_EDGES,
|
||||
PROPERTIES_DISABLED,
|
||||
};
|
||||
|
||||
template <class TValue>
|
||||
|
@ -15,9 +15,10 @@ namespace storage {
|
||||
|
||||
auto AdvanceToVisibleVertex(utils::SkipList<Vertex>::Iterator it,
|
||||
utils::SkipList<Vertex>::Iterator end,
|
||||
Transaction *tx, View view, Indices *indices) {
|
||||
Transaction *tx, View view, Indices *indices,
|
||||
Config::Items config) {
|
||||
while (it != end) {
|
||||
auto maybe_vertex = VertexAccessor::Create(&*it, tx, indices, view);
|
||||
auto maybe_vertex = VertexAccessor::Create(&*it, tx, indices, config, view);
|
||||
if (!maybe_vertex) {
|
||||
++it;
|
||||
continue;
|
||||
@ -32,20 +33,20 @@ AllVerticesIterable::Iterator::Iterator(AllVerticesIterable *self,
|
||||
: self_(self),
|
||||
it_(AdvanceToVisibleVertex(it, self->vertices_accessor_.end(),
|
||||
self->transaction_, self->view_,
|
||||
self->indices_)) {}
|
||||
self->indices_, self->config_)) {}
|
||||
|
||||
VertexAccessor AllVerticesIterable::Iterator::operator*() const {
|
||||
// TODO: current vertex accessor could be cached to avoid reconstructing every
|
||||
// time
|
||||
return *VertexAccessor::Create(&*it_, self_->transaction_, self_->indices_,
|
||||
self_->view_);
|
||||
self_->config_, self_->view_);
|
||||
}
|
||||
|
||||
AllVerticesIterable::Iterator &AllVerticesIterable::Iterator::operator++() {
|
||||
++it_;
|
||||
it_ = AdvanceToVisibleVertex(it_, self_->vertices_accessor_.end(),
|
||||
self_->transaction_, self_->view_,
|
||||
self_->indices_);
|
||||
self_->indices_, self_->config_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -290,7 +291,7 @@ bool VerticesIterable::Iterator::operator==(const Iterator &other) const {
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Storage(Config config) : config_(config) {
|
||||
Storage::Storage(Config config) : indices_(config.items), config_(config) {
|
||||
if (config_.gc.type == Config::Gc::Type::PERIODIC) {
|
||||
gc_runner_.Run("Storage GC", config_.gc.interval,
|
||||
[this] { this->CollectGarbage(); });
|
||||
@ -310,12 +311,14 @@ Storage::Accessor::Accessor(Storage *storage)
|
||||
// during exclusive operations.
|
||||
storage_guard_(storage_->main_lock_),
|
||||
transaction_(storage->CreateTransaction()),
|
||||
is_transaction_active_(true) {}
|
||||
is_transaction_active_(true),
|
||||
config_(storage->config_.items) {}
|
||||
|
||||
Storage::Accessor::Accessor(Accessor &&other) noexcept
|
||||
: storage_(other.storage_),
|
||||
transaction_(std::move(other.transaction_)),
|
||||
is_transaction_active_(other.is_transaction_active_) {
|
||||
is_transaction_active_(other.is_transaction_active_),
|
||||
config_(other.config_) {
|
||||
// Don't allow the other accessor to abort our transaction in destructor.
|
||||
other.is_transaction_active_ = false;
|
||||
}
|
||||
@ -334,7 +337,7 @@ VertexAccessor Storage::Accessor::CreateVertex() {
|
||||
CHECK(inserted) << "The vertex must be inserted here!";
|
||||
CHECK(it != acc.end()) << "Invalid Vertex accessor!";
|
||||
delta->prev.Set(&*it);
|
||||
return VertexAccessor{&*it, &transaction_, &storage_->indices_};
|
||||
return VertexAccessor(&*it, &transaction_, &storage_->indices_, config_);
|
||||
}
|
||||
|
||||
std::optional<VertexAccessor> Storage::Accessor::FindVertex(Gid gid,
|
||||
@ -342,7 +345,8 @@ std::optional<VertexAccessor> Storage::Accessor::FindVertex(Gid gid,
|
||||
auto acc = storage_->vertices_.access();
|
||||
auto it = acc.find(gid);
|
||||
if (it == acc.end()) return std::nullopt;
|
||||
return VertexAccessor::Create(&*it, &transaction_, &storage_->indices_, view);
|
||||
return VertexAccessor::Create(&*it, &transaction_, &storage_->indices_,
|
||||
config_, view);
|
||||
}
|
||||
|
||||
Result<bool> Storage::Accessor::DeleteVertex(VertexAccessor *vertex) {
|
||||
@ -373,8 +377,8 @@ Result<bool> Storage::Accessor::DetachDeleteVertex(VertexAccessor *vertex) {
|
||||
"accessor when deleting a vertex!";
|
||||
auto vertex_ptr = vertex->vertex_;
|
||||
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> out_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> out_edges;
|
||||
|
||||
{
|
||||
std::lock_guard<utils::SpinLock> guard(vertex_ptr->lock);
|
||||
@ -390,8 +394,8 @@ Result<bool> Storage::Accessor::DetachDeleteVertex(VertexAccessor *vertex) {
|
||||
|
||||
for (const auto &item : in_edges) {
|
||||
auto [edge_type, from_vertex, edge] = item;
|
||||
EdgeAccessor e{edge, edge_type, from_vertex,
|
||||
vertex_ptr, &transaction_, &storage_->indices_};
|
||||
EdgeAccessor e(edge, edge_type, from_vertex, vertex_ptr, &transaction_,
|
||||
&storage_->indices_, config_);
|
||||
auto ret = DeleteEdge(&e);
|
||||
if (ret.HasError()) {
|
||||
CHECK(ret.GetError() == Error::SERIALIZATION_ERROR)
|
||||
@ -401,8 +405,8 @@ Result<bool> Storage::Accessor::DetachDeleteVertex(VertexAccessor *vertex) {
|
||||
}
|
||||
for (const auto &item : out_edges) {
|
||||
auto [edge_type, to_vertex, edge] = item;
|
||||
EdgeAccessor e{edge, edge_type, vertex_ptr,
|
||||
to_vertex, &transaction_, &storage_->indices_};
|
||||
EdgeAccessor e(edge, edge_type, vertex_ptr, to_vertex, &transaction_,
|
||||
&storage_->indices_, config_);
|
||||
auto ret = DeleteEdge(&e);
|
||||
if (ret.HasError()) {
|
||||
CHECK(ret.GetError() == Error::SERIALIZATION_ERROR)
|
||||
@ -466,14 +470,18 @@ Result<EdgeAccessor> Storage::Accessor::CreateEdge(VertexAccessor *from,
|
||||
if (to_vertex->deleted) return Error::DELETED_OBJECT;
|
||||
}
|
||||
|
||||
auto gid = storage_->edge_id_.fetch_add(1, std::memory_order_acq_rel);
|
||||
auto acc = storage_->edges_.access();
|
||||
auto delta = CreateDeleteObjectDelta(&transaction_);
|
||||
auto [it, inserted] = acc.insert(Edge{storage::Gid::FromUint(gid), delta});
|
||||
CHECK(inserted) << "The edge must be inserted here!";
|
||||
CHECK(it != acc.end()) << "Invalid Edge accessor!";
|
||||
auto edge = &*it;
|
||||
delta->prev.Set(&*it);
|
||||
auto gid = storage::Gid::FromUint(
|
||||
storage_->edge_id_.fetch_add(1, std::memory_order_acq_rel));
|
||||
EdgeRef edge(gid);
|
||||
if (config_.properties_on_edges) {
|
||||
auto acc = storage_->edges_.access();
|
||||
auto delta = CreateDeleteObjectDelta(&transaction_);
|
||||
auto [it, inserted] = acc.insert(Edge(gid, delta));
|
||||
CHECK(inserted) << "The edge must be inserted here!";
|
||||
CHECK(it != acc.end()) << "Invalid Edge accessor!";
|
||||
edge = EdgeRef(&*it);
|
||||
delta->prev.Set(&*it);
|
||||
}
|
||||
|
||||
CreateAndLinkDelta(&transaction_, from_vertex, Delta::RemoveOutEdgeTag(),
|
||||
edge_type, to_vertex, edge);
|
||||
@ -483,23 +491,27 @@ Result<EdgeAccessor> Storage::Accessor::CreateEdge(VertexAccessor *from,
|
||||
edge_type, from_vertex, edge);
|
||||
to_vertex->in_edges.emplace_back(edge_type, from_vertex, edge);
|
||||
|
||||
return EdgeAccessor{edge, edge_type, from_vertex,
|
||||
to_vertex, &transaction_, &storage_->indices_};
|
||||
return EdgeAccessor(edge, edge_type, from_vertex, to_vertex, &transaction_,
|
||||
&storage_->indices_, config_);
|
||||
}
|
||||
|
||||
Result<bool> Storage::Accessor::DeleteEdge(EdgeAccessor *edge) {
|
||||
CHECK(edge->transaction_ == &transaction_)
|
||||
<< "EdgeAccessor must be from the same transaction as the storage "
|
||||
"accessor when deleting an edge!";
|
||||
auto edge_ptr = edge->edge_;
|
||||
auto edge_ref = edge->edge_;
|
||||
auto edge_type = edge->edge_type_;
|
||||
|
||||
std::lock_guard<utils::SpinLock> guard(edge_ptr->lock);
|
||||
std::unique_lock<utils::SpinLock> guard;
|
||||
if (config_.properties_on_edges) {
|
||||
auto edge_ptr = edge_ref.ptr;
|
||||
guard = std::unique_lock<utils::SpinLock>(edge_ptr->lock);
|
||||
|
||||
if (!PrepareForWrite(&transaction_, edge_ptr))
|
||||
return Error::SERIALIZATION_ERROR;
|
||||
if (!PrepareForWrite(&transaction_, edge_ptr))
|
||||
return Error::SERIALIZATION_ERROR;
|
||||
|
||||
if (edge_ptr->deleted) return false;
|
||||
if (edge_ptr->deleted) return false;
|
||||
}
|
||||
|
||||
auto from_vertex = edge->from_vertex_;
|
||||
auto to_vertex = edge->to_vertex_;
|
||||
@ -529,32 +541,43 @@ Result<bool> Storage::Accessor::DeleteEdge(EdgeAccessor *edge) {
|
||||
CHECK(!to_vertex->deleted) << "Invalid database state!";
|
||||
}
|
||||
|
||||
CreateAndLinkDelta(&transaction_, edge_ptr, Delta::RecreateObjectTag());
|
||||
edge_ptr->deleted = true;
|
||||
auto delete_edge_from_storage = [&edge_type, &edge_ref, this](auto *vertex,
|
||||
auto *edges) {
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link(edge_type, vertex, edge_ref);
|
||||
auto it = std::find(edges->begin(), edges->end(), link);
|
||||
if (config_.properties_on_edges) {
|
||||
CHECK(it != edges->end()) << "Invalid database state!";
|
||||
} else if (it == edges->end()) {
|
||||
return false;
|
||||
}
|
||||
std::swap(*it, *edges->rbegin());
|
||||
edges->pop_back();
|
||||
return true;
|
||||
};
|
||||
|
||||
auto op1 = delete_edge_from_storage(to_vertex, &from_vertex->out_edges);
|
||||
auto op2 = delete_edge_from_storage(from_vertex, &to_vertex->in_edges);
|
||||
|
||||
if (config_.properties_on_edges) {
|
||||
CHECK((op1 && op2)) << "Invalid database state!";
|
||||
} else {
|
||||
CHECK((op1 && op2) || (!op1 && !op2)) << "Invalid database state!";
|
||||
if (!op1 && !op2) {
|
||||
// The edge is already deleted.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_.properties_on_edges) {
|
||||
auto edge_ptr = edge_ref.ptr;
|
||||
CreateAndLinkDelta(&transaction_, edge_ptr, Delta::RecreateObjectTag());
|
||||
edge_ptr->deleted = true;
|
||||
}
|
||||
|
||||
CreateAndLinkDelta(&transaction_, from_vertex, Delta::AddOutEdgeTag(),
|
||||
edge_type, to_vertex, edge_ptr);
|
||||
{
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{edge_type, to_vertex,
|
||||
edge_ptr};
|
||||
auto it = std::find(from_vertex->out_edges.begin(),
|
||||
from_vertex->out_edges.end(), link);
|
||||
CHECK(it != from_vertex->out_edges.end()) << "Invalid database state!";
|
||||
std::swap(*it, *from_vertex->out_edges.rbegin());
|
||||
from_vertex->out_edges.pop_back();
|
||||
}
|
||||
|
||||
edge_type, to_vertex, edge_ref);
|
||||
CreateAndLinkDelta(&transaction_, to_vertex, Delta::AddInEdgeTag(), edge_type,
|
||||
from_vertex, edge_ptr);
|
||||
{
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{edge_type, from_vertex,
|
||||
edge_ptr};
|
||||
auto it =
|
||||
std::find(to_vertex->in_edges.begin(), to_vertex->in_edges.end(), link);
|
||||
CHECK(it != to_vertex->in_edges.end()) << "Invalid database state!";
|
||||
std::swap(*it, *to_vertex->in_edges.rbegin());
|
||||
to_vertex->in_edges.pop_back();
|
||||
}
|
||||
from_vertex, edge_ref);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -700,7 +723,7 @@ void Storage::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_IN_EDGE: {
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
current->vertex_edge.edge_type, current->vertex_edge.vertex,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->in_edges.begin(),
|
||||
@ -710,7 +733,7 @@ void Storage::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_OUT_EDGE: {
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
current->vertex_edge.edge_type, current->vertex_edge.vertex,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->out_edges.begin(),
|
||||
@ -720,7 +743,7 @@ void Storage::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::REMOVE_IN_EDGE: {
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
current->vertex_edge.edge_type, current->vertex_edge.vertex,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->in_edges.begin(),
|
||||
@ -731,7 +754,7 @@ void Storage::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::REMOVE_OUT_EDGE: {
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
current->vertex_edge.edge_type, current->vertex_edge.vertex,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->out_edges.begin(),
|
||||
|
@ -39,6 +39,7 @@ class AllVerticesIterable final {
|
||||
Transaction *transaction_;
|
||||
View view_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
|
||||
public:
|
||||
class Iterator final {
|
||||
@ -279,6 +280,7 @@ class Storage final {
|
||||
std::shared_lock<utils::RWLock> storage_guard_;
|
||||
Transaction transaction_;
|
||||
bool is_transaction_active_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
Accessor Access() { return Accessor{this}; }
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "utils/spin_lock.hpp"
|
||||
|
||||
#include "storage/v2/delta.hpp"
|
||||
#include "storage/v2/edge.hpp"
|
||||
#include "storage/v2/edge_ref.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
|
||||
namespace storage {
|
||||
@ -24,8 +24,8 @@ struct Vertex {
|
||||
std::vector<LabelId> labels;
|
||||
std::map<PropertyId, storage::PropertyValue> properties;
|
||||
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> out_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> out_edges;
|
||||
|
||||
utils::SpinLock lock;
|
||||
bool deleted;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "storage/v2/edge_accessor.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
#include "storage/v2/indices.hpp"
|
||||
#include "storage/v2/mvcc.hpp"
|
||||
|
||||
@ -11,6 +12,7 @@ namespace storage {
|
||||
std::optional<VertexAccessor> VertexAccessor::Create(Vertex *vertex,
|
||||
Transaction *transaction,
|
||||
Indices *indices,
|
||||
Config::Items config,
|
||||
View view) {
|
||||
bool is_visible = true;
|
||||
Delta *delta = nullptr;
|
||||
@ -41,7 +43,7 @@ std::optional<VertexAccessor> VertexAccessor::Create(Vertex *vertex,
|
||||
}
|
||||
});
|
||||
if (!is_visible) return std::nullopt;
|
||||
return VertexAccessor{vertex, transaction, indices};
|
||||
return VertexAccessor{vertex, transaction, indices, config};
|
||||
}
|
||||
|
||||
Result<bool> VertexAccessor::AddLabel(LabelId label) {
|
||||
@ -317,7 +319,7 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(
|
||||
|
||||
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
|
||||
const std::vector<EdgeTypeId> &edge_types, View view) const {
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> in_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> in_edges;
|
||||
bool deleted = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
@ -331,7 +333,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
|
||||
switch (delta.action) {
|
||||
case Delta::Action::ADD_IN_EDGE: {
|
||||
// Add the edge because we don't see the removal.
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
|
||||
delta.vertex_edge.edge};
|
||||
auto it = std::find(in_edges.begin(), in_edges.end(), link);
|
||||
@ -341,7 +343,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
|
||||
}
|
||||
case Delta::Action::REMOVE_IN_EDGE: {
|
||||
// Remove the label because we don't see the addition.
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
|
||||
delta.vertex_edge.edge};
|
||||
auto it = std::find(in_edges.begin(), in_edges.end(), link);
|
||||
@ -376,7 +378,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
|
||||
if (edge_types.empty() || std::find(edge_types.begin(), edge_types.end(),
|
||||
edge_type) != edge_types.end()) {
|
||||
ret.emplace_back(edge, edge_type, from_vertex, vertex_, transaction_,
|
||||
indices_);
|
||||
indices_, config_);
|
||||
}
|
||||
}
|
||||
return std::move(ret);
|
||||
@ -384,7 +386,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(
|
||||
|
||||
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
|
||||
const std::vector<EdgeTypeId> &edge_types, View view) const {
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, Edge *>> out_edges;
|
||||
std::vector<std::tuple<EdgeTypeId, Vertex *, EdgeRef>> out_edges;
|
||||
bool deleted = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
@ -398,7 +400,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
|
||||
switch (delta.action) {
|
||||
case Delta::Action::ADD_OUT_EDGE: {
|
||||
// Add the edge because we don't see the removal.
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
|
||||
delta.vertex_edge.edge};
|
||||
auto it = std::find(out_edges.begin(), out_edges.end(), link);
|
||||
@ -408,7 +410,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
|
||||
}
|
||||
case Delta::Action::REMOVE_OUT_EDGE: {
|
||||
// Remove the label because we don't see the addition.
|
||||
std::tuple<EdgeTypeId, Vertex *, Edge *> link{
|
||||
std::tuple<EdgeTypeId, Vertex *, EdgeRef> link{
|
||||
delta.vertex_edge.edge_type, delta.vertex_edge.vertex,
|
||||
delta.vertex_edge.edge};
|
||||
auto it = std::find(out_edges.begin(), out_edges.end(), link);
|
||||
@ -443,7 +445,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(
|
||||
if (edge_types.empty() || std::find(edge_types.begin(), edge_types.end(),
|
||||
edge_type) != edge_types.end()) {
|
||||
ret.emplace_back(edge, edge_type, vertex_, to_vertex, transaction_,
|
||||
indices_);
|
||||
indices_, config_);
|
||||
}
|
||||
}
|
||||
return std::move(ret);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "storage/v2/vertex.hpp"
|
||||
|
||||
#include "storage/v2/config.hpp"
|
||||
#include "storage/v2/result.hpp"
|
||||
#include "storage/v2/transaction.hpp"
|
||||
#include "storage/v2/view.hpp"
|
||||
@ -19,12 +20,17 @@ class VertexAccessor final {
|
||||
friend class Storage;
|
||||
|
||||
public:
|
||||
VertexAccessor(Vertex *vertex, Transaction *transaction, Indices *indices)
|
||||
: vertex_(vertex), transaction_(transaction), indices_(indices) {}
|
||||
VertexAccessor(Vertex *vertex, Transaction *transaction, Indices *indices,
|
||||
Config::Items config)
|
||||
: vertex_(vertex),
|
||||
transaction_(transaction),
|
||||
indices_(indices),
|
||||
config_(config) {}
|
||||
|
||||
static std::optional<VertexAccessor> Create(Vertex *vertex,
|
||||
Transaction *transaction,
|
||||
Indices *indices, View view);
|
||||
Indices *indices,
|
||||
Config::Items config, View view);
|
||||
|
||||
/// Add a label and return `true` if insertion took place.
|
||||
/// `false` is returned if the label already existed.
|
||||
@ -84,6 +90,7 @@ class VertexAccessor final {
|
||||
Vertex *vertex_;
|
||||
Transaction *transaction_;
|
||||
Indices *indices_;
|
||||
Config::Items config_;
|
||||
};
|
||||
|
||||
} // namespace storage
|
||||
|
@ -1,12 +1,20 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
class StorageEdgeTest : public ::testing::TestWithParam<bool> {};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EdgesWithProperties, StorageEdgeTest,
|
||||
::testing::Values(true));
|
||||
INSTANTIATE_TEST_CASE_P(EdgesWithoutProperties, StorageEdgeTest,
|
||||
::testing::Values(false));
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromSmallerCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromSmallerCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -173,8 +181,8 @@ TEST(StorageV2, EdgeCreateFromSmallerCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromLargerCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromLargerCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -341,8 +349,8 @@ TEST(StorageV2, EdgeCreateFromLargerCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromSameCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromSameCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@ -479,8 +487,8 @@ TEST(StorageV2, EdgeCreateFromSameCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromSmallerAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -742,8 +750,8 @@ TEST(StorageV2, EdgeCreateFromSmallerAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromLargerAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -1005,8 +1013,8 @@ TEST(StorageV2, EdgeCreateFromLargerAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeCreateFromSameAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@ -1216,8 +1224,8 @@ TEST(StorageV2, EdgeCreateFromSameAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -1478,8 +1486,8 @@ TEST(StorageV2, EdgeDeleteFromSmallerCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromLargerCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -1740,8 +1748,8 @@ TEST(StorageV2, EdgeDeleteFromLargerCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromSameCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@ -1950,8 +1958,8 @@ TEST(StorageV2, EdgeDeleteFromSameCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromSmallerAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -2360,8 +2368,8 @@ TEST(StorageV2, EdgeDeleteFromSmallerAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromLargerAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -2771,8 +2779,8 @@ TEST(StorageV2, EdgeDeleteFromLargerAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, EdgeDeleteFromSameAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@ -3103,8 +3111,8 @@ TEST(StorageV2, EdgeDeleteFromSameAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, VertexDetachDeleteSingleCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -3247,8 +3255,8 @@ TEST(StorageV2, VertexDetachDeleteSingleCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, VertexDetachDeleteMultipleCommit) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, VertexDetachDeleteMultipleCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex1 =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_vertex2 =
|
||||
@ -3598,8 +3606,8 @@ TEST(StorageV2, VertexDetachDeleteMultipleCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, VertexDetachDeleteSingleAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, VertexDetachDeleteSingleAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_from =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_to =
|
||||
@ -3850,8 +3858,8 @@ TEST(StorageV2, VertexDetachDeleteSingleAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
|
||||
storage::Storage store;
|
||||
TEST_P(StorageEdgeTest, VertexDetachDeleteMultipleAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = GetParam()}});
|
||||
storage::Gid gid_vertex1 =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
storage::Gid gid_vertex2 =
|
||||
@ -4545,8 +4553,8 @@ TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgePropertyCommit) {
|
||||
storage::Storage store;
|
||||
TEST(StorageWithProperties, EdgePropertyCommit) {
|
||||
storage::Storage store({.items = {.properties_on_edges = true}});
|
||||
storage::Gid gid =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
{
|
||||
@ -4682,8 +4690,8 @@ TEST(StorageV2, EdgePropertyCommit) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgePropertyAbort) {
|
||||
storage::Storage store;
|
||||
TEST(StorageWithProperties, EdgePropertyAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = true}});
|
||||
storage::Gid gid =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
@ -4990,8 +4998,8 @@ TEST(StorageV2, EdgePropertyAbort) {
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageV2, EdgePropertySerializationError) {
|
||||
storage::Storage store;
|
||||
TEST(StorageWithProperties, EdgePropertySerializationError) {
|
||||
storage::Storage store({.items = {.properties_on_edges = true}});
|
||||
storage::Gid gid =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
{
|
||||
@ -5099,3 +5107,74 @@ TEST(StorageV2, EdgePropertySerializationError) {
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageWithoutProperties, EdgePropertyAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = false}});
|
||||
storage::Gid gid =
|
||||
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
auto et = acc.NameToEdgeType("et5");
|
||||
auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue();
|
||||
ASSERT_EQ(edge.EdgeType(), et);
|
||||
ASSERT_EQ(edge.FromVertex(), vertex);
|
||||
ASSERT_EQ(edge.ToVertex(), vertex);
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
auto property = acc.NameToProperty("property5");
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
{
|
||||
auto res =
|
||||
edge.SetProperty(property, storage::PropertyValue("temporary"));
|
||||
ASSERT_TRUE(res.HasError());
|
||||
ASSERT_EQ(res.GetError(), storage::Error::PROPERTIES_DISABLED);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
{
|
||||
auto res = edge.SetProperty(property, storage::PropertyValue("nandare"));
|
||||
ASSERT_TRUE(res.HasError());
|
||||
ASSERT_EQ(res.GetError(), storage::Error::PROPERTIES_DISABLED);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
auto property = acc.NameToProperty("property5");
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::OLD)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::OLD)->size(), 0);
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW)->size(), 0);
|
||||
|
||||
auto other_property = acc.NameToProperty("other");
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(other_property, storage::View::OLD)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(other_property, storage::View::NEW)->IsNull());
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user