Introduce VertexData

This commit is contained in:
jbajic 2022-12-12 12:39:49 +01:00
parent 32322d39b8
commit 0cf440519e
12 changed files with 226 additions and 199 deletions

View File

@ -17,6 +17,7 @@ set(storage_v3_src_files
shard_rsm.cpp shard_rsm.cpp
bindings/typed_value.cpp bindings/typed_value.cpp
expr.cpp expr.cpp
vertex.cpp
request_helper.cpp) request_helper.cpp)
# ###################### # ######################

View File

@ -15,13 +15,13 @@
#include "storage/v3/edge_ref.hpp" #include "storage/v3/edge_ref.hpp"
#include "storage/v3/id_types.hpp" #include "storage/v3/id_types.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/vertex.hpp"
#include "storage/v3/vertex_id.hpp" #include "storage/v3/vertex_id.hpp"
#include "utils/logging.hpp" #include "utils/logging.hpp"
namespace memgraph::storage::v3 { namespace memgraph::storage::v3 {
// Forward declarations because we only store pointers here. // Forward declarations because we only store pointers here.
struct Vertex;
struct Edge; struct Edge;
struct Delta; struct Delta;
struct CommitInfo; struct CommitInfo;

View File

@ -21,7 +21,7 @@
namespace memgraph::storage::v3 { namespace memgraph::storage::v3 {
struct Vertex; using EdgeContainer = std::map<Gid, Edge>;
struct Edge { struct Edge {
Edge(Gid gid, Delta *delta) : gid(gid), deleted(false), delta(delta) { Edge(Gid gid, Delta *delta) : gid(gid), deleted(false), delta(delta) {
@ -34,13 +34,13 @@ struct Edge {
PropertyStore properties; PropertyStore properties;
bool deleted; bool deleted;
// uint8_t PAD; uint8_t PAD;
// uint16_t PAD; // uint16_t PAD;
Delta *delta; 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; }
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; }

View File

@ -25,7 +25,6 @@
namespace memgraph::storage::v3 { namespace memgraph::storage::v3 {
struct Vertex;
class VertexAccessor; class VertexAccessor;
struct Indices; struct Indices;

View File

@ -21,6 +21,7 @@
#include "storage/v3/mvcc.hpp" #include "storage/v3/mvcc.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/schemas.hpp" #include "storage/v3/schemas.hpp"
#include "storage/v3/vertex.hpp"
#include "utils/bound.hpp" #include "utils/bound.hpp"
#include "utils/logging.hpp" #include "utils/logging.hpp"
#include "utils/memory_tracker.hpp" #include "utils/memory_tracker.hpp"
@ -57,9 +58,9 @@ bool AnyVersionHasLabel(const Vertex &vertex, LabelId label, uint64_t timestamp)
bool deleted{false}; bool deleted{false};
const Delta *delta{nullptr}; const Delta *delta{nullptr};
{ {
has_label = utils::Contains(vertex.labels, label); has_label = utils::Contains(vertex.second.labels, label);
deleted = vertex.deleted; deleted = vertex.second.deleted;
delta = vertex.delta; delta = vertex.second.delta;
} }
if (!deleted && has_label) { if (!deleted && has_label) {
return true; return true;
@ -109,10 +110,10 @@ bool AnyVersionHasLabelProperty(const Vertex &vertex, LabelId label, PropertyId
bool deleted{false}; bool deleted{false};
const Delta *delta{nullptr}; const Delta *delta{nullptr};
{ {
has_label = utils::Contains(vertex.labels, label); has_label = utils::Contains(vertex.second.labels, label);
current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value); current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
deleted = vertex.deleted; deleted = vertex.second.deleted;
delta = vertex.delta; delta = vertex.second.delta;
} }
if (!deleted && has_label && current_value_equal_to_value) { 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}; bool has_label{false};
const Delta *delta{nullptr}; const Delta *delta{nullptr};
{ {
deleted = vertex.deleted; deleted = vertex.second.deleted;
has_label = utils::Contains(vertex.labels, label); has_label = utils::Contains(vertex.second.labels, label);
delta = vertex.delta; delta = vertex.second.delta;
} }
ApplyDeltasForRead(transaction, delta, view, [&deleted, &has_label, label](const Delta &delta) { ApplyDeltasForRead(transaction, delta, view, [&deleted, &has_label, label](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -218,10 +219,10 @@ bool CurrentVersionHasLabelProperty(const Vertex &vertex, LabelId label, Propert
bool current_value_equal_to_value = value.IsNull(); bool current_value_equal_to_value = value.IsNull();
const Delta *delta{nullptr}; const Delta *delta{nullptr};
{ {
deleted = vertex.deleted; deleted = vertex.second.deleted;
has_label = utils::Contains(vertex.labels, label); has_label = utils::Contains(vertex.second.labels, label);
current_value_equal_to_value = vertex.properties.IsPropertyEqual(key, value); current_value_equal_to_value = vertex.second.properties.IsPropertyEqual(key, value);
delta = vertex.delta; delta = vertex.second.delta;
} }
ApplyDeltasForRead(transaction, delta, view, ApplyDeltasForRead(transaction, delta, view,
[&deleted, &has_label, &current_value_equal_to_value, key, label, &value](const Delta &delta) { [&deleted, &has_label, &current_value_equal_to_value, key, label, &value](const Delta &delta) {
@ -282,8 +283,8 @@ bool LabelIndex::CreateIndex(LabelId label, VertexContainer &vertices) {
} }
try { try {
auto acc = it->second.access(); auto acc = it->second.access();
for ([[maybe_unused]] auto &[pk, vertex] : vertices) { for ([[maybe_unused]] auto &vertex : vertices) {
if (vertex.deleted || !utils::Contains(vertex.labels, label)) { if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
continue; continue;
} }
acc.insert(Entry{&vertex, 0}); acc.insert(Entry{&vertex, 0});
@ -395,7 +396,7 @@ void LabelPropertyIndex::UpdateOnAddLabel(LabelId label, Vertex *vertex, const T
if (label_prop.first != label) { if (label_prop.first != label) {
continue; continue;
} }
auto prop_value = vertex->properties.GetProperty(label_prop.second); auto prop_value = vertex->second.properties.GetProperty(label_prop.second);
if (!prop_value.IsNull()) { if (!prop_value.IsNull()) {
index.emplace(prop_value, Entry{prop_value, vertex, tx.start_timestamp.logical_id}); 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) { if (label_prop.second != property) {
continue; 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}); 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; return false;
} }
try { try {
for ([[maybe_unused]] auto &[pk, vertex] : vertices) { for ([[maybe_unused]] auto &vertex : vertices) {
if (vertex.deleted || !utils::Contains(vertex.labels, label)) { if (vertex.second.deleted || !VertexHasLabel(vertex, label)) {
continue; continue;
} }
auto value = vertex.properties.GetProperty(property); auto value = vertex.second.properties.GetProperty(property);
if (value.IsNull()) { if (value.IsNull()) {
continue; continue;
} }

View File

@ -18,7 +18,6 @@
#include <utility> #include <utility>
#include "storage/v3/config.hpp" #include "storage/v3/config.hpp"
#include "storage/v3/containers.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/transaction.hpp" #include "storage/v3/transaction.hpp"
#include "storage/v3/vertex_accessor.hpp" #include "storage/v3/vertex_accessor.hpp"

View File

@ -11,9 +11,13 @@
#pragma once #pragma once
#include <type_traits>
#include "storage/v3/edge.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/transaction.hpp" #include "storage/v3/transaction.hpp"
#include "storage/v3/vertex.hpp"
#include "storage/v3/view.hpp" #include "storage/v3/view.hpp"
#include "utils/concepts.hpp"
namespace memgraph::storage::v3 { 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 /// transaction) and returns a `bool` value indicating whether the caller can
/// proceed with a write operation. /// proceed with a write operation.
template <typename TObj> template <typename TObj>
requires utils::SameAsAnyOf<TObj, Edge, Vertex>
inline bool PrepareForWrite(Transaction *transaction, TObj *object) { 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 || if (delta_commit_info.start_or_commit_timestamp == transaction->commit_info->start_or_commit_timestamp ||
(delta_commit_info.is_locally_committed && (delta_commit_info.is_locally_committed &&
delta_commit_info.start_or_commit_timestamp < transaction->start_timestamp)) { 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. /// the delta into the object's delta list.
/// @throw std::bad_alloc /// @throw std::bad_alloc
template <typename TObj, class... Args> template <typename TObj, class... Args>
requires utils::SameAsAnyOf<TObj, Edge, Vertex>
inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&...args) { inline void CreateAndLinkDelta(Transaction *transaction, TObj *object, Args &&...args) {
auto delta = &transaction->deltas.emplace_back(std::forward<Args>(args)..., transaction->commit_info.get(), auto delta = &transaction->deltas.emplace_back(std::forward<Args>(args)..., transaction->commit_info.get(),
transaction->command_id); 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` // 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 // 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 // TODO(antaljanosbenjamin): clang-tidy detects (in my opinion a false positive) issue in
// `Shard::Accessor::CreateEdge`. // `Shard::Accessor::CreateEdge`.
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference) // 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. // 2. We need to set the previous delta of the new delta to the object.
delta->prev.Set(object); delta->prev.Set(object);
// 3. We need to set the previous delta of the existing delta to the new // 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. 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. // delta but won't modify it until we are done with all of our modifications.
if (object->delta) { if (delta_holder->delta) {
object->delta->prev.Set(delta); delta_holder->delta->prev.Set(delta);
} }
// 4. Finally, we need to set the object's delta to the new delta. The garbage // 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 // 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 // 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 // modification is being done, everybody else will wait until we are fully
// done with our modification before they read the object's delta value. // done with our modification before they read the object's delta value.
object->delta = delta; delta_holder->delta = delta;
} }
} // namespace memgraph::storage::v3 } // namespace memgraph::storage::v3

View File

@ -26,7 +26,6 @@
#include "io/network/endpoint.hpp" #include "io/network/endpoint.hpp"
#include "io/time.hpp" #include "io/time.hpp"
#include "storage/v3/containers.hpp"
#include "storage/v3/edge_accessor.hpp" #include "storage/v3/edge_accessor.hpp"
#include "storage/v3/id_types.hpp" #include "storage/v3/id_types.hpp"
#include "storage/v3/indices.hpp" #include "storage/v3/indices.hpp"
@ -39,6 +38,7 @@
#include "storage/v3/transaction.hpp" #include "storage/v3/transaction.hpp"
#include "storage/v3/vertex.hpp" #include "storage/v3/vertex.hpp"
#include "storage/v3/vertex_accessor.hpp" #include "storage/v3/vertex_accessor.hpp"
#include "storage/v3/view.hpp"
#include "utils/exceptions.hpp" #include "utils/exceptions.hpp"
#include "utils/file.hpp" #include "utils/file.hpp"
#include "utils/logging.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, std::optional<VertexAccessor> *vertex, Transaction *tx, View view, Indices *indices,
Config::Items config, const VertexValidator &vertex_validator) { Config::Items config, const VertexValidator &vertex_validator) {
while (it != end) { 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) { if (!*vertex) {
++it; ++it;
continue; continue;
@ -346,7 +346,7 @@ Shard::Accessor::Accessor(Shard &shard, Transaction &transaction)
: shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {} : shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {}
ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate( 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) { const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
OOMExceptionEnabler oom_exception; OOMExceptionEnabler oom_exception;
const auto schema = shard_->GetSchema(shard_->primary_label_)->second; const auto schema = shard_->GetSchema(shard_->primary_label_)->second;
@ -358,10 +358,10 @@ ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
} }
auto *delta = CreateDeleteObjectDelta(transaction_); auto *delta = CreateDeleteObjectDelta(transaction_);
auto [it, inserted] = shard_->vertices_.emplace(primary_properties, Vertex(delta, primary_properties)); auto [it, inserted] = shard_->vertices_.emplace(primary_properties, VertexData{delta});
delta->prev.Set(&it->second); 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) { if (!inserted) {
return SHARD_ERROR(ErrorCode::VERTEX_ALREADY_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()) { if (it == shard_->vertices_.end()) {
return std::nullopt; 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) { 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 (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
if (vertex_ptr->deleted) { if (vertex_ptr->second.deleted) {
return std::optional<VertexAccessor>{}; 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()); 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_, return std::make_optional<VertexAccessor>(vertex_ptr, transaction_, &shard_->indices_, config_,
shard_->vertex_validator_, true); shard_->vertex_validator_, true);
@ -422,20 +423,20 @@ ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>>
"accessor when deleting a vertex!"); "accessor when deleting a vertex!");
auto *vertex_ptr = vertex->vertex_; auto *vertex_ptr = vertex->vertex_;
std::vector<Vertex::EdgeLink> in_edges; std::vector<VertexData::EdgeLink> in_edges;
std::vector<Vertex::EdgeLink> out_edges; std::vector<VertexData::EdgeLink> out_edges;
{ {
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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; in_edges = vertex_ptr->second.in_edges;
out_edges = vertex_ptr->out_edges; out_edges = vertex_ptr->second.out_edges;
} }
std::vector<EdgeAccessor> deleted_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) { for (const auto &item : in_edges) {
auto [edge_type, from_vertex, edge] = item; auto [edge_type, from_vertex, edge] = item;
EdgeAccessor e(edge, edge_type, from_vertex, vertex_id, transaction_, &shard_->indices_, config_); 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); 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()); CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
vertex_ptr->deleted = true; vertex_ptr->second.deleted = true;
return std::make_optional<ReturnType>( return std::make_optional<ReturnType>(
VertexAccessor{vertex_ptr, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, true}, 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) { if (from_is_local) {
auto it = vertices.find(from_vertex_id.primary_key); auto it = vertices.find(from_vertex_id.primary_key);
MG_ASSERT(it != vertices.end(), "Cannot find local vertex"); MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
from_vertex = &it->second; from_vertex = &*it;
} }
if (to_is_local) { if (to_is_local) {
auto it = vertices.find(to_vertex_id.primary_key); auto it = vertices.find(to_vertex_id.primary_key);
MG_ASSERT(it != vertices.end(), "Cannot find local vertex"); MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
to_vertex = &it->second; to_vertex = &*it;
} }
if (from_is_local) { if (from_is_local) {
if (!PrepareForWrite(transaction_, from_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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 (to_is_local && to_vertex != from_vertex) {
if (!PrepareForWrite(transaction_, to_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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); EdgeRef edge(gid);
@ -524,11 +525,11 @@ ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, V
if (from_is_local) { if (from_is_local) {
CreateAndLinkDelta(transaction_, from_vertex, Delta::RemoveOutEdgeTag(), edge_type, to_vertex_id, edge); 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) { if (to_is_local) {
CreateAndLinkDelta(transaction_, to_vertex, Delta::RemoveInEdgeTag(), edge_type, from_vertex_id, edge); 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. // Increment edge count.
++shard_->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, ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id,
const Gid edge_id) { const Gid edge_id) {
Vertex *from_vertex{nullptr}; VertexContainer::value_type *from_vertex{nullptr};
Vertex *to_vertex{nullptr}; VertexContainer::value_type *to_vertex{nullptr};
auto &vertices = shard_->vertices_; auto &vertices = shard_->vertices_;
@ -550,13 +551,13 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
if (from_is_local) { if (from_is_local) {
auto it = vertices.find(from_vertex_id.primary_key); auto it = vertices.find(from_vertex_id.primary_key);
MG_ASSERT(it != vertices.end(), "Cannot find local vertex"); MG_ASSERT(it != vertices.end(), "Cannot find local vertex");
from_vertex = &it->second; from_vertex = &*it;
} }
if (to_is_local) { if (to_is_local) {
auto it = vertices.find(to_vertex_id.primary_key); auto it = vertices.find(to_vertex_id.primary_key);
MG_ASSERT(it != vertices.end(), "Cannot find local vertex"); 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"); 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)) { if (!PrepareForWrite(transaction_, from_vertex)) {
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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 (to_is_local && to_vertex != from_vertex) {
if (!PrepareForWrite(transaction_, to_vertex)) { if (!PrepareForWrite(transaction_, to_vertex)) {
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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 { 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{}; 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(), 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) { if (config_.properties_on_edges) {
MG_ASSERT(it != edges.end(), "Invalid database state!"); MG_ASSERT(it != edges.end(), "Invalid database state!");
} else if (it == edges.end()) { } else if (it == edges.end()) {
@ -598,8 +599,8 @@ ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId fr
return true; return true;
}; };
// NOLINTNEXTLINE(clang-analyzer-core.NonNullParamChecker) // NOLINTNEXTLINE(clang-analyzer-core.NonNullParamChecker)
auto success_on_to = to_is_local ? delete_edge_from_storage(to_vertex->in_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->out_edges) : false; auto success_on_from = from_is_local ? delete_edge_from_storage(from_vertex->second.out_edges) : false;
if (config_.properties_on_edges) { if (config_.properties_on_edges) {
// Because of the check above, we are sure that the vertex exists. // 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"); MG_ASSERT(edge_type.has_value(), "Edge type is not determined");
if (from_is_local) { 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) { 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. // Decrement edge count.
@ -690,41 +691,41 @@ void Shard::Accessor::Abort() {
auto prev = delta.prev.Get(); auto prev = delta.prev.Get();
switch (prev.type) { switch (prev.type) {
case PreviousPtr::Type::VERTEX: { case PreviousPtr::Type::VERTEX: {
auto *vertex = prev.vertex; auto &[pk, vertex] = *prev.vertex;
Delta *current = vertex->delta; Delta *current = vertex.delta;
while (current != nullptr && current->commit_info->start_or_commit_timestamp == transaction_->start_timestamp) { while (current != nullptr && current->commit_info->start_or_commit_timestamp == transaction_->start_timestamp) {
switch (current->action) { switch (current->action) {
case Delta::Action::REMOVE_LABEL: { case Delta::Action::REMOVE_LABEL: {
auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label); auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
MG_ASSERT(it != vertex->labels.end(), "Invalid database state!"); MG_ASSERT(it != vertex.labels.end(), "Invalid database state!");
std::swap(*it, *vertex->labels.rbegin()); std::swap(*it, *vertex.labels.rbegin());
vertex->labels.pop_back(); vertex.labels.pop_back();
break; break;
} }
case Delta::Action::ADD_LABEL: { case Delta::Action::ADD_LABEL: {
auto it = std::find(vertex->labels.begin(), vertex->labels.end(), current->label); auto it = std::find(vertex.labels.begin(), vertex.labels.end(), current->label);
MG_ASSERT(it == vertex->labels.end(), "Invalid database state!"); MG_ASSERT(it == vertex.labels.end(), "Invalid database state!");
vertex->labels.push_back(current->label); vertex.labels.push_back(current->label);
break; break;
} }
case Delta::Action::SET_PROPERTY: { case Delta::Action::SET_PROPERTY: {
vertex->properties.SetProperty(current->property.key, current->property.value); vertex.properties.SetProperty(current->property.key, current->property.value);
break; break;
} }
case Delta::Action::ADD_IN_EDGE: { case Delta::Action::ADD_IN_EDGE: {
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id, VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
current->vertex_edge.edge}; current->vertex_edge.edge};
auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link); auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
MG_ASSERT(it == vertex->in_edges.end(), "Invalid database state!"); MG_ASSERT(it == vertex.in_edges.end(), "Invalid database state!");
vertex->in_edges.push_back(link); vertex.in_edges.push_back(link);
break; break;
} }
case Delta::Action::ADD_OUT_EDGE: { case Delta::Action::ADD_OUT_EDGE: {
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id, VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
current->vertex_edge.edge}; current->vertex_edge.edge};
auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link); auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
MG_ASSERT(it == vertex->out_edges.end(), "Invalid database state!"); MG_ASSERT(it == vertex.out_edges.end(), "Invalid database state!");
vertex->out_edges.push_back(link); vertex.out_edges.push_back(link);
// Increment edge count. We only increment the count here because // Increment edge count. We only increment the count here because
// the information in `ADD_IN_EDGE` and `Edge/RECREATE_OBJECT` is // the information in `ADD_IN_EDGE` and `Edge/RECREATE_OBJECT` is
// redundant. Also, `Edge/RECREATE_OBJECT` isn't available when // redundant. Also, `Edge/RECREATE_OBJECT` isn't available when
@ -733,21 +734,21 @@ void Shard::Accessor::Abort() {
break; break;
} }
case Delta::Action::REMOVE_IN_EDGE: { case Delta::Action::REMOVE_IN_EDGE: {
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id, VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
current->vertex_edge.edge}; current->vertex_edge.edge};
auto it = std::find(vertex->in_edges.begin(), vertex->in_edges.end(), link); auto it = std::find(vertex.in_edges.begin(), vertex.in_edges.end(), link);
MG_ASSERT(it != vertex->in_edges.end(), "Invalid database state!"); MG_ASSERT(it != vertex.in_edges.end(), "Invalid database state!");
std::swap(*it, *vertex->in_edges.rbegin()); std::swap(*it, *vertex.in_edges.rbegin());
vertex->in_edges.pop_back(); vertex.in_edges.pop_back();
break; break;
} }
case Delta::Action::REMOVE_OUT_EDGE: { case Delta::Action::REMOVE_OUT_EDGE: {
Vertex::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id, VertexData::EdgeLink link{current->vertex_edge.edge_type, current->vertex_edge.vertex_id,
current->vertex_edge.edge}; current->vertex_edge.edge};
auto it = std::find(vertex->out_edges.begin(), vertex->out_edges.end(), link); auto it = std::find(vertex.out_edges.begin(), vertex.out_edges.end(), link);
MG_ASSERT(it != vertex->out_edges.end(), "Invalid database state!"); MG_ASSERT(it != vertex.out_edges.end(), "Invalid database state!");
std::swap(*it, *vertex->out_edges.rbegin()); std::swap(*it, *vertex.out_edges.rbegin());
vertex->out_edges.pop_back(); vertex.out_edges.pop_back();
// Decrement edge count. We only decrement the count here because // Decrement edge count. We only decrement the count here because
// the information in `REMOVE_IN_EDGE` and `Edge/DELETE_OBJECT` is // the information in `REMOVE_IN_EDGE` and `Edge/DELETE_OBJECT` is
// redundant. Also, `Edge/DELETE_OBJECT` isn't available when edge // redundant. Also, `Edge/DELETE_OBJECT` isn't available when edge
@ -756,20 +757,20 @@ void Shard::Accessor::Abort() {
break; break;
} }
case Delta::Action::DELETE_OBJECT: { case Delta::Action::DELETE_OBJECT: {
vertex->deleted = true; vertex.deleted = true;
shard_->deleted_vertices_.push_back(vertex->keys); shard_->deleted_vertices_.push_back(&pk);
break; break;
} }
case Delta::Action::RECREATE_OBJECT: { case Delta::Action::RECREATE_OBJECT: {
vertex->deleted = false; vertex.deleted = false;
break; break;
} }
} }
current = current->next; current = current->next;
} }
vertex->delta = current; vertex.delta = current;
if (current != nullptr) { if (current != nullptr) {
current->prev.Set(vertex); current->prev.Set(prev.vertex);
} }
break; break;
@ -964,10 +965,12 @@ void Shard::CollectGarbage(const io::Time current_time) {
auto prev = delta.prev.Get(); auto prev = delta.prev.Get();
switch (prev.type) { switch (prev.type) {
case PreviousPtr::Type::VERTEX: { case PreviousPtr::Type::VERTEX: {
Vertex *vertex = prev.vertex; // Here we need to get pk from prev pointer, and that is why change
vertex->delta = nullptr; // to the PrevPtr so it points to pair of pk and vertex
if (vertex->deleted) { auto &[pk, vertex] = *prev.vertex;
deleted_vertices_.push_back(vertex->keys); vertex.delta = nullptr;
if (vertex.deleted) {
deleted_vertices_.push_back(&pk);
} }
break; break;
} }
@ -1015,7 +1018,7 @@ void Shard::CollectGarbage(const io::Time current_time) {
} }
for (const auto &vertex : deleted_vertices_) { 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(); deleted_vertices_.clear();
{ {

View File

@ -25,7 +25,6 @@
#include "io/time.hpp" #include "io/time.hpp"
#include "kvstore/kvstore.hpp" #include "kvstore/kvstore.hpp"
#include "storage/v3/config.hpp" #include "storage/v3/config.hpp"
#include "storage/v3/containers.hpp"
#include "storage/v3/edge.hpp" #include "storage/v3/edge.hpp"
#include "storage/v3/edge_accessor.hpp" #include "storage/v3/edge_accessor.hpp"
#include "storage/v3/id_types.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 // Vertices that are logically deleted but still have to be removed from
// indices before removing them from the main storage. // 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 // Edges that are logically deleted and wait to be removed from the main
// storage. // storage.

View File

@ -9,16 +9,22 @@
// by the Apache License, Version 2.0, included in the file // by the Apache License, Version 2.0, included in the file
// licenses/APL.txt. // 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 "storage/v3/vertex.hpp"
#include <limits>
#include <tuple>
#include <type_traits>
#include <vector>
#include "storage/v3/delta.hpp"
namespace memgraph::storage::v3 { 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 } // namespace memgraph::storage::v3

View File

@ -16,7 +16,6 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include "storage/v3/delta.hpp"
#include "storage/v3/edge_ref.hpp" #include "storage/v3/edge_ref.hpp"
#include "storage/v3/id_types.hpp" #include "storage/v3/id_types.hpp"
#include "storage/v3/key_store.hpp" #include "storage/v3/key_store.hpp"
@ -28,17 +27,12 @@
namespace memgraph::storage::v3 { namespace memgraph::storage::v3 {
struct Vertex { struct Delta;
struct VertexData {
using EdgeLink = std::tuple<EdgeTypeId, VertexId, EdgeRef>; using EdgeLink = std::tuple<EdgeTypeId, VertexId, EdgeRef>;
Vertex(Delta *delta, PrimaryKey primary_properties) : keys{std::move(primary_properties)}, delta{delta} { explicit VertexData(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;
std::vector<LabelId> labels; std::vector<LabelId> labels;
PropertyStore properties; PropertyStore properties;
@ -52,8 +46,11 @@ struct Vertex {
Delta *delta; 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 } // namespace memgraph::storage::v3

View File

@ -36,8 +36,8 @@ std::pair<bool, bool> IsVisible(Vertex *vertex, Transaction *transaction, View v
bool deleted = false; bool deleted = false;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex->deleted; deleted = vertex->second.deleted;
delta = vertex->delta; delta = vertex->second.delta;
} }
ApplyDeltasForRead(transaction, delta, view, [&](const Delta &delta) { ApplyDeltasForRead(transaction, delta, view, [&](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -85,13 +85,14 @@ ShardResult<bool> VertexAccessor::AddLabel(LabelId label) {
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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); CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
vertex_->labels.push_back(label); vertex_->second.labels.push_back(label);
UpdateOnAddLabel(indices_, label, vertex_, *transaction_); 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 (!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); CreateAndLinkDelta(transaction_, vertex_, Delta::RemoveLabelTag(), label);
vertex_->labels.push_back(label); vertex_->second.labels.push_back(label);
UpdateOnAddLabel(indices_, label, vertex_, *transaction_); UpdateOnAddLabel(indices_, label, vertex_, *transaction_);
@ -122,15 +124,15 @@ ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
ShardResult<bool> VertexAccessor::RemoveLabel(LabelId label) { ShardResult<bool> VertexAccessor::RemoveLabel(LabelId label) {
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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); auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
if (it == vertex_->labels.end()) return false; if (it == vertex_->second.labels.end()) return false;
CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label); CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
std::swap(*it, *vertex_->labels.rbegin()); std::swap(*it, *vertex_->second.labels.rbegin());
vertex_->labels.pop_back(); vertex_->second.labels.pop_back();
return true; return true;
} }
@ -142,15 +144,15 @@ ShardResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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); auto it = std::find(vertex_->second.labels.begin(), vertex_->second.labels.end(), label);
if (it == vertex_->labels.end()) return false; if (it == vertex_->second.labels.end()) return false;
CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label); CreateAndLinkDelta(transaction_, vertex_, Delta::AddLabelTag(), label);
std::swap(*it, *vertex_->labels.rbegin()); std::swap(*it, *vertex_->second.labels.rbegin());
vertex_->labels.pop_back(); vertex_->second.labels.pop_back();
return true; return true;
} }
@ -162,9 +164,9 @@ ShardResult<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
bool has_label = false; bool has_label = false;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
has_label = label == vertex_validator_->primary_label_ || VertexHasLabel(*vertex_, label); 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) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &has_label, label](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -215,14 +217,14 @@ ShardResult<PrimaryKey> VertexAccessor::PrimaryKey(const View view) const {
if (const auto result = CheckVertexExistence(view); result.HasError()) { if (const auto result = CheckVertexExistence(view); result.HasError()) {
return result.GetError(); return result.GetError();
} }
return vertex_->keys; return vertex_->first;
} }
ShardResult<VertexId> VertexAccessor::Id(View view) const { ShardResult<VertexId> VertexAccessor::Id(View view) const {
if (const auto result = CheckVertexExistence(view); result.HasError()) { if (const auto result = CheckVertexExistence(view); result.HasError()) {
return result.GetError(); 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 { 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; std::vector<LabelId> labels;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
labels = vertex_->labels; labels = vertex_->second.labels;
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &labels](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &labels](const Delta &delta) {
switch (delta.action) { 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 (!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 // 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 // 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 // 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 // "modify in-place". Additionally, the created delta will make other
// transactions get a SERIALIZATION_ERROR. // transactions get a SERIALIZATION_ERROR.
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value); 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_); UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
@ -300,8 +302,8 @@ ShardResult<void> VertexAccessor::CheckVertexExistence(View view) const {
bool deleted = false; bool deleted = false;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -343,11 +345,11 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
} }
if (vertex_->deleted) { if (vertex_->second.deleted) {
return SHARD_ERROR(ErrorCode::DELETED_OBJECT); 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 // 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 // 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 // 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 // "modify in-place". Additionally, the created delta will make other
// transactions get a SERIALIZATION_ERROR. // transactions get a SERIALIZATION_ERROR.
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property, current_value); 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_); UpdateOnSetProperty(indices_, property, value, vertex_, *transaction_);
@ -365,15 +367,15 @@ ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId pro
ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() { ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR); 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) { for (const auto &property : properties) {
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property.first, property.second); CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(), property.first, property.second);
UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_, *transaction_); UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_, *transaction_);
} }
vertex_->properties.ClearProperties(); vertex_->second.properties.ClearProperties();
return std::move(properties); return std::move(properties);
} }
@ -396,11 +398,11 @@ PropertyValue VertexAccessor::GetPropertyValue(PropertyId property, View view) c
// Find PropertyId index in keystore // Find PropertyId index in keystore
for (size_t property_index{0}; property_index < schema->second.size(); ++property_index) { for (size_t property_index{0}; property_index < schema->second.size(); ++property_index) {
if (schema->second[property_index].property_id == property) { 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 { ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
@ -409,9 +411,9 @@ ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View
PropertyValue value; PropertyValue value;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
value = GetPropertyValue(property, view); value = GetPropertyValue(property, view);
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &value, property](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &value, property](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -453,10 +455,10 @@ ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View
std::map<PropertyId, PropertyValue> properties; std::map<PropertyId, PropertyValue> properties;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
// TODO(antaljanosbenjamin): Should this also return the primary key? // TODO(antaljanosbenjamin): Should this also return the primary key?
properties = vertex_->properties.Properties(); properties = vertex_->second.properties.Properties();
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &properties](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &properties](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -501,14 +503,14 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
const VertexId *destination_id) const { const VertexId *destination_id) const {
bool exists = true; bool exists = true;
bool deleted = false; bool deleted = false;
std::vector<Vertex::EdgeLink> in_edges; std::vector<VertexData::EdgeLink> in_edges;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
if (edge_types.empty() && nullptr == destination_id) { if (edge_types.empty() && nullptr == destination_id) {
in_edges = vertex_->in_edges; in_edges = vertex_->second.in_edges;
} else { } else {
for (const auto &item : vertex_->in_edges) { for (const auto &item : vertex_->second.in_edges) {
const auto &[edge_type, from_vertex, edge] = item; const auto &[edge_type, from_vertex, edge] = item;
if (nullptr != destination_id && from_vertex != *destination_id) { if (nullptr != destination_id && from_vertex != *destination_id) {
continue; continue;
@ -518,7 +520,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
in_edges.push_back(item); in_edges.push_back(item);
} }
} }
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead( ApplyDeltasForRead(
transaction_, delta, view, [&exists, &deleted, &in_edges, &edge_types, destination_id](const Delta &delta) { 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()) std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break; break;
// Add the edge because we don't see the removal. // 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); auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it == in_edges.end(), "Invalid database state!"); MG_ASSERT(it == in_edges.end(), "Invalid database state!");
in_edges.push_back(link); 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()) std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break; break;
// Remove the label because we don't see the addition. // 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); auto it = std::find(in_edges.begin(), in_edges.end(), link);
MG_ASSERT(it != in_edges.end(), "Invalid database state!"); MG_ASSERT(it != in_edges.end(), "Invalid database state!");
std::swap(*it, *in_edges.rbegin()); std::swap(*it, *in_edges.rbegin());
@ -571,7 +573,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const
return ret; return ret;
} }
ret.reserve(in_edges.size()); 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) { for (const auto &item : in_edges) {
const auto &[edge_type, from_vertex, edge] = item; const auto &[edge_type, from_vertex, edge] = item;
ret.emplace_back(edge, edge_type, from_vertex, id, transaction_, indices_, config_); 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 { const VertexId *destination_id) const {
bool exists = true; bool exists = true;
bool deleted = false; bool deleted = false;
std::vector<Vertex::EdgeLink> out_edges; std::vector<VertexData::EdgeLink> out_edges;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
if (edge_types.empty() && nullptr == destination_id) { if (edge_types.empty() && nullptr == destination_id) {
out_edges = vertex_->out_edges; out_edges = vertex_->second.out_edges;
} else { } else {
for (const auto &item : vertex_->out_edges) { for (const auto &item : vertex_->second.out_edges) {
const auto &[edge_type, to_vertex, edge] = item; const auto &[edge_type, to_vertex, edge] = item;
if (nullptr != destination_id && to_vertex != *destination_id) continue; 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()) 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); out_edges.push_back(item);
} }
} }
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead( ApplyDeltasForRead(
transaction_, delta, view, [&exists, &deleted, &out_edges, &edge_types, destination_id](const Delta &delta) { 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()) std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break; break;
// Add the edge because we don't see the removal. // 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); auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it == out_edges.end(), "Invalid database state!"); MG_ASSERT(it == out_edges.end(), "Invalid database state!");
out_edges.push_back(link); 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()) std::find(edge_types.begin(), edge_types.end(), delta.vertex_edge.edge_type) == edge_types.end())
break; break;
// Remove the label because we don't see the addition. // 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); auto it = std::find(out_edges.begin(), out_edges.end(), link);
MG_ASSERT(it != out_edges.end(), "Invalid database state!"); MG_ASSERT(it != out_edges.end(), "Invalid database state!");
std::swap(*it, *out_edges.rbegin()); std::swap(*it, *out_edges.rbegin());
@ -651,7 +653,7 @@ ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const
return ret; return ret;
} }
ret.reserve(out_edges.size()); 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) { for (const auto &item : out_edges) {
const auto &[edge_type, to_vertex, edge] = item; const auto &[edge_type, to_vertex, edge] = item;
ret.emplace_back(edge, edge_type, id, to_vertex, transaction_, indices_, config_); 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; size_t degree = 0;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
degree = vertex_->in_edges.size(); degree = vertex_->second.in_edges.size();
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) {
switch (delta.action) { switch (delta.action) {
@ -702,9 +704,9 @@ ShardResult<size_t> VertexAccessor::OutDegree(View view) const {
size_t degree = 0; size_t degree = 0;
Delta *delta = nullptr; Delta *delta = nullptr;
{ {
deleted = vertex_->deleted; deleted = vertex_->second.deleted;
degree = vertex_->out_edges.size(); degree = vertex_->second.out_edges.size();
delta = vertex_->delta; delta = vertex_->second.delta;
} }
ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) { ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &degree](const Delta &delta) {
switch (delta.action) { switch (delta.action) {