From 88f8a0ae689e4d0f95d1a716302927cfc8d01afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Pu=C5=A1i=C4=87?= Date: Wed, 17 Jan 2024 21:48:57 +0100 Subject: [PATCH] Add most of CRUD --- src/dbms/inmemory/replication_handlers.cpp | 6 +- src/mg_import_csv.cpp | 10 +- src/query/db_accessor.hpp | 50 ++++--- src/query/plan/operator.cpp | 31 ++++- src/query/procedure/mg_procedure_impl.cpp | 13 +- src/storage/v2/durability/snapshot.cpp | 3 +- src/storage/v2/durability/wal.cpp | 3 +- src/storage/v2/indices/indices.cpp | 34 ++++- src/storage/v2/indices/indices.hpp | 13 +- src/storage/v2/indices/text_index.cpp | 72 +++++++++- src/storage/v2/indices/text_index.hpp | 20 ++- src/storage/v2/inmemory/storage.cpp | 1 + src/storage/v2/storage.cpp | 6 + src/storage/v2/vertex_accessor.cpp | 148 +++++++++++---------- src/storage/v2/vertex_accessor.hpp | 15 ++- 15 files changed, 289 insertions(+), 136 deletions(-) diff --git a/src/dbms/inmemory/replication_handlers.cpp b/src/dbms/inmemory/replication_handlers.cpp index 2b8d6a86b..4b7a7c9b1 100644 --- a/src/dbms/inmemory/replication_handlers.cpp +++ b/src/dbms/inmemory/replication_handlers.cpp @@ -435,7 +435,7 @@ uint64_t InMemoryReplicationHandlers::ReadAndApplyDelta(storage::InMemoryStorage auto vertex = transaction->FindVertex(delta.vertex_add_remove_label.gid, View::NEW); if (!vertex) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); - auto ret = vertex->AddLabel(transaction->NameToLabel(delta.vertex_add_remove_label.label)); + auto ret = vertex->AddLabel(transaction->NameToLabel(delta.vertex_add_remove_label.label), true); if (ret.HasError() || !ret.GetValue()) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); break; @@ -447,7 +447,7 @@ uint64_t InMemoryReplicationHandlers::ReadAndApplyDelta(storage::InMemoryStorage auto vertex = transaction->FindVertex(delta.vertex_add_remove_label.gid, View::NEW); if (!vertex) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); - auto ret = vertex->RemoveLabel(transaction->NameToLabel(delta.vertex_add_remove_label.label)); + auto ret = vertex->RemoveLabel(transaction->NameToLabel(delta.vertex_add_remove_label.label), true); if (ret.HasError() || !ret.GetValue()) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); break; @@ -460,7 +460,7 @@ uint64_t InMemoryReplicationHandlers::ReadAndApplyDelta(storage::InMemoryStorage if (!vertex) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); auto ret = vertex->SetProperty(transaction->NameToProperty(delta.vertex_edge_set_property.property), - delta.vertex_edge_set_property.value); + delta.vertex_edge_set_property.value, true); if (ret.HasError()) throw utils::BasicException("Invalid transaction! Please raise an issue, {}:{}", __FILE__, __LINE__); break; diff --git a/src/mg_import_csv.cpp b/src/mg_import_csv.cpp index e8212b5f4..4679b7ba5 100644 --- a/src/mg_import_csv.cpp +++ b/src/mg_import_csv.cpp @@ -457,28 +457,30 @@ void ProcessNodeRow(memgraph::storage::Storage *store, const std::vectorNameToProperty(field.name), pv_id); + auto old_node_property = node.SetProperty(acc->NameToProperty(field.name), pv_id, false); if (!old_node_property.HasValue()) throw LoadException("Couldn't add property '{}' to the node", field.name); if (!old_node_property->IsNull()) throw LoadException("The property '{}' already exists", field.name); } id = node_id; } else if (field.type == "LABEL") { for (const auto &label : memgraph::utils::Split(value, FLAGS_array_delimiter)) { - auto node_label = node.AddLabel(acc->NameToLabel(label)); + auto node_label = node.AddLabel(acc->NameToLabel(label), false); if (!node_label.HasValue()) throw LoadException("Couldn't add label '{}' to the node", label); if (!*node_label) throw LoadException("The label '{}' already exists", label); } } else if (field.type != "IGNORE") { - auto old_node_property = node.SetProperty(acc->NameToProperty(field.name), StringToValue(value, field.type)); + auto old_node_property = + node.SetProperty(acc->NameToProperty(field.name), StringToValue(value, field.type), false); if (!old_node_property.HasValue()) throw LoadException("Couldn't add property '{}' to the node", field.name); if (!old_node_property->IsNull()) throw LoadException("The property '{}' already exists", field.name); } } for (const auto &label : additional_labels) { - auto node_label = node.AddLabel(acc->NameToLabel(label)); + auto node_label = node.AddLabel(acc->NameToLabel(label), false); if (!node_label.HasValue()) throw LoadException("Couldn't add label '{}' to the node", label); if (!*node_label) throw LoadException("The label '{}' already exists", label); } + // TODO: refresh text index if (acc->Commit().HasError()) throw LoadException("Couldn't store the node"); } diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp index d696e636b..d609b6c92 100644 --- a/src/query/db_accessor.hpp +++ b/src/query/db_accessor.hpp @@ -115,9 +115,13 @@ class VertexAccessor final { auto Labels(storage::View view) const { return impl_.Labels(view); } - storage::Result AddLabel(storage::LabelId label) { return impl_.AddLabel(label); } + storage::Result AddLabel(storage::LabelId label, bool update_text_index) { + return impl_.AddLabel(label, update_text_index); + } - storage::Result RemoveLabel(storage::LabelId label) { return impl_.RemoveLabel(label); } + storage::Result RemoveLabel(storage::LabelId label, bool update_text_index) { + return impl_.RemoveLabel(label, update_text_index); + } storage::Result HasLabel(storage::View view, storage::LabelId label) const { return impl_.HasLabel(label, view); @@ -129,25 +133,29 @@ class VertexAccessor final { return impl_.GetProperty(key, view); } - storage::Result SetProperty(storage::PropertyId key, const storage::PropertyValue &value) { - return impl_.SetProperty(key, value); + storage::Result SetProperty(storage::PropertyId key, const storage::PropertyValue &value, + bool update_text_index = false) { + return impl_.SetProperty(key, value, update_text_index); } - storage::Result InitProperties(const std::map &properties) { - return impl_.InitProperties(properties); + storage::Result InitProperties(const std::map &properties, + bool update_text_index = false) { + return impl_.InitProperties(properties, update_text_index); } storage::Result>> - UpdateProperties(std::map &properties) const { - return impl_.UpdateProperties(properties); + UpdateProperties(std::map &properties, + bool update_text_index = false) const { + return impl_.UpdateProperties(properties, update_text_index); } - storage::Result RemoveProperty(storage::PropertyId key) { - return SetProperty(key, storage::PropertyValue()); + storage::Result RemoveProperty(storage::PropertyId key, bool update_text_index = true) { + return SetProperty(key, storage::PropertyValue(), update_text_index); } - storage::Result> ClearProperties() { - return impl_.ClearProperties(); + storage::Result> ClearProperties( + bool update_text_index = false) { + return impl_.ClearProperties(update_text_index); } storage::Result InEdges(storage::View view, @@ -254,9 +262,13 @@ class SubgraphVertexAccessor final { auto Labels(storage::View view) const { return impl_.Labels(view); } - storage::Result AddLabel(storage::LabelId label) { return impl_.AddLabel(label); } + storage::Result AddLabel(storage::LabelId label, bool update_text_index) { + return impl_.AddLabel(label, update_text_index); + } - storage::Result RemoveLabel(storage::LabelId label) { return impl_.RemoveLabel(label); } + storage::Result RemoveLabel(storage::LabelId label, bool update_text_index) { + return impl_.RemoveLabel(label, update_text_index); + } storage::Result HasLabel(storage::View view, storage::LabelId label) const { return impl_.HasLabel(view, label); @@ -274,13 +286,15 @@ class SubgraphVertexAccessor final { storage::Result OutDegree(storage::View view) const { return impl_.OutDegree(view); } - storage::Result SetProperty(storage::PropertyId key, const storage::PropertyValue &value) { - return impl_.SetProperty(key, value); + storage::Result SetProperty(storage::PropertyId key, const storage::PropertyValue &value, + bool update_text_index = false) { + return impl_.SetProperty(key, value, update_text_index); } storage::Result>> - UpdateProperties(std::map &properties) const { - return impl_.UpdateProperties(properties); + UpdateProperties(std::map &properties, + bool update_text_index = false) const { + return impl_.UpdateProperties(properties, update_text_index); } VertexAccessor GetVertexAccessor() const; diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index 82269ca27..01fbd740d 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -217,7 +217,7 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, Frame *fram auto new_node = dba.InsertVertex(); context.execution_stats[ExecutionStats::Key::CREATED_NODES] += 1; for (auto label : node_info.labels) { - auto maybe_error = new_node.AddLabel(label); + auto maybe_error = new_node.AddLabel(label, false); if (maybe_error.HasError()) { switch (maybe_error.GetError()) { case storage::Error::SERIALIZATION_ERROR: @@ -251,6 +251,11 @@ VertexAccessor &CreateLocalVertex(const NodeCreationInfo &node_info, Frame *fram } MultiPropsInitChecked(&new_node, properties); + // TODO antepusic check if text search is turned on + if (flags::run_time::GetTextSearchEnabled()) { + // new_node.AddToTextSearch() + } + (*frame)[node_info.symbol] = new_node; return (*frame)[node_info.symbol].ValueVertex(); } @@ -2819,6 +2824,10 @@ bool SetProperty::SetPropertyCursor::Pull(Frame &frame, ExecutionContext &contex context.trigger_context_collector->RegisterSetObjectProperty(lhs.ValueVertex(), self_.property_, TypedValue{std::move(old_value)}, TypedValue{rhs}); } + // TODO antepusic: update text index + // new_node.UpdateInTextSearch() + if (flags::run_time::GetTextSearchEnabled()) { + } break; } case TypedValue::Type::Edge: { @@ -2975,6 +2984,10 @@ void SetPropertiesOnRecord(TRecordAccessor *record, const TypedValue &rhs, SetPr case TypedValue::Type::Vertex: { PropertiesMap new_properties = get_props(rhs.ValueVertex()); update_props(new_properties); + // TODO antepusic: update text index + // new_node.UpdateInTextSearch() + if (flags::run_time::GetTextSearchEnabled()) { + } break; } case TypedValue::Type::Map: { @@ -3102,7 +3115,7 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) { #endif for (auto label : self_.labels_) { - auto maybe_value = vertex.AddLabel(label); + auto maybe_value = vertex.AddLabel(label, false); if (maybe_value.HasError()) { switch (maybe_value.GetError()) { case storage::Error::SERIALIZATION_ERROR: @@ -3121,6 +3134,11 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) { } } + // TODO antepusic check if text search is turned on + if (flags::run_time::GetTextSearchEnabled()) { + // new_node.UpdateInTextSearch() + } + return true; } @@ -3262,7 +3280,7 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &cont #endif for (auto label : self_.labels_) { - auto maybe_value = vertex.RemoveLabel(label); + auto maybe_value = vertex.RemoveLabel(label, false); if (maybe_value.HasError()) { switch (maybe_value.GetError()) { case storage::Error::SERIALIZATION_ERROR: @@ -3282,6 +3300,11 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &cont } } + // TODO antepusic check if text search is turned on + if (flags::run_time::GetTextSearchEnabled()) { + // new_node.UpdateInTextSearch() + } + return true; } diff --git a/src/query/procedure/mg_procedure_impl.cpp b/src/query/procedure/mg_procedure_impl.cpp index 441e1597e..9c523fc12 100644 --- a/src/query/procedure/mg_procedure_impl.cpp +++ b/src/query/procedure/mg_procedure_impl.cpp @@ -1838,9 +1838,10 @@ mgp_error mgp_vertex_set_property(struct mgp_vertex *v, const char *property_nam const auto prop_key = std::visit([property_name](auto *impl) { return impl->NameToProperty(property_name); }, v->graph->impl); - const auto result = std::visit( - [prop_key, property_value](auto &impl) { return impl.SetProperty(prop_key, ToPropertyValue(*property_value)); }, - v->impl); + const auto result = + std::visit([prop_key, property_value]( + auto &impl) { return impl.SetProperty(prop_key, ToPropertyValue(*property_value), true); }, + v->impl); if (result.HasError()) { switch (result.GetError()) { case memgraph::storage::Error::DELETED_OBJECT: @@ -1896,7 +1897,7 @@ mgp_error mgp_vertex_set_properties(struct mgp_vertex *v, struct mgp_map *proper v->graph->impl)); } - const auto result = v->getImpl().UpdateProperties(props); + const auto result = v->getImpl().UpdateProperties(props, true); if (result.HasError()) { switch (result.GetError()) { case memgraph::storage::Error::DELETED_OBJECT: @@ -1953,7 +1954,7 @@ mgp_error mgp_vertex_add_label(struct mgp_vertex *v, mgp_label label) { throw ImmutableObjectException{"Cannot add a label to an immutable vertex!"}; } - const auto result = std::visit([label_id](auto &impl) { return impl.AddLabel(label_id); }, v->impl); + const auto result = std::visit([label_id](auto &impl) { return impl.AddLabel(label_id, true); }, v->impl); if (result.HasError()) { switch (result.GetError()) { @@ -1995,7 +1996,7 @@ mgp_error mgp_vertex_remove_label(struct mgp_vertex *v, mgp_label label) { if (!MgpVertexIsMutable(*v)) { throw ImmutableObjectException{"Cannot remove a label from an immutable vertex!"}; } - const auto result = std::visit([label_id](auto &impl) { return impl.RemoveLabel(label_id); }, v->impl); + const auto result = std::visit([label_id](auto &impl) { return impl.RemoveLabel(label_id, true); }, v->impl); if (result.HasError()) { switch (result.GetError()) { diff --git a/src/storage/v2/durability/snapshot.cpp b/src/storage/v2/durability/snapshot.cpp index 52872222b..87d70aa75 100644 --- a/src/storage/v2/durability/snapshot.cpp +++ b/src/storage/v2/durability/snapshot.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -799,6 +799,7 @@ RecoveredSnapshot LoadSnapshotVersion14(const std::filesystem::path &path, utils SPDLOG_TRACE("Recovered property \"{}\" with value \"{}\" for vertex {}.", name_id_mapper->IdToName(snapshot_id_map.at(*key)), *value, *gid); props.SetProperty(get_property_from_id(*key), *value); + // TODO antepusic: update text index here or at the end of LoadSnapshot()? } } diff --git a/src/storage/v2/durability/wal.cpp b/src/storage/v2/durability/wal.cpp index 8c28a6b6d..1b9f2e864 100644 --- a/src/storage/v2/durability/wal.cpp +++ b/src/storage/v2/durability/wal.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -788,6 +788,7 @@ RecoveryInfo LoadWal(const std::filesystem::path &path, RecoveredIndicesAndConst auto &property_value = delta.vertex_edge_set_property.value; vertex->properties.SetProperty(property_id, property_value); + // TODO antepusic: update text index here or at the end of LoadWal()? break; } diff --git a/src/storage/v2/indices/indices.cpp b/src/storage/v2/indices/indices.cpp index d0ab7695f..0967a7f7c 100644 --- a/src/storage/v2/indices/indices.cpp +++ b/src/storage/v2/indices/indices.cpp @@ -38,22 +38,44 @@ void Indices::RemoveObsoleteEntries(uint64_t oldest_active_start_timestamp) cons ->RemoveObsoleteEntries(oldest_active_start_timestamp); } -void Indices::UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx) const { +// void Indices::UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx) const { +// label_index_->UpdateOnAddLabel(label, vertex, tx); +// label_property_index_->UpdateOnAddLabel(label, vertex, tx); +// } + +// void Indices::UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx) const { +// label_index_->UpdateOnRemoveLabel(label, vertex, tx); +// label_property_index_->UpdateOnRemoveLabel(label, vertex, tx); +// } + +// void Indices::UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, +// const Transaction &tx) const { +// label_property_index_->UpdateOnSetProperty(property, value, vertex, tx); +// } + +void Indices::UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx, Storage *storage, + bool update_text_index) const { label_index_->UpdateOnAddLabel(label, vertex, tx); label_property_index_->UpdateOnAddLabel(label, vertex, tx); - text_index_->UpdateOnAddLabel(label, vertex, tx); + if (update_text_index) { + text_index_->UpdateOnAddLabel(label, vertex, storage, tx); + } } -void Indices::UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx) const { +void Indices::UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx, bool update_text_index) const { label_index_->UpdateOnRemoveLabel(label, vertex, tx); label_property_index_->UpdateOnRemoveLabel(label, vertex, tx); - text_index_->UpdateOnRemoveLabel(label, vertex, tx); + if (update_text_index) { + text_index_->UpdateOnRemoveLabel(label, vertex, tx); + } } void Indices::UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, - const Transaction &tx) const { + const Transaction &tx, Storage *storage, bool update_text_index) const { label_property_index_->UpdateOnSetProperty(property, value, vertex, tx); - text_index_->UpdateOnSetProperty(property, value, vertex, tx); + if (update_text_index) { + text_index_->UpdateOnSetProperty(vertex, storage, tx); + } } Indices::Indices(const Config &config, StorageMode storage_mode) { diff --git a/src/storage/v2/indices/indices.hpp b/src/storage/v2/indices/indices.hpp index d5e5a02ab..5f65cb316 100644 --- a/src/storage/v2/indices/indices.hpp +++ b/src/storage/v2/indices/indices.hpp @@ -56,14 +56,19 @@ struct Indices { /// This function should be called whenever a label is added to a vertex. /// @throw std::bad_alloc - void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx) const; + // void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx) const; + void UpdateOnAddLabel(LabelId label, Vertex *vertex, const Transaction &tx, Storage *storage, + bool update_text_index) const; - void UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx) const; + // void UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx) const; + void UpdateOnRemoveLabel(LabelId label, Vertex *vertex, const Transaction &tx, bool update_text_index) const; /// This function should be called whenever a property is modified on a vertex. /// @throw std::bad_alloc - void UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, - const Transaction &tx) const; + // void UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, + // const Transaction &tx) const; + void UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, const Transaction &tx, + Storage *storage, bool update_text_index) const; std::unique_ptr label_index_; std::unique_ptr label_property_index_; diff --git a/src/storage/v2/indices/text_index.cpp b/src/storage/v2/indices/text_index.cpp index fa3eef575..16916d9f0 100644 --- a/src/storage/v2/indices/text_index.cpp +++ b/src/storage/v2/indices/text_index.cpp @@ -17,17 +17,75 @@ namespace memgraph::storage { -void TextIndex::UpdateOnAddLabel(LabelId added_label, Vertex *vertex_after_update, const Transaction &tx) const { - // Add node to this label's text index +void TextIndex::AddNode(Vertex *vertex_after_update, Storage *storage, + const std::vector &applicable_text_indices) { + // NOTE: Text indexes are presently all-property indices. If we allow text indexes restricted to specific properties, + // an indexable document should be created for each applicable index. + nlohmann::json document = {}; + nlohmann::json properties = {}; + for (const auto &[prop_id, prop_value] : vertex_after_update->properties.Properties()) { + if (!prop_value.IsString()) continue; + properties[storage->PropertyToName(prop_id)] = prop_value.ValueString(); + } + + document["data"] = properties; + document["metadata"] = {}; + document["metadata"]["gid"] = vertex_after_update->gid.AsInt(); + // TODO add txid + document["metadata"]["deleted"] = false; + document["metadata"]["is_node"] = true; + + for (auto *index_context : applicable_text_indices) { + memcxx::text_search::add(*index_context, memcxx::text_search::DocumentInput{.data = document.dump()}, false); + } } -void TextIndex::UpdateOnRemoveLabel(LabelId removed_label, Vertex *vertex_after_update, const Transaction &tx) const { - // Remove node from this label's text index +void TextIndex::AddNode(Vertex *vertex_after_update, Storage *storage) { + auto applicable_text_indices = GetApplicableTextIndices(vertex_after_update); + if (applicable_text_indices.empty()) return; + AddNode(vertex_after_update, storage, applicable_text_indices); } -void TextIndex::UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, - const Transaction &tx) const { - // Delete this node's document and re-add the it with the new value +void TextIndex::UpdateNode(Vertex *vertex_after_update, Storage *storage) { + auto applicable_text_indices = GetApplicableTextIndices(vertex_after_update); + if (applicable_text_indices.empty()) return; + RemoveNode(vertex_after_update, applicable_text_indices); + AddNode(vertex_after_update, storage, applicable_text_indices); +} + +void TextIndex::RemoveNode(Vertex *vertex_after_update, + const std::vector &applicable_text_indices) { + auto search_node_to_be_deleted = memcxx::text_search::SearchInput{ + .search_query = fmt::format("metadata.gid:{}", vertex_after_update->gid.AsInt())}; + + for (auto *index_context : applicable_text_indices) { + memcxx::text_search::delete_document(*index_context, search_node_to_be_deleted, false); + } +} + +void TextIndex::RemoveNode(Vertex *vertex_after_update) { + auto applicable_text_indices = GetApplicableTextIndices(vertex_after_update); + if (applicable_text_indices.empty()) return; + RemoveNode(vertex_after_update, applicable_text_indices); +} + +void TextIndex::UpdateOnAddLabel(LabelId added_label, Vertex *vertex_after_update, Storage *storage, + const Transaction &tx) { + if (!label_to_index_.contains(added_label)) { + return; + } + AddNode(vertex_after_update, storage, {&index_.at(label_to_index_.at(added_label))}); +} + +void TextIndex::UpdateOnRemoveLabel(LabelId removed_label, Vertex *vertex_after_update, const Transaction &tx) { + if (!label_to_index_.contains(removed_label)) { + return; + } + RemoveNode(vertex_after_update, {&index_.at(label_to_index_.at(removed_label))}); +} + +void TextIndex::UpdateOnSetProperty(Vertex *vertex_after_update, Storage *storage, const Transaction &tx) { + UpdateNode(vertex_after_update, storage); } std::vector TextIndex::GetApplicableTextIndices(Vertex *vertex) { diff --git a/src/storage/v2/indices/text_index.hpp b/src/storage/v2/indices/text_index.hpp index 9d6ec0d13..91ae32a77 100644 --- a/src/storage/v2/indices/text_index.hpp +++ b/src/storage/v2/indices/text_index.hpp @@ -22,8 +22,15 @@ class DbAccessor; } namespace memgraph::storage { +class Storage; class TextIndex { + private: + void AddNode(Vertex *vertex, Storage *storage, + const std::vector &applicable_text_indices); + + void RemoveNode(Vertex *vertex, const std::vector &applicable_text_indices); + public: TextIndex() = default; @@ -37,12 +44,17 @@ class TextIndex { std::map index_; std::map label_to_index_; - void UpdateOnAddLabel(LabelId added_label, Vertex *vertex_after_update, const Transaction &tx) const; + void AddNode(Vertex *vertex, Storage *storage); - void UpdateOnRemoveLabel(LabelId removed_label, Vertex *vertex_after_update, const Transaction &tx) const; + void UpdateNode(Vertex *vertex, Storage *storage); - void UpdateOnSetProperty(PropertyId property, const PropertyValue &value, Vertex *vertex, - const Transaction &tx) const; + void RemoveNode(Vertex *vertex); + + void UpdateOnAddLabel(LabelId added_label, Vertex *vertex_after_update, Storage *storage, const Transaction &tx); + + void UpdateOnRemoveLabel(LabelId removed_label, Vertex *vertex_after_update, const Transaction &tx); + + void UpdateOnSetProperty(Vertex *vertex_after_update, Storage *storage, const Transaction &tx); std::vector GetApplicableTextIndices(Vertex *vertex); diff --git a/src/storage/v2/inmemory/storage.cpp b/src/storage/v2/inmemory/storage.cpp index ddcdff621..cc39108b4 100644 --- a/src/storage/v2/inmemory/storage.cpp +++ b/src/storage/v2/inmemory/storage.cpp @@ -974,6 +974,7 @@ void InMemoryStorage::InMemoryAccessor::Abort() { } // Setting the correct value vertex->properties.SetProperty(current->property.key, current->property.value); + // TODO antepusic: update text index here or at the end of Abort()? break; } case Delta::Action::ADD_IN_EDGE: { diff --git a/src/storage/v2/storage.cpp b/src/storage/v2/storage.cpp index 52dcad243..1dfd06258 100644 --- a/src/storage/v2/storage.cpp +++ b/src/storage/v2/storage.cpp @@ -152,6 +152,8 @@ Result> Storage::Accessor::DeleteVertex(VertexAcce return std::optional{}; } + // TODO antepusic remove from text index + const auto &[vertices, edges] = *value; MG_ASSERT(vertices.size() <= 1, "The number of deleted vertices is not less or equal to 1!"); @@ -184,6 +186,8 @@ Result>>> Stor return res.GetError(); } + // TODO antepusic remove from text index + auto &value = res.GetValue(); if (!value) { return std::optional{}; @@ -274,6 +278,8 @@ Storage::Accessor::DetachDelete(std::vector nodes, std::vector auto deleted_vertices = maybe_deleted_vertices.GetValue(); + // delete from text inde here + return std::make_optional(std::move(deleted_vertices), std::move(deleted_edges)); } diff --git a/src/storage/v2/vertex_accessor.cpp b/src/storage/v2/vertex_accessor.cpp index 7dc704684..51ea446c4 100644 --- a/src/storage/v2/vertex_accessor.cpp +++ b/src/storage/v2/vertex_accessor.cpp @@ -102,7 +102,7 @@ bool VertexAccessor::IsVisible(View view) const { return exists && (for_deleted_ || !deleted); } -Result VertexAccessor::AddLabel(LabelId label) { +Result VertexAccessor::AddLabel(LabelId label, bool update_text_index) { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -126,14 +126,14 @@ Result VertexAccessor::AddLabel(LabelId label) { /// TODO: some by pointers, some by reference => not good, make it better storage_->constraints_.unique_constraints_->UpdateOnAddLabel(label, *vertex_, transaction_->start_timestamp); transaction_->constraint_verification_info.AddedLabel(vertex_); - storage_->indices_.UpdateOnAddLabel(label, vertex_, *transaction_); + storage_->indices_.UpdateOnAddLabel(label, vertex_, *transaction_, storage_, update_text_index); transaction_->manyDeltasCache.Invalidate(vertex_, label); return true; } /// TODO: move to after update and change naming to vertex after update -Result VertexAccessor::RemoveLabel(LabelId label) { +Result VertexAccessor::RemoveLabel(LabelId label, bool update_text_index) { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -154,7 +154,7 @@ Result VertexAccessor::RemoveLabel(LabelId label) { /// TODO: some by pointers, some by reference => not good, make it better storage_->constraints_.unique_constraints_->UpdateOnRemoveLabel(label, *vertex_, transaction_->start_timestamp); - storage_->indices_.UpdateOnRemoveLabel(label, vertex_, *transaction_); + storage_->indices_.UpdateOnRemoveLabel(label, vertex_, *transaction_, update_text_index); transaction_->manyDeltasCache.Invalidate(vertex_, label); return true; @@ -254,7 +254,8 @@ Result> VertexAccessor::Labels(View view) const { return std::move(labels); } -Result VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value) { +Result VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value, + bool update_text_index) { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -275,21 +276,8 @@ Result VertexAccessor::SetProperty(PropertyId property, const Pro // transactions get a SERIALIZATION_ERROR. utils::AtomicMemoryBlock atomic_memory_block{ - [transaction = transaction_, storage = storage_, vertex = vertex_, &value, &property, ¤t_value]() { + [transaction = transaction_, vertex = vertex_, &value, &property, ¤t_value]() { CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), property, current_value); - if (flags::run_time::GetTextSearchEnabled()) { - for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { - auto search_input = memcxx::text_search::SearchInput{ - .search_query = fmt::format("metadata.gid:{}", vertex->gid.AsInt()), .return_fields = {"data"}}; - - auto search_result = memcxx::text_search::search(*index_context, search_input); - memcxx::text_search::delete_document(*index_context, search_input, true); - auto new_properties = search_result.docs[0].data; // TODO (pending real Tantivy results): parse result to - // JSON, set property and convert back to string - auto new_properties_document = memcxx::text_search::DocumentInput{.data = new_properties}; - memcxx::text_search::add(*index_context, new_properties_document, true); - } - } vertex->properties.SetProperty(property, value); }}; std::invoke(atomic_memory_block); @@ -299,13 +287,28 @@ Result VertexAccessor::SetProperty(PropertyId property, const Pro } else { transaction_->constraint_verification_info.RemovedProperty(vertex_); } - storage_->indices_.UpdateOnSetProperty(property, value, vertex_, *transaction_); + storage_->indices_.UpdateOnSetProperty(property, value, vertex_, *transaction_, storage_, update_text_index); transaction_->manyDeltasCache.Invalidate(vertex_, property); + // if (flags::run_time::GetTextSearchEnabled() && update_text_index) { + // for (auto *index_context : storage_->indices_.text_index_->GetApplicableTextIndices(vertex_)) { + // auto search_input = memcxx::text_search::SearchInput{ + // .search_query = fmt::format("metadata.gid:{}", vertex_->gid.AsInt()), .return_fields = {"data"}}; + + // auto search_result = memcxx::text_search::search(*index_context, search_input); + // memcxx::text_search::delete_document(*index_context, search_input, true); + // auto new_properties = search_result.docs[0].data; // TODO (pending real Tantivy results): parse result to + // // JSON, set property and convert back to string + // auto new_properties_document = memcxx::text_search::DocumentInput{.data = new_properties}; + // memcxx::text_search::add(*index_context, new_properties_document, true); + // } + // } + return std::move(current_value); } -Result VertexAccessor::InitProperties(const std::map &properties) { +Result VertexAccessor::InitProperties(const std::map &properties, + bool update_text_index) { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -318,22 +321,14 @@ Result VertexAccessor::InitProperties(const std::mapdeleted) return Error::DELETED_OBJECT; bool result{false}; utils::AtomicMemoryBlock atomic_memory_block{ - [&result, &properties, storage = storage_, transaction = transaction_, vertex = vertex_]() { + [&result, &properties, storage = storage_, transaction = transaction_, vertex = vertex_, update_text_index]() { if (!vertex->properties.InitProperties(properties)) { result = false; return; } - if (flags::run_time::GetTextSearchEnabled()) { - for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { - auto new_properties_document = - memcxx::text_search::DocumentInput{}; // TODO (pending real Tantivy operation): create a JSON, set - // properties and convert to string - memcxx::text_search::add(*index_context, new_properties_document, true); - } - } for (const auto &[property, value] : properties) { CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), property, PropertyValue()); - storage->indices_.UpdateOnSetProperty(property, value, vertex, *transaction); + storage->indices_.UpdateOnSetProperty(property, value, vertex, *transaction, storage, update_text_index); transaction->manyDeltasCache.Invalidate(vertex, property); if (!value.IsNull()) { transaction->constraint_verification_info.AddedProperty(vertex); @@ -345,11 +340,20 @@ Result VertexAccessor::InitProperties(const std::mapindices_.text_index_->GetApplicableTextIndices(vertex_)) { + // auto new_properties_document = + // memcxx::text_search::DocumentInput{}; // TODO (pending real Tantivy operation): create a JSON, set + // // properties and convert to string + // memcxx::text_search::add(*index_context, new_properties_document, true); + // } + // } + return result; } Result>> VertexAccessor::UpdateProperties( - std::map &properties) const { + std::map &properties, bool update_text_index) const { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -363,43 +367,43 @@ Result>> Vertex using ReturnType = decltype(vertex_->properties.UpdateProperties(properties)); std::optional id_old_new_change; - utils::AtomicMemoryBlock atomic_memory_block{ - [storage = storage_, transaction = transaction_, vertex = vertex_, &properties, &id_old_new_change]() { - id_old_new_change.emplace(vertex->properties.UpdateProperties(properties)); - if (flags::run_time::GetTextSearchEnabled()) { - for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { - auto search_input = memcxx::text_search::SearchInput{ - .search_query = fmt::format("metadata.gid:{}", vertex->gid.AsInt()), .return_fields = {"data"}}; + utils::AtomicMemoryBlock atomic_memory_block{[storage = storage_, transaction = transaction_, vertex = vertex_, + &properties, &id_old_new_change, update_text_index]() { + id_old_new_change.emplace(vertex->properties.UpdateProperties(properties)); + // if (flags::run_time::GetTextSearchEnabled()) { + // for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { + // auto search_input = memcxx::text_search::SearchInput{ + // .search_query = fmt::format("metadata.gid:{}", vertex->gid.AsInt()), .return_fields = {"data"}}; - auto search_result = memcxx::text_search::search(*index_context, search_input); - memcxx::text_search::delete_document(*index_context, search_input, true); - auto new_properties = search_result.docs[0].data; // TODO (pending real Tantivy results): parse result to - // JSON, set property and convert back to string - auto new_properties_document = memcxx::text_search::DocumentInput{.data = new_properties}; - memcxx::text_search::add(*index_context, new_properties_document, true); - } - } + // auto search_result = memcxx::text_search::search(*index_context, search_input); + // memcxx::text_search::delete_document(*index_context, search_input, true); + // auto new_properties = search_result.docs[0].data; // TODO (pending real Tantivy results): parse result to + // // JSON, set property and convert back to string + // auto new_properties_document = memcxx::text_search::DocumentInput{.data = new_properties}; + // memcxx::text_search::add(*index_context, new_properties_document, true); + // } + // } - if (!id_old_new_change.has_value()) { - return; - } - for (auto &[id, old_value, new_value] : *id_old_new_change) { - storage->indices_.UpdateOnSetProperty(id, new_value, vertex, *transaction); - CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), id, std::move(old_value)); - transaction->manyDeltasCache.Invalidate(vertex, id); - if (!new_value.IsNull()) { - transaction->constraint_verification_info.AddedProperty(vertex); - } else { - transaction->constraint_verification_info.RemovedProperty(vertex); - } - } - }}; + if (!id_old_new_change.has_value()) { + return; + } + for (auto &[id, old_value, new_value] : *id_old_new_change) { + storage->indices_.UpdateOnSetProperty(id, new_value, vertex, *transaction, storage, update_text_index); + CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), id, std::move(old_value)); + transaction->manyDeltasCache.Invalidate(vertex, id); + if (!new_value.IsNull()) { + transaction->constraint_verification_info.AddedProperty(vertex); + } else { + transaction->constraint_verification_info.RemovedProperty(vertex); + } + } + }}; std::invoke(atomic_memory_block); return id_old_new_change.has_value() ? std::move(id_old_new_change.value()) : ReturnType{}; } -Result> VertexAccessor::ClearProperties() { +Result> VertexAccessor::ClearProperties(bool update_text_index) { if (transaction_->edge_import_mode_active) { throw query::WriteVertexOperationInEdgeImportModeException(); } @@ -412,26 +416,28 @@ Result> VertexAccessor::ClearProperties() { using ReturnType = decltype(vertex_->properties.Properties()); std::optional properties; utils::AtomicMemoryBlock atomic_memory_block{ - [storage = storage_, transaction = transaction_, vertex = vertex_, &properties]() { + [storage = storage_, transaction = transaction_, vertex = vertex_, &properties, update_text_index]() { properties.emplace(vertex->properties.Properties()); if (!properties.has_value()) { return; } for (const auto &[property, value] : *properties) { CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), property, value); - storage->indices_.UpdateOnSetProperty(property, PropertyValue(), vertex, *transaction); + storage->indices_.UpdateOnSetProperty(property, PropertyValue(), vertex, *transaction, storage, + update_text_index); transaction->constraint_verification_info.RemovedProperty(vertex); transaction->manyDeltasCache.Invalidate(vertex, property); } vertex->properties.ClearProperties(); - if (flags::run_time::GetTextSearchEnabled()) { - for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { - auto search_input = - memcxx::text_search::SearchInput{.search_query = fmt::format("metadata.gid:{}", vertex->gid.AsInt())}; - memcxx::text_search::delete_document(*index_context, search_input, true); - } - } + // if (flags::run_time::GetTextSearchEnabled()) { + // for (auto *index_context : storage->indices_.text_index_->GetApplicableTextIndices(vertex)) { + // auto search_input = + // memcxx::text_search::SearchInput{.search_query = fmt::format("metadata.gid:{}", + // vertex->gid.AsInt())}; + // memcxx::text_search::delete_document(*index_context, search_input, true); + // } + // } }}; std::invoke(atomic_memory_block); diff --git a/src/storage/v2/vertex_accessor.hpp b/src/storage/v2/vertex_accessor.hpp index 0e5972d14..201335242 100644 --- a/src/storage/v2/vertex_accessor.hpp +++ b/src/storage/v2/vertex_accessor.hpp @@ -1,4 +1,4 @@ -// Copyright 2023 Memgraph Ltd. +// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -47,12 +47,12 @@ class VertexAccessor final { /// Add a label and return `true` if insertion took place. /// `false` is returned if the label already existed. /// @throw std::bad_alloc - Result AddLabel(LabelId label); + Result AddLabel(LabelId label, bool update_text_index); /// Remove a label and return `true` if deletion took place. /// `false` is returned if the vertex did not have a label already. /// @throw std::bad_alloc - Result RemoveLabel(LabelId label); + Result RemoveLabel(LabelId label, bool update_text_index); Result HasLabel(LabelId label, View view) const; @@ -63,19 +63,20 @@ class VertexAccessor final { /// Set a property value and return the old value. /// @throw std::bad_alloc - Result SetProperty(PropertyId property, const PropertyValue &value); + Result SetProperty(PropertyId property, const PropertyValue &value, bool update_text_index); /// Set property values only if property store is empty. Returns `true` if successully set all values, /// `false` otherwise. /// @throw std::bad_alloc - Result InitProperties(const std::map &properties); + Result InitProperties(const std::map &properties, + bool update_text_index); Result>> UpdateProperties( - std::map &properties) const; + std::map &properties, bool update_text_index) const; /// Remove all properties and return the values of the removed properties. /// @throw std::bad_alloc - Result> ClearProperties(); + Result> ClearProperties(bool update_text_index); /// @throw std::bad_alloc Result GetProperty(PropertyId property, View view) const;