diff options
Diffstat (limited to 'searchlib/src')
34 files changed, 536 insertions, 192 deletions
diff --git a/searchlib/src/tests/attribute/attribute_test.cpp b/searchlib/src/tests/attribute/attribute_test.cpp index 7eb43faac18..d2d3ccaad23 100644 --- a/searchlib/src/tests/attribute/attribute_test.cpp +++ b/searchlib/src/tests/attribute/attribute_test.cpp @@ -912,8 +912,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-post-int32", cfg); ptr->updateStat(true); - EXPECT_EQ(339020u, ptr->getStatus().getAllocated()); - EXPECT_EQ(101852u, ptr->getStatus().getUsed()); + EXPECT_EQ(338972u, ptr->getStatus().getAllocated()); + EXPECT_EQ(101492u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<IntegerAttribute, AttributeVector::largeint_t, int32_t>(ptr, values); } @@ -934,8 +934,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-post-float", cfg); ptr->updateStat(true); - EXPECT_EQ(339020, ptr->getStatus().getAllocated()); - EXPECT_EQ(101852u, ptr->getStatus().getUsed()); + EXPECT_EQ(338972u, ptr->getStatus().getAllocated()); + EXPECT_EQ(101492u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<FloatingPointAttribute, double, float>(ptr, values); } @@ -947,8 +947,8 @@ AttributeTest::testSingle() { AttributePtr ptr = createAttribute("sv-string", Config(BasicType::STRING, CollectionType::SINGLE)); ptr->updateStat(true); - EXPECT_EQ(117256u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); - EXPECT_EQ(53240u + sizeof_large_string_entry, ptr->getStatus().getUsed()); + EXPECT_EQ(116528u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); + EXPECT_EQ(52760u + sizeof_large_string_entry, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<StringAttribute, string, string>(ptr, values); } @@ -957,8 +957,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-fs-string", cfg); ptr->updateStat(true); - EXPECT_EQ(345624u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); - EXPECT_EQ(105176u + sizeof_large_string_entry, ptr->getStatus().getUsed()); + EXPECT_EQ(344848u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); + EXPECT_EQ(104408u + sizeof_large_string_entry, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<StringAttribute, string, string>(ptr, values); } @@ -1089,8 +1089,8 @@ AttributeTest::testArray() { AttributePtr ptr = createAttribute("a-int32", Config(BasicType::INT32, CollectionType::ARRAY)); ptr->updateStat(true); - EXPECT_EQ(512056u, ptr->getStatus().getAllocated()); - EXPECT_EQ(504392u, ptr->getStatus().getUsed()); + EXPECT_EQ(487480u, ptr->getStatus().getAllocated()); + EXPECT_EQ(479720u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1099,8 +1099,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("flags", cfg); ptr->updateStat(true); - EXPECT_EQ(512056u, ptr->getStatus().getAllocated()); - EXPECT_EQ(504392u, ptr->getStatus().getUsed()); + EXPECT_EQ(487480u, ptr->getStatus().getAllocated()); + EXPECT_EQ(479720u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1109,8 +1109,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("a-fs-int32", cfg); ptr->updateStat(true); - EXPECT_EQ(868788u, ptr->getStatus().getAllocated()); - EXPECT_EQ(606264u, ptr->getStatus().getUsed()); + EXPECT_EQ(844116u, ptr->getStatus().getAllocated()); + EXPECT_EQ(581232u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1128,8 +1128,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("a-fs-float", cfg); ptr->updateStat(true); - EXPECT_EQ(868788u, ptr->getStatus().getAllocated()); - EXPECT_EQ(606264u, ptr->getStatus().getUsed()); + EXPECT_EQ(844116u, ptr->getStatus().getAllocated()); + EXPECT_EQ(581232u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<FloatingPointAttribute, double>(ptr, values); } @@ -1140,8 +1140,8 @@ AttributeTest::testArray() { AttributePtr ptr = createAttribute("a-string", Config(BasicType::STRING, CollectionType::ARRAY)); ptr->updateStat(true); - EXPECT_EQ(625088u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); - EXPECT_EQ(557632u + sizeof_large_string_entry, ptr->getStatus().getUsed()); + EXPECT_EQ(599784u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); + EXPECT_EQ(532480u + sizeof_large_string_entry, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<StringAttribute, string>(ptr, values); } @@ -1150,8 +1150,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("afs-string", cfg); ptr->updateStat(true); - EXPECT_EQ(875392u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); - EXPECT_EQ(609588u + sizeof_large_string_entry, ptr->getStatus().getUsed()); + EXPECT_EQ(849992u + sizeof_large_string_entry, ptr->getStatus().getAllocated()); + EXPECT_EQ(584148u + sizeof_large_string_entry, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<StringAttribute, string>(ptr, values); } @@ -2334,6 +2334,10 @@ AttributeTest::test_paged_attribute(const vespalib::string& name, const vespalib size_t rounded_size = vespalib::round_up_to_page_size(1); size_t lid_mapping_size = 1200; size_t sv_maxlid = 1200; + if (rounded_size == 16_Ki) { + lid_mapping_size = 4200; + sv_maxlid = 1300; + } if (rounded_size == 64_Ki) { lid_mapping_size = 17000; sv_maxlid = 1500; diff --git a/searchlib/src/tests/attribute/extendattributes/extendattribute.cpp b/searchlib/src/tests/attribute/extendattributes/extendattribute.cpp index 8f056323733..3f775e99891 100644 --- a/searchlib/src/tests/attribute/extendattributes/extendattribute.cpp +++ b/searchlib/src/tests/attribute/extendattributes/extendattribute.cpp @@ -1,9 +1,25 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/gtest/gtest.h> +#include <vespa/eval/eval/fast_value.h> +#include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/value_codec.h> +#include <vespa/searchcommon/attribute/config.h> #include <vespa/searchlib/attribute/extendableattributes.h> #include <vespa/searchlib/attribute/single_raw_ext_attribute.h> +#include <vespa/searchlib/tensor/tensor_ext_attribute.h> +#include <vespa/searchlib/tensor/vector_bundle.h> +#include <vespa/vespalib/stllike/asciistream.h> +using search::attribute::Config; +using search::attribute::BasicType; +using search::attribute::CollectionType; using search::attribute::SingleRawExtAttribute; +using search::tensor::TensorExtAttribute; +using vespalib::eval::FastValueBuilderFactory; +using vespalib::eval::TensorSpec; +using vespalib::eval::Value; +using vespalib::eval::ValueType; namespace search { @@ -15,8 +31,46 @@ std::vector<char> as_vector(vespalib::ConstArrayRef<char> value) { return {value.data(), value.data() + value.size()}; } +std::vector<double> as_vector(vespalib::ConstArrayRef<double> value) { + return {value.data(), value.data() + value.size()}; +} + +vespalib::string vec_2d_spec("tensor(x[2])"); +vespalib::string vec_mixed_2d_spec("tensor(a{},x[2])"); + +TensorSpec +vec_2d(double x0, double x1) +{ + return TensorSpec(vec_2d_spec).add({{"x", 0}}, x0).add({{"x", 1}}, x1); +} + +TensorSpec +vec_mixed_2d(std::vector<std::vector<double>> val) +{ + TensorSpec spec(vec_mixed_2d_spec); + for (uint32_t a = 0; a < val.size(); ++a) { + vespalib::asciistream a_stream; + a_stream << a; + vespalib::string a_as_string = a_stream.str(); + for (uint32_t x = 0; x < val[a].size(); ++x) { + spec.add({{"a", a_as_string.c_str()},{"x", x}}, val[a][x]); + } + } + return spec; +} + +void add_doc(AttributeVector& attr, uint32_t exp_docid) +{ + uint32_t docid(0); + EXPECT_EQ(exp_docid, attr.getNumDocs()); + attr.addDoc(docid); + EXPECT_EQ(exp_docid, docid); + EXPECT_EQ(exp_docid + 1, attr.getNumDocs()); +} + class ExtendAttributeTest : public ::testing::Test { + std::vector<std::unique_ptr<Value>> _tensors; protected: ExtendAttributeTest() = default; ~ExtendAttributeTest() override = default; @@ -27,16 +81,22 @@ protected: template <typename Attribute> void testExtendString(Attribute & attr); void testExtendRaw(AttributeVector& attr); + void testExtendTensor(AttributeVector& attr); + const Value& create_tensor(const TensorSpec &spec); }; +const Value& +ExtendAttributeTest::create_tensor(const TensorSpec &spec) +{ + auto value = value_from_spec(spec, FastValueBuilderFactory::get()); + _tensors.emplace_back(std::move(value)); + return *_tensors.back(); +} + template <typename Attribute> void ExtendAttributeTest::testExtendInteger(Attribute & attr) { - uint32_t docId(0); - EXPECT_EQ(attr.getNumDocs(), 0u); - attr.addDoc(docId); - EXPECT_EQ(docId, 0u); - EXPECT_EQ(attr.getNumDocs(), 1u); + add_doc(attr, 0); attr.add(1, 10); EXPECT_EQ(attr.getInt(0), 1); attr.add(2, 20); @@ -51,9 +111,7 @@ void ExtendAttributeTest::testExtendInteger(Attribute & attr) EXPECT_EQ(v[1].getWeight(), 20); } } - attr.addDoc(docId); - EXPECT_EQ(docId, 1u); - EXPECT_EQ(attr.getNumDocs(), 2u); + add_doc(attr, 1); attr.add(3, 30); EXPECT_EQ(attr.getInt(1), 3); if (attr.hasMultiValue()) { @@ -69,11 +127,7 @@ void ExtendAttributeTest::testExtendInteger(Attribute & attr) template <typename Attribute> void ExtendAttributeTest::testExtendFloat(Attribute & attr) { - uint32_t docId(0); - EXPECT_EQ(attr.getNumDocs(), 0u); - attr.addDoc(docId); - EXPECT_EQ(docId, 0u); - EXPECT_EQ(attr.getNumDocs(), 1u); + add_doc(attr, 0); attr.add(1.7, 10); EXPECT_EQ(attr.getInt(0), 1); EXPECT_EQ(attr.getFloat(0), 1.7); @@ -89,9 +143,7 @@ void ExtendAttributeTest::testExtendFloat(Attribute & attr) EXPECT_EQ(v[1].getWeight(), 20); } } - attr.addDoc(docId); - EXPECT_EQ(docId, 1u); - EXPECT_EQ(attr.getNumDocs(), 2u); + add_doc(attr, 1); attr.add(3.6, 30); EXPECT_EQ(attr.getFloat(1), 3.6); if (attr.hasMultiValue()) { @@ -107,11 +159,7 @@ void ExtendAttributeTest::testExtendFloat(Attribute & attr) template <typename Attribute> void ExtendAttributeTest::testExtendString(Attribute & attr) { - uint32_t docId(0); - EXPECT_EQ(attr.getNumDocs(), 0u); - attr.addDoc(docId); - EXPECT_EQ(docId, 0u); - EXPECT_EQ(attr.getNumDocs(), 1u); + add_doc(attr, 0); attr.add("1.7", 10); auto buf = attr.get_raw(0); EXPECT_EQ(std::string(buf.data(), buf.size()), "1.7"); @@ -128,9 +176,7 @@ void ExtendAttributeTest::testExtendString(Attribute & attr) EXPECT_EQ(v[1].getWeight(), 20); } } - attr.addDoc(docId); - EXPECT_EQ(docId, 1u); - EXPECT_EQ(attr.getNumDocs(), 2u); + add_doc(attr, 1); attr.add("3.6", 30); buf = attr.get_raw(1); EXPECT_EQ(std::string(buf.data(), buf.size()), "3.6"); @@ -150,41 +196,77 @@ void ExtendAttributeTest::testExtendRaw(AttributeVector& attr) std::vector<char> zeros{10, 0, 0, 11}; auto* ext_attr = attr.getExtendInterface(); EXPECT_NE(nullptr, ext_attr); - uint32_t docId(0); - EXPECT_EQ(0u, attr.getNumDocs()); - attr.addDoc(docId); - EXPECT_EQ(0u, docId); - EXPECT_EQ(1u, attr.getNumDocs()); + add_doc(attr, 0); ext_attr->add(as_vector("1.7")); auto buf = attr.get_raw(0); EXPECT_EQ(as_vector("1.7"), as_vector(buf)); ext_attr->add(vespalib::ConstArrayRef<char>(as_vector("2.3"))); buf = attr.get_raw(0); EXPECT_EQ(as_vector("2.3"), as_vector(buf)); - attr.addDoc(docId); - EXPECT_EQ(1u, docId); - EXPECT_EQ(attr.getNumDocs(), 2u); + add_doc(attr, 1); ext_attr->add(as_vector("3.6")); buf = attr.get_raw(1); EXPECT_EQ(as_vector("3.6"), as_vector(buf)); buf = attr.get_raw(0); EXPECT_EQ(as_vector("2.3"), as_vector(buf)); - attr.addDoc(docId); - EXPECT_EQ(2u, docId); + add_doc(attr, 2); ext_attr->add(zeros); buf = attr.get_raw(2); EXPECT_EQ(zeros, as_vector(buf)); - attr.addDoc(docId); - EXPECT_EQ(3u, docId); + add_doc(attr, 3); buf = attr.get_raw(3); EXPECT_EQ(empty, as_vector(buf)); - attr.addDoc(docId); - EXPECT_EQ(4u, docId); + add_doc(attr, 4); ext_attr->add(empty); buf = attr.get_raw(4); EXPECT_EQ(empty, as_vector(buf)); } +void ExtendAttributeTest::testExtendTensor(AttributeVector& attr) +{ + std::vector<double> empty_cells{0.0, 0.0}; + std::vector<double> spec0_dense_cells{1.0, 2.0}; + std::vector<double> spec0_mixed_cells0{3.0, 4.0}; + std::vector<double> spec0_mixed_cells1{5.0, 6.0}; + bool dense = attr.getConfig().tensorType().is_dense(); + auto* ext_attr = attr.getExtendInterface(); + EXPECT_NE(nullptr, ext_attr); + auto* tensor_attr = attr.asTensorAttribute(); + EXPECT_NE(nullptr, tensor_attr); + add_doc(attr, 0); + TensorSpec spec0 = dense ? vec_2d(1.0, 2.0) : vec_mixed_2d({{3.0, 4.0}, {5.0, 6.0}}); + EXPECT_TRUE(ext_attr->add(create_tensor(spec0))); + auto tensor = tensor_attr->getTensor(0); + EXPECT_NE(nullptr, tensor.get()); + EXPECT_EQ(spec0, TensorSpec::from_value(*tensor)); + EXPECT_EQ(dense, tensor_attr->supports_extract_cells_ref()); + if (dense) { + EXPECT_EQ(spec0_dense_cells, as_vector(tensor_attr->extract_cells_ref(0).typify<double>())); + } + EXPECT_TRUE(tensor_attr->supports_get_tensor_ref()); + EXPECT_EQ(spec0, TensorSpec::from_value(tensor_attr->get_tensor_ref(0))); + EXPECT_FALSE(tensor_attr->supports_get_serialized_tensor_ref()); + auto vectors = tensor_attr->get_vectors(0); + if (dense) { + EXPECT_EQ(1, vectors.subspaces()); + EXPECT_EQ(spec0_dense_cells, as_vector(vectors.cells(0).typify<double>())); + EXPECT_EQ(spec0_dense_cells, as_vector(tensor_attr->get_vector(0, 0).typify<double>())); + EXPECT_EQ(empty_cells, as_vector(tensor_attr->get_vector(0, 1).typify<double>())); + } else { + EXPECT_EQ(2, vectors.subspaces()); + EXPECT_EQ(spec0_mixed_cells0, as_vector(vectors.cells(0).typify<double>())); + EXPECT_EQ(spec0_mixed_cells1, as_vector(vectors.cells(1).typify<double>())); + EXPECT_EQ(spec0_mixed_cells0, as_vector(tensor_attr->get_vector(0, 0).typify<double>())); + EXPECT_EQ(spec0_mixed_cells1, as_vector(tensor_attr->get_vector(0, 1).typify<double>())); + EXPECT_EQ(empty_cells, as_vector(tensor_attr->get_vector(0, 2).typify<double>())); + } + add_doc(attr, 1); + vectors = tensor_attr->get_vectors(1); + EXPECT_EQ(0, vectors.subspaces()); + EXPECT_EQ(empty_cells, as_vector(tensor_attr->get_vector(1, 0).typify<double>())); + EXPECT_EQ(nullptr, tensor_attr->getTensor(1).get()); +} + TEST_F(ExtendAttributeTest, single_integer_ext_attribute) { SingleIntegerExtAttribute siattr("si1"); @@ -255,6 +337,24 @@ TEST_F(ExtendAttributeTest, single_raw_ext_attribute) testExtendRaw(srattr); } +TEST_F(ExtendAttributeTest, tensor_ext_attribute_dense) +{ + Config cfg(BasicType::TENSOR, CollectionType::SINGLE); + cfg.setTensorType(ValueType::from_spec(vec_2d_spec)); + TensorExtAttribute tattr("td1", cfg); + EXPECT_TRUE(! tattr.hasMultiValue()); + testExtendTensor(tattr); +} + +TEST_F(ExtendAttributeTest, tensor_ext_attribute_mixed) +{ + Config cfg(BasicType::TENSOR, CollectionType::SINGLE); + cfg.setTensorType(ValueType::from_spec(vec_mixed_2d_spec)); + TensorExtAttribute tattr("tm1", cfg); + EXPECT_TRUE(! tattr.hasMultiValue()); + testExtendTensor(tattr); +} + } GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp index df2a5ea2ac9..17e852c8b92 100644 --- a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp +++ b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp @@ -22,11 +22,11 @@ using vespalib::datastore::CompactionStrategy; using vespalib::alloc::test::MemoryAllocatorObserver; using AllocStats = MemoryAllocatorObserver::Stats; -template <typename EntryT> +template <typename ElemT> void -assertArray(const std::vector<EntryT> &exp, vespalib::ConstArrayRef<EntryT> values) +assertArray(const std::vector<ElemT> &exp, vespalib::ConstArrayRef<ElemT> values) { - EXPECT_EQ(exp, std::vector<EntryT>(values.cbegin(), values.cend())); + EXPECT_EQ(exp, std::vector<ElemT>(values.cbegin(), values.cend())); } template <class MvMapping> @@ -69,10 +69,10 @@ public: constexpr float ALLOC_GROW_FACTOR = 0.2; -template <typename EntryT> +template <typename ElemT> class MappingTestBase : public ::testing::Test { protected: - using MvMapping = search::attribute::MultiValueMapping<EntryT>; + using MvMapping = search::attribute::MultiValueMapping<ElemT>; using AttributeType = MyAttribute<MvMapping>; AllocStats _stats; std::unique_ptr<MvMapping> _mvMapping; @@ -82,8 +82,8 @@ protected: using generation_t = vespalib::GenerationHandler::generation_t; public: - using ArrayRef = vespalib::ArrayRef<EntryT>; - using ConstArrayRef = vespalib::ConstArrayRef<EntryT>; + using ArrayRef = vespalib::ArrayRef<ElemT>; + using ConstArrayRef = vespalib::ConstArrayRef<ElemT>; MappingTestBase() : _stats(), _mvMapping(), @@ -99,9 +99,9 @@ public: _attr = std::make_unique<AttributeType>(*_mvMapping); _maxSmallArraySize = maxSmallArraySize; } - void setup(uint32_t maxSmallArraySize, size_t minArrays, size_t maxArrays, size_t numArraysForNewBuffer, bool enable_free_lists = true) { + void setup(uint32_t maxSmallArraySize, size_t min_entries, size_t max_entries, size_t num_entries_for_new_buffer, bool enable_free_lists = true) { ArrayStoreConfig config(maxSmallArraySize, - ArrayStoreConfig::AllocSpec(minArrays, maxArrays, numArraysForNewBuffer, ALLOC_GROW_FACTOR)); + ArrayStoreConfig::AllocSpec(min_entries, max_entries, num_entries_for_new_buffer, ALLOC_GROW_FACTOR)); config.enable_free_lists(enable_free_lists); _mvMapping = std::make_unique<MvMapping>(config, vespalib::GrowStrategy(), std::make_unique<MemoryAllocatorObserver>(_stats)); _attr = std::make_unique<AttributeType>(*_mvMapping); @@ -109,12 +109,12 @@ public: } ~MappingTestBase() { } - void set(uint32_t docId, const std::vector<EntryT> &values) { _mvMapping->set(docId, values); } + void set(uint32_t docId, const std::vector<ElemT> &values) { _mvMapping->set(docId, values); } ConstArrayRef get(uint32_t docId) { return _mvMapping->get(docId); } ArrayRef get_writable(uint32_t docId) { return _mvMapping->get_writable(docId); } - void assertGet(uint32_t docId, const std::vector<EntryT> &exp) { + void assertGet(uint32_t docId, const std::vector<ElemT> &exp) { ConstArrayRef act = get(docId); - EXPECT_EQ(exp, std::vector<EntryT>(act.cbegin(), act.cend())); + EXPECT_EQ(exp, std::vector<ElemT>(act.cbegin(), act.cend())); } void assign_generation(generation_t current_gen) { _mvMapping->assign_generation(current_gen); } void reclaim_memory(generation_t oldest_used_gen) { _mvMapping->reclaim_memory(oldest_used_gen); } diff --git a/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp b/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp index b57a2f42ea7..69478c09a25 100644 --- a/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp +++ b/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp @@ -1032,14 +1032,14 @@ TEST_F(BasicInverterTest, require_that_inversion_is_working) auto beforeStats = getFeatureStoreMemStats(_fic); LOG(info, - "Before feature compaction: allocElems=%zu, usedElems=%zu" - ", deadElems=%zu, holdElems=%zu" + "Before feature compaction: alloc_entries=%zu, used_entries=%zu" + ", dead_entries=%zu, hold_entries=%zu" ", freeBuffers=%u, activeBuffers=%u" ", holdBuffers=%u", - beforeStats._allocElems, - beforeStats._usedElems, - beforeStats._deadElems, - beforeStats._holdElems, + beforeStats._alloc_entries, + beforeStats._used_entries, + beforeStats._dead_entries, + beforeStats._hold_entries, beforeStats._freeBuffers, beforeStats._activeBuffers, beforeStats._holdBuffers); @@ -1052,14 +1052,14 @@ TEST_F(BasicInverterTest, require_that_inversion_is_working) myCommit(_fic, *_pushThreads); auto duringStats = getFeatureStoreMemStats(_fic); LOG(info, - "During feature compaction: allocElems=%zu, usedElems=%zu" - ", deadElems=%zu, holdElems=%zu" + "During feature compaction: alloc_entries=%zu, used_entries=%zu" + ", dead_entries=%zu, hold_entries=%zu" ", freeBuffers=%u, activeBuffers=%u" ", holdBuffers=%u", - duringStats._allocElems, - duringStats._usedElems, - duringStats._deadElems, - duringStats._holdElems, + duringStats._alloc_entries, + duringStats._used_entries, + duringStats._dead_entries, + duringStats._hold_entries, duringStats._freeBuffers, duringStats._activeBuffers, duringStats._holdBuffers); @@ -1067,14 +1067,14 @@ TEST_F(BasicInverterTest, require_that_inversion_is_working) myCommit(_fic, *_pushThreads); auto afterStats = getFeatureStoreMemStats(_fic); LOG(info, - "After feature compaction: allocElems=%zu, usedElems=%zu" - ", deadElems=%zu, holdElems=%zu" + "After feature compaction: alloc_entries=%zu, used_entries=%zu" + ", dead_entries=%zu, hold_entries=%zu" ", freeBuffers=%u, activeBuffers=%u" ", holdBuffers=%u", - afterStats._allocElems, - afterStats._usedElems, - afterStats._deadElems, - afterStats._holdElems, + afterStats._alloc_entries, + afterStats._used_entries, + afterStats._dead_entries, + afterStats._hold_entries, afterStats._freeBuffers, afterStats._activeBuffers, afterStats._holdBuffers); diff --git a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp index 8073fb8d232..e3b9cf9702d 100644 --- a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp +++ b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp @@ -462,8 +462,8 @@ TEST(MemoryIndexTest, require_that_num_docs_and_doc_id_limit_is_returned) TEST(MemoryIndexTest, require_that_we_understand_the_memory_footprint) { - constexpr size_t BASE_ALLOCATED = 361032u; - constexpr size_t BASE_USED = 151188u; + constexpr size_t BASE_ALLOCATED = 360936u; + constexpr size_t BASE_USED = 150804u; { MySetup setup; Index index(setup); diff --git a/searchlib/src/tests/predicate/document_features_store_test.cpp b/searchlib/src/tests/predicate/document_features_store_test.cpp index 4ac4bdc32f0..d30df9dba6e 100644 --- a/searchlib/src/tests/predicate/document_features_store_test.cpp +++ b/searchlib/src/tests/predicate/document_features_store_test.cpp @@ -165,17 +165,17 @@ TEST("require that both features and ranges are removed by 'remove'") { TEST("require that both features and ranges counts towards memory usage") { DocumentFeaturesStore features_store(10); - EXPECT_EQUAL(50136u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50064u, features_store.getMemoryUsage().usedBytes()); PredicateTreeAnnotations annotations; annotations.features.push_back(PredicateHash::hash64("foo=100-199")); features_store.insert(annotations, doc_id); - EXPECT_EQUAL(50144u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50072u, features_store.getMemoryUsage().usedBytes()); annotations.features.clear(); annotations.range_features.push_back({"foo", 100, 199}); features_store.insert(annotations, doc_id + 1); - EXPECT_EQUAL(50240u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50168u, features_store.getMemoryUsage().usedBytes()); } TEST("require that DocumentFeaturesStore can be serialized") { @@ -205,17 +205,17 @@ TEST("require that serialization cleans up wordstore") { PredicateTreeAnnotations annotations; annotations.range_features.push_back({"foo", 100, 199}); features_store.insert(annotations, doc_id); - EXPECT_EQUAL(50232u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50160u, features_store.getMemoryUsage().usedBytes()); annotations.range_features.push_back({"bar", 100, 199}); features_store.insert(annotations, doc_id + 1); - EXPECT_EQUAL(50620u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50548u, features_store.getMemoryUsage().usedBytes()); features_store.remove(doc_id + 1); - EXPECT_EQUAL(50572u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50500u, features_store.getMemoryUsage().usedBytes()); vespalib::DataBuffer buffer; features_store.serialize(buffer); DocumentFeaturesStore features_store2(buffer); - EXPECT_EQUAL(50232u, features_store2.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50160u, features_store2.getMemoryUsage().usedBytes()); } diff --git a/searchlib/src/vespa/searchlib/attribute/attributevector.h b/searchlib/src/vespa/searchlib/attribute/attributevector.h index 3d14622ca02..e40785911ea 100644 --- a/searchlib/src/vespa/searchlib/attribute/attributevector.h +++ b/searchlib/src/vespa/searchlib/attribute/attributevector.h @@ -38,6 +38,8 @@ namespace vespalib::alloc { class Alloc; } +namespace vespalib::eval { struct Value; } + namespace search { template <typename T> class ComponentGuard; @@ -86,6 +88,7 @@ public: virtual bool add(double, int32_t = 1) { return false; } virtual bool add(const char *, int32_t = 1) { return false; } virtual bool add(vespalib::ConstArrayRef<char>, int32_t = 1) { return false; } + virtual bool add(const vespalib::eval::Value&, int32_t = 1) { return false; } virtual ~IExtendAttribute() = default; }; diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h index bd624e9f388..4fce64aa762 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h +++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h @@ -12,18 +12,18 @@ namespace search::attribute { /** * Class for mapping from document id to an array of values. */ -template <typename EntryT, typename RefT = vespalib::datastore::EntryRefT<19> > +template <typename ElemT, typename RefT = vespalib::datastore::EntryRefT<19> > class MultiValueMapping : public MultiValueMappingBase { public: - using MultiValueType = EntryT; + using MultiValueType = ElemT; using RefType = RefT; - using ReadView = MultiValueMappingReadView<EntryT, RefT>; + using ReadView = MultiValueMappingReadView<ElemT, RefT>; private: - using ArrayRef = vespalib::ArrayRef<EntryT>; - using ArrayStore = vespalib::datastore::ArrayStore<EntryT, RefT>; + using ArrayRef = vespalib::ArrayRef<ElemT>; + using ArrayStore = vespalib::datastore::ArrayStore<ElemT, RefT>; using generation_t = vespalib::GenerationHandler::generation_t; - using ConstArrayRef = vespalib::ConstArrayRef<EntryT>; + using ConstArrayRef = vespalib::ConstArrayRef<ElemT>; ArrayStore _store; public: @@ -73,7 +73,7 @@ public: static vespalib::datastore::ArrayStoreConfig optimizedConfigForHugePage(size_t maxSmallArraySize, size_t hugePageSize, size_t smallPageSize, - size_t minNumArraysForNewBuffer, + size_t min_num_entries_for_new_buffer, float allocGrowFactor, bool enable_free_lists); }; diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp index b486fa60265..ab68bea58cc 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp +++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp @@ -7,8 +7,8 @@ namespace search::attribute { -template <typename EntryT, typename RefT> -MultiValueMapping<EntryT,RefT>::MultiValueMapping(const vespalib::datastore::ArrayStoreConfig &storeCfg, +template <typename ElemT, typename RefT> +MultiValueMapping<ElemT,RefT>::MultiValueMapping(const vespalib::datastore::ArrayStoreConfig &storeCfg, const vespalib::GrowStrategy &gs, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator) : MultiValueMappingBase(gs, ArrayStore::getGenerationHolderLocation(_store), memory_allocator), @@ -16,12 +16,12 @@ MultiValueMapping<EntryT,RefT>::MultiValueMapping(const vespalib::datastore::Arr { } -template <typename EntryT, typename RefT> -MultiValueMapping<EntryT,RefT>::~MultiValueMapping() = default; +template <typename ElemT, typename RefT> +MultiValueMapping<ElemT,RefT>::~MultiValueMapping() = default; -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> void -MultiValueMapping<EntryT,RefT>::set(uint32_t docId, ConstArrayRef values) +MultiValueMapping<ElemT,RefT>::set(uint32_t docId, ConstArrayRef values) { _indices.ensure_size(docId + 1); EntryRef oldRef(_indices[docId].load_relaxed()); @@ -31,18 +31,18 @@ MultiValueMapping<EntryT,RefT>::set(uint32_t docId, ConstArrayRef values) _store.remove(oldRef); } -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> vespalib::MemoryUsage -MultiValueMapping<EntryT,RefT>::update_stat(const CompactionStrategy& compaction_strategy) +MultiValueMapping<ElemT,RefT>::update_stat(const CompactionStrategy& compaction_strategy) { auto retval = _store.update_stat(compaction_strategy); retval.merge(_indices.getMemoryUsage()); return retval; } -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> void -MultiValueMapping<EntryT,RefT>::compact_worst(const CompactionStrategy& compaction_strategy) +MultiValueMapping<ElemT,RefT>::compact_worst(const CompactionStrategy& compaction_strategy) { vespalib::datastore::ICompactionContext::UP compactionContext(_store.compact_worst(compaction_strategy)); if (compactionContext) { @@ -50,29 +50,29 @@ MultiValueMapping<EntryT,RefT>::compact_worst(const CompactionStrategy& compacti } } -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> vespalib::MemoryUsage -MultiValueMapping<EntryT,RefT>::getArrayStoreMemoryUsage() const +MultiValueMapping<ElemT,RefT>::getArrayStoreMemoryUsage() const { return _store.getMemoryUsage(); } -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> vespalib::AddressSpace -MultiValueMapping<EntryT, RefT>::getAddressSpaceUsage() const { +MultiValueMapping<ElemT, RefT>::getAddressSpaceUsage() const { return _store.addressSpaceUsage(); } -template <typename EntryT, typename RefT> +template <typename ElemT, typename RefT> vespalib::datastore::ArrayStoreConfig -MultiValueMapping<EntryT, RefT>::optimizedConfigForHugePage(size_t maxSmallArraySize, +MultiValueMapping<ElemT, RefT>::optimizedConfigForHugePage(size_t maxSmallArraySize, size_t hugePageSize, size_t smallPageSize, - size_t minNumArraysForNewBuffer, + size_t min_num_entries_for_new_buffer, float allocGrowFactor, bool enable_free_lists) { - auto result = ArrayStore::optimizedConfigForHugePage(maxSmallArraySize, hugePageSize, smallPageSize, minNumArraysForNewBuffer, allocGrowFactor); + auto result = ArrayStore::optimizedConfigForHugePage(maxSmallArraySize, hugePageSize, smallPageSize, min_num_entries_for_new_buffer, allocGrowFactor); result.enable_free_lists(enable_free_lists); return result; } diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_read_view.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_read_view.h index 116e069e8b4..41138ff0890 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_read_view.h +++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_read_view.h @@ -11,12 +11,12 @@ namespace search::attribute { /** * Class for mapping from document id to an array of values as reader. */ -template <typename EntryT, typename RefT = vespalib::datastore::EntryRefT<19> > +template <typename ElemT, typename RefT = vespalib::datastore::EntryRefT<19> > class MultiValueMappingReadView { using AtomicEntryRef = vespalib::datastore::AtomicEntryRef; using Indices = vespalib::ConstArrayRef<AtomicEntryRef>; - using ArrayStore = vespalib::datastore::ArrayStore<EntryT, RefT>; + using ArrayStore = vespalib::datastore::ArrayStore<ElemT, RefT>; Indices _indices; const ArrayStore* _store; @@ -31,7 +31,7 @@ public: _store(store) { } - vespalib::ConstArrayRef<EntryT> get(uint32_t doc_id) const { return _store->get(_indices[doc_id].load_acquire()); } + vespalib::ConstArrayRef<ElemT> get(uint32_t doc_id) const { return _store->get(_indices[doc_id].load_acquire()); } bool valid() const noexcept { return _store != nullptr; } }; diff --git a/searchlib/src/vespa/searchlib/attribute/multinumericpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multinumericpostattribute.hpp index ea449300aef..1009fa2fb5f 100644 --- a/searchlib/src/vespa/searchlib/attribute/multinumericpostattribute.hpp +++ b/searchlib/src/vespa/searchlib/attribute/multinumericpostattribute.hpp @@ -51,7 +51,7 @@ template <typename B, typename M> MultiValueNumericPostingAttribute<B, M>::~MultiValueNumericPostingAttribute() { this->disableFreeLists(); - this->disableElemHoldList(); + this->disable_entry_hold_list(); clearAllPostings(); } diff --git a/searchlib/src/vespa/searchlib/attribute/multistringpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multistringpostattribute.hpp index cd46bbb5a8a..19840b5a474 100644 --- a/searchlib/src/vespa/searchlib/attribute/multistringpostattribute.hpp +++ b/searchlib/src/vespa/searchlib/attribute/multistringpostattribute.hpp @@ -27,7 +27,7 @@ template <typename B, typename T> MultiValueStringPostingAttributeT<B, T>::~MultiValueStringPostingAttributeT() { this->disableFreeLists(); - this->disableElemHoldList(); + this->disable_entry_hold_list(); clearAllPostings(); } diff --git a/searchlib/src/vespa/searchlib/attribute/postinglistattribute.h b/searchlib/src/vespa/searchlib/attribute/postinglistattribute.h index 29440b6ce43..ecf7a46f21e 100644 --- a/searchlib/src/vespa/searchlib/attribute/postinglistattribute.h +++ b/searchlib/src/vespa/searchlib/attribute/postinglistattribute.h @@ -58,7 +58,7 @@ protected: void updatePostings(PostingMap &changePost, const vespalib::datastore::EntryComparator &cmp); void clearAllPostings(); void disableFreeLists() { _postingList.disableFreeLists(); } - void disableElemHoldList() { _postingList.disableElemHoldList(); } + void disable_entry_hold_list() { _postingList.disable_entry_hold_list(); } void handle_load_posting_lists_and_update_enum_store(enumstore::EnumeratedPostingsLoader& loader); bool forwardedOnAddDoc(DocId doc, size_t wantSize, size_t wantCapacity); diff --git a/searchlib/src/vespa/searchlib/attribute/postingstore.cpp b/searchlib/src/vespa/searchlib/attribute/postingstore.cpp index 94720212faf..2703201b292 100644 --- a/searchlib/src/vespa/searchlib/attribute/postingstore.cpp +++ b/searchlib/src/vespa/searchlib/attribute/postingstore.cpp @@ -231,7 +231,7 @@ PostingStore<DataT>::dropBitVector(EntryRef &ref) (void) tree; (void) docFreq; _bvs.erase(ref.ref()); - _store.holdElem(iRef, 1); + _store.hold_entry(iRef); _status.decBitVectors(); _bvExtraBytes -= bv->writer().extraByteSize(); ref = ref2; @@ -267,7 +267,7 @@ PostingStore<DataT>::makeBitVector(EntryRef &ref) if (_enableOnlyBitVector) { BTreeType *tree = getWTreeEntry(iRef); tree->clear(_allocator); - _store.holdElem(ref, 1); + _store.hold_entry(ref); } else { bve->_tree = ref; } @@ -590,19 +590,19 @@ PostingStore<DataT>::clear(const EntryRef ref) assert(isBTree(iRef2)); BTreeType *tree = getWTreeEntry(iRef2); tree->clear(_allocator); - _store.holdElem(iRef2, 1); + _store.hold_entry(iRef2); } _bvs.erase(ref.ref()); _status.decBitVectors(); _bvExtraBytes -= bve->_bv->writer().extraByteSize(); - _store.holdElem(ref, 1); + _store.hold_entry(ref); } else { BTreeType *tree = getWTreeEntry(iRef); tree->clear(_allocator); - _store.holdElem(ref, 1); + _store.hold_entry(ref); } } else { - _store.holdElem(ref, clusterSize); + _store.hold_entry(ref); } } diff --git a/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp index 1775774171d..de4a7157dae 100644 --- a/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp +++ b/searchlib/src/vespa/searchlib/attribute/singlenumericpostattribute.hpp @@ -13,7 +13,7 @@ template <typename B> SingleValueNumericPostingAttribute<B>::~SingleValueNumericPostingAttribute() { this->disableFreeLists(); - this->disableElemHoldList(); + this->disable_entry_hold_list(); clearAllPostings(); } diff --git a/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp b/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp index eef72984e79..1ec9b54a73b 100644 --- a/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp +++ b/searchlib/src/vespa/searchlib/attribute/singlestringpostattribute.hpp @@ -27,7 +27,7 @@ template <typename B> SingleValueStringPostingAttributeT<B>::~SingleValueStringPostingAttributeT() { this->disableFreeLists(); - this->disableElemHoldList(); + this->disable_entry_hold_list(); clearAllPostings(); } diff --git a/searchlib/src/vespa/searchlib/memoryindex/feature_store.cpp b/searchlib/src/vespa/searchlib/memoryindex/feature_store.cpp index 72f4a7ae579..4bc7f5b1144 100644 --- a/searchlib/src/vespa/searchlib/memoryindex/feature_store.cpp +++ b/searchlib/src/vespa/searchlib/memoryindex/feature_store.cpp @@ -36,7 +36,7 @@ EntryRef FeatureStore::addFeatures(const uint8_t *src, uint64_t byteLen) { uint32_t pad = Aligner::pad(byteLen); - auto result = _store.rawAllocator<uint8_t>(_typeId).alloc(byteLen + pad, DECODE_SAFETY); + auto result = _store.rawAllocator<uint8_t>(_typeId).alloc((byteLen + pad) / buffer_array_size, DECODE_SAFETY_ENTRIES); uint8_t *dst = result.data; memcpy(dst, src, byteLen); dst += byteLen; @@ -113,7 +113,7 @@ FeatureStore::add_features_guard_bytes() { uint32_t len = DECODE_SAFETY; uint32_t pad = Aligner::pad(len); - auto result = _store.rawAllocator<uint8_t>(_typeId).alloc(len + pad); + auto result = _store.rawAllocator<uint8_t>(_typeId).alloc((len + pad) / buffer_array_size); memset(result.data, 0, len + pad); } diff --git a/searchlib/src/vespa/searchlib/memoryindex/feature_store.h b/searchlib/src/vespa/searchlib/memoryindex/feature_store.h index 53588fa2894..1e48189987e 100644 --- a/searchlib/src/vespa/searchlib/memoryindex/feature_store.h +++ b/searchlib/src/vespa/searchlib/memoryindex/feature_store.h @@ -29,6 +29,7 @@ private: using PosOccFieldsParams = bitcompression::PosOccFieldsParams; static constexpr uint32_t DECODE_SAFETY = 16; + static constexpr uint32_t DECODE_SAFETY_ENTRIES = 16 / buffer_array_size; DataStoreType _store; @@ -117,7 +118,7 @@ public: * overrun beyond the compressed data either goes into other features * already written or into the guard area. * - * If buffer type is changed to have a nonzero numArraysForNewBuffer then + * If buffer type is changed to have a nonzero num_entries_for_new_buffer then * extra logic to add guard bytes is needed when switching primary buffer * to avoid issues if the buffer is resumed as primary buffer later on. */ diff --git a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp index 4be3031303e..8dd76a90b14 100644 --- a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp +++ b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp @@ -55,9 +55,9 @@ template <bool interleaved_features> FieldIndex<interleaved_features>::~FieldIndex() { _postingListStore.disableFreeLists(); - _postingListStore.disableElemHoldList(); + _postingListStore.disable_entry_hold_list(); _dict.disableFreeLists(); - _dict.disableElemHoldList(); + _dict.disable_entry_hold_list(); // XXX: Kludge for (DictionaryTree::Iterator it = _dict.begin(); it.valid(); ++it) { diff --git a/searchlib/src/vespa/searchlib/memoryindex/word_store.cpp b/searchlib/src/vespa/searchlib/memoryindex/word_store.cpp index 3e4c38ceb0e..e330dc83055 100644 --- a/searchlib/src/vespa/searchlib/memoryindex/word_store.cpp +++ b/searchlib/src/vespa/searchlib/memoryindex/word_store.cpp @@ -27,7 +27,7 @@ WordStore::addWord(const vespalib::stringref word) { size_t wordSize = word.size() + 1; size_t bufferSize = wordSize + Aligner::pad(wordSize); - auto result = _store.rawAllocator<char>(_typeId).alloc(bufferSize); + auto result = _store.rawAllocator<char>(_typeId).alloc(bufferSize / buffer_array_size); char *be = result.data; for (size_t i = 0; i < word.size(); ++i) { *be++ = word[i]; diff --git a/searchlib/src/vespa/searchlib/predicate/document_features_store.cpp b/searchlib/src/vespa/searchlib/predicate/document_features_store.cpp index 604a467a6e6..a6a82ec09f8 100644 --- a/searchlib/src/vespa/searchlib/predicate/document_features_store.cpp +++ b/searchlib/src/vespa/searchlib/predicate/document_features_store.cpp @@ -102,7 +102,7 @@ DocumentFeaturesStore::DocumentFeaturesStore(DataBuffer &buffer) DocumentFeaturesStore::~DocumentFeaturesStore() { _word_index.disableFreeLists(); - _word_index.disableElemHoldList(); + _word_index.disable_entry_hold_list(); _word_index.getAllocator().freeze(); _word_index.clear(); } diff --git a/searchlib/src/vespa/searchlib/predicate/predicate_interval_store.cpp b/searchlib/src/vespa/searchlib/predicate/predicate_interval_store.cpp index af809b2fa69..af5aae6e519 100644 --- a/searchlib/src/vespa/searchlib/predicate/predicate_interval_store.cpp +++ b/searchlib/src/vespa/searchlib/predicate/predicate_interval_store.cpp @@ -95,7 +95,7 @@ PredicateIntervalStore::remove(EntryRef ref) { // BufferState &state = _store.getBufferState(buffer_id); // uint32_t type_id = state.getTypeId(); // uint32_t size = type_id <= MAX_ARRAY_SIZE ? type_id : 1; - // _store.holdElem(ref, size); + // _store.hold_entries(ref, size); } } diff --git a/searchlib/src/vespa/searchlib/predicate/simple_index.hpp b/searchlib/src/vespa/searchlib/predicate/simple_index.hpp index c6f640d72ed..9320488f88e 100644 --- a/searchlib/src/vespa/searchlib/predicate/simple_index.hpp +++ b/searchlib/src/vespa/searchlib/predicate/simple_index.hpp @@ -41,7 +41,7 @@ SimpleIndex<Posting, Key, DocId>::insertIntoVectorPosting(vespalib::datastore::E template <typename Posting, typename Key, typename DocId> SimpleIndex<Posting, Key, DocId>::~SimpleIndex() { _btree_posting_lists.disableFreeLists(); - _btree_posting_lists.disableElemHoldList(); + _btree_posting_lists.disable_entry_hold_list(); for (auto it = _dictionary.begin(); it.valid(); ++it) { vespalib::datastore::EntryRef ref(it.getData()); @@ -51,13 +51,13 @@ SimpleIndex<Posting, Key, DocId>::~SimpleIndex() { } _vector_posting_lists.disableFreeLists(); - _vector_posting_lists.disableElemHoldList(); + _vector_posting_lists.disable_entry_hold_list(); _vector_posting_lists.clear(); _vector_posting_lists.getAllocator().freeze(); _vector_posting_lists.getAllocator().reclaim_all_memory(); _dictionary.disableFreeLists(); - _dictionary.disableElemHoldList(); + _dictionary.disable_entry_hold_list(); _dictionary.clear(); _dictionary.getAllocator().freeze(); _dictionary.getAllocator().reclaim_all_memory(); diff --git a/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt b/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt index c8c5d4d4257..313863d8dcb 100644 --- a/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt +++ b/searchlib/src/vespa/searchlib/tensor/CMakeLists.txt @@ -40,6 +40,7 @@ vespa_add_library(searchlib_tensor OBJECT tensor_buffer_store.cpp tensor_buffer_type_mapper.cpp tensor_deserialize.cpp + tensor_ext_attribute.cpp tensor_store.cpp DEPENDS ) diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp index c373f6bdcd0..c51d0ec7fd3 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp @@ -62,10 +62,10 @@ DenseTensorStore::BufferType::BufferType(const TensorSizeCalc &tensorSizeCalc, s DenseTensorStore::BufferType::~BufferType() = default; void -DenseTensorStore::BufferType::cleanHold(void *buffer, size_t offset, - ElemCount numElems, CleanContext) +DenseTensorStore::BufferType::clean_hold(void *buffer, size_t offset, EntryCount num_entries, CleanContext) { - memset(static_cast<char *>(buffer) + offset, 0, numElems); + auto num_elems = num_entries * getArraySize(); + memset(static_cast<char *>(buffer) + offset * getArraySize(), 0, num_elems); } const vespalib::alloc::MemoryAllocator* @@ -107,7 +107,7 @@ DenseTensorStore::allocRawBuffer() { size_t bufSize = getBufSize(); size_t alignedBufSize = _tensorSizeCalc.alignedSize(); - auto result = _concreteStore.freeListRawAllocator<char>(0u).alloc(alignedBufSize); + auto result = _concreteStore.freeListRawAllocator<char>(0u).alloc(1); clearPadAreaAfterBuffer(result.data, bufSize, alignedBufSize); return result; } @@ -118,7 +118,7 @@ DenseTensorStore::holdTensor(EntryRef ref) if (!ref.valid()) { return; } - _concreteStore.holdElem(ref, _tensorSizeCalc.alignedSize()); + _concreteStore.hold_entry(ref); } TensorStore::EntryRef diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h index 9e326e0ab1e..0dd483e7f08 100644 --- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h +++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h @@ -44,7 +44,7 @@ public: public: BufferType(const TensorSizeCalc &tensorSizeCalc, std::shared_ptr<vespalib::alloc::MemoryAllocator> allocator); ~BufferType() override; - void cleanHold(void *buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) override; + void clean_hold(void *buffer, size_t offset, EntryCount num_entries, CleanContext cleanCtx) override; const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override; }; private: diff --git a/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.cpp index fa13ab6303c..8526138fd31 100644 --- a/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.cpp +++ b/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.cpp @@ -30,11 +30,11 @@ DirectTensorStore::TensorBufferType::TensorBufferType() } void -DirectTensorStore::TensorBufferType::cleanHold(void* buffer, size_t offset, ElemCount num_elems, CleanContext clean_ctx) +DirectTensorStore::TensorBufferType::clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext clean_ctx) { TensorSP* elem = static_cast<TensorSP*>(buffer) + offset; const auto& empty = empty_entry(); - for (size_t i = 0; i < num_elems; ++i) { + for (size_t i = 0; i < num_entries; ++i) { clean_ctx.extraBytesCleaned((*elem)->get_memory_usage().allocatedBytes()); *elem = empty; ++elem; @@ -69,7 +69,7 @@ DirectTensorStore::holdTensor(EntryRef ref) } const auto& tensor = _tensor_store.getEntry(ref); assert(tensor); - _tensor_store.holdElem(ref, 1, tensor->get_memory_usage().allocatedBytes()); + _tensor_store.hold_entry(ref, tensor->get_memory_usage().allocatedBytes()); } EntryRef diff --git a/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.h b/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.h index 01084e89776..1230494fe41 100644 --- a/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.h +++ b/searchlib/src/vespa/searchlib/tensor/direct_tensor_store.h @@ -20,7 +20,7 @@ namespace search::tensor { */ class DirectTensorStore : public TensorStore { private: - // Note: Must use SP (instead of UP) because of fallbackCopy() and initializeReservedElements() in BufferType, + // Note: Must use SP (instead of UP) because of fallback_copy() and initialize_reserved_entries() in BufferType, // and implementation of move(). using TensorSP = std::shared_ptr<vespalib::eval::Value>; using TensorStoreType = vespalib::datastore::DataStore<TensorSP>; @@ -32,7 +32,7 @@ private: using CleanContext = typename ParentType::CleanContext; public: TensorBufferType(); - void cleanHold(void* buffer, size_t offset, ElemCount num_elems, CleanContext clean_ctx) override; + void clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext clean_ctx) override; }; TensorStoreType _tensor_store; diff --git a/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.cpp b/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.cpp index cb074348f08..5d3b2206703 100644 --- a/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.cpp +++ b/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.cpp @@ -12,7 +12,7 @@ using vespalib::alloc::MemoryAllocator; namespace search::tensor { LargeSubspacesBufferType::LargeSubspacesBufferType(const AllocSpec& spec, std::shared_ptr<MemoryAllocator> memory_allocator, TensorBufferTypeMapper& type_mapper) noexcept - : ParentType(1u, spec.minArraysInBuffer, spec.maxArraysInBuffer, spec.numArraysForNewBuffer, spec.allocGrowFactor), + : ParentType(1u, spec.min_entries_in_buffer, spec.max_entries_in_buffer, spec.num_entries_for_new_buffer, spec.allocGrowFactor), _memory_allocator(std::move(memory_allocator)), _ops(type_mapper.get_tensor_buffer_operations()) { @@ -21,10 +21,10 @@ LargeSubspacesBufferType::LargeSubspacesBufferType(const AllocSpec& spec, std::s LargeSubspacesBufferType::~LargeSubspacesBufferType() = default; void -LargeSubspacesBufferType::cleanHold(void* buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) +LargeSubspacesBufferType::clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext cleanCtx) { auto elem = static_cast<ArrayType*>(buffer) + offset; - for (size_t i = 0; i < numElems; ++i) { + for (size_t i = 0; i < num_entries; ++i) { if (!elem->empty()) { cleanCtx.extraBytesCleaned(elem->size()); _ops.reclaim_labels({elem->data(), elem->size()}); @@ -35,10 +35,10 @@ LargeSubspacesBufferType::cleanHold(void* buffer, size_t offset, ElemCount numEl } void -LargeSubspacesBufferType::destroyElements(void *buffer, ElemCount numElems) +LargeSubspacesBufferType::destroy_entries(void *buffer, EntryCount num_entries) { auto elem = static_cast<ArrayType*>(buffer); - for (size_t i = 0; i < numElems; ++i) { + for (size_t i = 0; i < num_entries; ++i) { if (!elem->empty()) { _ops.reclaim_labels({elem->data(), elem->size()}); ArrayType().swap(*elem); @@ -48,11 +48,11 @@ LargeSubspacesBufferType::destroyElements(void *buffer, ElemCount numElems) } void -LargeSubspacesBufferType::fallbackCopy(void *newBuffer, const void *oldBuffer, ElemCount numElems) +LargeSubspacesBufferType::fallback_copy(void *newBuffer, const void *oldBuffer, EntryCount num_entries) { auto old_elems = static_cast<const ArrayType*>(oldBuffer); auto new_elems = static_cast<ArrayType*>(newBuffer); - for (size_t i = 0; i < numElems; ++i) { + for (size_t i = 0; i < num_entries; ++i) { auto& old_elem = old_elems[i]; new (new_elems + i) ArrayType(old_elem); if (!old_elem.empty()) { @@ -62,12 +62,12 @@ LargeSubspacesBufferType::fallbackCopy(void *newBuffer, const void *oldBuffer, E } void -LargeSubspacesBufferType::initializeReservedElements(void *buffer, ElemCount reservedElements) +LargeSubspacesBufferType::initialize_reserved_entries(void *buffer, EntryCount reserved_entries) { - auto new_elems = static_cast<ArrayType*>(buffer); + auto new_entries = static_cast<ArrayType*>(buffer); const auto& empty = empty_entry(); - for (size_t i = 0; i < reservedElements; ++i) { - new (new_elems + i) ArrayType(empty); + for (size_t i = 0; i < reserved_entries; ++i) { + new (new_entries + i) ArrayType(empty); } } diff --git a/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.h b/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.h index cfab8ef20af..8cce08e9d81 100644 --- a/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.h +++ b/searchlib/src/vespa/searchlib/tensor/large_subspaces_buffer_type.h @@ -30,10 +30,10 @@ class LargeSubspacesBufferType : public vespalib::datastore::BufferType<vespalib public: LargeSubspacesBufferType(const AllocSpec& spec, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator, TensorBufferTypeMapper& type_mapper) noexcept; ~LargeSubspacesBufferType() override; - void cleanHold(void* buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) override; - void destroyElements(void *buffer, ElemCount numElems) override; - void fallbackCopy(void *newBuffer, const void *oldBuffer, ElemCount numElems) override; - void initializeReservedElements(void *buffer, ElemCount reservedElements) override; + void clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext cleanCtx) override; + void destroy_entries(void *buffer, EntryCount num_entries) override; + void fallback_copy(void *newBuffer, const void *oldBuffer, EntryCount num_entries) override; + void initialize_reserved_entries(void *buffer, EntryCount reserved_entries) override; const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override; }; diff --git a/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.cpp b/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.cpp index 6a71388a3b9..7b54182f062 100644 --- a/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.cpp +++ b/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.cpp @@ -10,7 +10,7 @@ using vespalib::alloc::MemoryAllocator; namespace search::tensor { SmallSubspacesBufferType::SmallSubspacesBufferType(uint32_t array_size, const AllocSpec& spec, std::shared_ptr<MemoryAllocator> memory_allocator, TensorBufferTypeMapper& type_mapper) noexcept - : ParentType(array_size, spec.minArraysInBuffer, spec.maxArraysInBuffer, spec.numArraysForNewBuffer, spec.allocGrowFactor), + : ParentType(array_size, spec.min_entries_in_buffer, spec.max_entries_in_buffer, spec.num_entries_for_new_buffer, spec.allocGrowFactor), _memory_allocator(std::move(memory_allocator)), _ops(type_mapper.get_tensor_buffer_operations()) { @@ -19,45 +19,45 @@ SmallSubspacesBufferType::SmallSubspacesBufferType(uint32_t array_size, const Al SmallSubspacesBufferType::~SmallSubspacesBufferType() = default; void -SmallSubspacesBufferType::cleanHold(void* buffer, size_t offset, ElemCount numElems, CleanContext) +SmallSubspacesBufferType::clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext) { - char* elem = static_cast<char *>(buffer) + offset; - while (numElems >= getArraySize()) { + char* elem = static_cast<char *>(buffer) + offset * getArraySize(); + while (num_entries >= 1) { _ops.reclaim_labels(vespalib::ArrayRef<char>(elem, getArraySize())); elem += getArraySize(); - numElems -= getArraySize(); + --num_entries; } } void -SmallSubspacesBufferType::destroyElements(void *buffer, ElemCount numElems) +SmallSubspacesBufferType::destroy_entries(void *buffer, EntryCount num_entries) { char* elem = static_cast<char *>(buffer); - while (numElems >= getArraySize()) { + while (num_entries >= 1) { _ops.reclaim_labels(vespalib::ArrayRef<char>(elem, getArraySize())); elem += getArraySize(); - numElems -= getArraySize(); + --num_entries; } } void -SmallSubspacesBufferType::fallbackCopy(void *newBuffer, const void *oldBuffer, ElemCount numElems) +SmallSubspacesBufferType::fallback_copy(void *newBuffer, const void *oldBuffer, EntryCount num_entries) { - if (numElems > 0) { - memcpy(newBuffer, oldBuffer, numElems); + if (num_entries > 0) { + memcpy(newBuffer, oldBuffer, num_entries * getArraySize()); } const char *elem = static_cast<const char *>(oldBuffer); - while (numElems >= getArraySize()) { + while (num_entries >= 1) { _ops.copied_labels(unconstify(vespalib::ConstArrayRef<char>(elem, getArraySize()))); elem += getArraySize(); - numElems -= getArraySize(); + --num_entries; } } void -SmallSubspacesBufferType::initializeReservedElements(void *buffer, ElemCount reservedElements) +SmallSubspacesBufferType::initialize_reserved_entries(void *buffer, EntryCount reserved_entries) { - memset(buffer, 0, reservedElements); + memset(buffer, 0, reserved_entries * getArraySize()); } const vespalib::alloc::MemoryAllocator* diff --git a/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.h b/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.h index 5622e9970b8..2f287ef1f3d 100644 --- a/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.h +++ b/searchlib/src/vespa/searchlib/tensor/small_subspaces_buffer_type.h @@ -30,10 +30,10 @@ public: SmallSubspacesBufferType& operator=(SmallSubspacesBufferType&&) noexcept = delete; SmallSubspacesBufferType(uint32_t array_size, const AllocSpec& spec, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator, TensorBufferTypeMapper& type_mapper) noexcept; ~SmallSubspacesBufferType() override; - void cleanHold(void* buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) override; - void destroyElements(void *buffer, ElemCount numElems) override; - void fallbackCopy(void *newBuffer, const void *oldBuffer, ElemCount numElems) override; - void initializeReservedElements(void *buffer, ElemCount reservedElements) override; + void clean_hold(void* buffer, size_t offset, EntryCount num_entries, CleanContext cleanCtx) override; + void destroy_entries(void *buffer, EntryCount num_entries) override; + void fallback_copy(void *newBuffer, const void *oldBuffer, EntryCount num_entries) override; + void initialize_reserved_entries(void *buffer, EntryCount reserved_entries) override; const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override; }; diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.cpp new file mode 100644 index 00000000000..19c8cf6053b --- /dev/null +++ b/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.cpp @@ -0,0 +1,181 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "tensor_ext_attribute.h" +#include "serialized_tensor_ref.h" +#include "vector_bundle.h" +#include <vespa/eval/eval/fast_value.h> +#include <vespa/eval/eval/tensor_spec.h> +#include <vespa/eval/eval/value.h> +#include <vespa/eval/eval/value_codec.h> +#include <vespa/searchcommon/attribute/config.h> + +#include <vespa/log/log.h> +LOG_SETUP(".searchlib.tensor.tensor_ext_attribute"); + +using vespalib::eval::FastValueBuilderFactory; +using vespalib::eval::TensorSpec; +using vespalib::eval::TypedCells; +using vespalib::eval::Value; +using vespalib::eval::ValueType; + +namespace search::tensor { + +namespace { + +std::unique_ptr<Value> +create_empty_tensor(const ValueType& type) +{ + const auto &factory = FastValueBuilderFactory::get(); + TensorSpec empty_spec(type.to_spec()); + return vespalib::eval::value_from_spec(empty_spec, factory); +} + +} + +TensorExtAttribute::TensorExtAttribute(const vespalib::string& name, const Config& cfg) + : NotImplementedAttribute(name, cfg), + ITensorAttribute(), + IExtendAttribute(), + _subspace_type(cfg.tensorType()), + _empty(_subspace_type), + _empty_tensor(create_empty_tensor(cfg.tensorType())) +{ +} + +TensorExtAttribute::~TensorExtAttribute() = default; + +const ITensorAttribute* +TensorExtAttribute::asTensorAttribute() const +{ + return this; +} + +void +TensorExtAttribute::onCommit() +{ + LOG_ABORT("should not be reached"); +} + +void +TensorExtAttribute::onUpdateStat() +{ +} + +bool +TensorExtAttribute::addDoc(DocId& docId) +{ + docId = _data.size(); + _data.emplace_back(nullptr); + incNumDocs(); + setCommittedDocIdLimit(getNumDocs()); + return true; +} + +bool +TensorExtAttribute::add(const vespalib::eval::Value& v, int32_t) +{ + _data.back() = &v; + return true; +} + +IExtendAttribute* +TensorExtAttribute::getExtendInterface() +{ + return this; +} + +TypedCells +TensorExtAttribute::get_vector(uint32_t docid, uint32_t subspace) const +{ + auto vectors = get_vectors(docid); + return (subspace < vectors.subspaces()) ? vectors.cells(subspace) : _empty.cells(); +} + +VectorBundle +TensorExtAttribute::get_vectors(uint32_t docid) const +{ + auto tensor = _data[docid]; + if (tensor == nullptr) { + return VectorBundle(); + } + return VectorBundle(tensor->cells().data, tensor->index().size(), _subspace_type); +} + +std::unique_ptr<Value> +TensorExtAttribute::getTensor(uint32_t docid) const +{ + auto tensor = _data[docid]; + if (tensor == nullptr) { + return {}; + } + return FastValueBuilderFactory::get().copy(*tensor); +} + +std::unique_ptr<Value> +TensorExtAttribute::getEmptyTensor() const +{ + return FastValueBuilderFactory::get().copy(*_empty_tensor); +} + +TypedCells +TensorExtAttribute::extract_cells_ref(uint32_t docid) const +{ + return get_vector(docid, 0); +} + +const vespalib::eval::Value& +TensorExtAttribute::get_tensor_ref(uint32_t docid) const +{ + auto tensor = _data[docid]; + return (tensor == nullptr) ? *_empty_tensor : *tensor; +} + +SerializedTensorRef +TensorExtAttribute::get_serialized_tensor_ref(uint32_t) const +{ + notImplemented(); +} + +bool +TensorExtAttribute::supports_extract_cells_ref() const +{ + return getConfig().tensorType().is_dense(); +} + +bool +TensorExtAttribute::supports_get_tensor_ref() const +{ + return true; +} + +bool +TensorExtAttribute::supports_get_serialized_tensor_ref() const +{ + return false; +} + +const ValueType& +TensorExtAttribute::getTensorType() const +{ + return getConfig().tensorType(); +} + +TensorExtAttribute::DistanceMetric +TensorExtAttribute::distance_metric() const +{ + return getConfig().distance_metric(); +} + +uint32_t +TensorExtAttribute::get_num_docs() const +{ + return _data.size(); +} + +void +TensorExtAttribute::get_state(const vespalib::slime::Inserter& inserter) const +{ + (void) inserter; +} + +} diff --git a/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.h b/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.h new file mode 100644 index 00000000000..a58426cd146 --- /dev/null +++ b/searchlib/src/vespa/searchlib/tensor/tensor_ext_attribute.h @@ -0,0 +1,54 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "i_tensor_attribute.h" +#include "empty_subspace.h" +#include "subspace_type.h" +#include <vespa/searchlib/attribute/not_implemented_attribute.h> +#include <vespa/vespalib/stllike/allocator.h> + +namespace search::tensor { + +/** + * Attribute vector storing a pointer to single tensor value per + * document in streaming search. The tensor is not owned by this + * attribute vector. + */ +class TensorExtAttribute : public NotImplementedAttribute, + public ITensorAttribute, + public IExtendAttribute +{ + std::vector<const vespalib::eval::Value*> _data; + SubspaceType _subspace_type; + EmptySubspace _empty; + std::unique_ptr<vespalib::eval::Value> _empty_tensor; +public: + TensorExtAttribute(const vespalib::string& name, const Config& cfg); + ~TensorExtAttribute() override; + const ITensorAttribute* asTensorAttribute() const override; + void onCommit() override; + void onUpdateStat() override; + bool addDoc(DocId& docId) override; + bool add(const vespalib::eval::Value& v, int32_t) override; + IExtendAttribute* getExtendInterface() override; + // DocVectorAccess API + vespalib::eval::TypedCells get_vector(uint32_t docid, uint32_t subspace) const override; + VectorBundle get_vectors(uint32_t docid) const override; + + // ITensorAttribute API + std::unique_ptr<vespalib::eval::Value> getTensor(uint32_t docid) const override; + std::unique_ptr<vespalib::eval::Value> getEmptyTensor() const override; + vespalib::eval::TypedCells extract_cells_ref(uint32_t docid) const override; + const vespalib::eval::Value& get_tensor_ref(uint32_t docid) const override; + SerializedTensorRef get_serialized_tensor_ref(uint32_t docid) const override; + bool supports_extract_cells_ref() const override; + bool supports_get_tensor_ref() const override; + bool supports_get_serialized_tensor_ref() const override; + const vespalib::eval::ValueType & getTensorType() const override; + search::attribute::DistanceMetric distance_metric() const override; + uint32_t get_num_docs() const override; + void get_state(const vespalib::slime::Inserter& inserter) const override; +}; + +} |