Introduce VertexData
This commit is contained in:
parent
32322d39b8
commit
0cf440519e
@ -17,6 +17,7 @@ set(storage_v3_src_files
|
||||
shard_rsm.cpp
|
||||
bindings/typed_value.cpp
|
||||
expr.cpp
|
||||
vertex.cpp
|
||||
request_helper.cpp)
|
||||
|
||||
# ######################
|
||||
|
@ -15,13 +15,13 @@
|
||||
#include "storage/v3/edge_ref.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "storage/v3/vertex.hpp"
|
||||
#include "storage/v3/vertex_id.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
// Forward declarations because we only store pointers here.
|
||||
struct Vertex;
|
||||
struct Edge;
|
||||
struct Delta;
|
||||
struct CommitInfo;
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
struct Vertex;
|
||||
using EdgeContainer = std::map<Gid, Edge>;
|
||||
|
||||
struct Edge {
|
||||
Edge(Gid gid, Delta *delta) : gid(gid), deleted(false), delta(delta) {
|
||||
@ -34,13 +34,13 @@ struct Edge {
|
||||
PropertyStore properties;
|
||||
|
||||
bool deleted;
|
||||
// uint8_t PAD;
|
||||
uint8_t PAD;
|
||||
// uint16_t PAD;
|
||||
|
||||
Delta *delta;
|
||||
};
|
||||
|
||||
static_assert(alignof(Edge) >= 8, "The Edge should be aligned to at least 8!");
|
||||
// static_assert(alignof(Edge) >= 8, "The Edge should be aligned to at least 8!");
|
||||
|
||||
inline bool operator==(const Edge &first, const Edge &second) { return first.gid == second.gid; }
|
||||
inline bool operator<(const Edge &first, const Edge &second) { return first.gid < second.gid; }
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
struct Vertex;
|
||||
class VertexAccessor;
|
||||
struct Indices;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "storage/v3/mvcc.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "storage/v3/schemas.hpp"
|
||||
#include "storage/v3/vertex.hpp"
|
||||
#include "utils/bound.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/memory_tracker.hpp"
|
||||
@ -57,9 +58,9 @@ bool AnyVersionHasLabel(const Vertex &vertex, LabelId label, uint64_t timestamp)
|
||||
bool deleted{false};
|
||||
const Delta *delta{nullptr};
|
||||
{
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
deleted = vertex.deleted;
|
||||
delta = vertex.delta;
|
||||
has_label = utils::Contains(vertex.second.labels, label);
|
||||
deleted = vertex.second.deleted;
|
||||
delta = vertex.second.delta;
|
||||
}
|
||||
if (!deleted && has_label) {
|
||||
return true;
|
||||
@ -109,10 +110,10 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label, PropertyId
|
||||
bool deleted{false};
|
||||
const Delta *delta{nullptr};
|
||||
{
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value);
|
||||
deleted = vertex.deleted;
|
||||
delta = vertex.delta;
|
||||
has_label = utils::Contains(vertex.second.labels, label);
|
||||
current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
|
||||
deleted = vertex.second.deleted;
|
||||
delta = vertex.second.delta;
|
||||
}
|
||||
|
||||
if (!deleted && has_label && current_value_equal_to_value) {
|
||||
@ -167,9 +168,9 @@ bool CurrentVersionHasLabel(const Vertex &vertex, LabelId label, Transaction *tr
|
||||
bool has_label{false};
|
||||
const Delta *delta{nullptr};
|
||||
{
|
||||
deleted = vertex.deleted;
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
delta = vertex.delta;
|
||||
deleted = vertex.second.deleted;
|
||||
has_label = utils::Contains(vertex.second.labels, label);
|
||||
delta = vertex.second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction, delta, view, [&deleted, &has_label, label](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -218,10 +219,10 @@ bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label, Propert
|
||||
bool current_value_equal_to_value = value.IsNull();
|
||||
const Delta *delta{nullptr};
|
||||
{
|
||||
deleted = vertex.deleted;
|
||||
has_label = utils::Contains(vertex.labels, label);
|
||||
current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value);
|
||||
delta = vertex.delta;
|
||||
deleted = vertex.second.deleted;
|
||||
has_label = utils::Contains(vertex.second.labels, label);
|
||||
current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
|
||||
delta = vertex.second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction, delta, view,
|
||||
[&deleted, &has_label, ¤t_value_equal_to_value, key, label, &value](const Delta &delta) {
|
||||
@ -282,8 +283,8 @@ bool LabelIndex::CreateIndex(LabelId label, VertexContainer &vertices) {
|
||||
}
|
||||
try {
|
||||
auto acc = it->second.access();
|
||||
for ([[maybe_unused]] auto &[pk, vertex] : vertices) {
|
||||
if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
|
||||
for ([[maybe_unused]] auto &vertex : vertices) {
|
||||
if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
|
||||
continue;
|
||||
}
|
||||
acc.insert(Entry{&vertex, 0});
|
||||
@ -395,7 +396,7 @@ void LabelPropertyIndex::UpdateOnAddLabel(LabelId label, Vertex *vertex, const T
|
||||
if (label_prop.first != label) {
|
||||
continue;
|
||||
}
|
||||
auto prop_value = vertex->properties.GetProperty(label_prop.second);
|
||||
auto prop_value = vertex->second.properties.GetProperty(label_prop.second);
|
||||
if (!prop_value.IsNull()) {
|
||||
index.emplace(prop_value, Entry{prop_value, vertex, tx.start_timestamp.logical_id});
|
||||
}
|
||||
@ -411,7 +412,7 @@ void LabelPropertyIndex::UpdateOnSetProperty(PropertyId property, const Property
|
||||
if (label_prop.second != property) {
|
||||
continue;
|
||||
}
|
||||
if (utils::Contains(vertex->labels, label_prop.first)) {
|
||||
if (VertexHasLabel(*vertex, label_prop.first)) {
|
||||
index.emplace(value, Entry{value, vertex, tx.start_timestamp.logical_id});
|
||||
}
|
||||
}
|
||||
@ -426,11 +427,11 @@ bool LabelPropertyIndex::CreateIndex(LabelId label, PropertyId property, VertexC
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
for ([[maybe_unused]] auto &[pk, vertex] : vertices) {
|
||||
if (vertex.deleted || !utils::Contains(vertex.labels, label)) {
|
||||
for ([[maybe_unused]] auto &vertex : vertices) {
|
||||
if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
|
||||
continue;
|
||||
}
|
||||
auto value = vertex.properties.GetProperty(property);
|
||||
auto value = vertex.second.properties.GetProperty(property);
|
||||
if (value.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "storage/v3/config.hpp"
|
||||
#include "storage/v3/containers.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "storage/v3/transaction.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
|
@ -11,9 +11,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "storage/v3/edge.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "storage/v3/transaction.hpp"
|
||||
#include "storage/v3/vertex.hpp"
|
||||
#include "storage/v3/view.hpp"
|
||||
#include "utils/concepts.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
@ -77,10 +81,18 @@ inline void ApplyDeltasForRead(Transaction *transaction, const Delta *delta, Vie
|
||||
/// transaction) and returns a `bool` value indicating whether the caller can
|
||||
/// proceed with a write operation.
|
||||
template <typename TObj>
|
||||
requires utils::SameAsAnyOf<TObj, Edge, Vertex>
|
||||
inline bool PrepareForWrite(Transaction *transaction, TObj *object) {
|
||||
if (object->delta == nullptr) return true;
|
||||
auto *delta_holder = std::invoke([object]() -> auto * {
|
||||
if constexpr (std::is_same_v<TObj, Vertex>) {
|
||||
return &object->second;
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
});
|
||||
if (delta_holder->delta == nullptr) return true;
|
||||
|
||||
const auto &delta_commit_info = *object->delta->commit_info;
|
||||
const auto &delta_commit_info = *delta_holder->delta->commit_info;
|
||||
if (delta_commit_info.start_or_commit_timestamp == transaction->commit_info->start_or_commit_timestamp ||
|
||||
(delta_commit_info.is_locally_committed &&
|
||||
delta_commit_info.start_or_commit_timestamp < transaction->start_timestamp)) {
|
||||
@ -105,9 +117,17 @@ inline Delta *CreateDeleteObjectDelta(Transaction *transaction) {
|
||||
/// the delta into the object's delta list.
|
||||
/// @throw std::bad_alloc
|
||||
template <typename TObj, class... Args>
|
||||
requires utils::SameAsAnyOf<TObj, Edge, Vertex>
|
||||
inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&...args) {
|
||||
auto delta = &transaction->deltas.emplace_back(std::forward<Args>(args)..., transaction->commit_info.get(),
|
||||
transaction->command_id);
|
||||
auto *delta_holder = std::invoke([object]() -> auto * {
|
||||
if constexpr (std::is_same_v<TObj, Vertex>) {
|
||||
return &object->second;
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
});
|
||||
|
||||
// The operations are written in such order so that both `next` and `prev`
|
||||
// chains are valid at all times. The chains must be valid at all times
|
||||
@ -118,21 +138,21 @@ inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&..
|
||||
// TODO(antaljanosbenjamin): clang-tidy detects (in my opinion a false positive) issue in
|
||||
// `Shard::Accessor::CreateEdge`.
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
|
||||
delta->next = object->delta;
|
||||
delta->next = delta_holder->delta;
|
||||
// 2. We need to set the previous delta of the new delta to the object.
|
||||
delta->prev.Set(object);
|
||||
// 3. We need to set the previous delta of the existing delta to the new
|
||||
// delta. After this point the garbage collector will be able to see the new
|
||||
// delta but won't modify it until we are done with all of our modifications.
|
||||
if (object->delta) {
|
||||
object->delta->prev.Set(delta);
|
||||
if (delta_holder->delta) {
|
||||
delta_holder->delta->prev.Set(delta);
|
||||
}
|
||||
// 4. Finally, we need to set the object's delta to the new delta. The garbage
|
||||
// collector and other transactions will acquire the object lock to read the
|
||||
// delta from the object. Because the lock is held during the whole time this
|
||||
// modification is being done, everybody else will wait until we are fully
|
||||
// done with our modification before they read the object's delta value.
|
||||
object->delta = delta;
|
||||
delta_holder->delta = delta;
|
||||
}
|
||||
|
||||
} // namespace memgraph::storage::v3
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include "io/network/endpoint.hpp"
|
||||
#include "io/time.hpp"
|
||||
#include "storage/v3/containers.hpp"
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/indices.hpp"
|
||||
@ -39,6 +38,7 @@
|
||||
#include "storage/v3/transaction.hpp"
|
||||
#include "storage/v3/vertex.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
#include "storage/v3/view.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
@ -79,7 +79,7 @@ auto AdvanceToVisibleVertex(VertexContainer::iterator it, VertexContainer::itera
|
||||
std::optional<VertexAccessor> *vertex, Transaction *tx, View view, Indices *indices,
|
||||
Config::Items config, const VertexValidator &vertex_validator) {
|
||||
while (it != end) {
|
||||
*vertex = VertexAccessor::Create(&it->second, tx, indices, config, vertex_validator, view);
|
||||
*vertex = VertexAccessor::Create(&*it, tx, indices, config, vertex_validator, view);
|
||||
if (!*vertex) {
|
||||
++it;
|
||||
continue;
|
||||
@ -346,7 +346,7 @@ Shard::Accessor::Accessor(Shard &shard, Transaction &transaction)
|
||||
: shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {}
|
||||
|
||||
ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
||||
const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
|
||||
const std::vector<LabelId> &labels, const PrimaryKey &primary_properties,
|
||||
const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
|
||||
OOMExceptionEnabler oom_exception;
|
||||
const auto schema = shard_->GetSchema(shard_->primary_label_)->second;
|
||||
@ -358,10 +358,10 @@ ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
||||
}
|
||||
|
||||
auto *delta = CreateDeleteObjectDelta(transaction_);
|
||||
auto [it, inserted] = shard_->vertices_.emplace(primary_properties, Vertex(delta, primary_properties));
|
||||
delta->prev.Set(&it->second);
|
||||
auto [it, inserted] = shard_->vertices_.emplace(primary_properties, VertexData{delta});
|
||||
delta->prev.Set(&*it);
|
||||
|
||||
VertexAccessor vertex_acc{&it->second, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
|
||||
VertexAccessor vertex_acc{&*it, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
|
||||
if (!inserted) {
|
||||
return SHARD_ERROR(ErrorCode::VERTEX_ALREADY_INSERTED);
|
||||
}
|
||||
@ -389,7 +389,7 @@ std::optional<VertexAccessor> Shard::Accessor::FindVertex(std::vector<PropertyVa
|
||||
if (it == shard_->vertices_.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return VertexAccessor::Create(&it->second, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
|
||||
return VertexAccessor::Create(&*it, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
|
||||
}
|
||||
|
||||
ShardResult<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexAccessor *vertex) {
|
||||
@ -400,14 +400,15 @@ ShardResult<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexA
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_ptr->deleted) {
|
||||
if (vertex_ptr->second.deleted) {
|
||||
return std::optional<VertexAccessor>{};
|
||||
}
|
||||
|
||||
if (!vertex_ptr->in_edges.empty() || !vertex_ptr->out_edges.empty()) return SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES);
|
||||
if (!vertex_ptr->second.in_edges.empty() || !vertex_ptr->second.out_edges.empty())
|
||||
return SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES);
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
||||
vertex_ptr->deleted = true;
|
||||
vertex_ptr->second.deleted = true;
|
||||
|
||||
return std::make_optional<VertexAccessor>(vertex_ptr, transaction_, &shard_->indices_, config_,
|
||||
shard_->vertex_validator_, true);
|
||||
@ -422,20 +423,20 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
|
||||
"accessor when deleting a vertex!");
|
||||
auto *vertex_ptr = vertex->vertex_;
|
||||
|
||||
std::vector<Vertex::EdgeLink> in_edges;
|
||||
std::vector<Vertex::EdgeLink> out_edges;
|
||||
std::vector<VertexData::EdgeLink> in_edges;
|
||||
std::vector<VertexData::EdgeLink> out_edges;
|
||||
|
||||
{
|
||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_ptr->deleted) return std::optional<ReturnType>{};
|
||||
if (vertex_ptr->second.deleted) return std::optional<ReturnType>{};
|
||||
|
||||
in_edges = vertex_ptr->in_edges;
|
||||
out_edges = vertex_ptr->out_edges;
|
||||
in_edges = vertex_ptr->second.in_edges;
|
||||
out_edges = vertex_ptr->second.out_edges;
|
||||
}
|
||||
|
||||
std::vector<EdgeAccessor> deleted_edges;
|
||||
const VertexId vertex_id{shard_->primary_label_, vertex_ptr->keys};
|
||||
const VertexId vertex_id{shard_->primary_label_, *vertex->PrimaryKey(View::OLD)}; // TODO Replace
|
||||
for (const auto &item : in_edges) {
|
||||
auto [edge_type, from_vertex, edge] = item;
|
||||
EdgeAccessor e(edge, edge_type, from_vertex, vertex_id, transaction_, &shard_->indices_, config_);
|
||||
@ -469,10 +470,10 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
MG_ASSERT(!vertex_ptr->deleted, "Invalid database state!");
|
||||
MG_ASSERT(!vertex_ptr->second.deleted, "Invalid database state!");
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
||||
vertex_ptr->deleted = true;
|
||||
vertex_ptr->second.deleted = true;
|
||||
|
||||
return std::make_optional<ReturnType>(
|
||||
VertexAccessor{vertex_ptr, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, true},
|
||||
@ -494,22 +495,22 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
|
||||
if (from_is_local) {
|
||||
auto it = vertices.find(from_vertex_id.primary_key);
|
||||
MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
|
||||
from_vertex = &it->second;
|
||||
from_vertex = &*it;
|
||||
}
|
||||
|
||||
if (to_is_local) {
|
||||
auto it = vertices.find(to_vertex_id.primary_key);
|
||||
MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
|
||||
to_vertex = &it->second;
|
||||
to_vertex = &*it;
|
||||
}
|
||||
|
||||
if (from_is_local) {
|
||||
if (!PrepareForWrite(transaction_, from_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
if (from_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (from_vertex->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
}
|
||||
if (to_is_local && to_vertex != from_vertex) {
|
||||
if (!PrepareForWrite(transaction_, to_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
if (to_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (to_vertex->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
}
|
||||
|
||||
EdgeRef edge(gid);
|
||||
@ -524,11 +525,11 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
|
||||
|
||||
if (from_is_local) {
|
||||
CreateAndLinkDelta(transaction_, from_vertex, Delta::RemoveOutEdgeTag(), edge_type, to_vertex_id, edge);
|
||||
from_vertex->out_edges.emplace_back(edge_type, to_vertex_id, edge);
|
||||
from_vertex->second.out_edges.emplace_back(edge_type, to_vertex_id, edge);
|
||||
}
|
||||
if (to_is_local) {
|
||||
CreateAndLinkDelta(transaction_, to_vertex, Delta::RemoveInEdgeTag(), edge_type, from_vertex_id, edge);
|
||||
to_vertex->in_edges.emplace_back(edge_type, from_vertex_id, edge);
|
||||
from_vertex->second.in_edges.emplace_back(edge_type, from_vertex_id, edge);
|
||||
}
|
||||
// Increment edge count.
|
||||
++shard_->edge_count_;
|
||||
@ -539,8 +540,8 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
|
||||
|
||||
ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id,
|
||||
const Gid edge_id) {
|
||||
Vertex *from_vertex{nullptr};
|
||||
Vertex *to_vertex{nullptr};
|
||||
VertexContainer::value_type *from_vertex{nullptr};
|
||||
VertexContainer::value_type *to_vertex{nullptr};
|
||||
|
||||
auto &vertices = shard_->vertices_;
|
||||
|
||||
@ -550,13 +551,13 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
|
||||
if (from_is_local) {
|
||||
auto it = vertices.find(from_vertex_id.primary_key);
|
||||
MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
|
||||
from_vertex = &it->second;
|
||||
from_vertex = &*it;
|
||||
}
|
||||
|
||||
if (to_is_local) {
|
||||
auto it = vertices.find(to_vertex_id.primary_key);
|
||||
MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
|
||||
to_vertex = &it->second;
|
||||
to_vertex = &*it;
|
||||
}
|
||||
|
||||
MG_ASSERT(from_is_local || to_is_local, "Trying to delete an edge without having a local vertex");
|
||||
@ -565,13 +566,13 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
|
||||
if (!PrepareForWrite(transaction_, from_vertex)) {
|
||||
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
}
|
||||
MG_ASSERT(!from_vertex->deleted, "Invalid database state!");
|
||||
MG_ASSERT(!from_vertex->second.deleted, "Invalid database state!");
|
||||
}
|
||||
if (to_is_local && to_vertex != from_vertex) {
|
||||
if (!PrepareForWrite(transaction_, to_vertex)) {
|
||||
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
}
|
||||
MG_ASSERT(!to_vertex->deleted, "Invalid database state!");
|
||||
MG_ASSERT(!to_vertex->second.deleted, "Invalid database state!");
|
||||
}
|
||||
|
||||
const auto edge_ref = std::invoke([edge_id, this]() -> EdgeRef {
|
||||
@ -584,9 +585,9 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
|
||||
});
|
||||
|
||||
std::optional<EdgeTypeId> edge_type{};
|
||||
auto delete_edge_from_storage = [&edge_type, &edge_ref, this](std::vector<Vertex::EdgeLink> &edges) mutable {
|
||||
auto delete_edge_from_storage = [&edge_type, &edge_ref, this](std::vector<VertexData::EdgeLink> &edges) mutable {
|
||||
auto it = std::find_if(edges.begin(), edges.end(),
|
||||
[&edge_ref](const Vertex::EdgeLink &link) { return std::get<2>(link) == edge_ref; });
|
||||
[&edge_ref](const VertexData::EdgeLink &link) { return std::get<2>(link) == edge_ref; });
|
||||
if (config_.properties_on_edges) {
|
||||
MG_ASSERT(it != edges.end(), "Invalid database state!");
|
||||
} else if (it == edges.end()) {
|
||||
@ -598,8 +599,8 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
|
||||
return true;
|
||||
};
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.NonNullParamChecker)
|
||||
auto success_on_to = to_is_local ? delete_edge_from_storage(to_vertex->in_edges) : false;
|
||||
auto success_on_from = from_is_local ? delete_edge_from_storage(from_vertex->out_edges) : false;
|
||||
auto success_on_to = to_is_local ? delete_edge_from_storage(to_vertex->second.in_edges) : false;
|
||||
auto success_on_from = from_is_local ? delete_edge_from_storage(from_vertex->second.out_edges) : false;
|
||||
|
||||
if (config_.properties_on_edges) {
|
||||
// Because of the check above, we are sure that the vertex exists.
|
||||
@ -625,10 +626,10 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
|
||||
MG_ASSERT(edge_type.has_value(), "Edge type is not determined");
|
||||
|
||||
if (from_is_local) {
|
||||
CreateAndLinkDelta(transaction_, from_vertex, Delta::AddOutEdgeTag(), *edge_type, to_vertex_id, edge_ref);
|
||||
CreateAndLinkDelta(transaction_, &*from_vertex, Delta::AddOutEdgeTag(), *edge_type, to_vertex_id, edge_ref);
|
||||
}
|
||||
if (to_is_local) {
|
||||
CreateAndLinkDelta(transaction_, to_vertex, Delta::AddInEdgeTag(), *edge_type, from_vertex_id, edge_ref);
|
||||
CreateAndLinkDelta(transaction_, &*to_vertex, Delta::AddInEdgeTag(), *edge_type, from_vertex_id, edge_ref);
|
||||
}
|
||||
|
||||
// Decrement edge count.
|
||||
@ -690,41 +691,41 @@ void Shard::Accessor::Abort() {
|
||||
auto prev = delta.prev.Get();
|
||||
switch (prev.type) {
|
||||
case PreviousPtr::Type::VERTEX: {
|
||||
auto *vertex = prev.vertex;
|
||||
Delta *current = vertex->delta;
|
||||
auto &[pk, vertex] = *prev.vertex;
|
||||
Delta *current = vertex.delta;
|
||||
while (current != nullptr && current->commit_info->start_or_commit_timestamp == transaction_->start_timestamp) {
|
||||
switch (current->action) {
|
||||
case Delta::Action::REMOVE_LABEL: {
|
||||
auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label);
|
||||
MG_ASSERT(it != vertex->labels.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex->labels.rbegin());
|
||||
vertex->labels.pop_back();
|
||||
auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
|
||||
MG_ASSERT(it != vertex.labels.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex.labels.rbegin());
|
||||
vertex.labels.pop_back();
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_LABEL: {
|
||||
auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label);
|
||||
MG_ASSERT(it == vertex->labels.end(), "Invalid database state!");
|
||||
vertex->labels.push_back(current->label);
|
||||
auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
|
||||
MG_ASSERT(it == vertex.labels.end(), "Invalid database state!");
|
||||
vertex.labels.push_back(current->label);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::SET_PROPERTY: {
|
||||
vertex->properties.SetProperty(current->property.key, current->property.value);
|
||||
vertex.properties.SetProperty(current->property.key, current->property.value);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_IN_EDGE: {
|
||||
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link);
|
||||
MG_ASSERT(it == vertex->in_edges.end(), "Invalid database state!");
|
||||
vertex->in_edges.push_back(link);
|
||||
VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
|
||||
MG_ASSERT(it == vertex.in_edges.end(), "Invalid database state!");
|
||||
vertex.in_edges.push_back(link);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::ADD_OUT_EDGE: {
|
||||
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link);
|
||||
MG_ASSERT(it == vertex->out_edges.end(), "Invalid database state!");
|
||||
vertex->out_edges.push_back(link);
|
||||
VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
|
||||
MG_ASSERT(it == vertex.out_edges.end(), "Invalid database state!");
|
||||
vertex.out_edges.push_back(link);
|
||||
// Increment edge count. We only increment the count here because
|
||||
// the information in `ADD_IN_EDGE` and `Edge/RECREATE_OBJECT` is
|
||||
// redundant. Also, `Edge/RECREATE_OBJECT` isn't available when
|
||||
@ -733,21 +734,21 @@ void Shard::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::REMOVE_IN_EDGE: {
|
||||
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link);
|
||||
MG_ASSERT(it != vertex->in_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex->in_edges.rbegin());
|
||||
vertex->in_edges.pop_back();
|
||||
VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
|
||||
MG_ASSERT(it != vertex.in_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex.in_edges.rbegin());
|
||||
vertex.in_edges.pop_back();
|
||||
break;
|
||||
}
|
||||
case Delta::Action::REMOVE_OUT_EDGE: {
|
||||
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link);
|
||||
MG_ASSERT(it != vertex->out_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex->out_edges.rbegin());
|
||||
vertex->out_edges.pop_back();
|
||||
VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
|
||||
current->vertex_edge.edge};
|
||||
auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
|
||||
MG_ASSERT(it != vertex.out_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *vertex.out_edges.rbegin());
|
||||
vertex.out_edges.pop_back();
|
||||
// Decrement edge count. We only decrement the count here because
|
||||
// the information in `REMOVE_IN_EDGE` and `Edge/DELETE_OBJECT` is
|
||||
// redundant. Also, `Edge/DELETE_OBJECT` isn't available when edge
|
||||
@ -756,20 +757,20 @@ void Shard::Accessor::Abort() {
|
||||
break;
|
||||
}
|
||||
case Delta::Action::DELETE_OBJECT: {
|
||||
vertex->deleted = true;
|
||||
shard_->deleted_vertices_.push_back(vertex->keys);
|
||||
vertex.deleted = true;
|
||||
shard_->deleted_vertices_.push_back(&pk);
|
||||
break;
|
||||
}
|
||||
case Delta::Action::RECREATE_OBJECT: {
|
||||
vertex->deleted = false;
|
||||
vertex.deleted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
vertex->delta = current;
|
||||
vertex.delta = current;
|
||||
if (current != nullptr) {
|
||||
current->prev.Set(vertex);
|
||||
current->prev.Set(prev.vertex);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -964,10 +965,12 @@ void Shard::CollectGarbage(const io::Time current_time) {
|
||||
auto prev = delta.prev.Get();
|
||||
switch (prev.type) {
|
||||
case PreviousPtr::Type::VERTEX: {
|
||||
Vertex *vertex = prev.vertex;
|
||||
vertex->delta = nullptr;
|
||||
if (vertex->deleted) {
|
||||
deleted_vertices_.push_back(vertex->keys);
|
||||
// Here we need to get pk from prev pointer, and that is why change
|
||||
// to the PrevPtr so it points to pair of pk and vertex
|
||||
auto &[pk, vertex] = *prev.vertex;
|
||||
vertex.delta = nullptr;
|
||||
if (vertex.deleted) {
|
||||
deleted_vertices_.push_back(&pk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1015,7 +1018,7 @@ void Shard::CollectGarbage(const io::Time current_time) {
|
||||
}
|
||||
|
||||
for (const auto &vertex : deleted_vertices_) {
|
||||
MG_ASSERT(vertices_.erase(vertex), "Invalid database state!");
|
||||
MG_ASSERT(vertices_.erase(*vertex), "Invalid database state!");
|
||||
}
|
||||
deleted_vertices_.clear();
|
||||
{
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "io/time.hpp"
|
||||
#include "kvstore/kvstore.hpp"
|
||||
#include "storage/v3/config.hpp"
|
||||
#include "storage/v3/containers.hpp"
|
||||
#include "storage/v3/edge.hpp"
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
@ -387,7 +386,7 @@ class Shard final {
|
||||
|
||||
// Vertices that are logically deleted but still have to be removed from
|
||||
// indices before removing them from the main storage.
|
||||
std::list<PrimaryKey> deleted_vertices_;
|
||||
std::list<const PrimaryKey *> deleted_vertices_;
|
||||
|
||||
// Edges that are logically deleted and wait to be removed from the main
|
||||
// storage.
|
||||
|
@ -9,16 +9,22 @@
|
||||
// by the Apache License, Version 2.0, included in the file
|
||||
// licenses/APL.txt.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "storage/v3/edge.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/key_store.hpp"
|
||||
#include "storage/v3/vertex.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "storage/v3/delta.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using VertexContainer = std::map<PrimaryKey, Vertex>;
|
||||
using EdgeContainer = std::map<Gid, Edge>;
|
||||
|
||||
VertexData::VertexData(Delta *delta) : delta{delta} {
|
||||
MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT,
|
||||
"Vertex must be created with an initial DELETE_OBJECT delta!");
|
||||
}
|
||||
|
||||
bool VertexHasLabel(const Vertex &vertex, const LabelId label) { return utils::Contains(vertex.second.labels, label); }
|
||||
|
||||
} // namespace memgraph::storage::v3
|
@ -16,7 +16,6 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "storage/v3/delta.hpp"
|
||||
#include "storage/v3/edge_ref.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/key_store.hpp"
|
||||
@ -28,17 +27,12 @@
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
struct Vertex {
|
||||
struct Delta;
|
||||
|
||||
struct VertexData {
|
||||
using EdgeLink = std::tuple<EdgeTypeId, VertexId, EdgeRef>;
|
||||
|
||||
Vertex(Delta *delta, PrimaryKey primary_properties) : keys{std::move(primary_properties)}, delta{delta} {
|
||||
MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT,
|
||||
"Vertex must be created with an initial DELETE_OBJECT delta!");
|
||||
}
|
||||
|
||||
friend bool operator==(const Vertex &vertex, const PrimaryKey &primary_key) { return vertex.keys == primary_key; }
|
||||
|
||||
PrimaryKey keys;
|
||||
explicit VertexData(Delta *delta);
|
||||
|
||||
std::vector<LabelId> labels;
|
||||
PropertyStore properties;
|
||||
@ -52,8 +46,11 @@ struct Vertex {
|
||||
Delta *delta;
|
||||
};
|
||||
|
||||
static_assert(alignof(Vertex) >= 8, "The Vertex should be aligned to at least 8!");
|
||||
// static_assert(alignof(Vertex) >= 8, "The Vertex should be aligned to at least 8!");
|
||||
|
||||
inline bool VertexHasLabel(const Vertex &vertex, const LabelId label) { return utils::Contains(vertex.labels, label); }
|
||||
using VertexContainer = std::map<PrimaryKey, VertexData>;
|
||||
using Vertex = VertexContainer::value_type;
|
||||
|
||||
bool VertexHasLabel(const Vertex &vertex, LabelId label);
|
||||
|
||||
} // namespace memgraph::storage::v3
|
||||
|
@ -36,8 +36,8 @@ std::pair<bool, bool> IsVisible(Vertex *vertex, Transaction *transaction, View v
|
||||
bool deleted = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex->deleted;
|
||||
delta = vertex->delta;
|
||||
deleted = vertex->second.deleted;
|
||||
delta = vertex->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction, delta, view, [&](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -85,13 +85,14 @@ ShardResult<bool> VertexAccessor::AddLabel(LabelId label) {
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
||||
if (std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label) != vertex_->second.labels.end())
|
||||
return false;
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
|
||||
|
||||
vertex_->labels.push_back(label);
|
||||
vertex_->second.labels.push_back(label);
|
||||
|
||||
UpdateOnAddLabel(indices_, label, vertex_, *transaction_);
|
||||
|
||||
@ -106,13 +107,14 @@ ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
||||
if (std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label) != vertex_->second.labels.end())
|
||||
return false;
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
|
||||
|
||||
vertex_->labels.push_back(label);
|
||||
vertex_->second.labels.push_back(label);
|
||||
|
||||
UpdateOnAddLabel(indices_, label, vertex_, *transaction_);
|
||||
|
||||
@ -122,15 +124,15 @@ ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
|
||||
ShardResult<bool> VertexAccessor::RemoveLabel(LabelId label) {
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
||||
if (it == vertex_->labels.end()) return false;
|
||||
auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
|
||||
if (it == vertex_->second.labels.end()) return false;
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
|
||||
|
||||
std::swap(*it, *vertex_->labels.rbegin());
|
||||
vertex_->labels.pop_back();
|
||||
std::swap(*it, *vertex_->second.labels.rbegin());
|
||||
vertex_->second.labels.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -142,15 +144,15 @@ ShardResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
||||
if (it == vertex_->labels.end()) return false;
|
||||
auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
|
||||
if (it == vertex_->second.labels.end()) return false;
|
||||
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
|
||||
|
||||
std::swap(*it, *vertex_->labels.rbegin());
|
||||
vertex_->labels.pop_back();
|
||||
std::swap(*it, *vertex_->second.labels.rbegin());
|
||||
vertex_->second.labels.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -162,9 +164,9 @@ ShardResult<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
|
||||
bool has_label = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
deleted = vertex_->second.deleted;
|
||||
has_label = label == vertex_validator_->primary_label_ || VertexHasLabel(*vertex_, label);
|
||||
delta = vertex_->delta;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &has_label, label](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -215,14 +217,14 @@ ShardResult<PrimaryKey> VertexAccessor::PrimaryKey(const View view) const {
|
||||
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
||||
return result.GetError();
|
||||
}
|
||||
return vertex_->keys;
|
||||
return vertex_->first;
|
||||
}
|
||||
|
||||
ShardResult<VertexId> VertexAccessor::Id(View view) const {
|
||||
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
||||
return result.GetError();
|
||||
}
|
||||
return VertexId{vertex_validator_->primary_label_, vertex_->keys};
|
||||
return VertexId{vertex_validator_->primary_label_, vertex_->first};
|
||||
};
|
||||
|
||||
ShardResult<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
|
||||
@ -231,9 +233,9 @@ ShardResult<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
|
||||
std::vector<LabelId> labels;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
labels = vertex_->labels;
|
||||
delta = vertex_->delta;
|
||||
deleted = vertex_->second.deleted;
|
||||
labels = vertex_->second.labels;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &labels](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -278,9 +280,9 @@ ShardResult<PropertyValue> VertexAccessor::SetProperty(PropertyId property, cons
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
auto current_value = vertex_->properties.GetProperty(property);
|
||||
auto current_value = vertex_->second.properties.GetProperty(property);
|
||||
// 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
|
||||
@ -288,7 +290,7 @@ ShardResult<PropertyValue> VertexAccessor::SetProperty(PropertyId property, cons
|
||||
// "modify in-place". Additionally, the created delta will make other
|
||||
// transactions get a SERIALIZATION_ERROR.
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value);
|
||||
vertex_->properties.SetProperty(property, value);
|
||||
vertex_->second.properties.SetProperty(property, value);
|
||||
|
||||
UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
|
||||
|
||||
@ -300,8 +302,8 @@ ShardResult<void> VertexAccessor::CheckVertexExistence(View view) const {
|
||||
bool deleted = false;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
delta = vertex_->delta;
|
||||
deleted = vertex_->second.deleted;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -343,11 +345,11 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
|
||||
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
}
|
||||
|
||||
if (vertex_->deleted) {
|
||||
if (vertex_->second.deleted) {
|
||||
return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
}
|
||||
|
||||
auto current_value = vertex_->properties.GetProperty(property);
|
||||
auto current_value = vertex_->second.properties.GetProperty(property);
|
||||
// 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
|
||||
@ -355,7 +357,7 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
|
||||
// "modify in-place". Additionally, the created delta will make other
|
||||
// transactions get a SERIALIZATION_ERROR.
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value);
|
||||
vertex_->properties.SetProperty(property, value);
|
||||
vertex_->second.properties.SetProperty(property, value);
|
||||
|
||||
UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
|
||||
|
||||
@ -365,15 +367,15 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
|
||||
ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
|
||||
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||
|
||||
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
if (vertex_->second.deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||
|
||||
auto properties = vertex_->properties.Properties();
|
||||
auto properties = vertex_->second.properties.Properties();
|
||||
for (const auto &property : properties) {
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property.first, property.second);
|
||||
UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_, *transaction_);
|
||||
}
|
||||
|
||||
vertex_->properties.ClearProperties();
|
||||
vertex_->second.properties.ClearProperties();
|
||||
|
||||
return std::move(properties);
|
||||
}
|
||||
@ -396,11 +398,11 @@ PropertyValue VertexAccessor::GetPropertyValue(PropertyId property, View view) c
|
||||
// Find PropertyId index in keystore
|
||||
for (size_t property_index{0}; property_index < schema->second.size(); ++property_index) {
|
||||
if (schema->second[property_index].property_id == property) {
|
||||
return vertex_->keys[property_index];
|
||||
return vertex_->first[property_index];
|
||||
}
|
||||
}
|
||||
|
||||
return value = vertex_->properties.GetProperty(property);
|
||||
return value = vertex_->second.properties.GetProperty(property);
|
||||
}
|
||||
|
||||
ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
|
||||
@ -409,9 +411,9 @@ ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View
|
||||
PropertyValue value;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
deleted = vertex_->second.deleted;
|
||||
value = GetPropertyValue(property, view);
|
||||
delta = vertex_->delta;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &value, property](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -453,10 +455,10 @@ ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View
|
||||
std::map<PropertyId, PropertyValue> properties;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
deleted = vertex_->second.deleted;
|
||||
// TODO(antaljanosbenjamin): Should this also return the primary key?
|
||||
properties = vertex_->properties.Properties();
|
||||
delta = vertex_->delta;
|
||||
properties = vertex_->second.properties.Properties();
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &properties](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -501,14 +503,14 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
|
||||
const VertexId *destination_id) const {
|
||||
bool exists = true;
|
||||
bool deleted = false;
|
||||
std::vector<Vertex::EdgeLink> in_edges;
|
||||
std::vector<VertexData::EdgeLink> in_edges;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
deleted = vertex_->second.deleted;
|
||||
if (edge_types.empty() && nullptr == destination_id) {
|
||||
in_edges = vertex_->in_edges;
|
||||
in_edges = vertex_->second.in_edges;
|
||||
} else {
|
||||
for (const auto &item : vertex_->in_edges) {
|
||||
for (const auto &item : vertex_->second.in_edges) {
|
||||
const auto &[edge_type, from_vertex, edge] = item;
|
||||
if (nullptr != destination_id && from_vertex != *destination_id) {
|
||||
continue;
|
||||
@ -518,7 +520,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
|
||||
in_edges.push_back(item);
|
||||
}
|
||||
}
|
||||
delta = vertex_->delta;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(
|
||||
transaction_, delta, view, [&exists, &deleted, &in_edges, &edge_types, destination_id](const Delta &delta) {
|
||||
@ -529,7 +531,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
|
||||
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
|
||||
break;
|
||||
// Add the edge because we don't see the removal.
|
||||
Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
auto it = std::find(in_edges.begin(), in_edges.end(), link);
|
||||
MG_ASSERT(it == in_edges.end(), "Invalid database state!");
|
||||
in_edges.push_back(link);
|
||||
@ -541,7 +543,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
|
||||
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
|
||||
break;
|
||||
// Remove the label because we don't see the addition.
|
||||
Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
auto it = std::find(in_edges.begin(), in_edges.end(), link);
|
||||
MG_ASSERT(it != in_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *in_edges.rbegin());
|
||||
@ -571,7 +573,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
|
||||
return ret;
|
||||
}
|
||||
ret.reserve(in_edges.size());
|
||||
const auto id = VertexId{vertex_validator_->primary_label_, vertex_->keys};
|
||||
const auto id = VertexId{vertex_validator_->primary_label_, vertex_->first};
|
||||
for (const auto &item : in_edges) {
|
||||
const auto &[edge_type, from_vertex, edge] = item;
|
||||
ret.emplace_back(edge, edge_type, from_vertex, id, transaction_, indices_, config_);
|
||||
@ -583,14 +585,14 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
|
||||
const VertexId *destination_id) const {
|
||||
bool exists = true;
|
||||
bool deleted = false;
|
||||
std::vector<Vertex::EdgeLink> out_edges;
|
||||
std::vector<VertexData::EdgeLink> out_edges;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
deleted = vertex_->second.deleted;
|
||||
if (edge_types.empty() && nullptr == destination_id) {
|
||||
out_edges = vertex_->out_edges;
|
||||
out_edges = vertex_->second.out_edges;
|
||||
} else {
|
||||
for (const auto &item : vertex_->out_edges) {
|
||||
for (const auto &item : vertex_->second.out_edges) {
|
||||
const auto &[edge_type, to_vertex, edge] = item;
|
||||
if (nullptr != destination_id && to_vertex != *destination_id) continue;
|
||||
if (!edge_types.empty() && std::find(edge_types.begin(), edge_types.end(), edge_type) == edge_types.end())
|
||||
@ -598,7 +600,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
|
||||
out_edges.push_back(item);
|
||||
}
|
||||
}
|
||||
delta = vertex_->delta;
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(
|
||||
transaction_, delta, view, [&exists, &deleted, &out_edges, &edge_types, destination_id](const Delta &delta) {
|
||||
@ -609,7 +611,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
|
||||
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
|
||||
break;
|
||||
// Add the edge because we don't see the removal.
|
||||
Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
auto it = std::find(out_edges.begin(), out_edges.end(), link);
|
||||
MG_ASSERT(it == out_edges.end(), "Invalid database state!");
|
||||
out_edges.push_back(link);
|
||||
@ -621,7 +623,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
|
||||
std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
|
||||
break;
|
||||
// Remove the label because we don't see the addition.
|
||||
Vertex::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
VertexData::EdgeLink link{delta.vertex_edge.edge_type, delta.vertex_edge.vertex_id, delta.vertex_edge.edge};
|
||||
auto it = std::find(out_edges.begin(), out_edges.end(), link);
|
||||
MG_ASSERT(it != out_edges.end(), "Invalid database state!");
|
||||
std::swap(*it, *out_edges.rbegin());
|
||||
@ -651,7 +653,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
|
||||
return ret;
|
||||
}
|
||||
ret.reserve(out_edges.size());
|
||||
const auto id = VertexId{vertex_validator_->primary_label_, vertex_->keys};
|
||||
const auto id = VertexId{vertex_validator_->primary_label_, vertex_->first};
|
||||
for (const auto &item : out_edges) {
|
||||
const auto &[edge_type, to_vertex, edge] = item;
|
||||
ret.emplace_back(edge, edge_type, id, to_vertex, transaction_, indices_, config_);
|
||||
@ -665,9 +667,9 @@ ShardResult<size_t> VertexAccessor::InDegree(View view) const {
|
||||
size_t degree = 0;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
degree = vertex_->in_edges.size();
|
||||
delta = vertex_->delta;
|
||||
deleted = vertex_->second.deleted;
|
||||
degree = vertex_->second.in_edges.size();
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, °ree](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
@ -702,9 +704,9 @@ ShardResult<size_t> VertexAccessor::OutDegree(View view) const {
|
||||
size_t degree = 0;
|
||||
Delta *delta = nullptr;
|
||||
{
|
||||
deleted = vertex_->deleted;
|
||||
degree = vertex_->out_edges.size();
|
||||
delta = vertex_->delta;
|
||||
deleted = vertex_->second.deleted;
|
||||
degree = vertex_->second.out_edges.size();
|
||||
delta = vertex_->second.delta;
|
||||
}
|
||||
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, °ree](const Delta &delta) {
|
||||
switch (delta.action) {
|
||||
|
Loading…
Reference in New Issue
Block a user