From 5c4c6f9fe13163b055d1ad5ea05c5c9468fbe179 Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Mon, 6 Nov 2023 16:50:33 +0100 Subject: Add removeByGidAsync() to spi. --- .../conformancetest/conformancetest.cpp | 49 +++++++++++++++++++++ .../persistence/conformancetest/conformancetest.h | 7 +++ .../persistence/dummyimpl/dummypersistence.cpp | 37 ++++++++++++++++ .../vespa/persistence/dummyimpl/dummypersistence.h | 2 + .../src/vespa/persistence/spi/CMakeLists.txt | 1 + .../persistence/spi/doctype_gid_and_timestamp.cpp | 43 +++++++++++++++++++ .../persistence/spi/doctype_gid_and_timestamp.h | 50 ++++++++++++++++++++++ .../vespa/persistence/spi/persistenceprovider.h | 8 ++++ .../persistence_handler_map_test.cpp | 1 + .../persistenceengine/persistenceengine_test.cpp | 9 ++++ .../proton/persistenceengine/ipersistencehandler.h | 3 ++ .../proton/persistenceengine/persistenceengine.cpp | 21 +++++++++ .../proton/persistenceengine/persistenceengine.h | 1 + .../proton/server/persistencehandlerproxy.cpp | 7 +++ .../proton/server/persistencehandlerproxy.h | 3 ++ .../common/persistenceproviderwrapper.cpp | 12 ++++++ .../common/persistenceproviderwrapper.h | 1 + .../storage/persistence/provider_error_wrapper.cpp | 8 ++++ .../storage/persistence/provider_error_wrapper.h | 2 + 19 files changed, 265 insertions(+) create mode 100644 persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.cpp create mode 100644 persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h diff --git a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp index 75916d6b66c..0c46e1269d9 100644 --- a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp +++ b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -907,6 +908,35 @@ TEST_F(ConformanceTest, testRemoveMerge) } } +TEST_F(ConformanceTest, testRemoveByGid) +{ + document::TestDocMan testDocMan; + _factory->clear(); + PersistenceProviderUP spi(getSpi(*_factory, testDocMan)); + Context context(Priority(0), Trace::TraceLevel(0)); + + Bucket bucket(makeSpiBucket(BucketId(8, 0x01))); + std::shared_ptr doc1 = testDocMan.createRandomDocumentAtLocation(0x01, 1); + std::shared_ptr doc2 = testDocMan.createRandomDocumentAtLocation(0x01, 2); + spi->createBucket(bucket); + EXPECT_EQ(Result(), Result(spi->put(bucket, Timestamp(11), doc1))); + EXPECT_EQ(Result(), Result(spi->put(bucket, Timestamp(12), doc2))); + auto info = spi->getBucketInfo(bucket).getBucketInfo(); + EXPECT_EQ(2, info.getDocumentCount()); + std::vector ids; + ids.emplace_back(doc1->getId().getDocType(), doc1->getId().getGlobalId(), Timestamp(10)); + assert_remove_by_gid(*spi, bucket, ids, 0, 2, "ignored removebygid"); + ids.back().timestamp = Timestamp(11); + assert_remove_by_gid(*spi, bucket, ids, 1, 1, "removebygid"); + if (_factory->hasPersistence()) { + spi.reset(); + document::TestDocMan testDocMan2; + spi = getSpi(*_factory, testDocMan2); + info = spi->getBucketInfo(bucket).getBucketInfo(); + EXPECT_EQ(1, info.getDocumentCount()); + } +} + TEST_F(ConformanceTest, testUpdate) { document::TestDocMan testDocMan; @@ -2227,6 +2257,25 @@ ConformanceTest::test_empty_bucket_info(bool bucket_exists, bool active) EXPECT_EQ(active, info_result.getBucketInfo().isActive()); } +void +ConformanceTest::assert_remove_by_gid(PersistenceProvider& spi, + const Bucket& bucket, std::vector ids, + size_t exp_removed, size_t exp_remaining, + const vespalib::string& label) +{ + SCOPED_TRACE(label); + auto onDone = std::make_unique(); + auto future = onDone->future_result(); + spi.removeByGidAsync(bucket, std::move(ids), std::move(onDone)); + auto result = future.get(); + ASSERT_TRUE(result); + auto removeResult = dynamic_cast(result.get()); + ASSERT_TRUE(removeResult != nullptr); + EXPECT_EQ(exp_removed, removeResult->num_removed()); + auto info = spi.getBucketInfo(bucket).getBucketInfo(); + EXPECT_EQ(exp_remaining, info.getDocumentCount()); +} + TEST_F(ConformanceTest, test_empty_bucket_gives_empty_bucket_info) { test_empty_bucket_info(true, false); diff --git a/persistence/src/vespa/persistence/conformancetest/conformancetest.h b/persistence/src/vespa/persistence/conformancetest/conformancetest.h index 7cea989bdf5..555c4254ad9 100644 --- a/persistence/src/vespa/persistence/conformancetest/conformancetest.h +++ b/persistence/src/vespa/persistence/conformancetest/conformancetest.h @@ -152,6 +152,13 @@ protected: void test_empty_bucket_info(bool bucket_exists, bool active); + void assert_remove_by_gid(PersistenceProvider& spi, + const Bucket& bucket, + std::vector ids, + size_t exp_removed, + size_t exp_remaining, + const vespalib::string& label); + ConformanceTest(); ConformanceTest(const std::string &docType); }; diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp index 96cb37be3c2..0ea872a54a5 100644 --- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp +++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -252,6 +253,15 @@ BucketContent::getEntry(const DocumentId &did) const { return DocEntry::SP(); } +std::shared_ptr +BucketContent::getEntry(const document::GlobalId& gid) const { + auto it(_gidMap.find(gid)); + if (it != _gidMap.end()) { + return it->second; + } + return {}; +} + DocEntry::SP BucketContent::getEntry(Timestamp t) const { auto iter = lower_bound(_entries.begin(), _entries.end(), t, TimestampLess()); @@ -529,6 +539,33 @@ DummyPersistence::removeAsync(const Bucket& b, std::vector onComplete->onComplete(std::make_unique(numRemoves)); } +void +DummyPersistence::removeByGidAsync(const Bucket& b, std::vector ids, std::unique_ptr onComplete) +{ + verifyInitialized(); + assert(b.getBucketSpace() == FixedBucketSpaces::default_space()); + BucketContentGuard::UP bc(acquireBucketWithLock(b)); + + uint32_t numRemoves(0); + for (const auto& dt_gid_ts : ids) { + auto& gid = dt_gid_ts.gid; + auto t = dt_gid_ts.timestamp; + LOG(debug, "removeByGidAsync(%s, %" PRIu64 ", %s, %s)", b.toString().c_str(), uint64_t(t), dt_gid_ts.doc_type.c_str(), gid.toString().c_str()); + + while (!bc) { + internal_create_bucket(b); + bc = acquireBucketWithLock(b); + } + DocEntry::SP entry((*bc)->getEntry(gid)); + if (entry && entry->getTimestamp() <= t) { + numRemoves += entry->isRemove() ? 0 : 1; + (*bc)->eraseEntry(entry->getTimestamp()); + } + } + bc.reset(); + onComplete->onComplete(std::make_unique(numRemoves)); +} + GetResult DummyPersistence::get(const Bucket& b, const FieldSet& fieldSet, const DocumentId& did, Context&) const { diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h index 26b19a43aee..f7f58612b8d 100644 --- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h +++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.h @@ -74,6 +74,7 @@ struct BucketContent { bool hasTimestamp(Timestamp) const; void insert(DocEntry::SP); DocEntry::SP getEntry(const DocumentId&) const; + std::shared_ptr getEntry(const GlobalId& gid) const; DocEntry::SP getEntry(Timestamp) const; void eraseEntry(Timestamp t); void setActive(bool active = true) { @@ -161,6 +162,7 @@ public: GetResult get(const Bucket&, const document::FieldSet&, const DocumentId&, Context&) const override; void putAsync(const Bucket&, Timestamp, DocumentSP, OperationComplete::UP) override; void removeAsync(const Bucket& b, std::vector ids, OperationComplete::UP) override; + void removeByGidAsync(const Bucket& b, std::vector ids, std::unique_ptr) override; void updateAsync(const Bucket&, Timestamp, DocumentUpdateSP, OperationComplete::UP) override; CreateIteratorResult diff --git a/persistence/src/vespa/persistence/spi/CMakeLists.txt b/persistence/src/vespa/persistence/spi/CMakeLists.txt index 617334317e7..6c3eddaaabf 100644 --- a/persistence/src/vespa/persistence/spi/CMakeLists.txt +++ b/persistence/src/vespa/persistence/spi/CMakeLists.txt @@ -9,6 +9,7 @@ vespa_add_library(persistence_spi OBJECT clusterstate.cpp context.cpp docentry.cpp + doctype_gid_and_timestamp.cpp exceptions.cpp id_and_timestamp.cpp persistenceprovider.cpp diff --git a/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.cpp b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.cpp new file mode 100644 index 00000000000..1184c0b409f --- /dev/null +++ b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.cpp @@ -0,0 +1,43 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "doctype_gid_and_timestamp.h" +#include + +namespace storage::spi { + +DocTypeGidAndTimestamp::DocTypeGidAndTimestamp() + : doc_type(), + gid() +{ +} + +DocTypeGidAndTimestamp::DocTypeGidAndTimestamp(const vespalib::string& doc_type_, document::GlobalId gid_, Timestamp timestamp_) noexcept + : doc_type(doc_type_), + gid(std::move(gid_)), + timestamp(timestamp_) +{} + +DocTypeGidAndTimestamp::DocTypeGidAndTimestamp(const DocTypeGidAndTimestamp&) = default; +DocTypeGidAndTimestamp& DocTypeGidAndTimestamp::operator=(const DocTypeGidAndTimestamp&) = default; +DocTypeGidAndTimestamp::DocTypeGidAndTimestamp(DocTypeGidAndTimestamp&&) noexcept = default; +DocTypeGidAndTimestamp& DocTypeGidAndTimestamp::operator=(DocTypeGidAndTimestamp&&) noexcept = default; + +void DocTypeGidAndTimestamp::print(vespalib::asciistream& os) const { + os << doc_type << ":" << gid.toString() << " at time " << timestamp.getValue(); +} + +vespalib::string DocTypeGidAndTimestamp::to_string() const { + vespalib::asciistream os; + print(os); + return os.str(); +} + +vespalib::asciistream& operator<<(vespalib::asciistream& os, const DocTypeGidAndTimestamp& dt_gid_ts) { + dt_gid_ts.print(os); + return os; +} +std::ostream& operator<<(std::ostream& os, const DocTypeGidAndTimestamp& dt_gid_ts) { + os << dt_gid_ts.to_string(); + return os; +} + +} diff --git a/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h new file mode 100644 index 00000000000..449935ef830 --- /dev/null +++ b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h @@ -0,0 +1,50 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "types.h" +#include +#include +#include + +namespace vespalib { class asciistream; } + +namespace storage::spi { + +/** + * Convenience wrapper for referencing a document type and global id with + * a timestamp. + * + * Prefer this instead of a std::tuple due to named fields and a pre-provided hash function. + */ +struct DocTypeGidAndTimestamp { + vespalib::string doc_type; + document::GlobalId gid; + Timestamp timestamp; + + DocTypeGidAndTimestamp(); + DocTypeGidAndTimestamp(const vespalib::string& doc_type_, document::GlobalId gid_, Timestamp timestamp_) noexcept; + + DocTypeGidAndTimestamp(const DocTypeGidAndTimestamp&); + DocTypeGidAndTimestamp& operator=(const DocTypeGidAndTimestamp&); + DocTypeGidAndTimestamp(DocTypeGidAndTimestamp&&) noexcept; + DocTypeGidAndTimestamp& operator=(DocTypeGidAndTimestamp&&) noexcept; + + bool operator==(const DocTypeGidAndTimestamp& rhs) const noexcept { + return ((doc_type == rhs.doc_type) && (gid == rhs.gid)); + } + + void print(vespalib::asciistream&) const; + vespalib::string to_string() const; + + struct hash { + size_t operator()(const DocTypeGidAndTimestamp& dt_gid_ts) const noexcept { + const size_t h = document::GlobalId::hash()(dt_gid_ts.gid); + return h ^ (dt_gid_ts.timestamp + 0x9e3779b9U + (h << 6U) + (h >> 2U)); // Basically boost::hash_combine + } + }; +}; + +vespalib::asciistream& operator<<(vespalib::asciistream&, const DocTypeGidAndTimestamp&); +std::ostream& operator<<(std::ostream&, const DocTypeGidAndTimestamp&); + +} diff --git a/persistence/src/vespa/persistence/spi/persistenceprovider.h b/persistence/src/vespa/persistence/spi/persistenceprovider.h index cb32dc05eec..5fb90046c65 100644 --- a/persistence/src/vespa/persistence/spi/persistenceprovider.h +++ b/persistence/src/vespa/persistence/spi/persistenceprovider.h @@ -18,6 +18,7 @@ namespace storage::spi { class IResourceUsageListener; struct BucketExecutor; +struct DocTypeGidAndTimestamp; /** * This interface is the basis for a persistence provider in Vespa. A @@ -173,6 +174,13 @@ struct PersistenceProvider */ virtual void removeAsync(const Bucket&, std::vector ids, OperationComplete::UP) = 0; + /* + * Remove documents based on document type and gid and forget about them + * (don't keep track of the removed document). This operation is typically + * used as part of removing documents in a bucket that will be deleted. + */ + virtual void removeByGidAsync(const Bucket&, std::vector ids, std::unique_ptr) = 0; + /** * @see remove() *

diff --git a/searchcore/src/tests/proton/persistenceengine/persistence_handler_map/persistence_handler_map_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistence_handler_map/persistence_handler_map_test.cpp index 03fb8ff05a1..13e0c4380a7 100644 --- a/searchcore/src/tests/proton/persistenceengine/persistence_handler_map/persistence_handler_map_test.cpp +++ b/searchcore/src/tests/proton/persistenceengine/persistence_handler_map/persistence_handler_map_test.cpp @@ -18,6 +18,7 @@ struct DummyPersistenceHandler : public IPersistenceHandler { void handlePut(FeedToken, const storage::spi::Bucket &, storage::spi::Timestamp, DocumentSP) override {} void handleUpdate(FeedToken, const storage::spi::Bucket &, storage::spi::Timestamp, DocumentUpdateSP) override {} void handleRemove(FeedToken, const storage::spi::Bucket &, storage::spi::Timestamp, const document::DocumentId &) override {} + void handleRemoveByGid(FeedToken, const storage::spi::Bucket&, storage::spi::Timestamp, vespalib::stringref, const GlobalId&) override { } void handleListBuckets(IBucketIdListResultHandler &) override {} void handleSetClusterState(const storage::spi::ClusterState &, IGenericResultHandler &) override {} void handleSetActiveState(const storage::spi::Bucket &, storage::spi::BucketInfo::ActiveState, std::shared_ptr) override {} diff --git a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp index e2519933a53..787b0c365e4 100644 --- a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp +++ b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp @@ -27,6 +27,7 @@ using document::DocumentId; using document::DocumentType; using document::DocumentTypeRepo; using document::DocumentUpdate; +using document::GlobalId; using document::test::makeBucketSpace; using search::DocumentMetaData; using storage::spi::Bucket; @@ -218,6 +219,14 @@ struct MyHandler : public IPersistenceHandler, IBucketFreezer { handle(token, bucket, timestamp, id); } + void handleRemoveByGid(FeedToken token, const Bucket& bucket, + Timestamp timestamp, + vespalib::stringref, const GlobalId&) override { + bool wasFound = existingTimestamp > 0; + token->setResult(std::make_unique(wasFound), wasFound); + handle(token, bucket, timestamp, DocumentId()); + } + void handleListBuckets(IBucketIdListResultHandler &resultHandler) override { resultHandler.handle(BucketIdListResult(BucketId::List(bucketList.begin(), bucketList.end()))); } diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/ipersistencehandler.h b/searchcore/src/vespa/searchcore/proton/persistenceengine/ipersistencehandler.h index 2367228eaf1..dcc26e3b758 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/ipersistencehandler.h +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/ipersistencehandler.h @@ -47,6 +47,9 @@ public: virtual void handleRemove(FeedToken token, const storage::spi::Bucket &bucket, storage::spi::Timestamp timestamp, const document::DocumentId &id) = 0; + virtual void handleRemoveByGid(FeedToken token, const storage::spi::Bucket &bucket, + storage::spi::Timestamp timestamp, + vespalib::stringref doc_type, const document::GlobalId& gid) = 0; virtual void handleListBuckets(IBucketIdListResultHandler &resultHandler) = 0; virtual void handleSetClusterState(const storage::spi::ClusterState &calc, IGenericResultHandler &resultHandler) = 0; diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp index 2ccb1899be6..bf8915b2505 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp @@ -4,6 +4,7 @@ #include "ipersistenceengineowner.h" #include "transport_latch.h" #include +#include #include #include #include @@ -431,6 +432,26 @@ PersistenceEngine::removeAsyncSingle(const Bucket& b, Timestamp t, const Documen handler->handleRemove(feedtoken::make(std::move(transportContext)), b, t, id); } +void +PersistenceEngine::removeByGidAsync(const Bucket& b, std::vector ids, std::unique_ptr onComplete) +{ + ReadGuard rguard(_rwMutex); + for (const auto & dt_gid_ts : ids) { + DocTypeName doc_type(dt_gid_ts.doc_type); + IPersistenceHandler *handler = getHandler(rguard, b.getBucketSpace(), doc_type); + if (!handler) { + return onComplete->onComplete(std::make_unique(Result::ErrorType::PERMANENT_ERROR, + fmt("No handler for document type '%s'", + doc_type.toString().c_str()))); + } + } + auto transportContext = std::make_shared(ids.size(), std::move(onComplete)); + for (const auto & dt_gid_ts : ids) { + DocTypeName doc_type(dt_gid_ts.doc_type); + IPersistenceHandler *handler = getHandler(rguard, b.getBucketSpace(), doc_type); + handler->handleRemoveByGid(feedtoken::make(transportContext), b, dt_gid_ts.timestamp, dt_gid_ts.doc_type, dt_gid_ts.gid); + } +} void PersistenceEngine::updateAsync(const Bucket& b, Timestamp t, DocumentUpdate::SP upd, OperationComplete::UP onComplete) diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h index bfce7ed37d4..aeadb14f4f5 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h @@ -109,6 +109,7 @@ public: BucketInfoResult getBucketInfo(const Bucket&) const override; void putAsync(const Bucket &, Timestamp, storage::spi::DocumentSP, OperationComplete::UP) override; void removeAsync(const Bucket&, std::vector ids, OperationComplete::UP) override; + void removeByGidAsync(const Bucket&, std::vector ids, std::unique_ptr) override; void updateAsync(const Bucket&, Timestamp, storage::spi::DocumentUpdateSP, OperationComplete::UP) override; GetResult get(const Bucket&, const document::FieldSet&, const document::DocumentId&, Context&) const override; CreateIteratorResult diff --git a/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.cpp b/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.cpp index 77a1f65764a..ea401d143e1 100644 --- a/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.cpp @@ -54,6 +54,13 @@ PersistenceHandlerProxy::handleRemove(FeedToken token, const Bucket &bucket, Tim _feedHandler.handleOperation(std::move(token), std::move(op)); } +void +PersistenceHandlerProxy::handleRemoveByGid(FeedToken token, const storage::spi::Bucket &bucket, Timestamp timestamp, vespalib::stringref doc_type, const document::GlobalId& gid) +{ + auto op = std::make_unique(bucket.getBucketId().stripUnused(), timestamp, gid, doc_type); + _feedHandler.handleOperation(std::move(token), std::move(op)); +} + void PersistenceHandlerProxy::handleListBuckets(IBucketIdListResultHandler &resultHandler) { diff --git a/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.h b/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.h index 1f2115c7339..d3e77f2414c 100644 --- a/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.h +++ b/searchcore/src/vespa/searchcore/proton/server/persistencehandlerproxy.h @@ -35,6 +35,9 @@ public: void handleRemove(FeedToken token, const storage::spi::Bucket &bucket, storage::spi::Timestamp timestamp, const document::DocumentId &id) override; + void handleRemoveByGid(FeedToken token, const storage::spi::Bucket &bucket, + storage::spi::Timestamp timestamp, + vespalib::stringref doc_type, const document::GlobalId& gid) override; void handleListBuckets(IBucketIdListResultHandler &resultHandler) override; void handleSetClusterState(const storage::spi::ClusterState &calc, IGenericResultHandler &resultHandler) override; diff --git a/storage/src/tests/persistence/common/persistenceproviderwrapper.cpp b/storage/src/tests/persistence/common/persistenceproviderwrapper.cpp index 17bfa57bed8..0740e1d6fec 100644 --- a/storage/src/tests/persistence/common/persistenceproviderwrapper.cpp +++ b/storage/src/tests/persistence/common/persistenceproviderwrapper.cpp @@ -3,6 +3,7 @@ #include "persistenceproviderwrapper.h" #include #include +#include #include #include @@ -116,6 +117,17 @@ PersistenceProviderWrapper::removeAsync(const spi::Bucket& bucket, std::vector< _spi.removeAsync(bucket, std::move(ids), std::move(onComplete)); } +void +PersistenceProviderWrapper::removeByGidAsync(const spi::Bucket& bucket, std::vector ids, + std::unique_ptr onComplete) +{ + for (const auto & dt_gid_ts : ids) { + LOG_SPI("removeByGid(" << bucket << ", " << dt_gid_ts.timestamp << ", " << dt_gid_ts.doc_type << ", " << dt_gid_ts.gid << ")"); + } + CHECK_ERROR_ASYNC(spi::RemoveResult, FAIL_REMOVE, onComplete); + _spi.removeByGidAsync(bucket, std::move(ids), std::move(onComplete)); +} + void PersistenceProviderWrapper::removeIfFoundAsync(const spi::Bucket& bucket, spi::Timestamp timestamp, const spi::DocumentId& id, spi::OperationComplete::UP onComplete) diff --git a/storage/src/tests/persistence/common/persistenceproviderwrapper.h b/storage/src/tests/persistence/common/persistenceproviderwrapper.h index aad4746ea90..f1a277581d9 100644 --- a/storage/src/tests/persistence/common/persistenceproviderwrapper.h +++ b/storage/src/tests/persistence/common/persistenceproviderwrapper.h @@ -107,6 +107,7 @@ public: spi::BucketInfoResult getBucketInfo(const spi::Bucket&) const override; void putAsync(const spi::Bucket&, spi::Timestamp, spi::DocumentSP, spi::OperationComplete::UP) override; void removeAsync(const spi::Bucket&, std::vector ids, spi::OperationComplete::UP) override; + void removeByGidAsync(const spi::Bucket&, std::vector ids, std::unique_ptr) override; void removeIfFoundAsync(const spi::Bucket&, spi::Timestamp, const spi::DocumentId&, spi::OperationComplete::UP) override; void updateAsync(const spi::Bucket&, spi::Timestamp, spi::DocumentUpdateSP, spi::OperationComplete::UP) override; spi::GetResult get(const spi::Bucket&, const document::FieldSet&, const spi::DocumentId&, spi::Context&) const override; diff --git a/storage/src/vespa/storage/persistence/provider_error_wrapper.cpp b/storage/src/vespa/storage/persistence/provider_error_wrapper.cpp index 83e7dc24eb7..9a414cd295a 100644 --- a/storage/src/vespa/storage/persistence/provider_error_wrapper.cpp +++ b/storage/src/vespa/storage/persistence/provider_error_wrapper.cpp @@ -165,6 +165,14 @@ ProviderErrorWrapper::removeAsync(const spi::Bucket &bucket, std::vector ids, + std::unique_ptr onComplete) +{ + onComplete->addResultHandler(this); + _impl.removeByGidAsync(bucket, std::move(ids), std::move(onComplete)); +} + void ProviderErrorWrapper::removeIfFoundAsync(const spi::Bucket &bucket, spi::Timestamp ts, const document::DocumentId &docId, spi::OperationComplete::UP onComplete) diff --git a/storage/src/vespa/storage/persistence/provider_error_wrapper.h b/storage/src/vespa/storage/persistence/provider_error_wrapper.h index a4748d9479b..7c4518d1db1 100644 --- a/storage/src/vespa/storage/persistence/provider_error_wrapper.h +++ b/storage/src/vespa/storage/persistence/provider_error_wrapper.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include namespace storage { @@ -56,6 +57,7 @@ public: void putAsync(const spi::Bucket &, spi::Timestamp, spi::DocumentSP, spi::OperationComplete::UP) override; void removeAsync(const spi::Bucket&, std::vector, spi::OperationComplete::UP) override; + void removeByGidAsync(const spi::Bucket&, std::vector, std::unique_ptr) override; void removeIfFoundAsync(const spi::Bucket&, spi::Timestamp, const document::DocumentId&, spi::OperationComplete::UP) override; void updateAsync(const spi::Bucket &, spi::Timestamp, spi::DocumentUpdateSP, spi::OperationComplete::UP) override; void setActiveStateAsync(const spi::Bucket& b, spi::BucketInfo::ActiveState newState, spi::OperationComplete::UP onComplete) override; -- cgit v1.2.3 From 64369b4a2e36c4d9b354fe3ae7fdbb35e17023f3 Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Mon, 6 Nov 2023 22:17:15 +0100 Subject: Compare all elements of DocTypeGidAndTimestamp. --- persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h index 449935ef830..9ff4d0493fa 100644 --- a/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h +++ b/persistence/src/vespa/persistence/spi/doctype_gid_and_timestamp.h @@ -3,6 +3,7 @@ #include "types.h" #include +#include #include #include @@ -30,7 +31,8 @@ struct DocTypeGidAndTimestamp { DocTypeGidAndTimestamp& operator=(DocTypeGidAndTimestamp&&) noexcept; bool operator==(const DocTypeGidAndTimestamp& rhs) const noexcept { - return ((doc_type == rhs.doc_type) && (gid == rhs.gid)); + return ((doc_type == rhs.doc_type) && (gid == rhs.gid) && + (timestamp == rhs.timestamp)); } void print(vespalib::asciistream&) const; @@ -38,7 +40,8 @@ struct DocTypeGidAndTimestamp { struct hash { size_t operator()(const DocTypeGidAndTimestamp& dt_gid_ts) const noexcept { - const size_t h = document::GlobalId::hash()(dt_gid_ts.gid); + size_t h = document::GlobalId::hash()(dt_gid_ts.gid); + h = h ^ (vespalib::hash()(dt_gid_ts.doc_type) + 0x9e3779b9U + (h << 6U) + (h >> 2U)); return h ^ (dt_gid_ts.timestamp + 0x9e3779b9U + (h << 6U) + (h >> 2U)); // Basically boost::hash_combine } }; -- cgit v1.2.3