summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/JvmOptionsTest.java7
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java10
-rw-r--r--eval/src/tests/eval/fast_value/fast_value_test.cpp8
-rw-r--r--eval/src/tests/eval/simple_value/simple_value_test.cpp26
-rw-r--r--eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp6
-rw-r--r--eval/src/tests/eval/value_codec/value_codec_test.cpp8
-rw-r--r--eval/src/tests/instruction/generic_concat/generic_concat_test.cpp16
-rw-r--r--eval/src/tests/instruction/generic_create/generic_create_test.cpp8
-rw-r--r--eval/src/tests/instruction/generic_join/generic_join_test.cpp12
-rw-r--r--eval/src/tests/instruction/generic_map/generic_map_test.cpp8
-rw-r--r--eval/src/tests/instruction/generic_merge/generic_merge_test.cpp16
-rw-r--r--eval/src/tests/instruction/generic_peek/generic_peek_test.cpp8
-rw-r--r--eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp8
-rw-r--r--eval/src/tests/instruction/generic_rename/generic_rename_test.cpp8
-rw-r--r--eval/src/tests/instruction/join_with_number/join_with_number_function_test.cpp6
-rw-r--r--eval/src/tests/instruction/mixed_map_function/mixed_map_function_test.cpp20
-rw-r--r--eval/src/tests/instruction/mixed_simple_join_function/mixed_simple_join_function_test.cpp6
-rw-r--r--eval/src/tests/instruction/pow_as_map_optimizer/pow_as_map_optimizer_test.cpp6
-rw-r--r--eval/src/tests/instruction/sparse_dot_product_function/sparse_dot_product_function_test.cpp14
-rw-r--r--eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp16
-rw-r--r--eval/src/tests/streamed/value/streamed_value_test.cpp26
-rw-r--r--eval/src/vespa/eval/eval/fast_addr_map.h33
-rw-r--r--eval/src/vespa/eval/eval/fast_value.hpp15
-rw-r--r--eval/src/vespa/eval/instruction/sparse_dot_product_function.cpp111
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java26
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java18
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java29
-rw-r--r--persistence/src/vespa/persistence/dummyimpl/dummy_bucket_executor.h2
-rw-r--r--persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp12
-rw-r--r--persistence/src/vespa/persistence/spi/bucketexecutor.h1
-rw-r--r--searchcore/src/tests/proton/documentdb/lid_space_compaction/lid_space_jobtest.h9
-rw-r--r--searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp19
-rw-r--r--searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h1
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.cpp3
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.h1
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.cpp38
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.h8
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp8
-rw-r--r--storage/src/vespa/storage/persistence/filestorage/filestormanager.h1
-rw-r--r--vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java2
-rw-r--r--vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp11
-rw-r--r--vespalib/src/vespa/vespalib/util/string_id.h1
43 files changed, 305 insertions, 291 deletions
diff --git a/README.md b/README.md
index a2b64f20fc3..3056f619982 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<!-- Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
-[![#Vespa](https://vespa.ai/img/VespaLogoBlack.png)](https://vespa.ai)
+[![#Vespa](https://vespa.ai/assets/vespa-logo-color.png)](https://vespa.ai)
The big data serving engine - Store, search, rank and organize big data at user serving time.
Vespa is an engine for low-latency computation over large data sets.
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JvmOptionsTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JvmOptionsTest.java
index 294df42bd77..60af25a3087 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JvmOptionsTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/JvmOptionsTest.java
@@ -78,11 +78,11 @@ public class JvmOptionsTest extends ContainerModelBuilderTestBase {
}
private static void verifyIgnoreJvmGCOptions(boolean isHosted) throws IOException, SAXException {
- verifyIgnoreJvmGCOptionsIfJvmArgs("jvmargs", ContainerCluster.G1GC);
- verifyIgnoreJvmGCOptionsIfJvmArgs( "jvm-options", "-XX:+UseG1GC");
+ verifyIgnoreJvmGCOptionsIfJvmArgs("jvmargs", ContainerCluster.G1GC, isHosted);
+ verifyIgnoreJvmGCOptionsIfJvmArgs( "jvm-options", "-XX:+UseG1GC", isHosted);
}
- private static void verifyIgnoreJvmGCOptionsIfJvmArgs(String jvmOptionsName, String expectedGC) throws IOException, SAXException {
+ private static void verifyIgnoreJvmGCOptionsIfJvmArgs(String jvmOptionsName, String expectedGC, boolean isHosted) throws IOException, SAXException {
String servicesXml =
"<container version='1.0'>" +
" <nodes jvm-gc-options='-XX:+UseG1GC' " + jvmOptionsName + "='-XX:+UseParNewGC'>" +
@@ -95,6 +95,7 @@ public class JvmOptionsTest extends ContainerModelBuilderTestBase {
VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder()
.applicationPackage(applicationPackage)
.deployLogger(logger)
+ .properties(new TestProperties().setHostedVespa(isHosted))
.build());
QrStartConfig.Builder qrStartBuilder = new QrStartConfig.Builder();
model.getConfig(qrStartBuilder, "container/container.0");
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
index 979cd9060d9..081c6afa2b8 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
@@ -50,7 +50,7 @@ public class ControllerMaintenance extends AbstractComponent {
maintainers.add(new ApplicationOwnershipConfirmer(controller, intervals.applicationOwnershipConfirmer, controller.serviceRegistry().ownershipIssues()));
maintainers.add(new SystemUpgrader(controller, intervals.systemUpgrader));
maintainers.add(new JobRunner(controller, intervals.jobRunner));
- maintainers.add(new OsVersionStatusUpdater(controller, intervals.defaultInterval));
+ maintainers.add(new OsVersionStatusUpdater(controller, intervals.osVersionStatusUpdater));
maintainers.add(new ContactInformationMaintainer(controller, intervals.contactInformationMaintainer));
maintainers.add(new NameServiceDispatcher(controller, intervals.nameServiceDispatcher));
maintainers.add(new CostReportMaintainer(controller, intervals.costReportMaintainer, controller.serviceRegistry().costReportConsumer()));
@@ -98,6 +98,7 @@ public class ControllerMaintenance extends AbstractComponent {
private final Duration applicationOwnershipConfirmer;
private final Duration systemUpgrader;
private final Duration jobRunner;
+ private final Duration osVersionStatusUpdater;
private final Duration osUpgrader;
private final Duration contactInformationMaintainer;
private final Duration nameServiceDispatcher;
@@ -120,13 +121,14 @@ public class ControllerMaintenance extends AbstractComponent {
this.readyJobsTrigger = duration(1, MINUTES);
this.deploymentMetricsMaintainer = duration(10, MINUTES);
this.applicationOwnershipConfirmer = duration(12, HOURS);
- this.systemUpgrader = duration(90, SECONDS);
+ this.systemUpgrader = duration(2, MINUTES);
this.jobRunner = duration(90, SECONDS);
+ this.osVersionStatusUpdater = duration(2, MINUTES);
this.osUpgrader = duration(1, MINUTES);
this.contactInformationMaintainer = duration(12, HOURS);
- this.nameServiceDispatcher = duration(30, SECONDS);
+ this.nameServiceDispatcher = duration(1, MINUTES);
this.costReportMaintainer = duration(2, HOURS);
- this.resourceMeterMaintainer = duration(1, MINUTES);
+ this.resourceMeterMaintainer = duration(3, MINUTES);
this.cloudEventReporter = duration(30, MINUTES);
this.resourceTagMaintainer = duration(30, MINUTES);
this.systemRoutingPolicyMaintainer = duration(10, MINUTES);
diff --git a/eval/src/tests/eval/fast_value/fast_value_test.cpp b/eval/src/tests/eval/fast_value/fast_value_test.cpp
index 6cf43511977..9d29d8de660 100644
--- a/eval/src/tests/eval/fast_value/fast_value_test.cpp
+++ b/eval/src/tests/eval/fast_value/fast_value_test.cpp
@@ -142,9 +142,9 @@ TEST(FastValueBuilderTest, mixed_add_subspace_robustness) {
}
}
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> layouts = {
+const std::vector<GenSpec> layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -159,7 +159,9 @@ std::vector<GenSpec> layouts = {
TEST(FastValueBuilderFactoryTest, fast_values_can_be_copied) {
auto factory = FastValueBuilderFactory::get();
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, factory);
std::unique_ptr<Value> copy = factory.copy(*value);
TensorSpec actual = spec_from_value(*copy);
diff --git a/eval/src/tests/eval/simple_value/simple_value_test.cpp b/eval/src/tests/eval/simple_value/simple_value_test.cpp
index 09884b0ed0d..c1301bf6b1a 100644
--- a/eval/src/tests/eval/simple_value/simple_value_test.cpp
+++ b/eval/src/tests/eval/simple_value/simple_value_test.cpp
@@ -23,9 +23,9 @@ using Handle = SharedStringRepo::Handle;
vespalib::string as_str(string_id label) { return Handle::string_from_id(label); }
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> layouts = {
+const std::vector<GenSpec> layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -37,7 +37,7 @@ std::vector<GenSpec> layouts = {
G().map("x", {"a","b","c"}).idx("y", 5).map("z", {"i","j","k","l"})
};
-std::vector<GenSpec> join_layouts = {
+const std::vector<GenSpec> join_layouts = {
G(), G(),
G().idx("x", 5), G().idx("x", 5),
G().idx("x", 5), G().idx("y", 5),
@@ -67,7 +67,9 @@ TensorSpec simple_value_join(const TensorSpec &a, const TensorSpec &b, join_fun_
TEST(SimpleValueTest, simple_values_can_be_converted_from_and_to_tensor_spec) {
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, SimpleValueBuilderFactory::get());
TensorSpec actual = spec_from_value(*value);
EXPECT_EQ(actual, expect);
@@ -77,7 +79,9 @@ TEST(SimpleValueTest, simple_values_can_be_converted_from_and_to_tensor_spec) {
TEST(SimpleValueTest, simple_values_can_be_copied) {
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, SimpleValueBuilderFactory::get());
std::unique_ptr<Value> copy = SimpleValueBuilderFactory::get().copy(*value);
TensorSpec actual = spec_from_value(*copy);
@@ -124,10 +128,14 @@ GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
TEST(SimpleValueTest, new_generic_join_works_for_simple_values) {
ASSERT_TRUE((join_layouts.size() % 2) == 0);
for (size_t i = 0; i < join_layouts.size(); i += 2) {
- const auto l = join_layouts[i].seq(N_16ths);
- const auto r = join_layouts[i + 1].seq(N_16ths);
- for (TensorSpec lhs : { l.gen(), l.cpy().cells_double().gen() }) {
- for (TensorSpec rhs : { r.gen(), r.cpy().cells_double().gen() }) {
+ const auto l = join_layouts[i].cpy().seq(N_16ths);
+ const auto r = join_layouts[i + 1].cpy().seq(N_16ths);
+ for (TensorSpec lhs : { l.cpy().cells_float().gen(),
+ l.cpy().cells_double().gen() })
+ {
+ for (TensorSpec rhs : { r.cpy().cells_float().gen(),
+ r.cpy().cells_double().gen() })
+ {
for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Div::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
auto expect = ReferenceOperations::join(lhs, rhs, fun);
diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
index 18198a75f7d..dd21b663fa9 100644
--- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
+++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp
@@ -23,12 +23,10 @@ using namespace vespalib::eval::tensor_function;
const ValueBuilderFactory &simple_factory = SimpleValueBuilderFactory::get();
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TensorSpec spec(double v) { return TensorSpec("double").add({}, v); }
-
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
- .add("a", spec(1))
- .add("b", spec(2))
+ .add("a", GenSpec().seq_bias(1).gen())
+ .add("b", GenSpec().seq_bias(2).gen())
.add("x3", GenSpec().idx("x", 3).gen())
.add("x3f", GenSpec().idx("x", 3).cells_float().gen())
.add("x3m", GenSpec().map("x", 3).gen())
diff --git a/eval/src/tests/eval/value_codec/value_codec_test.cpp b/eval/src/tests/eval/value_codec/value_codec_test.cpp
index acce0f5667f..110b58c27de 100644
--- a/eval/src/tests/eval/value_codec/value_codec_test.cpp
+++ b/eval/src/tests/eval/value_codec/value_codec_test.cpp
@@ -15,9 +15,9 @@ using namespace vespalib::eval::test;
const ValueBuilderFactory &factory = SimpleValueBuilderFactory::get();
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> layouts = {
+const std::vector<GenSpec> layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -32,7 +32,9 @@ std::vector<GenSpec> layouts = {
TEST(ValueCodecTest, simple_values_can_be_converted_from_and_to_tensor_spec) {
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, factory);
TensorSpec actual = spec_from_value(*value);
EXPECT_EQ(actual, expect);
diff --git a/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp b/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
index 59c4c5bf0c8..17e012b8e33 100644
--- a/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
+++ b/eval/src/tests/instruction/generic_concat/generic_concat_test.cpp
@@ -18,11 +18,11 @@ using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
-std::vector<GenSpec> concat_layouts = {
+const std::vector<GenSpec> concat_layouts = {
G(), G(),
G(), G().idx("y", 5),
G().idx("y", 5), G(),
@@ -76,10 +76,14 @@ TensorSpec perform_generic_concat(const TensorSpec &a, const TensorSpec &b,
void test_generic_concat_with(const ValueBuilderFactory &factory) {
ASSERT_TRUE((concat_layouts.size() % 2) == 0);
for (size_t i = 0; i < concat_layouts.size(); i += 2) {
- const auto &l = concat_layouts[i];
- const auto &r = concat_layouts[i+1].seq(N_16ths);
- for (TensorSpec lhs : { l.gen(), l.cpy().cells_double().gen() }) {
- for (TensorSpec rhs : { r.gen(), r.cpy().cells_double().gen() }) {
+ const auto l = concat_layouts[i];
+ const auto r = concat_layouts[i+1].cpy().seq(N_16ths);
+ for (TensorSpec lhs : { l.cpy().cells_float().gen(),
+ l.cpy().cells_double().gen() })
+ {
+ for (TensorSpec rhs : { r.cpy().cells_float().gen(),
+ r.cpy().cells_double().gen() })
+ {
SCOPED_TRACE(fmt("\n===\nin LHS: %s\nin RHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
auto actual = perform_generic_concat(lhs, rhs, "y", factory);
auto expect = ReferenceOperations::concat(lhs, rhs, "y");
diff --git a/eval/src/tests/instruction/generic_create/generic_create_test.cpp b/eval/src/tests/instruction/generic_create/generic_create_test.cpp
index 2dce4509571..fcf4618d592 100644
--- a/eval/src/tests/instruction/generic_create/generic_create_test.cpp
+++ b/eval/src/tests/instruction/generic_create/generic_create_test.cpp
@@ -19,9 +19,9 @@ using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> create_layouts = {
+const std::vector<GenSpec> create_layouts = {
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
G().idx("x", 3).idx("y", 5).idx("z", 7),
@@ -91,7 +91,9 @@ TensorSpec perform_generic_create(const TensorSpec &a, const ValueBuilderFactory
void test_generic_create_with(const ValueBuilderFactory &factory) {
for (const auto &layout : create_layouts) {
- for (TensorSpec full : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec full : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
auto actual = perform_generic_create(full, factory);
auto expect = reference_create(full).normalize();
EXPECT_EQ(actual, expect);
diff --git a/eval/src/tests/instruction/generic_join/generic_join_test.cpp b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
index 55dc4c25389..f724cdf1024 100644
--- a/eval/src/tests/instruction/generic_join/generic_join_test.cpp
+++ b/eval/src/tests/instruction/generic_join/generic_join_test.cpp
@@ -19,9 +19,9 @@ using vespalib::make_string_short::fmt;
GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
-GenSpec G() { return GenSpec().cells_float().seq(N_16ths); }
+GenSpec G() { return GenSpec().seq(N_16ths); }
-std::vector<GenSpec> join_layouts = {
+const std::vector<GenSpec> join_layouts = {
G(), G(),
G().idx("x", 5), G().idx("x", 5),
G().idx("x", 5), G().idx("y", 5),
@@ -107,8 +107,12 @@ TEST(GenericJoinTest, generic_join_works_for_simple_and_fast_values) {
for (size_t i = 0; i < join_layouts.size(); i += 2) {
const auto &l = join_layouts[i];
const auto &r = join_layouts[i+1];
- for (TensorSpec lhs : { l.gen(), l.cpy().cells_double().gen() }) {
- for (TensorSpec rhs : { r.gen(), r.cpy().cells_double().gen() }) {
+ for (TensorSpec lhs : { l.cpy().cells_float().gen(),
+ l.cpy().cells_double().gen() })
+ {
+ for (TensorSpec rhs : { r.cpy().cells_float().gen(),
+ r.cpy().cells_double().gen() })
+ {
for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Div::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
auto expect = ReferenceOperations::join(lhs, rhs, fun);
diff --git a/eval/src/tests/instruction/generic_map/generic_map_test.cpp b/eval/src/tests/instruction/generic_map/generic_map_test.cpp
index aaa8990d794..8e39fa68072 100644
--- a/eval/src/tests/instruction/generic_map/generic_map_test.cpp
+++ b/eval/src/tests/instruction/generic_map/generic_map_test.cpp
@@ -19,9 +19,9 @@ using vespalib::make_string_short::fmt;
GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
-GenSpec G() { return GenSpec().cells_float().seq(N_16ths); }
+GenSpec G() { return GenSpec().seq(N_16ths); }
-std::vector<GenSpec> map_layouts = {
+const std::vector<GenSpec> map_layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -43,7 +43,9 @@ TensorSpec perform_generic_map(const TensorSpec &a, map_fun_t func, const ValueB
void test_generic_map_with(const ValueBuilderFactory &factory) {
for (const auto &layout : map_layouts) {
- for (TensorSpec lhs : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec lhs : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
for (auto func : {operation::Floor::f, operation::Fabs::f, operation::Square::f, operation::Inv::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\n===\n", lhs.to_string().c_str()));
auto expect = ReferenceOperations::map(lhs, func);
diff --git a/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp b/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
index f2ddd9b74d8..d5f7bc071f6 100644
--- a/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
+++ b/eval/src/tests/instruction/generic_merge/generic_merge_test.cpp
@@ -18,11 +18,11 @@ using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
-std::vector<GenSpec> merge_layouts = {
+const std::vector<GenSpec> merge_layouts = {
G(), G(),
G().idx("x", 5), G().idx("x", 5),
G().idx("x", 3).idx("y", 5), G().idx("x", 3).idx("y", 5),
@@ -48,10 +48,14 @@ TensorSpec perform_generic_merge(const TensorSpec &a, const TensorSpec &b, join_
void test_generic_merge_with(const ValueBuilderFactory &factory) {
ASSERT_TRUE((merge_layouts.size() % 2) == 0);
for (size_t i = 0; i < merge_layouts.size(); i += 2) {
- const auto &l = merge_layouts[i];
- const auto &r = merge_layouts[i+1].seq(N_16ths);
- for (TensorSpec lhs : { l.gen(), l.cpy().cells_double().gen() }) {
- for (TensorSpec rhs : { r.gen(), r.cpy().cells_double().gen() }) {
+ const auto l = merge_layouts[i];
+ const auto r = merge_layouts[i+1].cpy().seq(N_16ths);
+ for (TensorSpec lhs : { l.cpy().cells_float().gen(),
+ l.cpy().cells_double().gen() })
+ {
+ for (TensorSpec rhs : { r.cpy().cells_float().gen(),
+ r.cpy().cells_double().gen() })
+ {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
for (auto fun: {operation::Add::f, operation::Mul::f, operation::Sub::f, operation::Max::f}) {
auto expect = ReferenceOperations::merge(lhs, rhs, fun);
diff --git a/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp b/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
index 092a91711ba..c80e8a1296b 100644
--- a/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
+++ b/eval/src/tests/instruction/generic_peek/generic_peek_test.cpp
@@ -22,9 +22,9 @@ using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> peek_layouts = {
+const std::vector<GenSpec> peek_layouts = {
G().idx("x", 4),
G().idx("x", 4).idx("y", 5),
G().idx("x", 4).idx("y", 5).idx("z", 3),
@@ -194,7 +194,9 @@ void fill_dims_and_check(const TensorSpec &input,
void test_generic_peek_with(const ValueBuilderFactory &factory) {
for (const auto &layout : peek_layouts) {
- for (TensorSpec input : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec input : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
ValueType input_type = ValueType::from_spec(input.type());
const auto &dims = input_type.dimensions();
PeekSpec spec;
diff --git a/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp b/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
index 77317b0ee27..2c5baf234c4 100644
--- a/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
+++ b/eval/src/tests/instruction/generic_reduce/generic_reduce_test.cpp
@@ -20,9 +20,9 @@ using vespalib::make_string_short::fmt;
GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
-GenSpec G() { return GenSpec().cells_float().seq(N_16ths); }
+GenSpec G() { return GenSpec().seq(N_16ths); }
-std::vector<GenSpec> layouts = {
+const std::vector<GenSpec> layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -70,7 +70,9 @@ TEST(GenericReduceTest, sparse_reduce_plan_can_be_created) {
void test_generic_reduce_with(const ValueBuilderFactory &factory) {
for (const auto &layout: layouts) {
- for (TensorSpec input : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec input : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
SCOPED_TRACE(fmt("tensor type: %s, num_cells: %zu", input.type().c_str(), input.cells().size()));
for (Aggr aggr: {Aggr::SUM, Aggr::AVG, Aggr::MIN, Aggr::MAX}) {
SCOPED_TRACE(fmt("aggregator: %s", AggrNames::name_of(aggr)->c_str()));
diff --git a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
index 430e417e288..f0c2241202e 100644
--- a/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
+++ b/eval/src/tests/instruction/generic_rename/generic_rename_test.cpp
@@ -17,9 +17,9 @@ using namespace vespalib::eval::test;
using vespalib::make_string_short::fmt;
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> rename_layouts = {
+const std::vector<GenSpec> rename_layouts = {
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
G().idx("x", 3).idx("y", 5).idx("z", 7),
@@ -110,7 +110,9 @@ TensorSpec perform_generic_rename(const TensorSpec &a,
void test_generic_rename_with(const ValueBuilderFactory &factory) {
for (const auto &layout : rename_layouts) {
- for (TensorSpec lhs : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec lhs : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
ValueType lhs_type = ValueType::from_spec(lhs.type());
for (const auto & from_to : rename_from_to) {
ValueType renamed_type = lhs_type.rename(from_to.from, from_to.to);
diff --git a/eval/src/tests/instruction/join_with_number/join_with_number_function_test.cpp b/eval/src/tests/instruction/join_with_number/join_with_number_function_test.cpp
index 2d943aa569e..e6a256a493b 100644
--- a/eval/src/tests/instruction/join_with_number/join_with_number_function_test.cpp
+++ b/eval/src/tests/instruction/join_with_number/join_with_number_function_test.cpp
@@ -33,12 +33,10 @@ std::ostream &operator<<(std::ostream &os, Primary primary)
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TensorSpec spec(double v) { return TensorSpec("double").add({}, v); }
-
EvalFixture::ParamRepo make_params() {
auto repo = EvalFixture::ParamRepo()
- .add("a", spec(1.5))
- .add("number", spec(2.5))
+ .add("a", GenSpec().seq_bias(1.5).gen())
+ .add("number", GenSpec().seq_bias(2.5).gen())
.add("dense", GenSpec().idx("y", 5).gen())
.add_variants("x3y5", GenSpec().idx("x", 3).idx("y", 5))
.add_variants("mixed", GenSpec().map("x", {"a"}).idx("y", 5).map("z", {"d","e"}))
diff --git a/eval/src/tests/instruction/mixed_map_function/mixed_map_function_test.cpp b/eval/src/tests/instruction/mixed_map_function/mixed_map_function_test.cpp
index 45e885fac33..3a7d1368f03 100644
--- a/eval/src/tests/instruction/mixed_map_function/mixed_map_function_test.cpp
+++ b/eval/src/tests/instruction/mixed_map_function/mixed_map_function_test.cpp
@@ -13,19 +13,13 @@ using namespace vespalib::eval::tensor_function;
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TensorSpec spec(double v) { return TensorSpec("double").add({}, v); }
-TensorSpec sparse_spec = GenSpec().map("x", {"a"}).gen();
-TensorSpec mixed_spec = GenSpec().map("x", {"a"}).idx("y", 5).gen();
-
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
- .add("a", spec(1.5))
- .add("b", spec(2.5))
- .add("sparse", sparse_spec)
- .add("mixed", mixed_spec)
- .add_mutable("@sparse", sparse_spec)
- .add_mutable("@mixed", mixed_spec)
- .add_matrix("x", 5, "y", 3);
+ .add("a", GenSpec().seq_bias(1.5).gen())
+ .add("b", GenSpec().seq_bias(2.5).gen())
+ .add_variants("sparse", GenSpec().map("x", {"a"}))
+ .add_variants("mixed", GenSpec().map("x", {"a"}).idx("y", 5))
+ .add_variants("x5y3", GenSpec().idx("x", 5).idx("y", 3));
}
EvalFixture::ParamRepo param_repo = make_params();
@@ -57,12 +51,12 @@ void verify_not_optimized(const vespalib::string &expr) {
TEST(MapTest, dense_map_is_optimized) {
verify_optimized("map(x5y3,f(x)(x+10))", false);
- verify_optimized("map(x5y3f,f(x)(x+10))", false);
+ verify_optimized("map(x5y3_f,f(x)(x+10))", false);
}
TEST(MapTest, simple_dense_map_can_be_inplace) {
verify_optimized("map(@x5y3,f(x)(x+10))", true);
- verify_optimized("map(@x5y3f,f(x)(x+10))", true);
+ verify_optimized("map(@x5y3_f,f(x)(x+10))", true);
}
TEST(MapTest, scalar_map_is_not_optimized) {
diff --git a/eval/src/tests/instruction/mixed_simple_join_function/mixed_simple_join_function_test.cpp b/eval/src/tests/instruction/mixed_simple_join_function/mixed_simple_join_function_test.cpp
index 02e13fcbef3..105ae22e06e 100644
--- a/eval/src/tests/instruction/mixed_simple_join_function/mixed_simple_join_function_test.cpp
+++ b/eval/src/tests/instruction/mixed_simple_join_function/mixed_simple_join_function_test.cpp
@@ -43,12 +43,10 @@ std::ostream &operator<<(std::ostream &os, Overlap overlap)
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TensorSpec spec(double v) { return TensorSpec("double").add({}, v); }
-
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
- .add("a", spec(1.5))
- .add("b", spec(2.5))
+ .add("a", GenSpec().seq_bias(1.5).gen())
+ .add("b", GenSpec().seq_bias(2.5).gen())
.add("sparse", GenSpec().map("x", {"a", "b", "c"}).gen())
.add("mixed", GenSpec().map("x", {"a", "b", "c"}).idx("y", 5).idx("z", 3).gen())
.add("empty_mixed", GenSpec().map("x", {}).idx("y", 5).idx("z", 3).gen())
diff --git a/eval/src/tests/instruction/pow_as_map_optimizer/pow_as_map_optimizer_test.cpp b/eval/src/tests/instruction/pow_as_map_optimizer/pow_as_map_optimizer_test.cpp
index cceb18bfea6..fe32a59bb78 100644
--- a/eval/src/tests/instruction/pow_as_map_optimizer/pow_as_map_optimizer_test.cpp
+++ b/eval/src/tests/instruction/pow_as_map_optimizer/pow_as_map_optimizer_test.cpp
@@ -14,12 +14,10 @@ using namespace vespalib::eval;
const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
-TensorSpec spec(double v) { return TensorSpec("double").add({}, v); }
-
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
- .add("a", spec(1.5))
- .add("b", spec(2.5))
+ .add("a", GenSpec().seq_bias(1.5).gen())
+ .add("b", GenSpec().seq_bias(2.5).gen())
.add("sparse", GenSpec().map("x", {"a","b"}).gen())
.add("mixed", GenSpec().map("x", {"a"}).idx("y", 5).gen())
.add_variants("x5y3", GenSpec().idx("x", 5).idx("y", 3));
diff --git a/eval/src/tests/instruction/sparse_dot_product_function/sparse_dot_product_function_test.cpp b/eval/src/tests/instruction/sparse_dot_product_function/sparse_dot_product_function_test.cpp
index 65eab2778aa..ac333f5224a 100644
--- a/eval/src/tests/instruction/sparse_dot_product_function/sparse_dot_product_function_test.cpp
+++ b/eval/src/tests/instruction/sparse_dot_product_function/sparse_dot_product_function_test.cpp
@@ -17,10 +17,8 @@ const ValueBuilderFactory &test_factory = SimpleValueBuilderFactory::get();
EvalFixture::ParamRepo make_params() {
return EvalFixture::ParamRepo()
- .add("v1_x", GenSpec().map("x", 32, 1).seq_bias(3.0).gen())
- .add("v1_x_f", GenSpec().map("x", 32, 1).seq_bias(3.0).cells_float().gen())
- .add("v2_x", GenSpec().map("x", 16, 2).seq_bias(7.0).gen())
- .add("v2_x_f", GenSpec().map("x", 16, 2).seq_bias(7.0).cells_float().gen())
+ .add_variants("v1_x", GenSpec().map("x", 32, 1).seq_bias(3.0))
+ .add_variants("v2_x", GenSpec().map("x", 16, 2).seq_bias(7.0))
.add("v3_y", GenSpec().map("y", 10, 1).gen())
.add("v4_xd", GenSpec().idx("x", 10).gen())
.add("m1_xy", GenSpec().map("x", 32, 1).map("y", 16, 2).seq_bias(3.0).gen())
@@ -53,8 +51,6 @@ TEST(SparseDotProduct, expression_can_be_optimized)
{
assert_optimized("reduce(v1_x*v2_x,sum,x)");
assert_optimized("reduce(v2_x*v1_x,sum)");
- assert_optimized("reduce(v1_x*v2_x_f,sum)");
- assert_optimized("reduce(v1_x_f*v2_x,sum)");
assert_optimized("reduce(v1_x_f*v2_x_f,sum)");
}
@@ -80,6 +76,12 @@ TEST(SparseDotProduct, similar_expressions_are_not_optimized)
assert_not_optimized("reduce(m3_xym*m3_xym,sum)");
}
+TEST(SparseDotProduct, mixed_cell_types_are_not_optimized)
+{
+ assert_not_optimized("reduce(v1_x*v2_x_f,sum)");
+ assert_not_optimized("reduce(v1_x_f*v2_x,sum)");
+}
+
//-----------------------------------------------------------------------------
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp b/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
index 616649e914b..1013c98b424 100644
--- a/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
+++ b/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
@@ -52,16 +52,16 @@ GenSpec DocGen(size_t y_size, size_t z_size) { return GenSpec().cells_float().ma
GenSpec Que() { return QueGen(3, 5); }
GenSpec Doc() { return DocGen(6, 5); }
-GenSpec QueX0() { return QueGen(0, 5); }
-GenSpec DocX0() { return DocGen(0, 5); }
+GenSpec QueEmptyX() { return QueGen(0, 5); }
+GenSpec DocEmptyX() { return DocGen(0, 5); }
-GenSpec QueZ1() { return QueGen(3, 1); }
-GenSpec DocZ1() { return DocGen(6, 1); }
+GenSpec QueTrivialZ() { return QueGen(3, 1); }
+GenSpec DocTrivialZ() { return DocGen(6, 1); }
auto query = Que().gen();
auto document = Doc().gen();
-auto empty_query = QueX0().gen();
-auto empty_document = DocX0().gen();
+auto empty_query = QueEmptyX().gen();
+auto empty_document = DocEmptyX().gen();
TEST(SumMaxDotProduct, expressions_can_be_optimized)
{
@@ -81,8 +81,8 @@ TEST(SumMaxDotProduct, double_cells_are_not_optimized) {
}
TEST(SumMaxDotProduct, trivial_dot_product_is_not_optimized) {
- auto trivial_query = QueZ1().gen();
- auto trivial_document = DocZ1().gen();
+ auto trivial_query = QueTrivialZ().gen();
+ auto trivial_document = DocTrivialZ().gen();
assert_not_optimized(trivial_query, trivial_document);
}
diff --git a/eval/src/tests/streamed/value/streamed_value_test.cpp b/eval/src/tests/streamed/value/streamed_value_test.cpp
index d1b0e0a8d56..7aaa8cdebbc 100644
--- a/eval/src/tests/streamed/value/streamed_value_test.cpp
+++ b/eval/src/tests/streamed/value/streamed_value_test.cpp
@@ -23,9 +23,9 @@ using Handle = SharedStringRepo::Handle;
vespalib::string as_str(string_id label) { return Handle::string_from_id(label); }
-GenSpec G() { return GenSpec().cells_float(); }
+GenSpec G() { return GenSpec(); }
-std::vector<GenSpec> layouts = {
+const std::vector<GenSpec> layouts = {
G(),
G().idx("x", 3),
G().idx("x", 3).idx("y", 5),
@@ -37,7 +37,7 @@ std::vector<GenSpec> layouts = {
G().map("x", {"a","b","c"}).idx("y", 5).map("z", {"i","j","k","l"})
};
-std::vector<GenSpec> join_layouts = {
+const std::vector<GenSpec> join_layouts = {
G(), G(),
G().idx("x", 5), G().idx("x", 5),
G().idx("x", 5), G().idx("y", 5),
@@ -67,7 +67,9 @@ TensorSpec streamed_value_join(const TensorSpec &a, const TensorSpec &b, join_fu
TEST(StreamedValueTest, streamed_values_can_be_converted_from_and_to_tensor_spec) {
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, StreamedValueBuilderFactory::get());
TensorSpec actual = spec_from_value(*value);
EXPECT_EQ(actual, expect);
@@ -77,7 +79,9 @@ TEST(StreamedValueTest, streamed_values_can_be_converted_from_and_to_tensor_spec
TEST(StreamedValueTest, streamed_values_can_be_copied) {
for (const auto &layout: layouts) {
- for (TensorSpec expect : { layout.gen(), layout.cpy().cells_double().gen() }) {
+ for (TensorSpec expect : { layout.cpy().cells_float().gen(),
+ layout.cpy().cells_double().gen() })
+ {
std::unique_ptr<Value> value = value_from_spec(expect, StreamedValueBuilderFactory::get());
std::unique_ptr<Value> copy = StreamedValueBuilderFactory::get().copy(*value);
TensorSpec actual = spec_from_value(*copy);
@@ -124,10 +128,14 @@ GenSpec::seq_t N_16ths = [] (size_t i) noexcept { return (i + 1.0) / 16.0; };
TEST(StreamedValueTest, new_generic_join_works_for_streamed_values) {
ASSERT_TRUE((join_layouts.size() % 2) == 0);
for (size_t i = 0; i < join_layouts.size(); i += 2) {
- const auto l = join_layouts[i].seq(N_16ths);
- const auto r = join_layouts[i + 1].seq(N_16ths);
- for (TensorSpec lhs : { l.gen(), l.cpy().cells_double().gen() }) {
- for (TensorSpec rhs : { r.gen(), r.cpy().cells_double().gen() }) {
+ const auto l = join_layouts[i].cpy().seq(N_16ths);
+ const auto r = join_layouts[i + 1].cpy().seq(N_16ths);
+ for (TensorSpec lhs : { l.cpy().cells_float().gen(),
+ l.cpy().cells_double().gen() })
+ {
+ for (TensorSpec rhs : { r.cpy().cells_float().gen(),
+ r.cpy().cells_double().gen() })
+ {
for (auto fun: {operation::Add::f, operation::Sub::f, operation::Mul::f, operation::Max::f}) {
SCOPED_TRACE(fmt("\n===\nLHS: %s\nRHS: %s\n===\n", lhs.to_string().c_str(), rhs.to_string().c_str()));
auto expect = ReferenceOperations::join(lhs, rhs, fun);
diff --git a/eval/src/vespa/eval/eval/fast_addr_map.h b/eval/src/vespa/eval/eval/fast_addr_map.h
index d8f68d2a37c..7df6bd7fafc 100644
--- a/eval/src/vespa/eval/eval/fast_addr_map.h
+++ b/eval/src/vespa/eval/eval/fast_addr_map.h
@@ -20,9 +20,13 @@ namespace vespalib::eval {
class FastAddrMap
{
public:
- // label hasing functions
- static constexpr uint32_t hash_label(string_id label) { return label.hash(); }
- static constexpr uint32_t hash_label(const string_id *label) { return label->hash(); }
+ // label extracting functions
+ static constexpr string_id self(string_id label) { return label; }
+ static constexpr string_id self(const string_id *label) { return *label; }
+
+ // label hashing functions
+ static constexpr uint32_t hash_label(string_id label) { return label.value(); }
+ static constexpr uint32_t hash_label(const string_id *label) { return label->value(); }
static constexpr uint32_t combine_label_hash(uint32_t full_hash, uint32_t next_hash) {
return ((full_hash * 31) + next_hash);
}
@@ -71,27 +75,27 @@ public:
template <typename T>
constexpr uint32_t operator()(const AltKey<T> &key) const { return key.hash; }
constexpr uint32_t operator()(const Entry &entry) const { return entry.hash; }
+ constexpr uint32_t operator()(string_id label) const { return label.value(); }
};
// equality functor for sparse hash set
struct Equal {
const LabelView &label_view;
Equal(const LabelView &label_view_in) : label_view(label_view_in) {}
- static constexpr bool eq_labels(string_id a, string_id b) { return (a == b); }
- static constexpr bool eq_labels(string_id a, const string_id *b) { return (a == *b); }
template <typename T>
bool operator()(const Entry &a, const AltKey<T> &b) const {
- if ((a.hash != b.hash) || (b.key.size() != label_view.addr_size)) {
+ if (a.hash != b.hash) {
return false;
}
auto a_key = label_view.get_addr(a.tag.idx);
for (size_t i = 0; i < a_key.size(); ++i) {
- if (!eq_labels(a_key[i], b.key[i])) {
+ if (a_key[i] != self(b.key[i])) {
return false;
}
}
return true;
}
+ bool operator()(const Entry &a, string_id b) const { return (a.hash == b.value()); }
};
using HashType = hashtable<Entry, Entry, Hash, Equal, Identity, hashtable_base::and_modulator>;
@@ -101,8 +105,8 @@ private:
HashType _map;
public:
- FastAddrMap(size_t num_mapped_dims, const std::vector<string_id> &labels, size_t expected_subspaces)
- : _labels(num_mapped_dims, labels),
+ FastAddrMap(size_t num_mapped_dims, const std::vector<string_id> &labels_in, size_t expected_subspaces)
+ : _labels(num_mapped_dims, labels_in),
_map(expected_subspaces * 2, Hash(), Equal(_labels)) {}
~FastAddrMap();
FastAddrMap(const FastAddrMap &) = delete;
@@ -113,15 +117,24 @@ public:
ConstArrayRef<string_id> get_addr(size_t idx) const { return _labels.get_addr(idx); }
size_t size() const { return _map.size(); }
constexpr size_t addr_size() const { return _labels.addr_size; }
+ const std::vector<string_id> &labels() const { return _labels.labels; }
template <typename T>
size_t lookup(ConstArrayRef<T> addr, uint32_t hash) const {
+ // assert(addr_size() == addr.size());
AltKey<T> key{addr, hash};
auto pos = _map.find(key);
return (pos == _map.end()) ? npos() : pos->tag.idx;
}
+ size_t lookup_singledim(string_id addr) const {
+ // assert(addr_size() == 1);
+ auto pos = _map.find(addr);
+ return (pos == _map.end()) ? npos() : pos->tag.idx;
+ }
template <typename T>
size_t lookup(ConstArrayRef<T> addr) const {
- return lookup(addr, hash_labels(addr));
+ return (addr.size() == 1)
+ ? lookup_singledim(self(addr[0]))
+ : lookup(addr, hash_labels(addr));
}
void add_mapping(uint32_t hash) {
uint32_t idx = _map.size();
diff --git a/eval/src/vespa/eval/eval/fast_value.hpp b/eval/src/vespa/eval/eval/fast_value.hpp
index 5657c93f53f..88319df7590 100644
--- a/eval/src/vespa/eval/eval/fast_value.hpp
+++ b/eval/src/vespa/eval/eval/fast_value.hpp
@@ -6,6 +6,7 @@
#include <vespa/eval/instruction/generic_join.h>
#include <vespa/vespalib/stllike/hashtable.hpp>
#include <vespa/vespalib/util/shared_string_repo.h>
+#include <typeindex>
namespace vespalib::eval {
@@ -135,9 +136,9 @@ struct FastIterateView : public Value::Index::View {
//-----------------------------------------------------------------------------
using JoinAddrSource = instruction::SparseJoinPlan::Source;
+
// This is the class instructions will look for when optimizing sparse
// operations by calling inline functions directly.
-
struct FastValueIndex final : Value::Index {
FastAddrMap map;
FastValueIndex(size_t num_mapped_dims_in, const std::vector<string_id> &labels, size_t expected_subspaces_in)
@@ -164,6 +165,18 @@ struct FastValueIndex final : Value::Index {
std::unique_ptr<View> create_view(const std::vector<size_t> &dims) const override;
};
+inline bool is_fast(const Value::Index &index) {
+ return (std::type_index(typeid(index)) == std::type_index(typeid(FastValueIndex)));
+}
+
+inline bool are_fast(const Value::Index &a, const Value::Index &b) {
+ return (is_fast(a) && is_fast(b));
+}
+
+constexpr const FastValueIndex &as_fast(const Value::Index &index) {
+ return static_cast<const FastValueIndex &>(index);
+}
+
//-----------------------------------------------------------------------------
template <typename T>
diff --git a/eval/src/vespa/eval/instruction/sparse_dot_product_function.cpp b/eval/src/vespa/eval/instruction/sparse_dot_product_function.cpp
index 93ae2856372..7cc4417bdbb 100644
--- a/eval/src/vespa/eval/instruction/sparse_dot_product_function.cpp
+++ b/eval/src/vespa/eval/instruction/sparse_dot_product_function.cpp
@@ -2,8 +2,8 @@
#include "sparse_dot_product_function.h"
#include "generic_join.h"
-#include "detect_type.h"
#include <vespa/eval/eval/fast_value.hpp>
+#include <vespa/vespalib/util/typify.h>
namespace vespalib::eval {
@@ -13,62 +13,76 @@ using namespace instruction;
namespace {
-template <typename SCT, typename BCT>
-double my_fast_sparse_dot_product(const FastValueIndex &small_idx, const FastValueIndex &big_idx,
- const SCT *small_cells, const BCT *big_cells)
+template <typename CT>
+double my_sparse_dot_product_fallback(const Value::Index &lhs_idx, const Value::Index &rhs_idx,
+ const CT *lhs_cells, const CT *rhs_cells, size_t num_mapped_dims) __attribute__((noinline));
+template <typename CT>
+double my_sparse_dot_product_fallback(const Value::Index &lhs_idx, const Value::Index &rhs_idx,
+ const CT *lhs_cells, const CT *rhs_cells, size_t num_mapped_dims)
{
double result = 0.0;
- small_idx.map.each_map_entry([&](auto small_subspace, auto hash) {
- auto small_addr = small_idx.map.get_addr(small_subspace);
- auto big_subspace = big_idx.map.lookup(small_addr, hash);
- if (big_subspace != FastAddrMap::npos()) {
- result += (small_cells[small_subspace] * big_cells[big_subspace]);
- }
- });
+ SparseJoinPlan plan(num_mapped_dims);
+ SparseJoinState sparse(plan, lhs_idx, rhs_idx);
+ auto outer = sparse.first_index.create_view({});
+ auto inner = sparse.second_index.create_view(sparse.second_view_dims);
+ outer->lookup({});
+ while (outer->next_result(sparse.first_address, sparse.first_subspace)) {
+ inner->lookup(sparse.address_overlap);
+ if (inner->next_result(sparse.second_only_address, sparse.second_subspace)) {
+ result += (lhs_cells[sparse.lhs_subspace] * rhs_cells[sparse.rhs_subspace]);
+ }
+ }
return result;
}
-template <typename LCT, typename RCT>
-void my_sparse_dot_product_op(InterpretedFunction::State &state, uint64_t num_mapped_dims) {
- const auto &lhs_idx = state.peek(1).index();
- const auto &rhs_idx = state.peek(0).index();
- const LCT *lhs_cells = state.peek(1).cells().typify<LCT>().cbegin();
- const RCT *rhs_cells = state.peek(0).cells().typify<RCT>().cbegin();
- if (auto indexes = detect_type<FastValueIndex>(lhs_idx, rhs_idx)) {
-#if __has_cpp_attribute(likely)
- [[likely]];
-#endif
- const auto &lhs_fast = indexes.get<0>();
- const auto &rhs_fast = indexes.get<1>();
- double result = (rhs_fast.map.size() < lhs_fast.map.size())
- ? my_fast_sparse_dot_product(rhs_fast, lhs_fast, rhs_cells, lhs_cells)
- : my_fast_sparse_dot_product(lhs_fast, rhs_fast, lhs_cells, rhs_cells);
- state.pop_pop_push(state.stash.create<ScalarValue<double>>(result));
- } else {
-#if __has_cpp_attribute(unlikely)
- [[unlikely]];
-#endif
- double result = 0.0;
- SparseJoinPlan plan(num_mapped_dims);
- SparseJoinState sparse(plan, lhs_idx, rhs_idx);
- auto outer = sparse.first_index.create_view({});
- auto inner = sparse.second_index.create_view(sparse.second_view_dims);
- outer->lookup({});
- while (outer->next_result(sparse.first_address, sparse.first_subspace)) {
- inner->lookup(sparse.address_overlap);
- if (inner->next_result(sparse.second_only_address, sparse.second_subspace)) {
- result += (lhs_cells[sparse.lhs_subspace] * rhs_cells[sparse.rhs_subspace]);
+template <typename CT, bool single_dim>
+double my_fast_sparse_dot_product(const FastAddrMap *small_map, const FastAddrMap *big_map,
+ const CT *small_cells, const CT *big_cells)
+{
+ double result = 0.0;
+ if (big_map->size() < small_map->size()) {
+ std::swap(small_map, big_map);
+ std::swap(small_cells, big_cells);
+ }
+ if constexpr (single_dim) {
+ const auto &labels = small_map->labels();
+ for (size_t i = 0; i < labels.size(); ++i) {
+ auto big_subspace = big_map->lookup_singledim(labels[i]);
+ if (big_subspace != FastAddrMap::npos()) {
+ result += (small_cells[i] * big_cells[big_subspace]);
}
}
- state.pop_pop_push(state.stash.create<ScalarValue<double>>(result));
+ } else {
+ small_map->each_map_entry([&](auto small_subspace, auto hash) {
+ auto small_addr = small_map->get_addr(small_subspace);
+ auto big_subspace = big_map->lookup(small_addr, hash);
+ if (big_subspace != FastAddrMap::npos()) {
+ result += (small_cells[small_subspace] * big_cells[big_subspace]);
+ }
+ });
}
+ return result;
+}
+
+template <typename CT, bool single_dim>
+void my_sparse_dot_product_op(InterpretedFunction::State &state, uint64_t num_mapped_dims) {
+ const auto &lhs_idx = state.peek(1).index();
+ const auto &rhs_idx = state.peek(0).index();
+ const CT *lhs_cells = state.peek(1).cells().typify<CT>().cbegin();
+ const CT *rhs_cells = state.peek(0).cells().typify<CT>().cbegin();
+ double result = __builtin_expect(are_fast(lhs_idx, rhs_idx), true)
+ ? my_fast_sparse_dot_product<CT,single_dim>(&as_fast(lhs_idx).map, &as_fast(rhs_idx).map, lhs_cells, rhs_cells)
+ : my_sparse_dot_product_fallback<CT>(lhs_idx, rhs_idx, lhs_cells, rhs_cells, num_mapped_dims);
+ state.pop_pop_push(state.stash.create<ScalarValue<double>>(result));
}
struct MyGetFun {
- template <typename LCT, typename RCT>
- static auto invoke() { return my_sparse_dot_product_op<LCT,RCT>; }
+ template <typename CT, typename SINGLE_DIM>
+ static auto invoke() { return my_sparse_dot_product_op<CT,SINGLE_DIM::value>; }
};
+using MyTypify = TypifyValue<TypifyCellType,TypifyBool>;
+
} // namespace <unnamed>
SparseDotProductFunction::SparseDotProductFunction(const TensorFunction &lhs_in,
@@ -80,15 +94,18 @@ SparseDotProductFunction::SparseDotProductFunction(const TensorFunction &lhs_in,
InterpretedFunction::Instruction
SparseDotProductFunction::compile_self(const ValueBuilderFactory &, Stash &) const
{
- auto op = typify_invoke<2,TypifyCellType,MyGetFun>(lhs().result_type().cell_type(), rhs().result_type().cell_type());
- return InterpretedFunction::Instruction(op, lhs().result_type().count_mapped_dimensions());
+ size_t num_dims = lhs().result_type().count_mapped_dimensions();
+ auto op = typify_invoke<2,MyTypify,MyGetFun>(lhs().result_type().cell_type(),
+ (num_dims == 1));
+ return InterpretedFunction::Instruction(op, num_dims);
}
bool
SparseDotProductFunction::compatible_types(const ValueType &res, const ValueType &lhs, const ValueType &rhs)
{
return (res.is_scalar() && (res.cell_type() == CellType::DOUBLE) &&
- lhs.is_sparse() && (rhs.dimensions() == lhs.dimensions()));
+ lhs.is_sparse() && (rhs.dimensions() == lhs.dimensions()) &&
+ lhs.cell_type() == rhs.cell_type());
}
const TensorFunction &
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 1f2927663df..075166e4759 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -74,7 +74,7 @@ public class Flags {
public static final UnboundStringFlag RESPONSE_SEQUENCER_TYPE = defineStringFlag(
"response-sequencer-type", "ADAPTIVE",
- List.of("baldersheim"), "2020-12-02", "2021-02-01",
+ List.of("baldersheim"), "2020-12-02", "2022-01-01",
"Selects type of sequenced executor used for mbus responses, valid values are LATENCY, ADAPTIVE, THROUGHPUT",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
@@ -109,25 +109,11 @@ public class Flags {
public static final UnboundBooleanFlag USE_THREE_PHASE_UPDATES = defineFeatureFlag(
"use-three-phase-updates", false,
- List.of("vekterli"), "2020-12-02", "2021-02-01",
+ List.of("vekterli"), "2020-12-02", "2021-03-01",
"Whether to enable the use of three-phase updates when bucket replicas are out of sync.",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
- public static final UnboundBooleanFlag USE_FAST_VALUE_TENSOR_IMPLEMENTATION = defineFeatureFlag(
- "use-fast-value-tensor-implementation", false,
- List.of("geirst"), "2020-12-02", "2021-02-01",
- "Whether to use FastValueBuilderFactory as the tensor implementation on all content nodes.",
- "Takes effect at restart of content node process",
- ZONE_ID, APPLICATION_ID);
-
- public static final UnboundBooleanFlag TCP_ABORT_ON_OVERFLOW = defineFeatureFlag(
- "tcp-abort-on-overflow", false,
- List.of("andreer"), "2020-12-02", "2021-02-01",
- "Whether to set /proc/sys/net/ipv4/tcp_abort_on_overflow to 0 (false) or 1 (true)",
- "Takes effect on next host-admin tick.",
- HOSTNAME);
-
public static final UnboundStringFlag TLS_FOR_ZOOKEEPER_CLIENT_SERVER_COMMUNICATION = defineStringFlag(
"tls-for-zookeeper-client-server-communication", "OFF",
List.of("hmusum"), "2020-12-02", "2021-04-01",
@@ -183,14 +169,6 @@ public class Flags {
ZONE_ID
);
- public static final UnboundIntFlag TENANT_NODE_QUOTA = defineIntFlag(
- "tenant-node-quota", 5,
- List.of("andreer"), "2020-12-02", "2021-02-01",
- "The number of nodes a tenant is allowed to request per cluster",
- "Only takes effect on next deployment, if set to a value other than the default for flag!",
- APPLICATION_ID
- );
-
public static final UnboundBooleanFlag ONLY_PUBLIC_ACCESS = defineFeatureFlag(
"enable-public-only", false,
List.of("ogronnesby"), "2020-12-02", "2021-02-01",
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index 96bce8b71d4..05c20ee69f1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -17,10 +17,7 @@ import com.yahoo.config.provision.ProvisionLogger;
import com.yahoo.config.provision.Provisioner;
import com.yahoo.config.provision.Zone;
import com.yahoo.transaction.Mutex;
-import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
-import com.yahoo.vespa.flags.IntFlag;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
@@ -59,7 +56,6 @@ public class NodeRepositoryProvisioner implements Provisioner {
private final Activator activator;
private final Optional<LoadBalancerProvisioner> loadBalancerProvisioner;
private final NodeResourceLimits nodeResourceLimits;
- private final IntFlag tenantNodeQuota;
@Inject
public NodeRepositoryProvisioner(NodeRepository nodeRepository, Zone zone,
@@ -76,7 +72,6 @@ public class NodeRepositoryProvisioner implements Provisioner {
provisionServiceProvider.getHostProvisioner(),
loadBalancerProvisioner);
this.activator = new Activator(nodeRepository, loadBalancerProvisioner);
- this.tenantNodeQuota = Flags.TENANT_NODE_QUOTA.bindTo(flagSource);
}
@@ -92,10 +87,6 @@ public class NodeRepositoryProvisioner implements Provisioner {
if (cluster.group().isPresent()) throw new IllegalArgumentException("Node requests cannot specify a group");
- if ( ! hasQuota(application, requested.maxResources().nodes()))
- throw new IllegalArgumentException(requested + " requested for " + cluster +
- ". Max value exceeds your quota. Resolve this at https://cloud.vespa.ai/pricing");
-
nodeResourceLimits.ensureWithinAdvertisedLimits("Min", requested.minResources().nodeResources(), cluster);
nodeResourceLimits.ensureWithinAdvertisedLimits("Max", requested.maxResources().nodeResources(), cluster);
@@ -194,15 +185,6 @@ public class NodeRepositoryProvisioner implements Provisioner {
", downscaling to " + actualNodes + " nodes in " + zone.environment());
}
- private boolean hasQuota(ApplicationId application, int requestedNodes) {
- if ( ! this.zone.system().isPublic()) return true; // no quota management
-
- if (application.tenant().value().hashCode() == 3857) return requestedNodes <= 60;
- if (application.tenant().value().hashCode() == -1271827001) return requestedNodes <= 75;
-
- return requestedNodes <= tenantNodeQuota.with(FetchVector.Dimension.APPLICATION_ID, application.tenant().value()).value();
- }
-
private List<HostSpec> asSortedHosts(List<Node> nodes, NodeResources requestedResources) {
nodes.sort(Comparator.comparingInt(node -> node.allocation().get().membership().index()));
List<HostSpec> hosts = new ArrayList<>(nodes.size());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
index cbac5a39e09..be7d2656d13 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java
@@ -633,35 +633,6 @@ public class ProvisioningTest {
}
@Test
- public void out_of_quota() {
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(SystemName.Public,
- Environment.prod,
- RegionName.from("us-east"))).build();
-
- tester.makeReadyHosts(13, defaultResources).activateTenantHosts();
- ApplicationId application = ProvisioningTester.applicationId();
- try {
- prepare(application, 2, 2, 6, 3, defaultResources, tester);
- fail("Expected exception");
- }
- catch (IllegalArgumentException e) {
- assertEquals("6 nodes with [vcpu: 1.0, memory: 4.0 Gb, disk 10.0 Gb, bandwidth: 4.0 Gbps] requested for content cluster 'content0' 6.42. Max value exceeds your quota. Resolve this at https://cloud.vespa.ai/pricing",
- e.getMessage());
- }
- }
-
- @Test
- public void no_out_of_quota_outside_public() {
- ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(SystemName.main,
- Environment.prod,
- RegionName.from("us-east"))).build();
-
- tester.makeReadyHosts(13, defaultResources).activateTenantHosts();
- ApplicationId application = ProvisioningTester.applicationId();
- prepare(application, 2, 2, 6, 3, defaultResources, tester);
- }
-
- @Test
public void out_of_capacity_but_cannot_fail() {
ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build();
tester.makeReadyHosts(4, defaultResources).activateTenantHosts();
diff --git a/persistence/src/vespa/persistence/dummyimpl/dummy_bucket_executor.h b/persistence/src/vespa/persistence/dummyimpl/dummy_bucket_executor.h
index b832cb6c02c..2479787eb31 100644
--- a/persistence/src/vespa/persistence/dummyimpl/dummy_bucket_executor.h
+++ b/persistence/src/vespa/persistence/dummyimpl/dummy_bucket_executor.h
@@ -18,7 +18,7 @@ public:
DummyBucketExecutor(size_t numExecutors);
~DummyBucketExecutor() override;
std::unique_ptr<BucketTask> execute(const Bucket & bucket, std::unique_ptr<BucketTask> task) override;
- void sync() override;
+ void sync();
private:
std::unique_ptr<vespalib::SyncableThreadExecutor> _executor;
std::mutex _lock;
diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp
index 0865500d3c0..305f1c81192 100644
--- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp
+++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp
@@ -866,14 +866,10 @@ DummyPersistence::register_resource_usage_listener(IResourceUsageListener &liste
namespace {
-class SyncExecutorOnDestruction : public vespalib::IDestructorCallback {
+class ExecutorRegistration : public vespalib::IDestructorCallback {
public:
- explicit SyncExecutorOnDestruction(std::shared_ptr<BucketExecutor> executor) : _executor(std::move(executor)) { }
- ~SyncExecutorOnDestruction() override {
- if (_executor) {
- _executor->sync();
- }
- }
+ explicit ExecutorRegistration(std::shared_ptr<BucketExecutor> executor) : _executor(std::move(executor)) { }
+ ~ExecutorRegistration() override = default;
private:
std::shared_ptr<BucketExecutor> _executor;
};
@@ -885,7 +881,7 @@ DummyPersistence::register_executor(std::shared_ptr<BucketExecutor> executor)
{
assert(_bucket_executor.expired());
_bucket_executor = executor;
- return std::make_unique<SyncExecutorOnDestruction>(executor);
+ return std::make_unique<ExecutorRegistration>(executor);
}
std::string
diff --git a/persistence/src/vespa/persistence/spi/bucketexecutor.h b/persistence/src/vespa/persistence/spi/bucketexecutor.h
index 8237b78cca0..d1ada30959e 100644
--- a/persistence/src/vespa/persistence/spi/bucketexecutor.h
+++ b/persistence/src/vespa/persistence/spi/bucketexecutor.h
@@ -29,7 +29,6 @@ public:
struct BucketExecutor {
virtual ~BucketExecutor() = default;
virtual std::unique_ptr<BucketTask> execute(const Bucket & bucket, std::unique_ptr<BucketTask> task) = 0;
- virtual void sync() = 0;
};
}
diff --git a/searchcore/src/tests/proton/documentdb/lid_space_compaction/lid_space_jobtest.h b/searchcore/src/tests/proton/documentdb/lid_space_compaction/lid_space_jobtest.h
index fd1cf7fb5a8..dd2760022c2 100644
--- a/searchcore/src/tests/proton/documentdb/lid_space_compaction/lid_space_jobtest.h
+++ b/searchcore/src/tests/proton/documentdb/lid_space_compaction/lid_space_jobtest.h
@@ -5,8 +5,9 @@
#include <vespa/persistence/spi/bucketexecutor.h>
#include <vespa/vespalib/gtest/gtest.h>
+namespace storage::spi::dummy { class DummyBucketExecutor; }
struct JobTestBase : public ::testing::TestWithParam<bool> {
- std::unique_ptr<storage::spi::BucketExecutor> _bucketExecutor;
+ std::unique_ptr<storage::spi::dummy::DummyBucketExecutor> _bucketExecutor;
std::unique_ptr<vespalib::SyncableThreadExecutor> _singleExecutor;
std::unique_ptr<searchcorespi::index::IThreadService> _master;
std::shared_ptr<MyHandler> _handler;
@@ -54,7 +55,7 @@ struct JobTest : public JobTestBase {
std::unique_ptr<IMaintenanceJobRunner> _jobRunner;
JobTest();
- ~JobTest();
+ ~JobTest() override;
void init(uint32_t allowedLidBloat,
double allowedLidBloatFactor,
double resourceLimitFactor = RESOURCE_LIMIT_FACTOR,
@@ -68,7 +69,7 @@ struct JobTest : public JobTestBase {
class JobDisabledByRemoveOpsTest : public JobTest {
public:
JobDisabledByRemoveOpsTest();
- ~JobDisabledByRemoveOpsTest();
+ ~JobDisabledByRemoveOpsTest() override;
void job_is_disabled_while_remove_ops_are_ongoing(bool remove_batch);
void job_becomes_disabled_if_remove_ops_starts(bool remove_batch);
@@ -80,7 +81,7 @@ struct MyCountJobRunner;
struct MaxOutstandingJobTest : public JobTest {
std::unique_ptr<MyCountJobRunner> runner;
MaxOutstandingJobTest();
- ~MaxOutstandingJobTest();
+ ~MaxOutstandingJobTest() override;
void init(uint32_t maxOutstandingMoveOps);
void assertRunToBlocked();
void assertRunToNotBlocked();
diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
index b188b97404d..d92a945a42a 100644
--- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
+++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp
@@ -741,14 +741,10 @@ PersistenceEngine::getWLock() const
namespace {
-class SyncExecutorOnDestruction : public vespalib::IDestructorCallback {
+class ExecutorRegistration : public vespalib::IDestructorCallback {
public:
- explicit SyncExecutorOnDestruction(std::shared_ptr<BucketExecutor> executor) : _executor(std::move(executor)) { }
- ~SyncExecutorOnDestruction() override {
- if (_executor) {
- _executor->sync();
- }
- }
+ explicit ExecutorRegistration(std::shared_ptr<BucketExecutor> executor) : _executor(std::move(executor)) { }
+ ~ExecutorRegistration() override = default;
private:
std::shared_ptr<BucketExecutor> _executor;
};
@@ -760,7 +756,7 @@ PersistenceEngine::register_executor(std::shared_ptr<BucketExecutor> executor)
{
assert(_bucket_executor.expired());
_bucket_executor = executor;
- return std::make_unique<SyncExecutorOnDestruction>(executor);
+ return std::make_unique<ExecutorRegistration>(executor);
}
std::unique_ptr<BucketTask>
@@ -772,11 +768,4 @@ PersistenceEngine::execute(const storage::spi::Bucket &bucket, std::unique_ptr<B
return task;
}
-void PersistenceEngine::sync() {
- auto bucketExecutor = get_bucket_executor();
- if (bucketExecutor) {
- bucketExecutor->sync();
- }
-}
-
} // storage
diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h
index 77dfc74d765..f1f680f63f6 100644
--- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h
+++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.h
@@ -130,7 +130,6 @@ public:
WriteGuard getWLock() const;
ResourceUsageTracker &get_resource_usage_tracker() noexcept { return *_resource_usage_tracker; }
std::unique_ptr<BucketTask> execute(const Bucket &bucket, std::unique_ptr<BucketTask> task) override;
- void sync() override;
};
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.cpp b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.cpp
index d3dae686d2d..3987282ef34 100644
--- a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.cpp
@@ -130,6 +130,9 @@ LidSpaceCompactionJobBase::run()
}
if (_scanItr && !_scanItr->valid()) {
+ if (!inSync()) {
+ return false;
+ }
if (shouldRestartScanDocuments(_handler->getLidStatus())) {
_scanItr = _handler->getIterator();
} else {
diff --git a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.h b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.h
index 759a18361f7..e91502f766c 100644
--- a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.h
+++ b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_base.h
@@ -50,6 +50,7 @@ private:
void compactLidSpace(const search::LidUsageStats &stats);
bool remove_batch_is_ongoing() const;
bool remove_is_ongoing() const;
+ virtual bool inSync() const { return true; }
protected:
search::DocumentMetaData getNextDocument(const search::LidUsageStats &stats, bool retryLastDocument);
public:
diff --git a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.cpp b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.cpp
index cbf3de20b1f..acb81ef6976 100644
--- a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.cpp
@@ -11,6 +11,7 @@
#include <vespa/vespalib/util/destructor_callbacks.h>
#include <vespa/vespalib/util/lambdatask.h>
#include <cassert>
+#include <thread>
using search::DocumentMetaData;
using search::LidUsageStats;
@@ -34,19 +35,30 @@ CompactionJob::scanDocuments(const LidUsageStats &stats)
moveDocument(meta, std::make_shared<DoneContext>(std::make_pair(std::move(opsTracker), std::move(onDone))));
}));
if (failed) return false;
+ _startedCount.fetch_add(1, std::memory_order_relaxed);
if (isBlocked(BlockedReason::OUTSTANDING_OPS)) {
return true;
}
}
}
- if (!_scanItr->valid()) {
- sync();
- }
return false;
}
+namespace {
+ class IncOnDestruct {
+ public:
+ IncOnDestruct(std::atomic<size_t> & count) : _count(count) {}
+ ~IncOnDestruct() {
+ _count.fetch_add(1, std::memory_order_relaxed);
+ }
+ private:
+ std::atomic<size_t> & _count;
+ };
+}
void
CompactionJob::moveDocument(const search::DocumentMetaData & meta, std::shared_ptr<IDestructorCallback> context) {
+ IncOnDestruct countGuard(_executedCount);
+ if (_stopped.load(std::memory_order_relaxed)) return;
// The real lid must be sampled in the master thread.
//TODO remove target lid from createMoveOperation interface
auto op = _handler->createMoveOperation(meta, 0);
@@ -55,6 +67,7 @@ CompactionJob::moveDocument(const search::DocumentMetaData & meta, std::shared_p
if (meta.gid != op->getDocument()->getId().getGlobalId()) return;
_master.execute(makeLambdaTask([this, metaThen=meta, moveOp=std::move(op), onDone=std::move(context)]() {
+ if (_stopped.load(std::memory_order_relaxed)) return;
search::DocumentMetaData metaNow = _handler->getMetaData(metaThen.lid);
if (metaNow.lid != metaThen.lid) return;
if (metaNow.bucketId != metaThen.bucketId) return;
@@ -82,20 +95,25 @@ CompactionJob::CompactionJob(const DocumentDBLidSpaceCompactionConfig &config,
blockableConfig, clusterStateChangedNotifier, nodeRetired),
_master(master),
_bucketExecutor(bucketExecutor),
- _bucketSpace(bucketSpace)
-{
-}
+ _bucketSpace(bucketSpace),
+ _stopped(false),
+ _startedCount(0),
+ _executedCount(0)
+{ }
CompactionJob::~CompactionJob() = default;
-void
-CompactionJob::sync() {
- _bucketExecutor.sync();
+bool
+CompactionJob::inSync() const {
+ return _executedCount == _startedCount;
}
void
CompactionJob::onStop() {
- sync();
+ _stopped = true;
+ while ( ! inSync() ) {
+ std::this_thread::sleep_for(1ms);
+ }
}
} // namespace proton
diff --git a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.h b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.h
index 053950ebd2f..65b847d0468 100644
--- a/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.h
+++ b/searchcore/src/vespa/searchcore/proton/server/lid_space_compaction_job_take2.h
@@ -4,8 +4,9 @@
#include "lid_space_compaction_job_base.h"
#include <vespa/document/bucket/bucketspace.h>
+#include <atomic>
-namespace storage::spi { struct BucketExecutor;}
+namespace storage::spi { struct BucketExecutor; }
namespace searchcorespi::index { struct IThreadService; }
namespace vespalib { class IDestructorCallback; }
namespace proton {
@@ -28,11 +29,14 @@ private:
IThreadService & _master;
BucketExecutor &_bucketExecutor;
document::BucketSpace _bucketSpace;
+ std::atomic<bool> _stopped;
+ std::atomic<size_t> _startedCount;
+ std::atomic<size_t> _executedCount;
bool scanDocuments(const search::LidUsageStats &stats) override;
void moveDocument(const search::DocumentMetaData & meta, std::shared_ptr<IDestructorCallback> onDone);
void onStop() override;
- void sync();
+ bool inSync() const override;
public:
CompactionJob(const DocumentDBLidSpaceCompactionConfig &config,
std::shared_ptr<ILidSpaceCompactionHandler> handler,
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
index c71a7fee424..7c175686359 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormanager.cpp
@@ -49,10 +49,6 @@ public:
return _executor.execute(bucket, std::move(task));
}
- void sync() override {
- _executor.sync();
- }
-
private:
spi::BucketExecutor & _executor;
};
@@ -990,8 +986,4 @@ FileStorManager::execute(const spi::Bucket &bucket, std::unique_ptr<spi::BucketT
return task;
}
-void
-FileStorManager::sync() {
-}
-
} // storage
diff --git a/storage/src/vespa/storage/persistence/filestorage/filestormanager.h b/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
index 6eaef45e9bd..a48b4e0e208 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
+++ b/storage/src/vespa/storage/persistence/filestorage/filestormanager.h
@@ -175,7 +175,6 @@ private:
void update_reported_state_after_db_init();
std::unique_ptr<spi::BucketTask> execute(const spi::Bucket &bucket, std::unique_ptr<spi::BucketTask> task) override;
- void sync() override;
};
} // storage
diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
index daad1f8fb4b..02968352f0c 100644
--- a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
+++ b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java
@@ -88,7 +88,7 @@ public abstract class Maintainer implements Runnable {
try (var lock = jobControl.lockJob(name())) {
if (maintain()) jobMetrics.recordSuccessOf(name());
} catch (Throwable e) {
- log.log(Level.WARNING, this + " failed. Will retry in " + interval.toMinutes() + " minutes", e);
+ log.log(Level.WARNING, this + " failed. Will retry in " + interval, e);
} finally {
jobMetrics.forward(name());
}
diff --git a/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp b/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp
index 4c3c32c2326..97c767a17ed 100644
--- a/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp
+++ b/vespalib/src/tests/shared_string_repo/shared_string_repo_test.cpp
@@ -361,6 +361,8 @@ TEST("require that basic handle usage works") {
TEST_DO(verify_not_eq(empty, bar));
TEST_DO(verify_not_eq(foo, bar));
+ EXPECT_EQUAL(empty.id().hash(), 0u);
+ EXPECT_EQUAL(empty.id().value(), 0u);
EXPECT_TRUE(empty.id() == string_id());
EXPECT_TRUE(empty2.id() == string_id());
EXPECT_EQUAL(empty.as_string(), vespalib::string(""));
@@ -415,9 +417,11 @@ TEST("require that handle can be self-assigned") {
//-----------------------------------------------------------------------------
-void verify_direct(const vespalib::string &str) {
+void verify_direct(const vespalib::string &str, size_t value) {
size_t before = SharedStringRepo::stats().active_entries;
Handle handle(str);
+ EXPECT_EQUAL(handle.id().hash(), value + 1);
+ EXPECT_EQUAL(handle.id().value(), value + 1);
EXPECT_EQUAL(SharedStringRepo::stats().active_entries, before);
EXPECT_EQUAL(handle.as_string(), str);
}
@@ -425,14 +429,15 @@ void verify_direct(const vespalib::string &str) {
void verify_not_direct(const vespalib::string &str) {
size_t before = SharedStringRepo::stats().active_entries;
Handle handle(str);
+ EXPECT_EQUAL(handle.id().hash(), handle.id().value());
EXPECT_EQUAL(SharedStringRepo::stats().active_entries, before + 1);
EXPECT_EQUAL(handle.as_string(), str);
}
TEST("require that direct handles work as expected") {
- TEST_DO(verify_direct(""));
+ TEST_DO(verify_direct("", -1));
for (size_t i = 0; i < 100000; ++i) {
- verify_direct(fmt("%zu", i));
+ verify_direct(fmt("%zu", i), i);
}
TEST_DO(verify_not_direct(" "));
TEST_DO(verify_not_direct(" 5"));
diff --git a/vespalib/src/vespa/vespalib/util/string_id.h b/vespalib/src/vespa/vespalib/util/string_id.h
index 3e608c9d339..371caf8bf95 100644
--- a/vespalib/src/vespa/vespalib/util/string_id.h
+++ b/vespalib/src/vespa/vespalib/util/string_id.h
@@ -31,6 +31,7 @@ public:
constexpr string_id &operator=(const string_id &) noexcept = default;
constexpr string_id &operator=(string_id &&) noexcept = default;
constexpr uint32_t hash() const noexcept { return _id; }
+ constexpr uint32_t value() const noexcept { return _id; }
// NB: not lexical sorting order, but can be used in maps
constexpr bool operator<(const string_id &rhs) const noexcept { return (_id < rhs._id); }
constexpr bool operator==(const string_id &rhs) const noexcept { return (_id == rhs._id); }