summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Musum <musum@verizonmedia.com>2023-03-28 21:32:54 +0200
committerGitHub <noreply@github.com>2023-03-28 21:32:54 +0200
commit2fbb6238e72c9fbdeb6646edf769a0fd7cc1a39c (patch)
tree144b5935d1480993b5469c3c3e38d6c9a455bb08
parent99b509cbd2493135c8db1af13e3d7f5d1b71ba1c (diff)
parenta8c5345a7010e03d6af8a1176f75a1aac8b58df8 (diff)
Merge pull request #26622 from vespa-engine/revert-26616-toregge/explore-attribute-vector-in-writer-thread
Revert "Explore attribute vector in writer thread."
-rw-r--r--searchcore/CMakeLists.txt1
-rw-r--r--searchcore/src/tests/proton/attribute/attribute_manager/attribute_manager_test.cpp10
-rw-r--r--searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp4
-rw-r--r--searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/.gitignore1
-rw-r--r--searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/CMakeLists.txt9
-rw-r--r--searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/exclusive_attribute_read_accessor_test.cpp55
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt2
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.cpp34
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.h32
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp15
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.cpp15
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.h10
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp10
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h2
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.cpp60
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h53
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp6
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h1
-rw-r--r--searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h3
-rw-r--r--searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h3
20 files changed, 230 insertions, 96 deletions
diff --git a/searchcore/CMakeLists.txt b/searchcore/CMakeLists.txt
index 426e577b2d2..131460b0384 100644
--- a/searchcore/CMakeLists.txt
+++ b/searchcore/CMakeLists.txt
@@ -64,6 +64,7 @@ vespa_define_module(
src/tests/proton/attribute/attributes_state_explorer
src/tests/proton/attribute/document_field_extractor
src/tests/proton/attribute/document_field_populator
+ src/tests/proton/attribute/exclusive_attribute_read_accessor
src/tests/proton/attribute/imported_attributes_context
src/tests/proton/attribute/imported_attributes_repo
src/tests/proton/bucketdb/bucketdb
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 140012624c2..c9f3a1c1de8 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
@@ -5,6 +5,7 @@
#include <vespa/searchcore/proton/attribute/attribute_manager_reconfig.h>
#include <vespa/searchcore/proton/attribute/attribute_writer.h>
#include <vespa/searchcore/proton/attribute/attributemanager.h>
+#include <vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h>
#include <vespa/searchcore/proton/attribute/imported_attributes_repo.h>
#include <vespa/searchcore/proton/attribute/sequential_attributes_initializer.h>
#include <vespa/searchcore/proton/bucketdb/bucket_db_owner.h>
@@ -754,6 +755,15 @@ TEST_F("require that we can call functions on all attributes via functor",
EXPECT_EQUAL("a1,a2,a3", functor->getSortedNames());
}
+TEST_F("require that we can acquire exclusive read access to attribute", Fixture)
+{
+ f.addAttribute("attr");
+ ExclusiveAttributeReadAccessor::UP attrAccessor = f._m.getExclusiveReadAccessor("attr");
+ ExclusiveAttributeReadAccessor::UP noneAccessor = f._m.getExclusiveReadAccessor("none");
+ EXPECT_TRUE(attrAccessor.get() != nullptr);
+ EXPECT_TRUE(noneAccessor.get() == nullptr);
+}
+
TEST_F("require that imported attributes are exposed via attribute context together with regular attributes", Fixture)
{
f.addAttribute("attr");
diff --git a/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp b/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp
index aa4871d3a12..bcd200cfd2f 100644
--- a/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp
+++ b/searchcore/src/tests/proton/attribute/attributes_state_explorer/attributes_state_explorer_test.cpp
@@ -92,13 +92,13 @@ TEST_F(AttributesStateExplorerTest, require_that_attributes_are_exposed_as_child
{
StringVector children = _explorer.get_children_names();
std::sort(children.begin(), children.end());
- EXPECT_EQ(StringVector({"btree", "hash", "hybrid", "regular"}), children);
+ EXPECT_EQ(StringVector({"btree", "extra", "hash", "hybrid", "regular"}), children);
}
TEST_F(AttributesStateExplorerTest, require_that_attributes_are_explorable)
{
EXPECT_TRUE(_explorer.get_child("regular").get() != nullptr);
- EXPECT_TRUE(_explorer.get_child("extra").get() == nullptr);
+ EXPECT_TRUE(_explorer.get_child("extra").get() != nullptr);
EXPECT_TRUE(_explorer.get_child("not").get() == nullptr);
}
diff --git a/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/.gitignore b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/.gitignore
new file mode 100644
index 00000000000..f3666eecb6e
--- /dev/null
+++ b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/.gitignore
@@ -0,0 +1 @@
+searchcore_exclusive_attribute_read_accessor_test_app
diff --git a/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/CMakeLists.txt b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/CMakeLists.txt
new file mode 100644
index 00000000000..981d2acd7c5
--- /dev/null
+++ b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchcore_exclusive_attribute_read_accessor_test_app TEST
+ SOURCES
+ exclusive_attribute_read_accessor_test.cpp
+ DEPENDS
+ searchcore_attribute
+ searchcore_pcommon
+)
+vespa_add_test(NAME searchcore_exclusive_attribute_read_accessor_test_app COMMAND searchcore_exclusive_attribute_read_accessor_test_app)
diff --git a/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/exclusive_attribute_read_accessor_test.cpp b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/exclusive_attribute_read_accessor_test.cpp
new file mode 100644
index 00000000000..8b093be08b7
--- /dev/null
+++ b/searchcore/src/tests/proton/attribute/exclusive_attribute_read_accessor/exclusive_attribute_read_accessor_test.cpp
@@ -0,0 +1,55 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/testkit/testapp.h>
+
+#include <vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h>
+#include <vespa/searchcommon/attribute/config.h>
+#include <vespa/searchlib/attribute/attributefactory.h>
+#include <vespa/searchlib/attribute/attributevector.h>
+#include <vespa/vespalib/util/sequencedtaskexecutor.h>
+#include <vespa/vespalib/util/gate.h>
+
+using namespace proton;
+using namespace search;
+using namespace vespalib;
+
+using ReadGuard = ExclusiveAttributeReadAccessor::Guard;
+VESPA_THREAD_STACK_TAG(test_executor)
+
+AttributeVector::SP
+createAttribute()
+{
+ attribute::Config cfg(attribute::BasicType::INT32, attribute::CollectionType::SINGLE);
+ return search::AttributeFactory::createAttribute("myattr", cfg);
+}
+
+struct Fixture
+{
+ AttributeVector::SP attribute;
+ std::unique_ptr<ISequencedTaskExecutor> writer;
+ ExclusiveAttributeReadAccessor accessor;
+
+ Fixture()
+ : attribute(createAttribute()),
+ writer(SequencedTaskExecutor::create(test_executor, 1)),
+ accessor(attribute, *writer)
+ {}
+};
+
+TEST_F("require that attribute write thread is blocked while guard is held", Fixture)
+{
+ ReadGuard::UP guard = f.accessor.takeGuard();
+ Gate gate;
+ f.writer->execute(f.writer->getExecutorIdFromName(f.attribute->getNamePrefix()), [&gate]() { gate.countDown(); });
+ bool reachedZero = gate.await(100ms);
+ EXPECT_FALSE(reachedZero);
+ EXPECT_EQUAL(1u, gate.getCount());
+
+ guard.reset();
+ gate.await();
+ EXPECT_EQUAL(0u, gate.getCount());
+}
+
+TEST_MAIN()
+{
+ TEST_RUN_ALL();
+}
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt
index 70a91b418a9..82bb188870f 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt
+++ b/searchcore/src/vespa/searchcore/proton/attribute/CMakeLists.txt
@@ -7,7 +7,6 @@ vespa_add_library(searchcore_attribute STATIC
attribute_collection_spec.cpp
attribute_config_inspector.cpp
attribute_directory.cpp
- attribute_executor.cpp
attribute_factory.cpp
attribute_initializer.cpp
attribute_initializer_result.cpp
@@ -31,6 +30,7 @@ vespa_add_library(searchcore_attribute STATIC
document_field_extractor.cpp
document_field_populator.cpp
document_field_retriever.cpp
+ exclusive_attribute_read_accessor.cpp
filter_attribute_manager.cpp
flushableattribute.cpp
imported_attributes_context.cpp
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.cpp
deleted file mode 100644
index 4d854bfdca1..00000000000
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#include "attribute_executor.h"
-#include "i_attribute_manager.h"
-#include <vespa/searchlib/attribute/attributevector.h>
-#include <vespa/vespalib/util/isequencedtaskexecutor.h>
-#include <future>
-
-using search::AttributeVector;
-
-namespace proton {
-
-AttributeExecutor::AttributeExecutor(std::shared_ptr<IAttributeManager> mgr,
- std::shared_ptr<AttributeVector> attr)
- : _mgr(std::move(mgr)),
- _attr(std::move(attr))
-{
-}
-
-AttributeExecutor::~AttributeExecutor() = default;
-
-void
-AttributeExecutor::run_sync(std::function<void()> task) const
-{
- vespalib::string name = _attr->getNamePrefix();
- auto& writer = _mgr->getAttributeFieldWriter();
- std::promise<void> promise;
- auto future = promise.get_future();
- auto id = writer.getExecutorIdFromName(name);
- writer.execute(id, [&task, promise=std::move(promise)]() mutable { task(); promise.set_value(); });
- future.wait();
-}
-
-} // namespace proton
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.h
deleted file mode 100644
index 4a13fe1d886..00000000000
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_executor.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-#pragma once
-
-#include <vespa/vespalib/stllike/string.h>
-#include <functional>
-#include <memory>
-
-namespace search { class AttributeVector; }
-
-namespace proton {
-
-struct IAttributeManager;
-
-/*
- * Class for executing task in attribute vector write thread.
- */
-class AttributeExecutor
-{
-private:
- std::shared_ptr<IAttributeManager> _mgr;
- std::shared_ptr<search::AttributeVector> _attr;
-
-public:
- AttributeExecutor(std::shared_ptr<IAttributeManager> mgr,
- std::shared_ptr<search::AttributeVector> attr);
- ~AttributeExecutor();
- void run_sync(std::function<void()> task) const;
- const search::AttributeVector& get_attr() const noexcept { return *_attr; }
-};
-
-} // namespace proton
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp
index 1ea02c729ff..b7d6cf9e87a 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_manager_explorer.cpp
@@ -1,11 +1,9 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "attribute_manager_explorer.h"
-#include "attribute_executor.h"
#include "attribute_vector_explorer.h"
#include <vespa/searchlib/attribute/attributevector.h>
-using search::AttributeVector;
using vespalib::slime::Inserter;
namespace proton {
@@ -27,7 +25,8 @@ AttributeManagerExplorer::get_state(const Inserter &inserter, bool full) const
std::vector<vespalib::string>
AttributeManagerExplorer::get_children_names() const
{
- auto& attributes = _mgr->getWritableAttributes();
+ std::vector<search::AttributeGuard> attributes;
+ _mgr->getAttributeListAll(attributes);
std::vector<vespalib::string> names;
for (const auto &attr : attributes) {
names.push_back(attr->getName());
@@ -38,13 +37,11 @@ AttributeManagerExplorer::get_children_names() const
std::unique_ptr<vespalib::StateExplorer>
AttributeManagerExplorer::get_child(vespalib::stringref name) const
{
- auto guard = _mgr->getAttribute(name);
- auto attr = guard ? guard->getSP() : std::shared_ptr<AttributeVector>();
- if (attr && _mgr->getWritableAttribute(name) != nullptr) {
- auto executor = std::make_unique<AttributeExecutor>(_mgr, std::move(attr));
- return std::make_unique<AttributeVectorExplorer>(std::move(executor));
+ auto attr = _mgr->getExclusiveReadAccessor(name);
+ if (attr.get() != nullptr) {
+ return std::make_unique<AttributeVectorExplorer>(std::move(attr));
}
- return {};
+ return std::unique_ptr<vespalib::StateExplorer>();
}
} // namespace proton
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.cpp
index 2deabeda797..c153f873480 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.cpp
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "attribute_vector_explorer.h"
-#include "attribute_executor.h"
#include <vespa/searchlib/attribute/i_enum_store.h>
#include <vespa/searchlib/attribute/i_enum_store_dictionary.h>
#include <vespa/searchlib/attribute/multi_value_mapping.h>
@@ -18,7 +17,6 @@ using search::IEnumStore;
using vespalib::AddressSpace;
using vespalib::MemoryUsage;
using search::attribute::MultiValueMappingBase;
-using search::attribute::IAttributeVector;
using search::attribute::IPostingListAttributeBase;
using namespace vespalib::slime;
@@ -118,21 +116,16 @@ convertPostingBaseToSlime(const IPostingListAttributeBase &postingBase, Cursor &
}
-AttributeVectorExplorer::AttributeVectorExplorer(std::unique_ptr<AttributeExecutor> executor)
- : _executor(std::move(executor))
+AttributeVectorExplorer::AttributeVectorExplorer(ExclusiveAttributeReadAccessor::UP attribute)
+ : _attribute(std::move(attribute))
{
}
void
AttributeVectorExplorer::get_state(const vespalib::slime::Inserter &inserter, bool full) const
{
- auto& attr = _executor->get_attr();
- _executor->run_sync([this, &attr, &inserter, full] { get_state_helper(attr, inserter, full); });
-}
-
-void
-AttributeVectorExplorer::get_state_helper(const AttributeVector& attr, const vespalib::slime::Inserter &inserter, bool full) const
-{
+ ExclusiveAttributeReadAccessor::Guard::UP readGuard = _attribute->takeGuard();
+ const AttributeVector &attr = readGuard->get();
const Status &status = attr.getStatus();
Cursor &object = inserter.insertObject();
if (full) {
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.h b/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.h
index f7bcc98d321..204a81ed629 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.h
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attribute_vector_explorer.h
@@ -2,25 +2,21 @@
#pragma once
+#include "exclusive_attribute_read_accessor.h"
#include <vespa/vespalib/net/http/state_explorer.h>
-namespace search { class AttributeVector; }
-
namespace proton {
-class AttributeExecutor;
-
/**
* Class used to explore the state of an attribute vector.
*/
class AttributeVectorExplorer : public vespalib::StateExplorer
{
private:
- std::unique_ptr<const AttributeExecutor> _executor;
+ ExclusiveAttributeReadAccessor::UP _attribute;
- void get_state_helper(const search::AttributeVector& attr, const vespalib::slime::Inserter &inserter, bool full) const;
public:
- AttributeVectorExplorer(std::unique_ptr<AttributeExecutor> executor);
+ AttributeVectorExplorer(ExclusiveAttributeReadAccessor::UP attribute);
// Implements vespalib::StateExplorer
void get_state(const vespalib::slime::Inserter &inserter, bool full) const override;
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp
index ee04f17d378..161a4294908 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.cpp
@@ -638,6 +638,16 @@ AttributeManager::asyncForAttribute(const vespalib::string &name, std::unique_pt
[attr=std::move(attrsp), func=std::move(func)]() { (*func)(*attr); });
}
+ExclusiveAttributeReadAccessor::UP
+AttributeManager::getExclusiveReadAccessor(const vespalib::string &name) const
+{
+ AttributeVector::SP attribute = findAttribute(name);
+ if (attribute) {
+ return std::make_unique<ExclusiveAttributeReadAccessor>(attribute, _attributeFieldWriter);
+ }
+ return {};
+}
+
void
AttributeManager::setImportedAttributes(std::unique_ptr<ImportedAttributesRepo> attributes)
{
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h
index d6d0964f97e..c924c1c5b20 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h
+++ b/searchcore/src/vespa/searchcore/proton/attribute/attributemanager.h
@@ -182,6 +182,8 @@ public:
void asyncForEachAttribute(std::shared_ptr<IAttributeFunctor> func, OnDone onDone) const override;
void asyncForAttribute(const vespalib::string &name, std::unique_ptr<IAttributeFunctor> func) const override;
+ ExclusiveAttributeReadAccessor::UP getExclusiveReadAccessor(const vespalib::string &name) const override;
+
void setImportedAttributes(std::unique_ptr<ImportedAttributesRepo> attributes) override;
const ImportedAttributesRepo *getImportedAttributes() const override { return _importedAttributes.get(); }
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.cpp b/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.cpp
new file mode 100644
index 00000000000..ed72418ced4
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.cpp
@@ -0,0 +1,60 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "exclusive_attribute_read_accessor.h"
+#include <vespa/vespalib/util/gate.h>
+#include <vespa/searchlib/attribute/attributevector.h>
+#include <vespa/vespalib/util/isequencedtaskexecutor.h>
+
+namespace proton {
+
+using search::AttributeVector;
+using vespalib::ISequencedTaskExecutor;
+using vespalib::Executor;
+using vespalib::Gate;
+
+using GateSP = std::shared_ptr<Gate>;
+
+ExclusiveAttributeReadAccessor::Guard::Guard(const AttributeVector &attribute,
+ const GateSP &exitGate)
+ : _attribute(attribute),
+ _exitGate(exitGate)
+{
+}
+
+ExclusiveAttributeReadAccessor::Guard::~Guard()
+{
+ _exitGate->countDown();
+}
+
+ExclusiveAttributeReadAccessor::
+ExclusiveAttributeReadAccessor(const AttributeVector::SP &attribute,
+ ISequencedTaskExecutor &attributeFieldWriter)
+ : _attribute(attribute),
+ _attributeFieldWriter(attributeFieldWriter)
+{
+}
+
+namespace {
+
+void
+attributeWriteBlockingTask(AttributeVector::SP attribute, GateSP entranceGate, GateSP exitGate)
+{
+ attribute->commit(true);
+ entranceGate->countDown();
+ exitGate->await();
+}
+
+}
+
+ExclusiveAttributeReadAccessor::Guard::UP
+ExclusiveAttributeReadAccessor::takeGuard()
+{
+ GateSP entranceGate = std::make_shared<Gate>();
+ GateSP exitGate = std::make_shared<Gate>();
+ _attributeFieldWriter.execute(_attributeFieldWriter.getExecutorIdFromName(_attribute->getNamePrefix()),
+ [this, entranceGate, exitGate]() { attributeWriteBlockingTask(_attribute, entranceGate, exitGate); });
+ entranceGate->await();
+ return std::make_unique<Guard>(*_attribute, exitGate);
+}
+
+} // namespace proton
diff --git a/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h b/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h
new file mode 100644
index 00000000000..aa756764b1a
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/proton/attribute/exclusive_attribute_read_accessor.h
@@ -0,0 +1,53 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <memory>
+
+namespace search {
+ class AttributeVector;
+}
+namespace vespalib {
+ class Gate;
+ class ISequencedTaskExecutor;
+}
+
+namespace proton {
+
+/**
+ * Class that provides exclusive read access to an attribute vector
+ * while the write thread for that attribute is blocked.
+ *
+ * The attribute write thread is blocked while a guard is held.
+ */
+class ExclusiveAttributeReadAccessor
+{
+public:
+ class Guard
+ {
+ private:
+ const search::AttributeVector &_attribute;
+ std::shared_ptr<vespalib::Gate> _exitGate;
+
+ public:
+ using UP = std::unique_ptr<Guard>;
+ Guard(const search::AttributeVector &attribute,
+ const std::shared_ptr<vespalib::Gate> &exitGate);
+ ~Guard();
+ const search::AttributeVector &get() const { return _attribute; }
+ };
+
+private:
+ using AttributeVectorSP = std::shared_ptr<search::AttributeVector>;
+ AttributeVectorSP _attribute;
+ vespalib::ISequencedTaskExecutor &_attributeFieldWriter;
+
+public:
+ using UP = std::unique_ptr<ExclusiveAttributeReadAccessor>;
+
+ ExclusiveAttributeReadAccessor(const AttributeVectorSP &attribute,
+ vespalib::ISequencedTaskExecutor &attributeFieldWriter);
+ Guard::UP takeGuard();
+};
+
+} // namespace proton
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 6329c633727..6f6cd01b4a4 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp
+++ b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.cpp
@@ -232,6 +232,12 @@ FilterAttributeManager::asyncForAttribute(const vespalib::string &name, std::uni
}
+ExclusiveAttributeReadAccessor::UP
+FilterAttributeManager::getExclusiveReadAccessor(const vespalib::string &name) const
+{
+ return (acceptAttribute(name)) ? _mgr->getExclusiveReadAccessor(name) : ExclusiveAttributeReadAccessor::UP();
+}
+
void
FilterAttributeManager::setImportedAttributes(std::unique_ptr<ImportedAttributesRepo>)
{
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 6d5ff682ca1..dff18290330 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h
+++ b/searchcore/src/vespa/searchcore/proton/attribute/filter_attribute_manager.h
@@ -52,6 +52,7 @@ public:
const std::vector<search::AttributeVector *> & getWritableAttributes() const override;
void asyncForEachAttribute(std::shared_ptr<IConstAttributeFunctor> func) const override;
void asyncForEachAttribute(std::shared_ptr<IAttributeFunctor> func, OnDone onDone) const override;
+ ExclusiveAttributeReadAccessor::UP getExclusiveReadAccessor(const vespalib::string &name) const override;
void setImportedAttributes(std::unique_ptr<ImportedAttributesRepo> attributes) override;
const ImportedAttributesRepo *getImportedAttributes() const override;
std::shared_ptr<search::attribute::ReadableAttributeVector> readable_attribute_vector(const string& name) const override;
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 5e60e950cc4..437e7bd0208 100644
--- a/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h
+++ b/searchcore/src/vespa/searchcore/proton/attribute/i_attribute_manager.h
@@ -2,6 +2,7 @@
#pragma once
+#include "exclusive_attribute_read_accessor.h"
#include "i_attribute_factory.h"
#include <vespa/searchcommon/attribute/i_attribute_functor.h>
#include <vespa/searchcore/proton/common/i_transient_resource_usage_provider.h>
@@ -101,6 +102,8 @@ struct IAttributeManager : public search::IAttributeManager
virtual void asyncForEachAttribute(std::shared_ptr<IConstAttributeFunctor> func) const = 0;
virtual void asyncForEachAttribute(std::shared_ptr<IAttributeFunctor> func, OnDone onDone) const = 0;
+ virtual ExclusiveAttributeReadAccessor::UP getExclusiveReadAccessor(const vespalib::string &name) const = 0;
+
virtual void setImportedAttributes(std::unique_ptr<ImportedAttributesRepo> attributes) = 0;
virtual const ImportedAttributesRepo *getImportedAttributes() const = 0;
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 babecb6a77d..f85baa8c0ac 100644
--- a/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h
+++ b/searchcore/src/vespa/searchcore/proton/test/mock_attribute_manager.h
@@ -91,6 +91,9 @@ public:
void asyncForEachAttribute(std::shared_ptr<IConstAttributeFunctor>) const override { }
void asyncForEachAttribute(std::shared_ptr<IAttributeFunctor>, OnDone) const override { }
+ ExclusiveAttributeReadAccessor::UP getExclusiveReadAccessor(const vespalib::string &) const override {
+ return ExclusiveAttributeReadAccessor::UP();
+ }
void setImportedAttributes(std::unique_ptr<ImportedAttributesRepo> importedAttributes) override {
_importedAttributes = std::move(importedAttributes);
}