aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2023-06-28 10:30:47 +0200
committerGitHub <noreply@github.com>2023-06-28 10:30:47 +0200
commit22665b557168ee0912d25cc3172c551242977152 (patch)
tree3b9b29d9765b2310b5fc9974dba6ca3eddc50a8b
parent521a408530bf9f8217b34498bccce116497408dd (diff)
parente6c567b9601968d88d0011e85d799abc554b33ae (diff)
Merge pull request #27562 from vespa-engine/havardpe/current-index-setup
add tool used to wire CurrentIndex dependencies in grouping
-rw-r--r--searchlib/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/expression/current_index_setup/CMakeLists.txt9
-rw-r--r--searchlib/src/tests/expression/current_index_setup/current_index_setup_test.cpp58
-rw-r--r--searchlib/src/vespa/searchlib/expression/CMakeLists.txt1
-rw-r--r--searchlib/src/vespa/searchlib/expression/current_index_setup.cpp74
-rw-r--r--searchlib/src/vespa/searchlib/expression/current_index_setup.h48
6 files changed, 191 insertions, 0 deletions
diff --git a/searchlib/CMakeLists.txt b/searchlib/CMakeLists.txt
index 07045684d6e..eb199a7ba44 100644
--- a/searchlib/CMakeLists.txt
+++ b/searchlib/CMakeLists.txt
@@ -126,6 +126,7 @@ vespa_define_module(
src/tests/engine/proto_converter
src/tests/engine/proto_rpc_adapter
src/tests/expression/attributenode
+ src/tests/expression/current_index_setup
src/tests/features
src/tests/features/beta
src/tests/features/bm25
diff --git a/searchlib/src/tests/expression/current_index_setup/CMakeLists.txt b/searchlib/src/tests/expression/current_index_setup/CMakeLists.txt
new file mode 100644
index 00000000000..dc50dea4ce3
--- /dev/null
+++ b/searchlib/src/tests/expression/current_index_setup/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(searchlib_current_index_setup_test_app TEST
+ SOURCES
+ current_index_setup_test.cpp
+ DEPENDS
+ searchlib
+ GTest::GTest
+)
+vespa_add_test(NAME searchlib_current_index_setup_test_app COMMAND searchlib_current_index_setup_test_app)
diff --git a/searchlib/src/tests/expression/current_index_setup/current_index_setup_test.cpp b/searchlib/src/tests/expression/current_index_setup/current_index_setup_test.cpp
new file mode 100644
index 00000000000..20818e576dd
--- /dev/null
+++ b/searchlib/src/tests/expression/current_index_setup/current_index_setup_test.cpp
@@ -0,0 +1,58 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/searchlib/expression/current_index_setup.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using search::expression::CurrentIndex;
+using search::expression::CurrentIndexSetup;
+
+TEST(CurrentIndexSetupTest, bound_structs_can_be_resolved) {
+ CurrentIndexSetup setup;
+ CurrentIndex foo_idx;
+ CurrentIndex bar_idx;
+ setup.bind("foo", foo_idx);
+ setup.bind("foo.bar", bar_idx);
+ EXPECT_EQ(setup.resolve("plain"), nullptr);
+ EXPECT_EQ(setup.resolve("foo.a"), &foo_idx);
+ EXPECT_EQ(setup.resolve("foo.b"), &foo_idx);
+ EXPECT_EQ(setup.resolve("foo.c"), &foo_idx);
+ EXPECT_EQ(setup.resolve("foo.bar.x"), &bar_idx);
+ EXPECT_EQ(setup.resolve("foo.bar.y"), &bar_idx);
+ EXPECT_EQ(setup.resolve("baz.f"), nullptr);
+ EXPECT_EQ(setup.resolve("foo.baz.f"), nullptr);
+}
+
+TEST(CurrentIndexSetupTest, unbound_struct_usage_can_be_captured) {
+ CurrentIndexSetup setup;
+ CurrentIndexSetup::Usage usage;
+ CurrentIndex foo_idx;
+ setup.bind("foo", foo_idx);
+ EXPECT_FALSE(usage.has_single_unbound_struct());
+ {
+ CurrentIndexSetup::Usage::Bind capture_guard(setup, usage);
+ EXPECT_EQ(setup.resolve("foo.a"), &foo_idx);
+ EXPECT_EQ(setup.resolve("bar.a"), nullptr);
+ EXPECT_EQ(setup.resolve("bar.b"), nullptr);
+ EXPECT_EQ(setup.resolve("plain"), nullptr);
+ }
+ EXPECT_EQ(setup.resolve("baz.a"), nullptr);
+ EXPECT_TRUE(usage.has_single_unbound_struct());
+ EXPECT_EQ(usage.get_unbound_struct_name(), "bar");
+}
+
+TEST(CurrentIndexSetupTest, multi_unbound_struct_conflict_can_be_captured) {
+ CurrentIndexSetup setup;
+ CurrentIndexSetup::Usage usage;
+ EXPECT_FALSE(usage.has_single_unbound_struct());
+ {
+ CurrentIndexSetup::Usage::Bind capture_guard(setup, usage);
+ EXPECT_FALSE(usage.has_single_unbound_struct());
+ EXPECT_EQ(setup.resolve("foo.a"), nullptr);
+ EXPECT_TRUE(usage.has_single_unbound_struct());
+ EXPECT_EQ(setup.resolve("bar.a"), nullptr);
+ EXPECT_FALSE(usage.has_single_unbound_struct());
+ }
+ EXPECT_FALSE(usage.has_single_unbound_struct());
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt
index 9a3e377e5ef..6942a827fe9 100644
--- a/searchlib/src/vespa/searchlib/expression/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/expression/CMakeLists.txt
@@ -4,6 +4,7 @@ vespa_add_library(searchlib_expression OBJECT
attribute_map_lookup_node.cpp
attributenode.cpp
attributeresult.cpp
+ current_index_setup.cpp
enumattributeresult.cpp
perdocexpression.cpp
expressiontree.cpp
diff --git a/searchlib/src/vespa/searchlib/expression/current_index_setup.cpp b/searchlib/src/vespa/searchlib/expression/current_index_setup.cpp
new file mode 100644
index 00000000000..6660728dea7
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/expression/current_index_setup.cpp
@@ -0,0 +1,74 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "current_index_setup.h"
+#include <vespa/vespalib/stllike/hash_map.hpp>
+#include <cassert>
+
+namespace search::expression {
+
+void
+CurrentIndexSetup::Usage::notify_unbound_struct_usage(vespalib::stringref name)
+{
+ _unbound.insert(name);
+}
+
+CurrentIndexSetup::Usage::Usage()
+ : _unbound()
+{
+}
+
+CurrentIndexSetup::Usage::~Usage() = default;
+
+vespalib::stringref
+CurrentIndexSetup::Usage::get_unbound_struct_name() const
+{
+ assert(has_single_unbound_struct());
+ return *_unbound.begin();
+}
+
+CurrentIndexSetup::Usage::Bind::Bind(CurrentIndexSetup &setup, Usage &usage) noexcept
+ : _setup(setup)
+{
+ auto prev = setup.capture(std::addressof(usage));
+ assert(prev == nullptr); // no nesting
+}
+
+CurrentIndexSetup::Usage::Bind::~Bind()
+{
+ [[maybe_unused]] auto prev = _setup.capture(nullptr);
+}
+
+CurrentIndexSetup::CurrentIndexSetup()
+ : _bound(), _usage(nullptr)
+{
+}
+
+CurrentIndexSetup::~CurrentIndexSetup() = default;
+
+const CurrentIndex *
+CurrentIndexSetup::resolve(vespalib::stringref field_name) const
+{
+ size_t pos = field_name.rfind('.');
+ if (pos > field_name.size()) {
+ return nullptr;
+ }
+ auto struct_name = field_name.substr(0, pos);
+ auto entry = _bound.find(struct_name);
+ if (entry == _bound.end()) {
+ if (_usage != nullptr) {
+ _usage->notify_unbound_struct_usage(struct_name);
+ }
+ return nullptr;
+ }
+ return entry->second;
+}
+
+void
+CurrentIndexSetup::bind(vespalib::stringref struct_name, const CurrentIndex &index)
+{
+ auto res = _bound.insert(std::make_pair(vespalib::string(struct_name),
+ std::addressof(index)));
+ assert(res.second); // struct must be either bound or unbound
+}
+
+}
diff --git a/searchlib/src/vespa/searchlib/expression/current_index_setup.h b/searchlib/src/vespa/searchlib/expression/current_index_setup.h
new file mode 100644
index 00000000000..4f835d064bb
--- /dev/null
+++ b/searchlib/src/vespa/searchlib/expression/current_index_setup.h
@@ -0,0 +1,48 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "currentindex.h"
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vespalib/stllike/hash_map.h>
+#include <vespa/vespalib/stllike/hash_set.h>
+#include <utility>
+
+namespace search::expression {
+
+class CurrentIndexSetup {
+public:
+ class Usage {
+ private:
+ friend class CurrentIndexSetup;
+ vespalib::hash_set<vespalib::string> _unbound;
+ void notify_unbound_struct_usage(vespalib::stringref name);
+ public:
+ Usage();
+ ~Usage();
+ [[nodiscard]] bool has_single_unbound_struct() const noexcept {
+ return (_unbound.size() == 1);
+ }
+ vespalib::stringref get_unbound_struct_name() const;
+ class Bind {
+ private:
+ CurrentIndexSetup &_setup;
+ public:
+ Bind(CurrentIndexSetup &setup, Usage &usage) noexcept;
+ ~Bind();
+ };
+ };
+private:
+ vespalib::hash_map<vespalib::string, const CurrentIndex *> _bound;
+ Usage *_usage;
+ [[nodiscard]] Usage *capture(Usage *usage) noexcept {
+ return std::exchange(_usage, usage);
+ }
+public:
+ CurrentIndexSetup();
+ ~CurrentIndexSetup();
+ [[nodiscard]] const CurrentIndex *resolve(vespalib::stringref field_name) const;
+ void bind(vespalib::stringref struct_name, const CurrentIndex &index);
+};
+
+}