diff --git a/src/storage/v3/config.hpp b/src/storage/v3/config.hpp index 9d6dec759..bb99905df 100644 --- a/src/storage/v3/config.hpp +++ b/src/storage/v3/config.hpp @@ -14,6 +14,7 @@ #include #include #include +#include "storage/v3/id_types.hpp" #include "storage/v3/isolation_level.hpp" #include "storage/v3/transaction.hpp" diff --git a/src/storage/v3/durability/snapshot.cpp b/src/storage/v3/durability/snapshot.cpp index 9ae4d00ab..50fd418c1 100644 --- a/src/storage/v3/durability/snapshot.cpp +++ b/src/storage/v3/durability/snapshot.cpp @@ -19,6 +19,7 @@ #include "storage/v3/edge_accessor.hpp" #include "storage/v3/edge_ref.hpp" #include "storage/v3/mvcc.hpp" +#include "storage/v3/schema_validator.hpp" #include "storage/v3/schemas.hpp" #include "storage/v3/vertex_accessor.hpp" #include "storage/v3/vertices_skip_list.hpp" @@ -636,7 +637,7 @@ void CreateSnapshot(Transaction *transaction, const std::filesystem::path &snaps const std::filesystem::path &wal_directory, uint64_t snapshot_retention_count, VerticesSkipList *vertices, utils::SkipList *edges, NameIdMapper *name_id_mapper, Indices *indices, Constraints *constraints, Config::Items items, - const SchemaValidator &schema_validator, const std::string &uuid, const std::string_view epoch_id, + const VertexValidator &vertex_validator, const std::string &uuid, const std::string_view epoch_id, const std::deque> &epoch_history, utils::FileRetainer *file_retainer) { // Ensure that the storage directory exists. @@ -718,7 +719,7 @@ void CreateSnapshot(Transaction *transaction, const std::filesystem::path &snaps // here. // TODO(jbajic) Fix snapshot with new schema rules auto ea = EdgeAccessor{edge_ref, EdgeTypeId::FromUint(0UL), nullptr, nullptr, transaction, indices, constraints, - items, schema_validator}; + items, vertex_validator}; // Get edge data. auto maybe_props = ea.Properties(View::OLD); @@ -746,7 +747,7 @@ void CreateSnapshot(Transaction *transaction, const std::filesystem::path &snaps auto acc = vertices->access(); for (auto &lgo_vertex : acc) { // The visibility check is implemented for vertices so we use it here. - auto va = VertexAccessor::Create(&lgo_vertex.vertex, transaction, indices, constraints, items, schema_validator, + auto va = VertexAccessor::Create(&lgo_vertex.vertex, transaction, indices, constraints, items, vertex_validator, View::OLD); if (!va) continue; diff --git a/src/storage/v3/edge_accessor.cpp b/src/storage/v3/edge_accessor.cpp index b4d275d69..f0ddd6cc1 100644 --- a/src/storage/v3/edge_accessor.cpp +++ b/src/storage/v3/edge_accessor.cpp @@ -51,11 +51,11 @@ bool EdgeAccessor::IsVisible(const View view) const { } VertexAccessor EdgeAccessor::FromVertex() const { - return {from_vertex_, transaction_, indices_, constraints_, config_, *schema_validator_}; + return {from_vertex_, transaction_, indices_, constraints_, config_, *vertex_validator_}; } VertexAccessor EdgeAccessor::ToVertex() const { - return {to_vertex_, transaction_, indices_, constraints_, config_, *schema_validator_}; + return {to_vertex_, transaction_, indices_, constraints_, config_, *vertex_validator_}; } Result EdgeAccessor::SetProperty(PropertyId property, const PropertyValue &value) { diff --git a/src/storage/v3/edge_accessor.hpp b/src/storage/v3/edge_accessor.hpp index 8a17b163c..8dfaee31e 100644 --- a/src/storage/v3/edge_accessor.hpp +++ b/src/storage/v3/edge_accessor.hpp @@ -17,6 +17,7 @@ #include "storage/v3/edge_ref.hpp" #include "storage/v3/config.hpp" +#include "storage/v3/id_types.hpp" #include "storage/v3/result.hpp" #include "storage/v3/schema_validator.hpp" #include "storage/v3/transaction.hpp" @@ -36,7 +37,7 @@ class EdgeAccessor final { public: EdgeAccessor(EdgeRef edge, EdgeTypeId edge_type, Vertex *from_vertex, Vertex *to_vertex, Transaction *transaction, Indices *indices, Constraints *constraints, Config::Items config, - const SchemaValidator &schema_validator, bool for_deleted = false) + const VertexValidator &vertex_validator, bool for_deleted = false) : edge_(edge), edge_type_(edge_type), from_vertex_(from_vertex), @@ -45,7 +46,7 @@ class EdgeAccessor final { indices_(indices), constraints_(constraints), config_(config), - schema_validator_{&schema_validator}, + vertex_validator_{&vertex_validator}, for_deleted_(for_deleted) {} /// @return true if the object is visible from the current transaction @@ -94,7 +95,7 @@ class EdgeAccessor final { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; // if the accessor was created for a deleted edge. // Accessor behaves differently for some methods based on this diff --git a/src/storage/v3/indices.cpp b/src/storage/v3/indices.cpp index e69aa9d7e..82e7eadf2 100644 --- a/src/storage/v3/indices.cpp +++ b/src/storage/v3/indices.cpp @@ -13,9 +13,9 @@ #include +#include "storage/v3/id_types.hpp" #include "storage/v3/mvcc.hpp" #include "storage/v3/property_value.hpp" -#include "storage/v3/schema_validator.hpp" #include "storage/v3/schemas.hpp" #include "utils/bound.hpp" #include "utils/logging.hpp" @@ -327,7 +327,7 @@ void LabelIndex::RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp) { LabelIndex::Iterable::Iterator::Iterator(Iterable *self, utils::SkipList::Iterator index_iterator) : self_(self), index_iterator_(index_iterator), - current_vertex_accessor_(nullptr, nullptr, nullptr, nullptr, self_->config_, *self_->schema_validator_), + current_vertex_accessor_(nullptr, nullptr, nullptr, nullptr, self_->config_, *self_->vertex_validator_), current_vertex_(nullptr) { AdvanceUntilValid(); } @@ -346,7 +346,7 @@ void LabelIndex::Iterable::Iterator::AdvanceUntilValid() { if (CurrentVersionHasLabel(*index_iterator_->vertex, self_->label_, self_->transaction_, self_->view_)) { current_vertex_ = index_iterator_->vertex; current_vertex_accessor_ = VertexAccessor{current_vertex_, self_->transaction_, self_->indices_, - self_->constraints_, self_->config_, *self_->schema_validator_}; + self_->constraints_, self_->config_, *self_->vertex_validator_}; break; } } @@ -354,7 +354,7 @@ void LabelIndex::Iterable::Iterator::AdvanceUntilValid() { LabelIndex::Iterable::Iterable(utils::SkipList::Accessor index_accessor, LabelId label, View view, Transaction *transaction, Indices *indices, Constraints *constraints, - Config::Items config, const SchemaValidator &schema_validator) + Config::Items config, const VertexValidator &vertex_validator) : index_accessor_(std::move(index_accessor)), label_(label), view_(view), @@ -362,7 +362,7 @@ LabelIndex::Iterable::Iterable(utils::SkipList::Accessor index_accessor, indices_(indices), constraints_(constraints), config_(config), - schema_validator_(&schema_validator) {} + vertex_validator_(&vertex_validator) {} void LabelIndex::RunGC() { for (auto &index_entry : index_) { @@ -480,7 +480,7 @@ void LabelPropertyIndex::RemoveObsoleteEntries(uint64_t oldest_active_start_time LabelPropertyIndex::Iterable::Iterator::Iterator(Iterable *self, utils::SkipList::Iterator index_iterator) : self_(self), index_iterator_(index_iterator), - current_vertex_accessor_(nullptr, nullptr, nullptr, nullptr, self_->config_, *self_->schema_validator_), + current_vertex_accessor_(nullptr, nullptr, nullptr, nullptr, self_->config_, *self_->vertex_validator_), current_vertex_(nullptr) { AdvanceUntilValid(); } @@ -520,7 +520,7 @@ void LabelPropertyIndex::Iterable::Iterator::AdvanceUntilValid() { index_iterator_->value, self_->transaction_, self_->view_)) { current_vertex_ = index_iterator_->vertex; current_vertex_accessor_ = VertexAccessor(current_vertex_, self_->transaction_, self_->indices_, - self_->constraints_, self_->config_, *self_->schema_validator_); + self_->constraints_, self_->config_, *self_->vertex_validator_); break; } } @@ -543,7 +543,7 @@ LabelPropertyIndex::Iterable::Iterable(utils::SkipList::Accessor index_ac const std::optional> &lower_bound, const std::optional> &upper_bound, View view, Transaction *transaction, Indices *indices, Constraints *constraints, - Config::Items config, const SchemaValidator &schema_validator) + Config::Items config, const VertexValidator &vertex_validator) : index_accessor_(std::move(index_accessor)), label_(label), property_(property), @@ -554,7 +554,7 @@ LabelPropertyIndex::Iterable::Iterable(utils::SkipList::Accessor index_ac indices_(indices), constraints_(constraints), config_(config), - schema_validator_(&schema_validator) { + vertex_validator_(&vertex_validator) { // We have to fix the bounds that the user provided to us. If the user // provided only one bound we should make sure that only values of that type // are returned by the iterator. We ensure this by supplying either an diff --git a/src/storage/v3/indices.hpp b/src/storage/v3/indices.hpp index e7ae2d593..01c611c97 100644 --- a/src/storage/v3/indices.hpp +++ b/src/storage/v3/indices.hpp @@ -18,7 +18,6 @@ #include "storage/v3/config.hpp" #include "storage/v3/property_value.hpp" -#include "storage/v3/schema_validator.hpp" #include "storage/v3/transaction.hpp" #include "storage/v3/vertex_accessor.hpp" #include "storage/v3/vertices_skip_list.hpp" @@ -54,8 +53,8 @@ class LabelIndex { }; public: - LabelIndex(Indices *indices, Constraints *constraints, Config::Items config, const SchemaValidator &schema_validator) - : indices_(indices), constraints_(constraints), config_(config), schema_validator_{&schema_validator} {} + LabelIndex(Indices *indices, Constraints *constraints, Config::Items config, const VertexValidator &vertex_validator) + : indices_(indices), constraints_(constraints), config_(config), vertex_validator_{&vertex_validator} {} /// @throw std::bad_alloc void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx); @@ -75,7 +74,7 @@ class LabelIndex { class Iterable { public: Iterable(utils::SkipList::Accessor index_accessor, LabelId label, View view, Transaction *transaction, - Indices *indices, Constraints *constraints, Config::Items config, const SchemaValidator &schema_validator); + Indices *indices, Constraints *constraints, Config::Items config, const VertexValidator &vertex_validator); class Iterator { public: @@ -108,14 +107,14 @@ class LabelIndex { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; }; /// Returns an self with vertices visible from the given transaction. Iterable Vertices(LabelId label, View view, Transaction *transaction) { auto it = index_.find(label); MG_ASSERT(it != index_.end(), "Index for label {} doesn't exist", label.AsUint()); - return {it->second.access(), label, view, transaction, indices_, constraints_, config_, *schema_validator_}; + return {it->second.access(), label, view, transaction, indices_, constraints_, config_, *vertex_validator_}; } int64_t ApproximateVertexCount(LabelId label) { @@ -133,7 +132,7 @@ class LabelIndex { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; }; class LabelPropertyIndex { @@ -152,8 +151,8 @@ class LabelPropertyIndex { public: LabelPropertyIndex(Indices *indices, Constraints *constraints, Config::Items config, - const SchemaValidator &schema_validator) - : indices_(indices), constraints_(constraints), config_(config), schema_validator_{&schema_validator} {} + const VertexValidator &vertex_validator) + : indices_(indices), constraints_(constraints), config_(config), vertex_validator_{&vertex_validator} {} /// @throw std::bad_alloc void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx); @@ -177,7 +176,7 @@ class LabelPropertyIndex { Iterable(utils::SkipList::Accessor index_accessor, LabelId label, PropertyId property, const std::optional> &lower_bound, const std::optional> &upper_bound, View view, Transaction *transaction, - Indices *indices, Constraints *constraints, Config::Items config, const SchemaValidator &schema_validator); + Indices *indices, Constraints *constraints, Config::Items config, const VertexValidator &vertex_validator); class Iterator { public: @@ -214,17 +213,17 @@ class LabelPropertyIndex { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; }; Iterable Vertices(LabelId label, PropertyId property, const std::optional> &lower_bound, const std::optional> &upper_bound, View view, Transaction *transaction, - const SchemaValidator &schema_validator) { + const VertexValidator &vertex_validator) { auto it = index_.find({label, property}); MG_ASSERT(it != index_.end(), "Index for label {} and property {} doesn't exist", label.AsUint(), property.AsUint()); return {it->second.access(), label, property, lower_bound, upper_bound, view, - transaction, indices_, constraints_, config_, schema_validator}; + transaction, indices_, constraints_, config_, vertex_validator}; } int64_t ApproximateVertexCount(LabelId label, PropertyId property) const { @@ -253,13 +252,13 @@ class LabelPropertyIndex { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; }; struct Indices { - Indices(Constraints *constraints, Config::Items config, const SchemaValidator &schema_validator) - : label_index(this, constraints, config, schema_validator), - label_property_index(this, constraints, config, schema_validator) {} + Indices(Constraints *constraints, Config::Items config, const VertexValidator &vertex_validator) + : label_index(this, constraints, config, vertex_validator), + label_property_index(this, constraints, config, vertex_validator) {} // Disable copy and move because members hold pointer to `this`. Indices(const Indices &) = delete; diff --git a/src/storage/v3/replication/replication_server.cpp b/src/storage/v3/replication/replication_server.cpp index 1905071ce..f26615cf9 100644 --- a/src/storage/v3/replication/replication_server.cpp +++ b/src/storage/v3/replication/replication_server.cpp @@ -163,9 +163,9 @@ void Shard::ReplicationServer::SnapshotHandler(slk::Reader *req_reader, slk::Bui shard_->constraints_ = Constraints(); shard_->indices_.label_index = - LabelIndex(&shard_->indices_, &shard_->constraints_, shard_->config_.items, shard_->schema_validator_); + LabelIndex(&shard_->indices_, &shard_->constraints_, shard_->config_.items, shard_->vertex_validator_); shard_->indices_.label_property_index = - LabelPropertyIndex(&shard_->indices_, &shard_->constraints_, shard_->config_.items, shard_->schema_validator_); + LabelPropertyIndex(&shard_->indices_, &shard_->constraints_, shard_->config_.items, shard_->vertex_validator_); try { spdlog::debug("Loading snapshot"); auto recovered_snapshot = durability::RecoveredSnapshot{}; diff --git a/src/storage/v3/schema_validator.cpp b/src/storage/v3/schema_validator.cpp index ea46e550b..b69a3b5b8 100644 --- a/src/storage/v3/schema_validator.cpp +++ b/src/storage/v3/schema_validator.cpp @@ -103,4 +103,19 @@ SchemaValidator::SchemaValidator(Schemas &schemas) : schemas_{schemas} {} return std::nullopt; } +VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label) + : schema_validator{&schema_validator}, primary_label_{primary_label} {} + +[[nodiscard]] std::optional VertexValidator::ValidatePropertyUpdate(PropertyId property_id) const { + return schema_validator->ValidatePropertyUpdate(primary_label_, property_id); +}; + +[[nodiscard]] std::optional VertexValidator::ValidateAddLabel(LabelId label) const { + return schema_validator->ValidateLabelUpdate(label); +} + +[[nodiscard]] std::optional VertexValidator::ValidateRemoveLabel(LabelId label) const { + return schema_validator->ValidateLabelUpdate(label); +} + } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/schema_validator.hpp b/src/storage/v3/schema_validator.hpp index e64a2ead5..54943a336 100644 --- a/src/storage/v3/schema_validator.hpp +++ b/src/storage/v3/schema_validator.hpp @@ -63,6 +63,20 @@ class SchemaValidator { Schemas &schemas_; }; +struct VertexValidator { + explicit VertexValidator(const SchemaValidator &schema_validator, LabelId primary_label); + + [[nodiscard]] std::optional ValidatePropertyUpdate(PropertyId property_id) const; + + [[nodiscard]] std::optional ValidateAddLabel(LabelId label) const; + + [[nodiscard]] std::optional ValidateRemoveLabel(LabelId label) const; + + const SchemaValidator *schema_validator; + + LabelId primary_label_; +}; + template using ResultSchema = utils::BasicResult, TValue>; diff --git a/src/storage/v3/shard.cpp b/src/storage/v3/shard.cpp index bd90327c9..1260004bf 100644 --- a/src/storage/v3/shard.cpp +++ b/src/storage/v3/shard.cpp @@ -70,9 +70,9 @@ void InsertVertexPKIntoList(auto &container, const PrimaryKey &primary_key) { co auto AdvanceToVisibleVertex(VerticesSkipList::Iterator it, VerticesSkipList::Iterator end, std::optional *vertex, Transaction *tx, View view, Indices *indices, - Constraints *constraints, Config::Items config, const SchemaValidator &schema_validator) { + Constraints *constraints, Config::Items config, const VertexValidator &vertex_validator) { while (it != end) { - *vertex = VertexAccessor::Create(&it->vertex, tx, indices, constraints, config, schema_validator, view); + *vertex = VertexAccessor::Create(&it->vertex, tx, indices, constraints, config, vertex_validator, view); if (!*vertex) { ++it; continue; @@ -85,14 +85,14 @@ auto AdvanceToVisibleVertex(VerticesSkipList::Iterator it, VerticesSkipList::Ite AllVerticesIterable::Iterator::Iterator(AllVerticesIterable *self, VerticesSkipList::Iterator it) : self_(self), it_(AdvanceToVisibleVertex(it, self->vertices_accessor_.end(), &self->vertex_, self->transaction_, self->view_, - self->indices_, self_->constraints_, self->config_, *self_->schema_validator_)) {} + self->indices_, self_->constraints_, self->config_, *self_->vertex_validator_)) {} VertexAccessor AllVerticesIterable::Iterator::operator*() const { return *self_->vertex_; } AllVerticesIterable::Iterator &AllVerticesIterable::Iterator::operator++() { ++it_; it_ = AdvanceToVisibleVertex(it_, self_->vertices_accessor_.end(), &self_->vertex_, self_->transaction_, self_->view_, - self_->indices_, self_->constraints_, self_->config_, *self_->schema_validator_); + self_->indices_, self_->constraints_, self_->config_, *self_->vertex_validator_); return *this; } @@ -321,7 +321,8 @@ Shard::Shard(const LabelId primary_label, const PrimaryKey min_primary_key, min_primary_key_{min_primary_key}, max_primary_key_{max_primary_key}, schema_validator_{schemas_}, - indices_{&constraints_, config.items, schema_validator_}, + vertex_validator_{schema_validator_, primary_label}, + indices_{&constraints_, config.items, vertex_validator_}, isolation_level_{config.transaction.isolation_level}, config_{config}, snapshot_directory_{config_.durability.storage_directory / durability::kSnapshotDirectory}, @@ -496,10 +497,10 @@ ResultSchema Shard::Accessor::CreateVertexAndValidate( } auto acc = shard_->vertices_.access(); auto *delta = CreateDeleteObjectDelta(&transaction_); - auto [it, inserted] = acc.insert({Vertex{delta, primary_label, primary_properties}}); + auto [it, inserted] = acc.insert({Vertex{delta, primary_properties}}); VertexAccessor vertex_acc{&it->vertex, &transaction_, &shard_->indices_, - &shard_->constraints_, config_, shard_->schema_validator_}; + &shard_->constraints_, config_, shard_->vertex_validator_}; MG_ASSERT(inserted, "The vertex must be inserted here!"); MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!"); @@ -529,7 +530,7 @@ std::optional Shard::Accessor::FindVertex(std::vectorvertex, &transaction_, &shard_->indices_, &shard_->constraints_, config_, - shard_->schema_validator_, view); + shard_->vertex_validator_, view); } Result> Shard::Accessor::DeleteVertex(VertexAccessor *vertex) { @@ -550,7 +551,7 @@ Result> Shard::Accessor::DeleteVertex(VertexAccess vertex_ptr->deleted = true; return std::make_optional(vertex_ptr, &transaction_, &shard_->indices_, &shard_->constraints_, - config_, shard_->schema_validator_, true); + config_, shard_->vertex_validator_, true); } Result>>> Shard::Accessor::DetachDeleteVertex( @@ -578,7 +579,7 @@ Result>>> Shar for (const auto &item : in_edges) { auto [edge_type, from_vertex, edge] = item; EdgeAccessor e(edge, edge_type, from_vertex, vertex_ptr, &transaction_, &shard_->indices_, &shard_->constraints_, - config_, shard_->schema_validator_); + config_, shard_->vertex_validator_); auto ret = DeleteEdge(&e); if (ret.HasError()) { MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!"); @@ -592,7 +593,7 @@ Result>>> Shar for (const auto &item : out_edges) { auto [edge_type, to_vertex, edge] = item; EdgeAccessor e(edge, edge_type, vertex_ptr, to_vertex, &transaction_, &shard_->indices_, &shard_->constraints_, - config_, shard_->schema_validator_); + config_, shard_->vertex_validator_); auto ret = DeleteEdge(&e); if (ret.HasError()) { MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!"); @@ -616,7 +617,7 @@ Result>>> Shar vertex_ptr->deleted = true; return std::make_optional(VertexAccessor{vertex_ptr, &transaction_, &shard_->indices_, - &shard_->constraints_, config_, shard_->schema_validator_, true}, + &shard_->constraints_, config_, shard_->vertex_validator_, true}, std::move(deleted_edges)); } @@ -662,7 +663,7 @@ Result Shard::Accessor::CreateEdge(VertexAccessor *from, VertexAcc ++shard_->edge_count_; return EdgeAccessor(edge, edge_type, from_vertex, to_vertex, &transaction_, &shard_->indices_, &shard_->constraints_, - config_, shard_->schema_validator_); + config_, shard_->vertex_validator_); } Result Shard::Accessor::CreateEdge(VertexAccessor *from, VertexAccessor *to, EdgeTypeId edge_type, @@ -715,7 +716,7 @@ Result Shard::Accessor::CreateEdge(VertexAccessor *from, VertexAcc ++shard_->edge_count_; return EdgeAccessor(edge, edge_type, from_vertex, to_vertex, &transaction_, &shard_->indices_, &shard_->constraints_, - config_, shard_->schema_validator_); + config_, shard_->vertex_validator_); } Result> Shard::Accessor::DeleteEdge(EdgeAccessor *edge) { @@ -783,7 +784,7 @@ Result> Shard::Accessor::DeleteEdge(EdgeAccessor *ed --shard_->edge_count_; return std::make_optional(edge_ref, edge_type, from_vertex, to_vertex, &transaction_, &shard_->indices_, - &shard_->constraints_, config_, shard_->schema_validator_, true); + &shard_->constraints_, config_, shard_->vertex_validator_, true); } const std::string &Shard::Accessor::LabelToName(LabelId label) const { return shard_->LabelToName(label); } @@ -1208,20 +1209,20 @@ VerticesIterable Shard::Accessor::Vertices(LabelId label, View view) { VerticesIterable Shard::Accessor::Vertices(LabelId label, PropertyId property, View view) { return VerticesIterable(shard_->indices_.label_property_index.Vertices( - label, property, std::nullopt, std::nullopt, view, &transaction_, shard_->schema_validator_)); + label, property, std::nullopt, std::nullopt, view, &transaction_, shard_->vertex_validator_)); } VerticesIterable Shard::Accessor::Vertices(LabelId label, PropertyId property, const PropertyValue &value, View view) { return VerticesIterable(shard_->indices_.label_property_index.Vertices( label, property, utils::MakeBoundInclusive(value), utils::MakeBoundInclusive(value), view, &transaction_, - shard_->schema_validator_)); + shard_->vertex_validator_)); } VerticesIterable Shard::Accessor::Vertices(LabelId label, PropertyId property, const std::optional> &lower_bound, const std::optional> &upper_bound, View view) { return VerticesIterable(shard_->indices_.label_property_index.Vertices( - label, property, lower_bound, upper_bound, view, &transaction_, shard_->schema_validator_)); + label, property, lower_bound, upper_bound, view, &transaction_, shard_->vertex_validator_)); } Transaction Shard::CreateTransaction(IsolationLevel isolation_level) { diff --git a/src/storage/v3/shard.hpp b/src/storage/v3/shard.hpp index 8a42e542d..fcc80e4f0 100644 --- a/src/storage/v3/shard.hpp +++ b/src/storage/v3/shard.hpp @@ -79,7 +79,7 @@ class AllVerticesIterable final { Indices *indices_; Constraints *constraints_; Config::Items config_; - const SchemaValidator *schema_validator_; + const VertexValidator *vertex_validator_; const Schemas *schemas_; std::optional vertex_; @@ -102,14 +102,14 @@ class AllVerticesIterable final { AllVerticesIterable(VerticesSkipList::Accessor vertices_accessor, Transaction *transaction, View view, Indices *indices, Constraints *constraints, Config::Items config, - const SchemaValidator &schema_validator) + const VertexValidator &vertex_validator) : vertices_accessor_(std::move(vertices_accessor)), transaction_(transaction), view_(view), indices_(indices), constraints_(constraints), config_(config), - schema_validator_{&schema_validator} {} + vertex_validator_{&vertex_validator} {} Iterator begin() { return {this, vertices_accessor_.begin()}; } Iterator end() { return {this, vertices_accessor_.end()}; } @@ -246,7 +246,7 @@ class Shard final { VerticesIterable Vertices(View view) { return VerticesIterable(AllVerticesIterable(shard_->vertices_.access(), &transaction_, view, &shard_->indices_, &shard_->constraints_, shard_->config_.items, - shard_->schema_validator_)); + shard_->vertex_validator_)); } VerticesIterable Vertices(LabelId label, View view); @@ -519,6 +519,7 @@ class Shard final { uint64_t edge_count_{0}; SchemaValidator schema_validator_; + VertexValidator vertex_validator_; Constraints constraints_; Indices indices_; Schemas schemas_; diff --git a/src/storage/v3/vertex.hpp b/src/storage/v3/vertex.hpp index 08ae747b3..4b2fbe9f8 100644 --- a/src/storage/v3/vertex.hpp +++ b/src/storage/v3/vertex.hpp @@ -28,19 +28,11 @@ namespace memgraph::storage::v3 { struct Vertex { - Vertex(Delta *delta, LabelId primary_label, const std::vector &primary_properties) - : primary_label{primary_label}, keys{primary_properties}, delta{delta} { + Vertex(Delta *delta, const std::vector &primary_properties) : keys{primary_properties}, delta{delta} { MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT, "Vertex must be created with an initial DELETE_OBJECT delta!"); } - Vertex(LabelId primary_label, const std::vector &primary_properties) - : primary_label{primary_label}, keys(primary_properties) { - MG_ASSERT(delta == nullptr || delta->action == Delta::Action::DELETE_OBJECT, - "Vertex must be created with an initial DELETE_OBJECT delta!"); - } - - LabelId primary_label; KeyStore keys; std::vector labels; @@ -57,8 +49,6 @@ struct Vertex { static_assert(alignof(Vertex) >= 8, "The Vertex should be aligned to at least 8!"); -inline bool VertexHasLabel(const Vertex &vertex, const LabelId label) { - return vertex.primary_label == label || utils::Contains(vertex.labels, label); -} +inline bool VertexHasLabel(const Vertex &vertex, const LabelId label) { return utils::Contains(vertex.labels, label); } } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/vertex_accessor.cpp b/src/storage/v3/vertex_accessor.cpp index ff8b34276..a7e423387 100644 --- a/src/storage/v3/vertex_accessor.cpp +++ b/src/storage/v3/vertex_accessor.cpp @@ -64,12 +64,12 @@ std::pair IsVisible(Vertex *vertex, Transaction *transaction, View v std::optional VertexAccessor::Create(Vertex *vertex, Transaction *transaction, Indices *indices, Constraints *constraints, Config::Items config, - const SchemaValidator &schema_validator, View view) { + const VertexValidator &vertex_validator, View view) { if (const auto [exists, deleted] = detail::IsVisible(vertex, transaction, view); !exists || deleted) { return std::nullopt; } - return VertexAccessor{vertex, transaction, indices, constraints, config, schema_validator}; + return VertexAccessor{vertex, transaction, indices, constraints, config, vertex_validator}; } bool VertexAccessor::IsVisible(View view) const { @@ -96,7 +96,7 @@ Result VertexAccessor::AddLabel(LabelId label) { } ResultSchema VertexAccessor::AddLabelAndValidate(LabelId label) { - if (const auto maybe_violation_error = vertex_validator_.ValidateAddLabel(label); maybe_violation_error) { + if (const auto maybe_violation_error = vertex_validator_->ValidateAddLabel(label); maybe_violation_error) { return {*maybe_violation_error}; } utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception; @@ -132,7 +132,7 @@ Result VertexAccessor::RemoveLabel(LabelId label) { } ResultSchema VertexAccessor::RemoveLabelAndValidate(LabelId label) { - if (const auto maybe_violation_error = vertex_validator_.ValidateRemoveLabel(label); maybe_violation_error) { + if (const auto maybe_violation_error = vertex_validator_->ValidateRemoveLabel(label); maybe_violation_error) { return {*maybe_violation_error}; } @@ -157,7 +157,7 @@ Result VertexAccessor::HasLabel(LabelId label, View view) const { Delta *delta = nullptr; { deleted = vertex_->deleted; - has_label = VertexHasLabel(*vertex_, label); + has_label = label == vertex_validator_->primary_label_ || VertexHasLabel(*vertex_, label); delta = vertex_->delta; } ApplyDeltasForRead(transaction_, delta, view, [&exists, &deleted, &has_label, label](const Delta &delta) { @@ -227,7 +227,7 @@ Result VertexAccessor::PrimaryLabel(const View view) const { }); if (!exists) return Error::NONEXISTENT_OBJECT; if (!for_deleted_ && deleted) return Error::DELETED_OBJECT; - return vertex_->primary_label; + return vertex_validator_->primary_label_; } Result VertexAccessor::PrimaryKey(const View view) const { @@ -338,7 +338,7 @@ Result VertexAccessor::SetProperty(PropertyId property, const Pro } ResultSchema VertexAccessor::SetPropertyAndValidate(PropertyId property, const PropertyValue &value) { - if (auto maybe_violation_error = vertex_validator_.ValidatePropertyUpdate(property); maybe_violation_error) { + if (auto maybe_violation_error = vertex_validator_->ValidatePropertyUpdate(property); maybe_violation_error) { return {*maybe_violation_error}; } utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception; @@ -546,7 +546,7 @@ Result> VertexAccessor::InEdges(View view, const std:: for (const auto &item : in_edges) { const auto &[edge_type, from_vertex, edge] = item; ret.emplace_back(edge, edge_type, from_vertex, vertex_, transaction_, indices_, constraints_, config_, - *vertex_validator_.schema_validator); + *vertex_validator_); } return std::move(ret); } @@ -626,7 +626,7 @@ Result> VertexAccessor::OutEdges(View view, const std: for (const auto &item : out_edges) { const auto &[edge_type, to_vertex, edge] = item; ret.emplace_back(edge, edge_type, vertex_, to_vertex, transaction_, indices_, constraints_, config_, - *vertex_validator_.schema_validator); + *vertex_validator_); } return std::move(ret); } @@ -705,21 +705,4 @@ Result VertexAccessor::OutDegree(View view) const { return degree; } -VertexAccessor::VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const Vertex *vertex) - : schema_validator{&schema_validator}, vertex_{vertex} {} - -[[nodiscard]] std::optional VertexAccessor::VertexValidator::ValidatePropertyUpdate( - PropertyId property_id) const { - MG_ASSERT(vertex_ != nullptr, "Cannot validate vertex which is nullptr"); - return schema_validator->ValidatePropertyUpdate(vertex_->primary_label, property_id); -}; - -[[nodiscard]] std::optional VertexAccessor::VertexValidator::ValidateAddLabel(LabelId label) const { - return schema_validator->ValidateLabelUpdate(label); -} - -[[nodiscard]] std::optional VertexAccessor::VertexValidator::ValidateRemoveLabel(LabelId label) const { - return schema_validator->ValidateLabelUpdate(label); -} - } // namespace memgraph::storage::v3 diff --git a/src/storage/v3/vertex_accessor.hpp b/src/storage/v3/vertex_accessor.hpp index 71e297478..33556e3f6 100644 --- a/src/storage/v3/vertex_accessor.hpp +++ b/src/storage/v3/vertex_accessor.hpp @@ -31,39 +31,24 @@ struct Constraints; class VertexAccessor final { private: - struct VertexValidator { - // TODO(jbajic) Beware since vertex is pointer it will be accessed even as nullptr - explicit VertexValidator(const SchemaValidator &schema_validator, const Vertex *vertex); - - [[nodiscard]] std::optional ValidatePropertyUpdate(PropertyId property_id) const; - - [[nodiscard]] std::optional ValidateAddLabel(LabelId label) const; - - [[nodiscard]] std::optional ValidateRemoveLabel(LabelId label) const; - - const SchemaValidator *schema_validator; - - private: - const Vertex *vertex_; - }; friend class Shard; public: // Be careful when using VertexAccessor since it can be instantiated with // nullptr values VertexAccessor(Vertex *vertex, Transaction *transaction, Indices *indices, Constraints *constraints, - Config::Items config, const SchemaValidator &schema_validator, bool for_deleted = false) + Config::Items config, const VertexValidator &vertex_validator, bool for_deleted = false) : vertex_(vertex), transaction_(transaction), indices_(indices), constraints_(constraints), config_(config), - vertex_validator_{schema_validator, vertex}, + vertex_validator_{&vertex_validator}, for_deleted_(for_deleted) {} static std::optional Create(Vertex *vertex, Transaction *transaction, Indices *indices, Constraints *constraints, Config::Items config, - const SchemaValidator &schema_validator, View view); + const VertexValidator &vertex_validator, View view); /// @return true if the object is visible from the current transaction bool IsVisible(View view) const; @@ -148,7 +133,7 @@ class VertexAccessor final { Indices *indices_; Constraints *constraints_; Config::Items config_; - VertexValidator vertex_validator_; + const VertexValidator *vertex_validator_; // if the accessor was created for a deleted vertex. // Accessor behaves differently for some methods based on this