From 5337bc72e789586875f4732950841c9720eaff5b Mon Sep 17 00:00:00 2001 From: Tor Egge Date: Mon, 6 Feb 2023 16:18:49 +0100 Subject: Reapply make attribute collection spec serial num optional. Pass reconfig serial num explicitly to various reconfigure member functions since it might not be available from attribute collection spec. --- .../attribute_initializer_test.cpp | 13 +++++- .../attribute_manager/attribute_manager_test.cpp | 33 +++++++++++++- .../documentdb/configurer/configurer_test.cpp | 52 ++++++++++++++-------- .../searchcore/proton/attribute/CMakeLists.txt | 1 + .../proton/attribute/attribute_collection_spec.cpp | 2 +- .../proton/attribute/attribute_collection_spec.h | 7 +-- .../attribute_collection_spec_factory.cpp | 2 +- .../attribute/attribute_collection_spec_factory.h | 3 +- .../proton/attribute/attribute_factory.cpp | 6 ++- .../proton/attribute/attribute_factory.h | 2 +- .../proton/attribute/attribute_initializer.cpp | 15 ++++--- .../proton/attribute/attribute_initializer.h | 7 +-- .../attribute/attribute_manager_initializer.cpp | 2 +- .../attribute/attribute_manager_reconfig.cpp | 28 ++++++++++++ .../proton/attribute/attribute_manager_reconfig.h | 28 ++++++++++++ .../proton/attribute/attributemanager.cpp | 28 +++++++++--- .../searchcore/proton/attribute/attributemanager.h | 3 +- .../attribute/attributes_initializer_base.cpp | 5 ++- .../proton/attribute/attributes_initializer_base.h | 2 +- .../proton/attribute/filter_attribute_manager.cpp | 6 +++ .../proton/attribute/filter_attribute_manager.h | 1 + .../proton/attribute/i_attribute_factory.h | 3 +- .../proton/attribute/i_attribute_manager.h | 3 ++ .../proton/server/fast_access_doc_subdb.cpp | 4 +- .../proton/server/fast_access_doc_subdb.h | 2 +- .../server/fast_access_doc_subdb_configurer.cpp | 8 ++-- .../server/fast_access_doc_subdb_configurer.h | 3 +- .../server/searchable_doc_subdb_configurer.cpp | 13 +++--- .../server/searchable_doc_subdb_configurer.h | 6 ++- .../proton/server/searchabledocsubdb.cpp | 4 +- .../proton/test/mock_attribute_manager.h | 4 ++ 31 files changed, 227 insertions(+), 69 deletions(-) create mode 100644 searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.cpp create mode 100644 searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.h diff --git a/searchcore/src/tests/proton/attribute/attribute_initializer/attribute_initializer_test.cpp b/searchcore/src/tests/proton/attribute/attribute_initializer/attribute_initializer_test.cpp index 106bdf5cc98..52b7a7ce60a 100644 --- a/searchcore/src/tests/proton/attribute/attribute_initializer/attribute_initializer_test.cpp +++ b/searchcore/src/tests/proton/attribute/attribute_initializer/attribute_initializer_test.cpp @@ -95,7 +95,7 @@ struct Fixture vespalib::ThreadStackExecutor _executor; Fixture(); ~Fixture(); - std::unique_ptr createInitializer(AttributeSpec && spec, SerialNum serialNum); + std::unique_ptr createInitializer(AttributeSpec && spec, std::optional serialNum); }; Fixture::Fixture() @@ -109,7 +109,7 @@ Fixture::Fixture() Fixture::~Fixture() = default; std::unique_ptr -Fixture::createInitializer(AttributeSpec &&spec, SerialNum serialNum) +Fixture::createInitializer(AttributeSpec &&spec, std::optional serialNum) { return std::make_unique(_diskLayout->createAttributeDir(spec.getName()), "test.subdb", std::move(spec), serialNum, _factory, _executor); } @@ -241,6 +241,15 @@ TEST("require that transient memory usage is reported for attribute load without EXPECT_EQUAL(0u, avi->get_transient_memory_usage()); } +TEST("require that saved attribute is ignored when serial num is not set") +{ + saveAttr("a", int32_sv, 10, 2); + Fixture f; + auto av = f.createInitializer({"a", int32_sv}, std::nullopt)->init().getAttribute(); + EXPECT_EQUAL(0u, av->getCreateSerialNum()); + EXPECT_EQUAL(1u, av->getNumDocs()); +} + } TEST_MAIN() diff --git a/searchcore/src/tests/proton/attribute/attribute_manager/attribute_manager_test.cpp b/searchcore/src/tests/proton/attribute/attribute_manager/attribute_manager_test.cpp index 616bf9edf6a..29639448023 100644 --- a/searchcore/src/tests/proton/attribute/attribute_manager/attribute_manager_test.cpp +++ b/searchcore/src/tests/proton/attribute/attribute_manager/attribute_manager_test.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -222,7 +223,7 @@ SequentialAttributeManager::SequentialAttributeManager(const AttributeManager &c : initializer(newSpec.getDocIdLimit()), mgr(currMgr, std::move(newSpec), initializer) { - mgr.addInitializedAttributes(initializer.getInitializedAttributes()); + mgr.addInitializedAttributes(initializer.getInitializedAttributes(), std::nullopt, std::nullopt); } SequentialAttributeManager::~SequentialAttributeManager() = default; @@ -877,6 +878,36 @@ TEST_F("transient resource usage is zero in steady state", Fixture) EXPECT_EQUAL(0u, usage.memory()); } +TEST_F("late create serial number is set on new attributes", Fixture) +{ + auto am1 = f.make_manager(); + am1->addAttribute({"a1", INT32_SINGLE}, 4); + auto a1 = am1->getAttribute("a1")->getSP(); + uint32_t docid = 0; + a1->addDoc(docid); + EXPECT_EQUAL(1u, docid); + a1->clearDoc(docid); + a1->commit(CommitParam(5)); + AttrSpecList new_spec; + new_spec.emplace_back("a1", INT32_SINGLE); + new_spec.emplace_back("a2", INT32_SINGLE); + // late serial number + auto am2 = am1->prepare_create(AttrMgrSpec(std::move(new_spec), 10, std::nullopt))->create(14, 20); + auto am3 = std::dynamic_pointer_cast(am2); + EXPECT_TRUE(a1 == am3->getAttribute("a1")->getSP()); + auto a2 = am3->getAttribute("a2")->getSP(); + TEST_DO(assertCreateSerialNum(*am3, "a1", 4)); + TEST_DO(assertCreateSerialNum(*am3, "a2", 20)); + TEST_DO(assertShrinkTargetSerial(*am3, "a1", 3)); + TEST_DO(assertShrinkTargetSerial(*am3, "a2", 19)); + EXPECT_EQUAL(0u, am3->getFlushedSerialNum("a1")); + EXPECT_EQUAL(0u, am3->getFlushedSerialNum("a2")); + EXPECT_EQUAL(2u, a1->getNumDocs()); + EXPECT_EQUAL(2u, a1->getCommittedDocIdLimit()); + EXPECT_EQUAL(14u, a2->getNumDocs()); + EXPECT_EQUAL(14u, a2->getCommittedDocIdLimit()); +} + TEST_MAIN() { std::filesystem::remove_all(std::filesystem::path(test_dir)); diff --git a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp index db5fb1ae294..2877005e2c1 100644 --- a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp +++ b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp @@ -47,6 +47,7 @@ using namespace vespa::config::search; using namespace vespalib; using proton::matching::SessionManager; +using search::SerialNum; using searchcorespi::IndexSearchable; using searchcorespi::index::IThreadingService; using proton::test::MockGidToLidChangeHandler; @@ -165,12 +166,14 @@ struct Fixture void reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, const ReconfigParams& reconfig_params, - IDocumentDBReferenceResolver& resolver); + IDocumentDBReferenceResolver& resolver, + SerialNum serial_num); IReprocessingInitializer::UP reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, AttributeCollectionSpec&& attr_spec, const ReconfigParams& reconfig_params, - IDocumentDBReferenceResolver& resolver); + IDocumentDBReferenceResolver& resolver, + SerialNum serial_num); }; Fixture::Fixture() @@ -240,10 +243,11 @@ void Fixture::reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, const ReconfigParams& reconfig_params, - IDocumentDBReferenceResolver& resolver) + IDocumentDBReferenceResolver& resolver, + SerialNum serial_num) { auto prepared_reconfig = _configurer->prepare_reconfig(new_config_snapshot, old_config_snapshot, reconfig_params); - _configurer->reconfigure(new_config_snapshot, old_config_snapshot, reconfig_params, resolver, *prepared_reconfig); + _configurer->reconfigure(new_config_snapshot, old_config_snapshot, reconfig_params, resolver, *prepared_reconfig, serial_num); } IReprocessingInitializer::UP @@ -251,10 +255,11 @@ Fixture::reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, AttributeCollectionSpec&& attr_spec, const ReconfigParams& reconfig_params, - IDocumentDBReferenceResolver& resolver) + IDocumentDBReferenceResolver& resolver, + SerialNum serial_num) { auto prepared_reconfig = _configurer->prepare_reconfig(new_config_snapshot, old_config_snapshot, reconfig_params); - return _configurer->reconfigure(new_config_snapshot, old_config_snapshot, std::move(attr_spec), reconfig_params, resolver, *prepared_reconfig); + return _configurer->reconfigure(new_config_snapshot, old_config_snapshot, std::move(attr_spec), reconfig_params, resolver, *prepared_reconfig, serial_num); } using MySummaryAdapter = test::MockSummaryAdapter; @@ -325,17 +330,19 @@ struct FastAccessFixture IReprocessingInitializer::UP reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, - AttributeCollectionSpec&& attr_spec); + AttributeCollectionSpec&& attr_spec, + SerialNum serial_num); }; IReprocessingInitializer::UP FastAccessFixture::reconfigure(const DocumentDBConfig& new_config_snapshot, const DocumentDBConfig& old_config_snapshot, - AttributeCollectionSpec&& attr_spec) + AttributeCollectionSpec&& attr_spec, + SerialNum serial_num) { ReconfigParams reconfig_params{CCR()}; auto prepared_reconfig = _configurer.prepare_reconfig(new_config_snapshot, old_config_snapshot, reconfig_params); - return _configurer.reconfigure(new_config_snapshot, old_config_snapshot, std::move(attr_spec), *prepared_reconfig); + return _configurer.reconfigure(new_config_snapshot, old_config_snapshot, std::move(attr_spec), *prepared_reconfig, serial_num); } DocumentDBConfig::SP @@ -500,9 +507,10 @@ TEST_F("require that we can reconfigure attribute manager", Fixture) ViewPtrs o = f._views.getViewPtrs(); ReconfigParams params(CCR().setAttributesChanged(true).setSchemaChanged(true)); // Use new config snapshot == old config snapshot (only relevant for reprocessing) + SerialNum reconfig_serial_num = 0; f.reconfigure(*createConfig(), *createConfig(), - AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, 0), - params, f._resolver); + AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, reconfig_serial_num), + params, f._resolver, reconfig_serial_num); ViewPtrs n = f._views.getViewPtrs(); { // verify search view @@ -538,9 +546,10 @@ checkAttributeWriterChangeOnRepoChange(Fixture &f, bool docTypeRepoChanged) auto oldAttributeWriter = getAttributeWriter(f); ReconfigParams params(CCR().setDocumentTypeRepoChanged(docTypeRepoChanged)); // Use new config snapshot == old config snapshot (only relevant for reprocessing) + SerialNum reconfig_serial_num = 0; f.reconfigure(*createConfig(), *createConfig(), - AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, 0), - params, f._resolver); + AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, reconfig_serial_num), + params, f._resolver, reconfig_serial_num); auto newAttributeWriter = getAttributeWriter(f); if (docTypeRepoChanged) { EXPECT_NOT_EQUAL(oldAttributeWriter, newAttributeWriter); @@ -558,10 +567,11 @@ TEST_F("require that we get new attribute writer if document type repo changes", TEST_F("require that reconfigure returns reprocessing initializer when changing attributes", Fixture) { ReconfigParams params(CCR().setAttributesChanged(true).setSchemaChanged(true)); + SerialNum reconfig_serial_num = 0; IReprocessingInitializer::UP init = f.reconfigure(*createConfig(), *createConfig(), - AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, 0), - params, f._resolver); + AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, reconfig_serial_num), + params, f._resolver, reconfig_serial_num); EXPECT_TRUE(init.get() != nullptr); EXPECT_TRUE((dynamic_cast(init.get())) != nullptr); @@ -571,8 +581,9 @@ TEST_F("require that reconfigure returns reprocessing initializer when changing TEST_F("require that we can reconfigure attribute writer", FastAccessFixture) { FastAccessFeedView::SP o = f._view._feedView.get(); + SerialNum reconfig_serial_num = 0; f.reconfigure(*createConfig(), *createConfig(), - AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, 0)); + AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, reconfig_serial_num), reconfig_serial_num); FastAccessFeedView::SP n = f._view._feedView.get(); FastAccessFeedViewComparer cmp(o, n); @@ -584,8 +595,9 @@ TEST_F("require that we can reconfigure attribute writer", FastAccessFixture) TEST_F("require that reconfigure returns reprocessing initializer", FastAccessFixture) { + SerialNum reconfig_serial_num = 0; IReprocessingInitializer::UP init = f.reconfigure(*createConfig(), *createConfig(), - AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, 0)); + AttributeCollectionSpec(AttributeCollectionSpec::AttributeList(), 1, reconfig_serial_num), reconfig_serial_num); EXPECT_TRUE(init.get() != nullptr); EXPECT_TRUE((dynamic_cast(init.get())) != nullptr); @@ -597,7 +609,8 @@ TEST_F("require that we can reconfigure summary manager", Fixture) ViewPtrs o = f._views.getViewPtrs(); ReconfigParams params(CCR().setSummaryChanged(true)); // Use new config snapshot == old config snapshot (only relevant for reprocessing) - f.reconfigure(*createConfig(), *createConfig(), params, f._resolver); + SerialNum reconfig_serial_num = 0; + f.reconfigure(*createConfig(), *createConfig(), params, f._resolver, reconfig_serial_num); ViewPtrs n = f._views.getViewPtrs(); { // verify search view @@ -616,8 +629,9 @@ TEST_F("require that we can reconfigure matchers", Fixture) { ViewPtrs o = f._views.getViewPtrs(); // Use new config snapshot == old config snapshot (only relevant for reprocessing) + SerialNum reconfig_serial_num = 0; f.reconfigure(*createConfig(o.fv->getSchema()), *createConfig(o.fv->getSchema()), - ReconfigParams(CCR().setRankProfilesChanged(true)), f._resolver); + ReconfigParams(CCR().setRankProfilesChanged(true)), f._resolver, reconfig_serial_num); ViewPtrs n = f._views.getViewPtrs(); { // verify search view diff --git a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt index 856c89eae37..82bb188870f 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt +++ b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt @@ -12,6 +12,7 @@ vespa_add_library(searchcore_attribute STATIC attribute_initializer_result.cpp attribute_manager_explorer.cpp attribute_manager_initializer.cpp + attribute_manager_reconfig.cpp attribute_populator.cpp attribute_spec.cpp attribute_transient_memory_calculator.cpp diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.cpp index 35c54d31fd0..9f23e8bb50b 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.cpp @@ -4,7 +4,7 @@ namespace proton { -AttributeCollectionSpec::AttributeCollectionSpec(AttributeList && attributes, uint32_t docIdLimit, SerialNum currentSerialNum) +AttributeCollectionSpec::AttributeCollectionSpec(AttributeList && attributes, uint32_t docIdLimit, std::optional currentSerialNum) : _attributes(std::move(attributes)), _docIdLimit(docIdLimit), _currentSerialNum(currentSerialNum) diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.h index 1ee9e92ce8c..406739aac94 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec.h @@ -4,6 +4,7 @@ #include "attribute_spec.h" #include +#include #include namespace proton { @@ -21,10 +22,10 @@ private: AttributeList _attributes; uint32_t _docIdLimit; - SerialNum _currentSerialNum; + std::optional _currentSerialNum; public: - AttributeCollectionSpec(AttributeList && attributes, uint32_t docIdLimit, SerialNum currentSerialNum); + AttributeCollectionSpec(AttributeList && attributes, uint32_t docIdLimit, std::optional currentSerialNum); ~AttributeCollectionSpec(); const AttributeList &getAttributes() const { return _attributes; @@ -35,7 +36,7 @@ public: uint32_t getDocIdLimit() const { return _docIdLimit; } - SerialNum getCurrentSerialNum() const { + const std::optional& getCurrentSerialNum() const noexcept { return _currentSerialNum; } bool hasAttribute(const vespalib::string &name) const; diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.cpp index 663491e9c64..2be0e0a58f8 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.cpp @@ -20,7 +20,7 @@ AttributeCollectionSpecFactory::~AttributeCollectionSpecFactory() = default; std::unique_ptr AttributeCollectionSpecFactory::create(const AttributesConfig &attrCfg, uint32_t docIdLimit, - search::SerialNum serialNum) const + std::optional serialNum) const { AttributeCollectionSpec::AttributeList attrs; // Amortize memory spike cost over N docs diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.h index 8ef06f20bac..06b3f677640 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_collection_spec_factory.h @@ -5,6 +5,7 @@ #include "attribute_collection_spec.h" #include #include +#include namespace vespa::config::search::internal { class InternalAttributesType; }; @@ -26,7 +27,7 @@ public: AttributeCollectionSpecFactory(const AllocStrategy& alloc_strategy, bool fastAccessOnly); ~AttributeCollectionSpecFactory(); - std::unique_ptr create(const AttributesConfig &attrCfg, uint32_t docIdLimit, search::SerialNum serialNum) const; + std::unique_ptr create(const AttributesConfig &attrCfg, uint32_t docIdLimit, std::optional serialNum) const; }; } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.cpp index 45b1dc41057..707b70510f8 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.cpp @@ -19,9 +19,11 @@ AttributeFactory::create(const vespalib::string &name, const search::attribute:: } void -AttributeFactory::setupEmpty(const AttributeVector::SP &vec, search::SerialNum serialNum) const +AttributeFactory::setupEmpty(const AttributeVector::SP &vec, std::optional serialNum) const { - vec->setCreateSerialNum(serialNum); + if (serialNum.has_value()) { + vec->setCreateSerialNum(serialNum.value()); + } vec->addReservedDoc(); } diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.h index 4b8021d1bc0..7901b55801c 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_factory.h @@ -16,7 +16,7 @@ public: AttributeFactory(); AttributeVectorSP create(const vespalib::string &name, const search::attribute::Config &cfg) const override; - void setupEmpty(const AttributeVectorSP &vec, search::SerialNum serialNum) const override; + void setupEmpty(const AttributeVectorSP &vec, std::optional serialNum) const override; }; } diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_initializer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_initializer.cpp index 19e387a2b64..16be2c1bd25 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_initializer.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_initializer.cpp @@ -209,11 +209,12 @@ void AttributeInitializer::setupEmptyAttribute(AttributeVectorSP &attr, search::SerialNum serialNum, const AttributeHeader &header) const { - if (header.getCreateSerialNum() > _currentSerialNum) { - logAttributeTooNew(header, _currentSerialNum); + assert(_currentSerialNum.has_value()); + if (header.getCreateSerialNum() > _currentSerialNum.value()) { + logAttributeTooNew(header, _currentSerialNum.value()); } - if (serialNum < _currentSerialNum) { - logAttributeTooOld(header, serialNum, _currentSerialNum); + if (serialNum < _currentSerialNum.value()) { + logAttributeTooOld(header, serialNum, _currentSerialNum.value()); } if (!headerTypeOK(header, attr->getConfig())) { logAttributeWrongType(attr, header); @@ -234,7 +235,7 @@ AttributeInitializer::createAndSetupEmptyAttribute() const AttributeInitializer::AttributeInitializer(const std::shared_ptr &attrDir, const vespalib::string &documentSubDbName, AttributeSpec && spec, - uint64_t currentSerialNum, + std::optional currentSerialNum, const IAttributeFactory &factory, vespalib::Executor& shared_executor) : _attrDir(attrDir), @@ -246,7 +247,9 @@ AttributeInitializer::AttributeInitializer(const std::shared_ptr #include +#include namespace search::attribute { class AttributeHeader; } namespace vespalib { class Executor; } @@ -28,7 +29,7 @@ private: std::shared_ptr _attrDir; const vespalib::string _documentSubDbName; const AttributeSpec _spec; - const uint64_t _currentSerialNum; + const std::optional _currentSerialNum; const IAttributeFactory &_factory; vespalib::Executor &_shared_executor; std::unique_ptr _header; @@ -47,12 +48,12 @@ private: public: AttributeInitializer(const std::shared_ptr &attrDir, const vespalib::string &documentSubDbName, - AttributeSpec && spec, uint64_t currentSerialNum, const IAttributeFactory &factory, + AttributeSpec && spec, std::optional currentSerialNum, const IAttributeFactory &factory, vespalib::Executor& shared_executor); ~AttributeInitializer(); AttributeInitializerResult init() const; - uint64_t getCurrentSerialNum() const { return _currentSerialNum; } + const std::optional& getCurrentSerialNum() const noexcept { return _currentSerialNum; } size_t get_transient_memory_usage() const; }; diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_initializer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_initializer.cpp index 3d6d522dd44..c15a15e44e5 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_initializer.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_initializer.cpp @@ -86,7 +86,7 @@ void AttributeManagerInitializerTask::run() { _attrMgr->addExtraAttribute(_documentMetaStore); - _attrMgr->addInitializedAttributes(_attributesResult.get()); + _attrMgr->addInitializedAttributes(_attributesResult.get(), std::nullopt, std::nullopt); _attrMgr->pruneRemovedFields(_configSerialNum); _promise.set_value(); } diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.cpp new file mode 100644 index 00000000000..2942256f534 --- /dev/null +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.cpp @@ -0,0 +1,28 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "attribute_manager_reconfig.h" +#include "attributemanager.h" +#include "sequential_attributes_initializer.h" +#include + +namespace proton { + +AttributeManagerReconfig::AttributeManagerReconfig(std::shared_ptr mgr, + std::unique_ptr initializer) + : _mgr(std::move(mgr)), + _initializer(std::move(initializer)) +{ +} + +AttributeManagerReconfig::~AttributeManagerReconfig() = default; + +std::shared_ptr +AttributeManagerReconfig::create(std::optional docid_limit, std::optional serial_num) +{ + assert(_mgr); + _mgr->addInitializedAttributes(_initializer->getInitializedAttributes(), docid_limit, serial_num); + return std::move(_mgr); +} + + +} diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.h new file mode 100644 index 00000000000..da8ae163fb5 --- /dev/null +++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_reconfig.h @@ -0,0 +1,28 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include +#include +#include + +namespace proton { + +class AttributeManager; +class SequentialAttributesInitializer; + +/** + * Class representing the result of the prepare step of an AttributeManager + * reconfig. + */ +class AttributeManagerReconfig { + std::shared_ptr _mgr; + std::unique_ptr _initializer; +public: + AttributeManagerReconfig(std::shared_ptr mgr, + std::unique_ptr initializer); + ~AttributeManagerReconfig(); + std::shared_ptr create(std::optional docid_limit, std::optional serial_num); +}; + +} diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp index c03ae3b2f1f..e27fae65de3 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp @@ -3,6 +3,7 @@ #include "attributemanager.h" #include "attribute_directory.h" #include "attribute_factory.h" +#include "attribute_manager_reconfig.h" #include "attribute_type_matcher.h" #include "attributedisklayout.h" #include "flushableattribute.h" @@ -210,7 +211,7 @@ AttributeManager::addNewAttributes(const Spec &newSpec, { for (auto &aspec : toBeAdded) { LOG(debug, "Creating initializer for attribute vector '%s': docIdLimit=%u, serialNumber=%" PRIu64, - aspec.getName().c_str(), newSpec.getDocIdLimit(), newSpec.getCurrentSerialNum()); + aspec.getName().c_str(), newSpec.getDocIdLimit(), newSpec.getCurrentSerialNum().value_or(0)); auto initializer = std::make_unique(_diskLayout->createAttributeDir(aspec.getName()), _documentSubDbName, std::move(aspec), newSpec.getCurrentSerialNum(), @@ -324,11 +325,17 @@ AttributeManager::addAttribute(AttributeSpec && spec, uint64_t serialNum) } void -AttributeManager::addInitializedAttributes(const std::vector &attributes) +AttributeManager::addInitializedAttributes(const std::vector &attributes, std::optional docid_limit, std::optional serial_num) { for (const auto &result : attributes) { assert(result); auto attr = result.getAttribute(); + if (docid_limit.has_value()) { + AttributeManager::padAttribute(*attr, docid_limit.value()); + } + if (serial_num.has_value()) { + attr->setCreateSerialNum(serial_num.value()); + } attr->setInterlock(_interlock); auto shrinker = allocShrinker(attr, _attributeFieldWriter, *_diskLayout); addAttribute(AttributeWrap::normalAttribute(std::move(attr)), shrinker); @@ -484,13 +491,20 @@ AttributeManager::createContext() const return std::make_unique(*this); } +std::unique_ptr +AttributeManager::prepare_create(Spec&& spec) const +{ + auto initializer = std::make_unique(spec.getDocIdLimit()); + auto result = std::make_shared(*this, std::move(spec), *initializer); + return std::make_unique(std::move(result), std::move(initializer)); +} + proton::IAttributeManager::SP -AttributeManager::create(Spec && spec) const +AttributeManager::create(Spec&& spec) const { - SequentialAttributesInitializer initializer(spec.getDocIdLimit()); - proton::AttributeManager::SP result = std::make_shared(*this, std::move(spec), initializer); - result->addInitializedAttributes(initializer.getInitializedAttributes()); - return result; + assert(spec.getCurrentSerialNum().has_value()); + auto prepared_result = prepare_create(std::move(spec)); + return prepared_result->create(std::nullopt, std::nullopt); } std::vector diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h index 65729767dbb..35895e5422c 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h @@ -123,7 +123,7 @@ public: AttributeVectorSP addAttribute(AttributeSpec && spec, uint64_t serialNum); - void addInitializedAttributes(const std::vector &attributes); + void addInitializedAttributes(const std::vector &attributes, std::optional docid_limit, std::optional serial_num); void addExtraAttribute(const AttributeVectorSP &attribute); @@ -151,6 +151,7 @@ public: // Implements proton::IAttributeManager + std::unique_ptr prepare_create(Spec && spec) const override; proton::IAttributeManager::SP create(Spec && spec) const override; std::vector getFlushTargets() const override; diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.cpp index 7fcf541fd02..391e188e3fd 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.cpp @@ -8,7 +8,7 @@ namespace proton { void AttributesInitializerBase::considerPadAttribute(search::AttributeVector &attribute, - search::SerialNum currentSerialNum, + std::optional currentSerialNum, uint32_t newDocIdLimit) { /* @@ -32,7 +32,8 @@ AttributesInitializerBase::considerPadAttribute(search::AttributeVector &attribu * 1, since a replay of a non-corrupted transaction log should * grow the attribute as needed. */ - if (attribute.getStatus().getLastSyncToken() < currentSerialNum) { + if (!currentSerialNum.has_value() || + attribute.getStatus().getLastSyncToken() < currentSerialNum.value()) { AttributeManager::padAttribute(attribute, newDocIdLimit); attribute.commit(); assert(newDocIdLimit <= attribute.getNumDocs()); diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.h b/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.h index de300b7bc52..9eae1b40f17 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/attributes_initializer_base.h @@ -21,7 +21,7 @@ protected: public: static void considerPadAttribute(search::AttributeVector &attribute, - search::SerialNum currentSerialNum, + std::optional currentSerialNum, uint32_t newDocIdLimit); AttributesInitializerBase(); diff --git a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp index 88475db472c..8f57546d3c5 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp +++ b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp @@ -77,6 +77,12 @@ FilterAttributeManager::createContext() const { throw vespalib::IllegalArgumentException("Not implemented"); } +std::unique_ptr +FilterAttributeManager::prepare_create(AttributeCollectionSpec&&) const +{ + throw vespalib::IllegalArgumentException("Not implemented"); +} + IAttributeManager::SP FilterAttributeManager::create(AttributeCollectionSpec &&) const { throw vespalib::IllegalArgumentException("Not implemented"); diff --git a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h index 1a10000978e..4397bf81107 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h @@ -38,6 +38,7 @@ public: std::unique_ptr getAttributeReadGuard(const vespalib::string &name, bool stableEnumGuard) const override; // Implements proton::IAttributeManager + std::unique_ptr prepare_create(AttributeCollectionSpec&& spec) const override; IAttributeManager::SP create(AttributeCollectionSpec &&) const override; std::vector getFlushTargets() const override; search::SerialNum getOldestFlushedSerialNumber() const override; diff --git a/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_factory.h b/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_factory.h index 6405ca79a4d..caa576e483e 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_factory.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_factory.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace search { class AttributeVector; } namespace search::attribute { class Config; } @@ -23,7 +24,7 @@ struct IAttributeFactory virtual AttributeVectorSP create(const vespalib::string &name, const search::attribute::Config &cfg) const = 0; virtual void setupEmpty(const AttributeVectorSP &vec, - search::SerialNum serialNum) const = 0; + std::optional serialNum) const = 0; }; } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h b/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h index ce163827d42..00a95607010 100644 --- a/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h +++ b/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h @@ -21,6 +21,7 @@ namespace vespalib { namespace proton { +class AttributeManagerReconfig; class ImportedAttributesRepo; /** @@ -36,6 +37,8 @@ struct IAttributeManager : public search::IAttributeManager using IAttributeFunctor = search::attribute::IAttributeFunctor; using IConstAttributeFunctor = search::attribute::IConstAttributeFunctor; + virtual std::unique_ptr prepare_create(AttributeCollectionSpec&& spec) const = 0; + /** * Create a new attribute manager based on the content of the current one and * the given attribute collection spec. diff --git a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.cpp b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.cpp index 3e2bd4f520a..5a2e9447f9c 100644 --- a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.cpp @@ -102,7 +102,7 @@ FastAccessDocSubDB::setupAttributeManager(AttributeManager::SP attrMgrResult) std::unique_ptr -FastAccessDocSubDB::createAttributeSpec(const AttributesConfig &attrCfg, const AllocStrategy& alloc_strategy, SerialNum serialNum) const +FastAccessDocSubDB::createAttributeSpec(const AttributesConfig &attrCfg, const AllocStrategy& alloc_strategy, std::optional serialNum) const { uint32_t docIdLimit(_dms->getCommittedDocIdLimit()); AttributeCollectionSpecFactory factory(alloc_strategy, _fastAccessAttributesOnly); @@ -270,7 +270,7 @@ FastAccessDocSubDB::applyConfig(const DocumentDBConfig &newConfigSnapshot, const std::unique_ptr attrSpec = createAttributeSpec(newConfigSnapshot.getAttributesConfig(), alloc_strategy, serialNum); IReprocessingInitializer::UP initializer = - _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, std::move(*attrSpec), prepared_reconfig); + _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, std::move(*attrSpec), prepared_reconfig, serialNum); if (initializer->hasReprocessors()) { tasks.push_back(IReprocessingTask::SP(createReprocessingTask(*initializer, newConfigSnapshot.getDocumentTypeRepoSP()).release())); diff --git a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.h b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.h index dec8dd3687b..cec2e8595cf 100644 --- a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.h +++ b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb.h @@ -91,7 +91,7 @@ protected: std::shared_ptr _attribute_interlock; DocIdLimit _docIdLimit; - std::unique_ptr createAttributeSpec(const AttributesConfig &attrCfg, const AllocStrategy& alloc_strategy, SerialNum serialNum) const; + std::unique_ptr createAttributeSpec(const AttributesConfig &attrCfg, const AllocStrategy& alloc_strategy, std::optional serialNum) const; AttributeManager::SP getAndResetInitAttributeManager(); virtual IFlushTargetList getFlushTargetsInternal() override; void reconfigureAttributeMetrics(const IAttributeManager &newMgr, const IAttributeManager &oldMgr); diff --git a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.cpp b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.cpp index 80c609caf61..a8211d246e1 100644 --- a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.cpp @@ -58,11 +58,13 @@ IReprocessingInitializer::UP FastAccessDocSubDBConfigurer::reconfigure(const DocumentDBConfig &newConfig, const DocumentDBConfig &oldConfig, AttributeCollectionSpec && attrSpec, - const DocumentSubDBReconfig& prepared_reconfig) + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num) { (void) prepared_reconfig; FastAccessFeedView::SP oldView = _feedView.get(); - search::SerialNum currentSerialNum = attrSpec.getCurrentSerialNum(); + auto& attr_spec_serial_num = attrSpec.getCurrentSerialNum(); + assert(!attr_spec_serial_num.has_value() || attr_spec_serial_num.value() == serial_num); IAttributeWriter::SP writer = _factory->create(oldView->getAttributeWriter(), std::move(attrSpec)); reconfigureFeedView(*oldView, newConfig.getSchemaSP(), newConfig.getDocumentTypeRepoSP(), writer); @@ -75,7 +77,7 @@ FastAccessDocSubDBConfigurer::reconfigure(const DocumentDBConfig &newConfig, return std::make_unique (ARIConfig(writer->getAttributeManager(), *newConfig.getSchemaSP()), ARIConfig(oldView->getAttributeWriter()->getAttributeManager(), *oldConfig.getSchemaSP()), - inspector, oldIndexschemaInspector, _subDbName, currentSerialNum); + inspector, oldIndexschemaInspector, _subDbName, serial_num); } } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.h b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.h index d39a41519a6..6d57a9cc3de 100644 --- a/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.h +++ b/searchcore/src/vespa/searchcore/proton/server/fast_access_doc_subdb_configurer.h @@ -38,7 +38,8 @@ public: IReprocessingInitializer::UP reconfigure(const DocumentDBConfig &newConfig, const DocumentDBConfig &oldConfig, AttributeCollectionSpec && attrSpec, - const DocumentSubDBReconfig& prepared_reconfig); + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num); }; } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp index 2263876c04e..f3b83e08546 100644 --- a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp @@ -158,11 +158,12 @@ reconfigure(const DocumentDBConfig &newConfig, const DocumentDBConfig &oldConfig, const ReconfigParams ¶ms, IDocumentDBReferenceResolver &resolver, - const DocumentSubDBReconfig& prepared_reconfig) + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num) { assert(!params.shouldAttributeManagerChange()); AttributeCollectionSpec attrSpec(AttributeCollectionSpec::AttributeList(), 0, 0); - reconfigure(newConfig, oldConfig, std::move(attrSpec), params, resolver, prepared_reconfig); + reconfigure(newConfig, oldConfig, std::move(attrSpec), params, resolver, prepared_reconfig, serial_num); } namespace { @@ -195,12 +196,14 @@ SearchableDocSubDBConfigurer::reconfigure(const DocumentDBConfig &newConfig, AttributeCollectionSpec && attrSpec, const ReconfigParams ¶ms, IDocumentDBReferenceResolver &resolver, - const DocumentSubDBReconfig& prepared_reconfig) + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num) { bool shouldMatchViewChange = prepared_reconfig.has_matchers_changed(); bool shouldSearchViewChange = false; bool shouldFeedViewChange = params.shouldSchemaChange(); - search::SerialNum currentSerialNum = attrSpec.getCurrentSerialNum(); + auto& attr_spec_serial_num = attrSpec.getCurrentSerialNum(); + assert(!attr_spec_serial_num.has_value() || attr_spec_serial_num.value() == serial_num); SearchView::SP searchView = _searchView.get(); auto matchers = prepared_reconfig.matchers(); IReprocessingInitializer::UP initializer; @@ -219,7 +222,7 @@ SearchableDocSubDBConfigurer::reconfigure(const DocumentDBConfig &newConfig, attrWriter = newAttrWriter; shouldFeedViewChange = true; initializer = createAttributeReprocessingInitializer(newConfig, newAttrMgr, oldConfig, oldAttrMgr, - _subDbName, currentSerialNum); + _subDbName, serial_num); } else if (params.shouldAttributeWriterChange()) { attrWriter = std::make_shared(attrMgr); shouldFeedViewChange = true; diff --git a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.h b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.h index 0937a754640..b3ec169afeb 100644 --- a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.h +++ b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.h @@ -84,7 +84,8 @@ public: const DocumentDBConfig &oldConfig, const ReconfigParams ¶ms, IDocumentDBReferenceResolver &resolver, - const DocumentSubDBReconfig& prepared_reconfig); + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num); IReprocessingInitializer::UP reconfigure(const DocumentDBConfig &newConfig, @@ -92,7 +93,8 @@ public: AttributeCollectionSpec && attrSpec, const ReconfigParams ¶ms, IDocumentDBReferenceResolver &resolver, - const DocumentSubDBReconfig& prepared_reconfig); + const DocumentSubDBReconfig& prepared_reconfig, + search::SerialNum serial_num); }; } // namespace proton diff --git a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp index 3f79b02830d..89925e8a77d 100644 --- a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp @@ -154,7 +154,7 @@ SearchableDocSubDB::applyConfig(const DocumentDBConfig &newConfigSnapshot, const std::unique_ptr attrSpec = createAttributeSpec(newConfigSnapshot.getAttributesConfig(), alloc_strategy, serialNum); IReprocessingInitializer::UP initializer = - _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, std::move(*attrSpec), params, resolver, prepared_reconfig); + _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, std::move(*attrSpec), params, resolver, prepared_reconfig, serialNum); if (initializer && initializer->hasReprocessors()) { tasks.emplace_back(createReprocessingTask(*initializer, newConfigSnapshot.getDocumentTypeRepoSP())); } @@ -163,7 +163,7 @@ SearchableDocSubDB::applyConfig(const DocumentDBConfig &newConfigSnapshot, const reconfigureAttributeMetrics(*newMgr, *oldMgr); } } else { - _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, params, resolver, prepared_reconfig); + _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, params, resolver, prepared_reconfig, serialNum); } syncViews(); return tasks; diff --git a/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h b/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h index 987d60dff01..2261fccd628 100644 --- a/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h +++ b/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include #include #include @@ -49,6 +50,9 @@ public: search::attribute::IAttributeContext::UP createContext() const override { return _mock.createContext(); } + std::unique_ptr prepare_create(AttributeCollectionSpec&&) const override { + return {}; + } IAttributeManager::SP create(AttributeCollectionSpec &&) const override { return IAttributeManager::SP(); } -- cgit v1.2.3