Add most of CRUD

This commit is contained in:
Ante Pušić 2024-01-17 21:48:57 +01:00
parent 605a425bb3
commit 88f8a0ae68
15 changed files with 289 additions and 136 deletions

View File

@ -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;

View File

@ -457,28 +457,30 @@ void ProcessNodeRow(memgraph::storage::Storage *store, const std::vector<std::st
} else {
pv_id = memgraph::storage::PropertyValue(node_id.id);
}
auto old_node_property = node.SetProperty(acc->NameToProperty(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");
}

View File

@ -115,9 +115,13 @@ class VertexAccessor final {
auto Labels(storage::View view) const { return impl_.Labels(view); }
storage::Result<bool> AddLabel(storage::LabelId label) { return impl_.AddLabel(label); }
storage::Result<bool> AddLabel(storage::LabelId label, bool update_text_index) {
return impl_.AddLabel(label, update_text_index);
}
storage::Result<bool> RemoveLabel(storage::LabelId label) { return impl_.RemoveLabel(label); }
storage::Result<bool> RemoveLabel(storage::LabelId label, bool update_text_index) {
return impl_.RemoveLabel(label, update_text_index);
}
storage::Result<bool> 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<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
return impl_.SetProperty(key, value);
storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value,
bool update_text_index = false) {
return impl_.SetProperty(key, value, update_text_index);
}
storage::Result<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties) {
return impl_.InitProperties(properties);
storage::Result<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties,
bool update_text_index = false) {
return impl_.InitProperties(properties, update_text_index);
}
storage::Result<std::vector<std::tuple<storage::PropertyId, storage::PropertyValue, storage::PropertyValue>>>
UpdateProperties(std::map<storage::PropertyId, storage::PropertyValue> &properties) const {
return impl_.UpdateProperties(properties);
UpdateProperties(std::map<storage::PropertyId, storage::PropertyValue> &properties,
bool update_text_index = false) const {
return impl_.UpdateProperties(properties, update_text_index);
}
storage::Result<storage::PropertyValue> RemoveProperty(storage::PropertyId key) {
return SetProperty(key, storage::PropertyValue());
storage::Result<storage::PropertyValue> RemoveProperty(storage::PropertyId key, bool update_text_index = true) {
return SetProperty(key, storage::PropertyValue(), update_text_index);
}
storage::Result<std::map<storage::PropertyId, storage::PropertyValue>> ClearProperties() {
return impl_.ClearProperties();
storage::Result<std::map<storage::PropertyId, storage::PropertyValue>> ClearProperties(
bool update_text_index = false) {
return impl_.ClearProperties(update_text_index);
}
storage::Result<EdgeVertexAccessorResult> InEdges(storage::View view,
@ -254,9 +262,13 @@ class SubgraphVertexAccessor final {
auto Labels(storage::View view) const { return impl_.Labels(view); }
storage::Result<bool> AddLabel(storage::LabelId label) { return impl_.AddLabel(label); }
storage::Result<bool> AddLabel(storage::LabelId label, bool update_text_index) {
return impl_.AddLabel(label, update_text_index);
}
storage::Result<bool> RemoveLabel(storage::LabelId label) { return impl_.RemoveLabel(label); }
storage::Result<bool> RemoveLabel(storage::LabelId label, bool update_text_index) {
return impl_.RemoveLabel(label, update_text_index);
}
storage::Result<bool> HasLabel(storage::View view, storage::LabelId label) const {
return impl_.HasLabel(view, label);
@ -274,13 +286,15 @@ class SubgraphVertexAccessor final {
storage::Result<size_t> OutDegree(storage::View view) const { return impl_.OutDegree(view); }
storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value) {
return impl_.SetProperty(key, value);
storage::Result<storage::PropertyValue> SetProperty(storage::PropertyId key, const storage::PropertyValue &value,
bool update_text_index = false) {
return impl_.SetProperty(key, value, update_text_index);
}
storage::Result<std::vector<std::tuple<storage::PropertyId, storage::PropertyValue, storage::PropertyValue>>>
UpdateProperties(std::map<storage::PropertyId, storage::PropertyValue> &properties) const {
return impl_.UpdateProperties(properties);
UpdateProperties(std::map<storage::PropertyId, storage::PropertyValue> &properties,
bool update_text_index = false) const {
return impl_.UpdateProperties(properties, update_text_index);
}
VertexAccessor GetVertexAccessor() const;

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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()?
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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<LabelIndex> label_index_;
std::unique_ptr<LabelPropertyIndex> label_property_index_;

View File

@ -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<memcxx::text_search::Context *> &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<memcxx::text_search::Context *> &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<memcxx::text_search::Context *> TextIndex::GetApplicableTextIndices(Vertex *vertex) {

View File

@ -22,8 +22,15 @@ class DbAccessor;
}
namespace memgraph::storage {
class Storage;
class TextIndex {
private:
void AddNode(Vertex *vertex, Storage *storage,
const std::vector<memcxx::text_search::Context *> &applicable_text_indices);
void RemoveNode(Vertex *vertex, const std::vector<memcxx::text_search::Context *> &applicable_text_indices);
public:
TextIndex() = default;
@ -37,12 +44,17 @@ class TextIndex {
std::map<std::string, memcxx::text_search::Context> index_;
std::map<LabelId, std::string> 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<memcxx::text_search::Context *> GetApplicableTextIndices(Vertex *vertex);

View File

@ -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: {

View File

@ -152,6 +152,8 @@ Result<std::optional<VertexAccessor>> Storage::Accessor::DeleteVertex(VertexAcce
return std::optional<VertexAccessor>{};
}
// 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<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Stor
return res.GetError();
}
// TODO antepusic remove from text index
auto &value = res.GetValue();
if (!value) {
return std::optional<ReturnType>{};
@ -274,6 +278,8 @@ Storage::Accessor::DetachDelete(std::vector<VertexAccessor *> nodes, std::vector
auto deleted_vertices = maybe_deleted_vertices.GetValue();
// delete from text inde here
return std::make_optional<ReturnType>(std::move(deleted_vertices), std::move(deleted_edges));
}

View File

@ -102,7 +102,7 @@ bool VertexAccessor::IsVisible(View view) const {
return exists && (for_deleted_ || !deleted);
}
Result<bool> VertexAccessor::AddLabel(LabelId label) {
Result<bool> VertexAccessor::AddLabel(LabelId label, bool update_text_index) {
if (transaction_->edge_import_mode_active) {
throw query::WriteVertexOperationInEdgeImportModeException();
}
@ -126,14 +126,14 @@ Result<bool> 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<bool> VertexAccessor::RemoveLabel(LabelId label) {
Result<bool> VertexAccessor::RemoveLabel(LabelId label, bool update_text_index) {
if (transaction_->edge_import_mode_active) {
throw query::WriteVertexOperationInEdgeImportModeException();
}
@ -154,7 +154,7 @@ Result<bool> 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<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
return std::move(labels);
}
Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value) {
Result<PropertyValue> 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<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const Pro
// transactions get a SERIALIZATION_ERROR.
utils::AtomicMemoryBlock atomic_memory_block{
[transaction = transaction_, storage = storage_, vertex = vertex_, &value, &property, &current_value]() {
[transaction = transaction_, vertex = vertex_, &value, &property, &current_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<PropertyValue> 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<bool> VertexAccessor::InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties) {
Result<bool> VertexAccessor::InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties,
bool update_text_index) {
if (transaction_->edge_import_mode_active) {
throw query::WriteVertexOperationInEdgeImportModeException();
}
@ -318,22 +321,14 @@ Result<bool> VertexAccessor::InitProperties(const std::map<storage::PropertyId,
if (vertex_->deleted) 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<bool> VertexAccessor::InitProperties(const std::map<storage::PropertyId,
}};
std::invoke(atomic_memory_block);
// if (flags::run_time::GetTextSearchEnabled() && update_text_index) {
// 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);
// }
// }
return result;
}
Result<std::vector<std::tuple<PropertyId, PropertyValue, PropertyValue>>> VertexAccessor::UpdateProperties(
std::map<storage::PropertyId, storage::PropertyValue> &properties) const {
std::map<storage::PropertyId, storage::PropertyValue> &properties, bool update_text_index) const {
if (transaction_->edge_import_mode_active) {
throw query::WriteVertexOperationInEdgeImportModeException();
}
@ -363,43 +367,43 @@ Result<std::vector<std::tuple<PropertyId, PropertyValue, PropertyValue>>> Vertex
using ReturnType = decltype(vertex_->properties.UpdateProperties(properties));
std::optional<ReturnType> 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<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties(bool update_text_index) {
if (transaction_->edge_import_mode_active) {
throw query::WriteVertexOperationInEdgeImportModeException();
}
@ -412,26 +416,28 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
using ReturnType = decltype(vertex_->properties.Properties());
std::optional<ReturnType> 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);

View File

@ -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<bool> AddLabel(LabelId label);
Result<bool> 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<bool> RemoveLabel(LabelId label);
Result<bool> RemoveLabel(LabelId label, bool update_text_index);
Result<bool> 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<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
Result<PropertyValue> 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<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties);
Result<bool> InitProperties(const std::map<storage::PropertyId, storage::PropertyValue> &properties,
bool update_text_index);
Result<std::vector<std::tuple<PropertyId, PropertyValue, PropertyValue>>> UpdateProperties(
std::map<storage::PropertyId, storage::PropertyValue> &properties) const;
std::map<storage::PropertyId, storage::PropertyValue> &properties, bool update_text_index) const;
/// Remove all properties and return the values of the removed properties.
/// @throw std::bad_alloc
Result<std::map<PropertyId, PropertyValue>> ClearProperties();
Result<std::map<PropertyId, PropertyValue>> ClearProperties(bool update_text_index);
/// @throw std::bad_alloc
Result<PropertyValue> GetProperty(PropertyId property, View view) const;