From 1788e606912086fded3511b442bc3bcc85cf38b8 Mon Sep 17 00:00:00 2001 From: gvolfing Date: Wed, 20 Mar 2024 16:13:42 +0100 Subject: [PATCH] Add automatic index creation functionality --- src/storage/v2/disk/storage.cpp | 10 +++++--- src/storage/v2/disk/storage.hpp | 6 +++-- src/storage/v2/inmemory/storage.cpp | 39 ++++++++++++++++++++++++++--- src/storage/v2/inmemory/storage.hpp | 6 +++-- src/storage/v2/storage.hpp | 12 +++++++-- src/storage/v2/vertex_accessor.cpp | 7 ++++++ 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/storage/v2/disk/storage.cpp b/src/storage/v2/disk/storage.cpp index 21fa5ecc7..8f8ef5e06 100644 --- a/src/storage/v2/disk/storage.cpp +++ b/src/storage/v2/disk/storage.cpp @@ -1905,8 +1905,11 @@ void DiskStorage::DiskAccessor::FinalizeTransaction() { } } -utils::BasicResult DiskStorage::DiskAccessor::CreateIndex(LabelId label) { - MG_ASSERT(unique_guard_.owns_lock(), "Create index requires unique access to the storage!"); +utils::BasicResult DiskStorage::DiskAccessor::CreateIndex( + LabelId label, bool unique_access_needed) { + if (unique_access_needed) { + MG_ASSERT(unique_guard_.owns_lock(), "Create index requires unique access to the storage!"); + } auto *on_disk = static_cast(storage_); auto *disk_label_index = static_cast(on_disk->indices_.label_index_.get()); if (!disk_label_index->CreateIndex(label, on_disk->SerializeVerticesForLabelIndex(label))) { @@ -1934,7 +1937,8 @@ utils::BasicResult DiskStorage::DiskAccessor: return {}; } -utils::BasicResult DiskStorage::DiskAccessor::CreateIndex(EdgeTypeId /*edge_type*/) { +utils::BasicResult DiskStorage::DiskAccessor::CreateIndex( + EdgeTypeId /*edge_type*/, bool /*unique_access_needed*/) { throw utils::NotYetImplemented( "Edge-type index related operations are not yet supported using on-disk storage mode."); } diff --git a/src/storage/v2/disk/storage.hpp b/src/storage/v2/disk/storage.hpp index 349a7454a..9b74c0af0 100644 --- a/src/storage/v2/disk/storage.hpp +++ b/src/storage/v2/disk/storage.hpp @@ -160,11 +160,13 @@ class DiskStorage final : public Storage { void FinalizeTransaction() override; - utils::BasicResult CreateIndex(LabelId label) override; + utils::BasicResult CreateIndex(LabelId label, + bool unique_access_needed = true) override; utils::BasicResult CreateIndex(LabelId label, PropertyId property) override; - utils::BasicResult CreateIndex(EdgeTypeId edge_type) override; + utils::BasicResult CreateIndex(EdgeTypeId edge_type, + bool unique_access_needed = true) override; utils::BasicResult DropIndex(LabelId label) override; diff --git a/src/storage/v2/inmemory/storage.cpp b/src/storage/v2/inmemory/storage.cpp index dab56750b..b8d74f392 100644 --- a/src/storage/v2/inmemory/storage.cpp +++ b/src/storage/v2/inmemory/storage.cpp @@ -315,6 +315,13 @@ Result InMemoryStorage::InMemoryAccessor::CreateEdge(VertexAccesso guard_from.lock(); } + // TODO short-circuit + if (storage_->config_.salient.items.enable_edge_type_index_auto_creation) { + if (!storage_->indices_.edge_type_index_->IndexExists(edge_type)) { + storage_->edge_types_to_auto_index_->emplace(edge_type); + } + } + if (!PrepareForWrite(&transaction_, from_vertex)) return Error::SERIALIZATION_ERROR; if (from_vertex->deleted) return Error::DELETED_OBJECT; @@ -805,6 +812,25 @@ utils::BasicResult InMemoryStorage::InMemoryAcce { std::unique_lock engine_guard(storage_->engine_lock_); + + if (storage_->config_.salient.items.enable_label_index_auto_creation) { + storage_->labels_to_auto_index_.WithLock([&](auto &label_indices) { + for (const auto label : label_indices) { + CreateIndex(label, false); + } + label_indices.clear(); + }); + } + + if (storage_->config_.salient.items.enable_edge_type_index_auto_creation) { + storage_->edge_types_to_auto_index_.WithLock([&](auto &edge_type_indices) { + for (const auto edge_type : edge_type_indices) { + CreateIndex(edge_type, false); + } + edge_type_indices.clear(); + }); + } + auto *mem_unique_constraints = static_cast(storage_->constraints_.unique_constraints_.get()); commit_timestamp_.emplace(mem_storage->CommitTimestamp(reparg.desired_commit_timestamp)); @@ -1253,8 +1279,11 @@ void InMemoryStorage::InMemoryAccessor::FinalizeTransaction() { } } -utils::BasicResult InMemoryStorage::InMemoryAccessor::CreateIndex(LabelId label) { - MG_ASSERT(unique_guard_.owns_lock(), "Creating label index requires a unique access to the storage!"); +utils::BasicResult InMemoryStorage::InMemoryAccessor::CreateIndex( + LabelId label, bool unique_access_needed) { + if (unique_access_needed) { + MG_ASSERT(unique_guard_.owns_lock(), "Creating label index requires a unique access to the storage!"); + } auto *in_memory = static_cast(storage_); auto *mem_label_index = static_cast(in_memory->indices_.label_index_.get()); if (!mem_label_index->CreateIndex(label, in_memory->vertices_.access(), std::nullopt)) { @@ -1282,8 +1311,10 @@ utils::BasicResult InMemoryStorage::InMemoryA } utils::BasicResult InMemoryStorage::InMemoryAccessor::CreateIndex( - EdgeTypeId edge_type) { - MG_ASSERT(unique_guard_.owns_lock(), "Create index requires a unique access to the storage!"); + EdgeTypeId edge_type, bool unique_access_needed) { + if (unique_access_needed) { + MG_ASSERT(unique_guard_.owns_lock(), "Create index requires a unique access to the storage!"); + } auto *in_memory = static_cast(storage_); auto *mem_edge_type_index = static_cast(in_memory->indices_.edge_type_index_.get()); if (!mem_edge_type_index->CreateIndex(edge_type, in_memory->vertices_.access())) { diff --git a/src/storage/v2/inmemory/storage.hpp b/src/storage/v2/inmemory/storage.hpp index 6d10e0fbd..47e969f0e 100644 --- a/src/storage/v2/inmemory/storage.hpp +++ b/src/storage/v2/inmemory/storage.hpp @@ -241,7 +241,8 @@ class InMemoryStorage final : public Storage { /// * `IndexDefinitionError`: the index already exists. /// * `ReplicationError`: there is at least one SYNC replica that has not confirmed receiving the transaction. /// @throw std::bad_alloc - utils::BasicResult CreateIndex(LabelId label) override; + utils::BasicResult CreateIndex(LabelId label, + bool unique_access_needed = true) override; /// Create an index. /// Returns void if the index has been created. @@ -257,7 +258,8 @@ class InMemoryStorage final : public Storage { /// * `ReplicationError`: there is at least one SYNC replica that has not confirmed receiving the transaction. /// * `IndexDefinitionError`: the index already exists. /// @throw std::bad_alloc - utils::BasicResult CreateIndex(EdgeTypeId edge_type) override; + utils::BasicResult CreateIndex(EdgeTypeId edge_type, + bool unique_access_needed = true) override; /// Drop an existing index. /// Returns void if the index has been dropped. diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp index 58936bd56..7c984b963 100644 --- a/src/storage/v2/storage.hpp +++ b/src/storage/v2/storage.hpp @@ -272,11 +272,13 @@ class Storage { std::vector ListAllPossiblyPresentEdgeTypes() const; - virtual utils::BasicResult CreateIndex(LabelId label) = 0; + virtual utils::BasicResult CreateIndex(LabelId label, + bool unique_access_needed = true) = 0; virtual utils::BasicResult CreateIndex(LabelId label, PropertyId property) = 0; - virtual utils::BasicResult CreateIndex(EdgeTypeId edge_type) = 0; + virtual utils::BasicResult CreateIndex(EdgeTypeId edge_type, + bool unique_access_needed = true) = 0; virtual utils::BasicResult DropIndex(LabelId label) = 0; @@ -435,6 +437,12 @@ class Storage { utils::SynchronizedMetaDataStore stored_node_labels_; utils::SynchronizedMetaDataStore stored_edge_types_; + // Sets that hold onto labels and edge-types that have to be created. + // Used only if the label/edge-type autocreation flags are enabled, + // does not affect index creation otherwise. + utils::Synchronized, utils::SpinLock> labels_to_auto_index_; + utils::Synchronized, utils::SpinLock> edge_types_to_auto_index_; + std::atomic vertex_id_{0}; std::atomic edge_id_{0}; }; diff --git a/src/storage/v2/vertex_accessor.cpp b/src/storage/v2/vertex_accessor.cpp index 83dcc003b..65a32db7b 100644 --- a/src/storage/v2/vertex_accessor.cpp +++ b/src/storage/v2/vertex_accessor.cpp @@ -118,6 +118,13 @@ Result VertexAccessor::AddLabel(LabelId label) { storage_->stored_node_labels_.try_insert(label); } + // TODO short-circuit + if (storage_->config_.salient.items.enable_label_index_auto_creation) { + if (!storage_->indices_.label_index_->IndexExists(label)) { + storage_->labels_to_auto_index_->emplace(label); + } + } + /// TODO: some by pointers, some by reference => not good, make it better storage_->constraints_.unique_constraints_->UpdateOnAddLabel(label, *vertex_, transaction_->start_timestamp); if (transaction_->constraint_verification_info) transaction_->constraint_verification_info->AddedLabel(vertex_);