summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--application/pom.xml30
-rw-r--r--cloud-tenant-base-dependencies-enforcer/pom.xml9
-rw-r--r--config-model/src/main/java/com/yahoo/schema/processing/TensorFieldProcessor.java13
-rw-r--r--config-model/src/test/java/com/yahoo/schema/processing/TensorFieldTestCase.java18
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/CloudAccount.java23
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java4
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/FileReferenceDoesNotExistException.java (renamed from fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileReferenceDoesNotExistException.java)4
-rw-r--r--container-core/pom.xml93
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java16
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java2
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java23
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java29
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java10
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java58
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java10
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java23
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java13
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java31
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java6
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java6
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java8
-rw-r--r--container-core/src/main/java/com/yahoo/metrics/ContainerMetrics.java45
-rw-r--r--container-core/src/main/java/com/yahoo/metrics/Unit.java4
-rw-r--r--container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def3
-rw-r--r--container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def3
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java4
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java2
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java6
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java18
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java1
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java19
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java19
-rw-r--r--container-dev/pom.xml20
-rw-r--r--container-test/pom.xml20
-rw-r--r--fat-model-dependencies/pom.xml4
-rw-r--r--fileacquirer/abi-spec.json11
-rw-r--r--fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirer.java1
-rw-r--r--fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirerImpl.java21
-rw-r--r--fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/MockFileAcquirer.java1
-rw-r--r--fileacquirer/src/test/java/MockFileAcquirerTest.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java90
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java83
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java40
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacity.java12
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java29
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java14
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java2
-rw-r--r--parent/pom.xml27
-rw-r--r--screwdriver.yaml1
-rw-r--r--searchcore/src/tests/proton/matching/index_environment/index_environment_test.cpp20
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/indexenvironment.cpp4
-rw-r--r--searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp31
-rw-r--r--searchlib/src/vespa/searchlib/attribute/address_space_components.cpp1
-rw-r--r--searchlib/src/vespa/searchlib/attribute/address_space_components.h1
-rw-r--r--searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp3
-rw-r--r--searchlib/src/vespa/searchlib/tensor/hnsw_nodeid_mapping.h2
-rw-r--r--vespa-dependencies-enforcer/allowed-maven-dependencies.txt34
-rw-r--r--vespalib/src/tests/coro/async_io/async_io_test.cpp86
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreeaggregator.h2
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreeinserter.h2
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreeiterator.h20
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreenodeallocator.h2
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreenodestore.h2
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreeremover.h4
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreerootbase.h2
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreestore.h6
-rw-r--r--vespalib/src/vespa/vespalib/btree/minmaxaggregated.h2
-rw-r--r--vespalib/src/vespa/vespalib/coro/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/coro/async_crypto_socket.cpp261
-rw-r--r--vespalib/src/vespa/vespalib/coro/async_crypto_socket.h31
-rw-r--r--vespalib/src/vespa/vespalib/coro/async_io.h6
-rw-r--r--vespalib/src/vespa/vespalib/coro/generator.h6
-rw-r--r--vespalib/src/vespa/vespalib/data/slime/external_memory.h2
-rw-r--r--vespalib/src/vespa/vespalib/data/smart_buffer.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_btree_dictionary_read_snapshot.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h4
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_value_filter.h2
-rw-r--r--vespalib/src/vespa/vespalib/geo/zcurve.h6
-rw-r--r--vespalib/src/vespa/vespalib/net/selector.h4
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hashtable.h2
-rw-r--r--vespalib/src/vespa/vespalib/test/datastore/buffer_stats.h4
-rw-r--r--vespalib/src/vespa/vespalib/util/benchmark_timer.h6
-rw-r--r--vespalib/src/vespa/vespalib/util/binary_hamming_distance.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/exceptions.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/mmap_file_allocator.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/mmap_file_allocator_factory.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/thread_bundle.h2
-rw-r--r--vespalog/src/test/bufferedlogskiptest.cpp2
-rw-r--r--vespalog/src/test/bufferedlogtest.cpp2
-rw-r--r--vespalog/src/vespa/log/bufferedlogger.h32
-rw-r--r--vespalog/src/vespa/log/log.cpp33
-rw-r--r--vespalog/src/vespa/log/log.h150
104 files changed, 1156 insertions, 656 deletions
diff --git a/application/pom.xml b/application/pom.xml
index d1aea1d6a78..d404cb9bbf5 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -133,8 +133,8 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -146,35 +146,43 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
- <scope>test</scope>
+ <artifactId>jetty-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
- <scope>test</scope>
+ <artifactId>jetty-util</artifactId>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
+ </dependency>
+ <!-- END JETTY embedded jars -->
+
+ <dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
@@ -184,8 +192,6 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
- <!-- END JETTY embedded jars -->
-
</dependencies>
<build>
diff --git a/cloud-tenant-base-dependencies-enforcer/pom.xml b/cloud-tenant-base-dependencies-enforcer/pom.xml
index 78178c9f5dc..3dc0f370e53 100644
--- a/cloud-tenant-base-dependencies-enforcer/pom.xml
+++ b/cloud-tenant-base-dependencies-enforcer/pom.xml
@@ -44,8 +44,7 @@
<javax.servlet-api.version>3.1.0</javax.servlet-api.version>
<javax.ws.rs-api.version>2.0.1</javax.ws.rs-api.version>
<jaxb.version>2.3.0</jaxb.version>
- <jetty.version>9.4.49.v20220914</jetty.version>
- <jetty-alpn.version>1.1.3.v20160715</jetty-alpn.version>
+ <jetty.version>11.0.13</jetty.version>
<org.lz4.version>1.8.0</org.lz4.version>
<org.json.version>20220320</org.json.version> <!-- TODO: Remove on Vespa 9 -->
<slf4j.version>1.7.32</slf4j.version> <!-- WARNING: when updated, also update c.y.v.tenant:base pom -->
@@ -206,22 +205,20 @@
<include>org.bouncycastle:bcpkix-jdk18on:${bouncycastle.version}:test</include>
<include>org.bouncycastle:bcprov-jdk18on:${bouncycastle.version}:test</include>
<include>org.bouncycastle:bcutil-jdk18on:${bouncycastle.version}:test</include>
- <include>org.eclipse.jetty.alpn:alpn-api:jar:${jetty-alpn.version}:test</include>
<include>org.eclipse.jetty.http2:http2-common:${jetty.version}:test</include>
<include>org.eclipse.jetty.http2:http2-hpack:${jetty.version}:test</include>
<include>org.eclipse.jetty.http2:http2-server:${jetty.version}:test</include>
+ <include>org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api:5.0.2:test</include>
+ <include>org.eclipse.jetty:jetty-alpn-client:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-alpn-java-server:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-alpn-server:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-client:${jetty.version}:test</include>
- <include>org.eclipse.jetty:jetty-continuation:jar:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-http:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-io:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-jmx:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-security:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-server:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-servlet:${jetty.version}:test</include>
- <include>org.eclipse.jetty:jetty-servlets:jar:${jetty.version}:test</include>
- <include>org.eclipse.jetty:jetty-util-ajax:jar:${jetty.version}:test</include>
<include>org.eclipse.jetty:jetty-util:${jetty.version}:test</include>
<include>org.hamcrest:hamcrest-core:1.3:test</include>
diff --git a/config-model/src/main/java/com/yahoo/schema/processing/TensorFieldProcessor.java b/config-model/src/main/java/com/yahoo/schema/processing/TensorFieldProcessor.java
index e0ce9917179..37da07f8227 100644
--- a/config-model/src/main/java/com/yahoo/schema/processing/TensorFieldProcessor.java
+++ b/config-model/src/main/java/com/yahoo/schema/processing/TensorFieldProcessor.java
@@ -44,17 +44,26 @@ public class TensorFieldProcessor extends Processor {
private void validateIndexingScripsForTensorField(SDField field) {
if (field.doesIndexing() && !isTensorTypeThatSupportsHnswIndex(field)) {
fail(schema, field, "A tensor of type '" + tensorTypeToString(field) + "' does not support having an 'index'. " +
- "Currently, only tensors with 1 indexed dimension supports that.");
+ "Currently, only tensors with 1 indexed dimension or 1 mapped + 1 indexed dimension support that.");
}
}
private boolean isTensorTypeThatSupportsHnswIndex(ImmutableSDField field) {
var type = ((TensorDataType)field.getDataType()).getTensorType();
- // Tensors with 1 indexed dimension supports a hnsw index (used for approximate nearest neighbor search).
+ // Tensors with 1 indexed dimension support hnsw index (used for approximate nearest neighbor search).
if ((type.dimensions().size() == 1) &&
type.dimensions().get(0).isIndexed()) {
return true;
}
+ // Tensors with 1 mapped + 1 indexed dimension support hnsw index (aka multiple vectors per document).
+ if (type.dimensions().size() == 2) {
+ var a = type.dimensions().get(0);
+ var b = type.dimensions().get(1);
+ if ((a.isMapped() && b.isIndexed()) ||
+ (a.isIndexed() && b.isMapped())) {
+ return true;
+ }
+ }
return false;
}
diff --git a/config-model/src/test/java/com/yahoo/schema/processing/TensorFieldTestCase.java b/config-model/src/test/java/com/yahoo/schema/processing/TensorFieldTestCase.java
index 60e1e35fb2e..b7817900dac 100644
--- a/config-model/src/test/java/com/yahoo/schema/processing/TensorFieldTestCase.java
+++ b/config-model/src/test/java/com/yahoo/schema/processing/TensorFieldTestCase.java
@@ -35,7 +35,7 @@ public class TensorFieldTestCase {
}
catch (IllegalArgumentException e) {
assertEquals("For schema 'test', field 'f1': A tensor of type 'tensor(x{})' does not support having an 'index'. " +
- "Currently, only tensors with 1 indexed dimension supports that.",
+ "Currently, only tensors with 1 indexed dimension or 1 mapped + 1 indexed dimension support that.",
e.getMessage());
}
}
@@ -86,6 +86,12 @@ public class TensorFieldTestCase {
}
@Test
+ void tensor_with_one_mapped_and_one_indexed_dimension_can_have_hnsw_index() throws ParseException {
+ assertHnswIndexParams("tensor(x{},y[64])", "", 16, 200);
+ assertHnswIndexParams("tensor(x[64],y{})", "", 16, 200);
+ }
+
+ @Test
void hnsw_index_parameters_can_be_specified() throws ParseException {
assertHnswIndexParams("index { hnsw { max-links-per-node: 32 } }", 32, 200);
assertHnswIndexParams("index { hnsw { neighbors-to-explore-at-insert: 300 } }", 16, 300);
@@ -157,7 +163,11 @@ public class TensorFieldTestCase {
}
private void assertHnswIndexParams(String indexSpec, int maxLinksPerNode, int neighborsToExploreAtInsert) throws ParseException {
- var sd = getSdWithIndexSpec(indexSpec);
+ assertHnswIndexParams("tensor(x[64])", indexSpec, maxLinksPerNode, neighborsToExploreAtInsert);
+ }
+
+ private void assertHnswIndexParams(String tensorType, String indexSpec, int maxLinksPerNode, int neighborsToExploreAtInsert) throws ParseException {
+ var sd = getSdWithIndexSpec(tensorType, indexSpec);
var search = createFromString(sd).getSchema();
var attr = search.getAttribute("t1");
var params = attr.hnswIndexParams();
@@ -166,8 +176,8 @@ public class TensorFieldTestCase {
assertEquals(neighborsToExploreAtInsert, params.get().neighborsToExploreAtInsert());
}
- private String getSdWithIndexSpec(String indexSpec) {
- return getSd(joinLines("field t1 type tensor(x[64]) {",
+ private String getSdWithIndexSpec(String tensorType, String indexSpec) {
+ return getSd(joinLines("field t1 type " + tensorType + " {",
" indexing: attribute | index",
" " + indexSpec,
"}"));
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/CloudAccount.java b/config-provisioning/src/main/java/com/yahoo/config/provision/CloudAccount.java
index 974e5203e76..215afbca255 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/CloudAccount.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/CloudAccount.java
@@ -2,6 +2,7 @@
package com.yahoo.config.provision;
import ai.vespa.validation.PatternedStringWrapper;
+import ai.vespa.validation.Validation;
import java.util.regex.Pattern;
@@ -14,11 +15,23 @@ public class CloudAccount extends PatternedStringWrapper<CloudAccount> {
private static final String EMPTY = "";
private static final String AWS_ACCOUNT_ID = "[0-9]{12}";
+ private static final Pattern AWS_ACCOUNT_ID_PATTERN = Pattern.compile(AWS_ACCOUNT_ID);
private static final String GCP_PROJECT_ID = "[a-z][a-z0-9-]{4,28}[a-z0-9]";
+ private static final Pattern GCP_PROJECT_ID_PATTERN = Pattern.compile(GCP_PROJECT_ID);
/** Empty value. When this is used, either implicitly or explicitly, the zone will use its default account */
public static final CloudAccount empty = new CloudAccount("", EMPTY, "cloud account");
+ /** Verifies accountId is a valid AWS account ID, or throw an IllegalArgumentException. */
+ public static void requireAwsAccountId(String accountId) {
+ Validation.requireMatch(accountId, "AWS account ID", AWS_ACCOUNT_ID_PATTERN);
+ }
+
+ /** Verifies accountId is a valid GCP project ID, or throw an IllegalArgumentException. */
+ public static void requireGcpProjectId(String projectId) {
+ Validation.requireMatch(projectId, "GCP project ID", GCP_PROJECT_ID_PATTERN);
+ }
+
private CloudAccount(String value, String regex, String description) {
super(value, Pattern.compile("^(" + regex + ")$"), description);
}
@@ -34,6 +47,16 @@ public class CloudAccount extends PatternedStringWrapper<CloudAccount> {
!equals(zone.cloud().account());
}
+ /** Verifies this account is a valid AWS account ID, or throw an IllegalArgumentException. */
+ public void requireAwsAccountId() {
+ requireAwsAccountId(value());
+ }
+
+ /** Verifies this account is a valid GCP project ID, or throw an IllegalArgumentException. */
+ public void requireGcpProjectId() {
+ requireGcpProjectId(value());
+ }
+
public static CloudAccount from(String cloudAccount) {
return switch (cloudAccount) {
// Tenants are allowed to specify "default" in services.xml.
diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
index 1e90f3974a5..3705c167960 100644
--- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
+++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java
@@ -10,7 +10,6 @@ import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.Type;
-
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -21,7 +20,6 @@ import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Logger;
@@ -60,6 +58,8 @@ public class ConfigPayloadApplier<T extends ConfigInstance.Builder> {
stack.push(new NamedBuilder(rootBuilder));
try {
handleValue(payload.getSlime().get());
+ } catch (FileReferenceDoesNotExistException e) {
+ throw e;
} catch (Exception e) {
throw new RuntimeException("Not able to create config builder for payload '" + payload.toString() + "'", e);
}
diff --git a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileReferenceDoesNotExistException.java b/config/src/main/java/com/yahoo/vespa/config/FileReferenceDoesNotExistException.java
index 95aa07d14a7..b8767e6deb1 100644
--- a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileReferenceDoesNotExistException.java
+++ b/config/src/main/java/com/yahoo/vespa/config/FileReferenceDoesNotExistException.java
@@ -1,5 +1,5 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.filedistribution.fileacquirer;
+package com.yahoo.vespa.config;
/**
* @author Tony Vaagenes
@@ -8,7 +8,7 @@ public class FileReferenceDoesNotExistException extends RuntimeException {
public final String fileReference;
- FileReferenceDoesNotExistException(String fileReference) {
+ public FileReferenceDoesNotExistException(String fileReference) {
super("Could not retrieve file with file reference '" + fileReference + "'");
this.fileReference = fileReference;
}
diff --git a/container-core/pom.xml b/container-core/pom.xml
index bdcaab3900b..2b1d2253534 100644
--- a/container-core/pom.xml
+++ b/container-core/pom.xml
@@ -14,6 +14,7 @@
<artifactId>container-core</artifactId>
<version>8-SNAPSHOT</version>
<packaging>container-plugin</packaging>
+
<dependencies>
<!-- COMPILE scope -->
@@ -139,40 +140,119 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
+ <!-- Required for JDK9ServerALPNProcessor through ServiceLoader API -->
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</dependency>
<!-- END JETTY embedded jars -->
@@ -281,11 +361,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<scope>provided</scope>
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java b/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
index 47ff229cc7b..57fbd5eb96c 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
@@ -3,9 +3,9 @@ package com.yahoo.container.jdisc.utils;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.yolean.Exceptions;
-import org.eclipse.jetty.http.MultiPartFormInputStream;
+import jakarta.servlet.http.Part;
+import org.eclipse.jetty.server.MultiPartFormInputStream;
-import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java b/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
index b194124294c..c2faa1cd10a 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
@@ -2,7 +2,7 @@
package com.yahoo.jdisc.http;
import org.eclipse.jetty.http.HttpCookie;
-import org.eclipse.jetty.server.CookieCutter;
+import org.eclipse.jetty.server.Cookies;
import java.util.Arrays;
import java.util.HashSet;
@@ -180,7 +180,7 @@ public class Cookie {
}
public static List<Cookie> fromCookieHeader(String headerVal) {
- CookieCutter cookieCutter = new CookieCutter();
+ Cookies cookieCutter = new Cookies();
cookieCutter.addCookieField(headerVal);
return Arrays.stream(cookieCutter.getCookies())
.map(servletCookie -> {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java b/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
index 598a924b327..4ad38a9f965 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
@@ -8,15 +8,14 @@ import com.yahoo.jdisc.handler.ContentChannel;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.service.CurrentContainer;
-import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.UrlEncoded;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.security.Principal;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -116,15 +115,10 @@ public class HttpRequest extends Request {
}
private static Map<String, List<String>> getUriQueryParameters(URI uri) {
- MultiMap<String> queryParameters = new MultiMap<>();
- new HttpURI(uri).decodeQueryTo(queryParameters);
-
- // Do a deep copy so we do not leak Jetty classes outside
- Map<String, List<String>> deepCopiedQueryParameters = new HashMap<>();
- for (Map.Entry<String, List<String>> entry : queryParameters.entrySet()) {
- deepCopiedQueryParameters.put(entry.getKey(), new ArrayList<>(entry.getValue()));
- }
- return deepCopiedQueryParameters;
+ if (uri.getRawQuery() == null) return Map.of();
+ MultiMap<String> params = new MultiMap<>();
+ UrlEncoded.decodeUtf8To(uri.getRawQuery(), params);
+ return Map.copyOf(params);
}
public Method getMethod() {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
index 13a63efeaa9..5b51eeee7d6 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
@@ -8,6 +8,7 @@ import com.yahoo.container.logging.RequestLog;
import com.yahoo.container.logging.RequestLogEntry;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.ServerConfig;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.http2.HTTP2Stream;
import org.eclipse.jetty.http2.server.HttpTransportOverHTTP2;
import org.eclipse.jetty.server.HttpChannel;
@@ -16,7 +17,6 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
-import javax.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
index 6282e334409..f2118008af3 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
@@ -9,6 +9,8 @@ import com.yahoo.jdisc.http.ssl.impl.DefaultConnectorSsl;
import com.yahoo.security.tls.MixedMode;
import com.yahoo.security.tls.TransportSecurityUtils;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http.HttpCompliance;
+import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
@@ -137,8 +139,17 @@ public class ConnectorFactory {
httpConfig.setOutputBufferSize(connectorConfig.outputBufferSize());
httpConfig.setRequestHeaderSize(connectorConfig.requestHeaderSize());
httpConfig.setResponseHeaderSize(connectorConfig.responseHeaderSize());
+
+ // Disable use of ByteBuffer.allocateDirect()
+ httpConfig.setUseInputDirectByteBuffers(false);
+ httpConfig.setUseOutputDirectByteBuffers(false);
+
+ httpConfig.setHttpCompliance(HttpCompliance.RFC7230);
+ // TODO Vespa 9 Use default URI compliance (LEGACY == old Jetty 9.4 compliance)
+ httpConfig.setUriCompliance(UriCompliance.LEGACY);
if (isSslEffectivelyEnabled(connectorConfig)) {
- httpConfig.addCustomizer(new SecureRequestCustomizer());
+ // Explicitly disable SNI checking as Jetty's SNI checking trust manager is not part of our SSLContext trust manager chain
+ httpConfig.addCustomizer(new SecureRequestCustomizer(false, false, -1, false));
}
String serverNameFallback = connectorConfig.serverName().fallback();
if (!serverNameFallback.isBlank()) httpConfig.setServerAuthority(new HostPort(serverNameFallback));
@@ -169,12 +180,14 @@ public class ConnectorFactory {
}
private SslConnectionFactory newSslConnectionFactory(Metric metric, ConnectionFactory wrappedFactory) {
- SslConnectionFactory connectionFactory = new SslConnectionFactory(createSslContextFactory(), wrappedFactory.getProtocol());
- connectionFactory.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort()));
- return connectionFactory;
+ var fac = new SslConnectionFactory(createSslContextFactory(), wrappedFactory.getProtocol());
+ fac.setDirectBuffersForDecryption(false);
+ fac.setDirectBuffersForDecryption(false);
+ fac.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort()));
+ return fac;
}
- private SslContextFactory createSslContextFactory() {
+ private SslContextFactory.Server createSslContextFactory() {
DefaultConnectorSsl ssl = new DefaultConnectorSsl();
sslProvider.configureSsl(ssl, connectorConfig.name(), connectorConfig.listenPort());
return ssl.createSslContextFactory();
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
index ac50cbbb518..342d7ab9c4a 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
@@ -4,14 +4,24 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.security.SslContextBuilder;
+import com.yahoo.security.TrustAllX509TrustManager;
import com.yahoo.security.tls.TransportSecurityOptions;
import com.yahoo.security.tls.TransportSecurityUtils;
-import com.yahoo.security.TrustAllX509TrustManager;
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.ProxyProtocolClientConnectionFactory;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.DetectorConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SslConnectionFactory;
@@ -19,14 +29,6 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import javax.net.ssl.SSLContext;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
@@ -89,7 +91,7 @@ class HealthCheckProxyHandler extends HandlerWrapper {
Optional.ofNullable(targetConnector.getConnectionFactory(SslConnectionFactory.class))
.or(() -> Optional.ofNullable(targetConnector.getConnectionFactory(DetectorConnectionFactory.class))
.map(detectorConnFactory -> detectorConnFactory.getBean(SslConnectionFactory.class)))
- .map(connFactory -> (SslContextFactory.Server) connFactory.getSslContextFactory())
+ .map(SslConnectionFactory::getSslContextFactory)
.orElseThrow(() -> new IllegalArgumentException("Health check proxy can only target https port"));
boolean proxyProtocol = targetConnector.connectorConfig().proxyProtocol().enabled();
return new ProxyTarget(targetPort, clientTimeout,handlerTimeout, cacheExpiry, sslContextFactory, proxyProtocol);
@@ -269,13 +271,14 @@ class HealthCheckProxyHandler extends HandlerWrapper {
synchronized (this) {
if (client == null) {
int timeoutMillis = (int) clientTimeout.toMillis();
- SslContextFactory.Client clientSsl = new SslContextFactory.Client();
+ var clientSsl = new SslContextFactory.Client();
clientSsl.setHostnameVerifier((__, ___) -> true);
clientSsl.setSslContext(getSslContext(serverSsl));
- HttpClient client = new HttpClient(clientSsl);
+ var connector = new ClientConnector();
+ connector.setSslContextFactory(clientSsl);
+ HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(connector));
client.setMaxConnectionsPerDestination(4);
client.setConnectTimeout(timeoutMillis);
- client.setStopTimeout(timeoutMillis);
client.setIdleTimeout(timeoutMillis);
client.setUserAgentField(new HttpField(HttpHeader.USER_AGENT, "health-check-proxy-client"));
client.start();
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
index 9292e2024df..b4c933c1168 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
@@ -12,6 +12,11 @@ import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpRequest;
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
@@ -20,11 +25,6 @@ import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Callback;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
index 8a298fb3268..d45a8789e4c 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
@@ -3,10 +3,10 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.service.CurrentContainer;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Utf8Appendable;
-import javax.servlet.http.HttpServletRequest;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.cert.X509Certificate;
@@ -94,6 +94,6 @@ class HttpRequestFactory {
}
private static X509Certificate[] getCertChain(HttpServletRequest servletRequest) {
- return (X509Certificate[]) servletRequest.getAttribute("javax.servlet.request.X509Certificate");
+ return (X509Certificate[]) servletRequest.getAttribute(RequestUtils.SERVLET_REQUEST_X509CERT);
}
}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
index 3fb81cb5352..81789881b68 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
@@ -4,6 +4,11 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.ServerConfig;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.AsyncContextEvent;
@@ -11,14 +16,8 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpChannelState;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.component.Graceful;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -27,12 +26,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.ObjLongConsumer;
import java.util.stream.Collectors;
@@ -49,7 +46,7 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
static final String requestTypeAttribute = "requestType";
- private final AtomicReference<FutureCallback> shutdown = new AtomicReference<>();
+ private final Shutdown shutdown;
private final List<String> monitoringHandlerPaths;
private final List<String> searchHandlerPaths;
private final Set<String> ignoredUserAgents;
@@ -66,6 +63,10 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
this.monitoringHandlerPaths = monitoringHandlerPaths;
this.searchHandlerPaths = searchHandlerPaths;
this.ignoredUserAgents = Set.copyOf(ignoredUserAgents);
+ this.shutdown = new Shutdown(this) {
+ @Override public boolean isShutdownDone() { return inFlight.get() == 0; }
+ };
+
}
private final AsyncListener completionWatcher = new AsyncListener() {
@@ -97,7 +98,7 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
try {
Handler handler = getHandler();
- if (handler != null && shutdown.get() == null && isStarted()) {
+ if (handler != null && !shutdown.isShutdown() && isStarted()) {
handler.handle(path, baseRequest, request, response);
} else if ( ! baseRequest.isHandled()) {
baseRequest.setHandled(true);
@@ -129,14 +130,9 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
.increment());
}
long live = inFlight.decrementAndGet();
- FutureCallback shutdownCb = shutdown.get();
- if (shutdownCb != null) {
- if (flushableResponse != null) {
- flushableResponse.flushBuffer();
- }
- if (live == 0) {
- shutdownCb.succeeded();
- }
+ if (shutdown.isShutdown()) {
+ if (flushableResponse != null) flushableResponse.flushBuffer();
+ if (live == 0) shutdown.check();
}
}
@@ -162,35 +158,19 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
@Override
protected void doStart() throws Exception {
- shutdown.set(null);
+ shutdown.cancel();
super.doStart();
}
@Override
protected void doStop() throws Exception {
+ shutdown.cancel();
super.doStop();
- FutureCallback shutdownCb = shutdown.get();
- if ( ! shutdownCb.isDone()) {
- shutdownCb.failed(new TimeoutException());
- }
}
- @Override
- public Future<Void> shutdown() {
- FutureCallback shutdownCb = new FutureCallback(false);
- shutdown.compareAndSet(null, shutdownCb);
- shutdownCb = shutdown.get();
- if (inFlight.get() == 0) {
- shutdownCb.succeeded();
- }
- return shutdownCb;
- }
+ @Override public CompletableFuture<Void> shutdown() { return shutdown.shutdown(); }
+ @Override public boolean isShutdown() { return shutdown.isShutdown(); }
- @Override
- public boolean isShutdown() {
- FutureCallback futureCallback = shutdown.get();
- return futureCallback != null && futureCallback.isDone();
- }
static class Dimensions {
final String protocol;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
index 4b4aff0a9bd..bd052f14867 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
@@ -5,13 +5,13 @@ import com.yahoo.container.logging.AccessLogEntry;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.handler.OverloadException;
import com.yahoo.jdisc.http.HttpRequest.Method;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
-import javax.servlet.ServletException;
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
index b3069a64821..b17877cee84 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
@@ -3,16 +3,13 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
-import org.eclipse.jetty.http.HttpCompliance;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.io.ConnectionStatistics;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
-import javax.servlet.ServletRequest;
-import javax.servlet.http.HttpServletRequest;
-import java.net.Socket;
-import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -26,8 +23,6 @@ class JDiscServerConnector extends ServerConnector {
private final Metric.Context metricCtx;
private final ConnectionStatistics statistics;
private final ConnectorConfig config;
- private final boolean tcpKeepAlive;
- private final boolean tcpNoDelay;
private final Metric metric;
private final String connectorName;
private final int listenPort;
@@ -36,14 +31,13 @@ class JDiscServerConnector extends ServerConnector {
ConnectionMetricAggregator connectionMetricAggregator, ConnectionFactory... factories) {
super(server, factories);
this.config = config;
- this.tcpKeepAlive = config.tcpKeepAliveEnabled();
- this.tcpNoDelay = config.tcpNoDelay();
this.metric = metric;
this.connectorName = config.name();
this.listenPort = config.listenPort();
this.metricCtx = metric.createContext(createConnectorDimensions(listenPort, connectorName, 0));
this.statistics = new ConnectionStatistics();
+ setAcceptedTcpNoDelay(config.tcpNoDelay());
addBean(statistics);
ConnectorConfig.Throttling throttlingConfig = config.throttling();
if (throttlingConfig.enabled()) {
@@ -56,17 +50,6 @@ class JDiscServerConnector extends ServerConnector {
setAcceptQueueSize(config.acceptQueueSize());
setReuseAddress(config.reuseAddress());
setIdleTimeout((long) (config.idleTimeout() * 1000));
- addBean(HttpCompliance.RFC7230);
- }
-
- @Override
- protected void configure(final Socket socket) {
- super.configure(socket);
- try {
- socket.setKeepAlive(tcpKeepAlive);
- socket.setTcpNoDelay(tcpNoDelay);
- } catch (SocketException ignored) {
- }
}
public ConnectionStatistics getStatistics() {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
index 53d8698c417..6406125dcc3 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
@@ -30,6 +30,7 @@ import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.StandardConstants;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
@@ -113,7 +114,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
info.setProxyProtocolVersion("v2");
}
if (connection.getEndPoint() instanceof ProxyConnectionFactory.ProxyEndPoint) {
- InetSocketAddress remoteAddress = connection.getEndPoint().getRemoteAddress();
+ var remoteAddress = connection.getEndPoint().getRemoteSocketAddress();
info.setRemoteAddress(remoteAddress);
}
});
@@ -243,7 +244,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
private long httpBytesSent = 0;
private long requests = 0;
private long responses = 0;
- private InetSocketAddress remoteAddress;
+ private SocketAddress remoteAddress;
private byte[] sslSessionId;
private String sslProtocol;
private String sslCipherSuite;
@@ -290,7 +291,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
synchronized ConnectionInfo incrementResponses() { ++this.responses; return this; }
- synchronized ConnectionInfo setRemoteAddress(InetSocketAddress remoteAddress) {
+ synchronized ConnectionInfo setRemoteAddress(SocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
@@ -354,9 +355,9 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
builder.withLocalAddress(localAddress.getHostString())
.withLocalPort(localAddress.getPort());
}
- if (remoteAddress != null) {
- builder.withRemoteAddress(remoteAddress.getHostString())
- .withRemotePort(remoteAddress.getPort());
+ if (remoteAddress instanceof InetSocketAddress isa) {
+ builder.withRemoteAddress(isa.getHostString())
+ .withRemotePort(isa.getPort());
}
if (sslProtocol != null && sslCipherSuite != null && sslSessionId != null) {
builder.withSslProtocol(sslProtocol)
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 775c903f5f8..7b723b3a48e 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -27,8 +27,6 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHttpOutputInterceptor;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.log.JavaUtilLog;
-import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import javax.management.remote.JMXServiceURL;
@@ -70,8 +68,6 @@ public class JettyHttpServer extends AbstractServerProvider {
if (connectorFactories.allComponents().isEmpty())
throw new IllegalArgumentException("No connectors configured.");
- initializeJettyLogging();
-
server = new Server();
server.setStopTimeout((long)(serverConfig.stopTimeout() * 1000.0));
server.setRequestLog(new AccessLogRequestLog(requestLog, serverConfig.accessLog()));
@@ -96,15 +92,6 @@ public class JettyHttpServer extends AbstractServerProvider {
this.metricsReporter = new ServerMetricReporter(metric, server);
}
- private static void initializeJettyLogging() {
- // Note: Jetty is logging stderr if no logger is explicitly configured
- try {
- Log.setLog(new JavaUtilLog());
- } catch (Exception e) {
- throw new RuntimeException("Unable to initialize logging framework for Jetty");
- }
- }
-
private static void setupJmx(Server server, ServerConfig serverConfig) {
if (serverConfig.jmx().enabled()) {
System.setProperty("java.rmi.server.hostname", "localhost");
@@ -152,7 +139,7 @@ public class JettyHttpServer extends AbstractServerProvider {
}
StatisticsHandler root = newGenericStatisticsHandler();
addChainToRoot(root, List.of(
- newResponseStatisticsHandler(serverCfg), newGzipHandler(serverCfg), perConnectorHandlers));
+ newResponseStatisticsHandler(serverCfg), newGzipHandler(), perConnectorHandlers));
return root;
}
@@ -253,22 +240,18 @@ public class JettyHttpServer extends AbstractServerProvider {
return statisticsHandler;
}
- private static GzipHandler newGzipHandler(ServerConfig serverConfig) {
- GzipHandler gzipHandler = new GzipHandlerWithVaryHeaderFixed();
- gzipHandler.setCompressionLevel(serverConfig.responseCompressionLevel());
- gzipHandler.setInflateBufferSize(8 * 1024);
- gzipHandler.setIncludedMethods("GET", "POST", "PUT", "PATCH");
- return gzipHandler;
- }
+ private static GzipHandler newGzipHandler() { return new GzipHandlerWithVaryHeaderFixed(); }
/** A subclass which overrides Jetty's default behavior of including user-agent in the vary field */
private static class GzipHandlerWithVaryHeaderFixed extends GzipHandler {
- @Override
- public HttpField getVaryField() {
- return GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING;
+ GzipHandlerWithVaryHeaderFixed() {
+ setInflateBufferSize(8 * 1024);
+ setIncludedMethods("GET", "POST", "PUT", "PATCH");
}
+ @Override public HttpField getVaryField() { return GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING; }
+
}
}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
index 1bc862bc787..da4de957739 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
@@ -1,12 +1,12 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.http.server.jetty;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
-
-import javax.servlet.http.HttpServletRequest;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
/**
* @author bjorncs
@@ -15,7 +15,7 @@ public class RequestUtils {
public static final String JDISC_REQUEST_X509CERT = "jdisc.request.X509Certificate";
public static final String JDISC_REQUEST_CHAIN = "jdisc.request.chain";
public static final String JDISC_RESPONSE_CHAIN = "jdisc.response.chain";
- public static final String SERVLET_REQUEST_X509CERT = "javax.servlet.request.X509Certificate";
+ public static final String SERVLET_REQUEST_X509CERT = SecureRequestCustomizer.JAKARTA_SERVLET_REQUEST_X_509_CERTIFICATE;
// The local port as reported by servlet spec. This will be influenced by Host header and similar mechanisms.
// The request URI uses the local listen port as the URI is used for handler routing/bindings.
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
index 4b66715fcf7..d853282a5f5 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
@@ -2,9 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.handler.CompletionHandler;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
index 3703878f595..2f2c48e0b48 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
@@ -3,10 +3,10 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.handler.CompletionHandler;
import com.yahoo.jdisc.handler.ContentChannel;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Objects;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
index e90dde0e4eb..6afb55f5b13 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
@@ -9,10 +9,10 @@ import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpResponse;
import com.yahoo.jdisc.service.BindingSetNotFoundException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.MimeTypes;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
index b420aabc598..96f0cdebd62 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
@@ -3,13 +3,13 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.ConnectorConfig;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
-import javax.servlet.DispatcherType;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
diff --git a/container-core/src/main/java/com/yahoo/metrics/ContainerMetrics.java b/container-core/src/main/java/com/yahoo/metrics/ContainerMetrics.java
index 01108ff36e9..5c2f1c1be79 100644
--- a/container-core/src/main/java/com/yahoo/metrics/ContainerMetrics.java
+++ b/container-core/src/main/java/com/yahoo/metrics/ContainerMetrics.java
@@ -62,7 +62,50 @@ public enum ContainerMetrics {
MEM_DIRECT_COUNT("mem.direct.count", Unit.BYTE, "Number of direct memory allocations"),
MEM_NATIVE_TOTAL("mem.native.total", Unit.BYTE, "Total available native memory"),
MEM_NATIVE_FREE("mem.native.free", Unit.BYTE, "Currently free native memory"),
- MEM_NATIVE_USED("mem.native.used", Unit.BYTE, "Native memory currently used");
+ MEM_NATIVE_USED("mem.native.used", Unit.BYTE, "Native memory currently used"),
+
+
+ // SearchChain metrics
+ PEAK_QPS("peak_qps", Unit.OPERATION_PER_SECOND, "The highest number of qps for a second for this metrics shapshot"),
+ SEARCH_CONNECTIONS("search_connections", Unit.CONNECTION, "Number of search connections"),
+ FEED_LATENCY("feed.latency", Unit.MILLISECOND, "Feed latency"),
+ FEED_HTTP_REQUESTS("feed.http-requests", Unit.OPERATION, "Feed HTTP requests"),
+ QUERIES("queries", Unit.OPERATION, "Query volume"),
+ QUERY_CONTAINER_LATENCY("query_container_latency", Unit.MILLISECOND, "The query execution time consumed in the container"),
+ QUERY_LATENCY("query_latency", Unit.MILLISECOND, "The overall query latency as seen by the container"),
+ QUERY_TIMEOUT("query_timeout", Unit.MILLISECOND, "The amount of time allowed for query execytion, from the client"),
+ FAILED_QUERIES("failed_queries", Unit.OPERATION, "The number of failed queries"),
+ DEGRADED_QUERIES("degraded_queries", Unit.OPERATION, "The number of degraded queries, e.g. due to some conent nodes not responding in time"),
+ HITS_PER_QUERY("hits_per_query", Unit.HIT, "The number of hits returned"),
+ QUERY_HIT_OFFSET("query_hit_offset", Unit.HIT, "The offset for hits returned"),
+ DOCUMENTS_COVERED("documents_covered", Unit.DOCUMENT, "The combined number of documents considered during query evaluation"),
+ DOCUMENTS_TOTAL("documents_total", Unit.DOCUMENT, "The number of documents to be evaluated if all requests had been fully executed"),
+ DOCUMENTS_TARGET_TOTAL("documents_target_total", Unit.DOCUMENT, "The target number of total documents to be evaluated when when all data is in sync"),
+ JDISC_RENDER_LATENCY("jdisc.render.latency", Unit.MILLISECOND, "The time used by the container to render responses"),
+ QUERY_ITEM_COUNT("query_item_count", Unit.QUERY_ITEM, "The number of query items (terms, phrases, etc)"),
+
+ TOTAL_HITS_PER_QUERY("totalhits_per_query", Unit.HIT, "The total number of documents found to match queries"),
+ EMPTY_RESULTS("empty_results", Unit.OPERATION, "Number of queries matching no documents"),
+ REQUESTS_OVER_QUOTA("requestsOverQuota", Unit.OPERATION, "The number of requests rejected due to exceeding quota"),
+
+ RELEVANCE_AT_1("relevance.at_1", Unit.RELEVANCE, "The relevance of hit number 1"),
+ RELEVANCE_AT_3("relevance.at_3", Unit.RELEVANCE, "The relevance of hit number 3"),
+ RELEVANCE_AT_10("relevance.at_10", Unit.RELEVANCE, "The relevance of hit number 10"),
+
+ // Errors from search container
+ ERROR_TIMEOUT("error.timeout", Unit.OPERATION, "Requests that timed out"),
+ ERROR_BACKENDS_OOS("error.backends_oos", Unit.OPERATION, "Requests that failed due to no available backends nodes"),
+ ERROR_PLUGIN_FAILURE("error.plugin_failure", Unit.OPERATION, "Requests that failed due to plugin failure"),
+ ERROR_BACKEND_COMMUNICATION_ERROR("error.backend_communication_error", Unit.OPERATION, "Requests that failed due to backend communication error"),
+ ERROR_EMPTY_DOCUMENT_SUMMARIES("error.empty_document_summaries", Unit.OPERATION, "Requests that failed due to missing document summaries"),
+ ERROR_INVALID_QUERY_PARAMETER("error.invalid_query_parameter", Unit.OPERATION, "Requests that failed due to invalid query parameters"),
+ ERROR_INTERNAL_SERVER_ERROR("error.internal_server_error", Unit.OPERATION, "Requests that failed due to internal server error"),
+ ERROR_MISCONFIGURED_SERVER("error.misconfigured_server", Unit.OPERATION, "Requests that failed due to misconfigured server"),
+ ERROR_INVALID_QUERY_TRANSFORMATION("error.invalid_query_transformation", Unit.OPERATION, "Requests that failed due to invalid query transformation"),
+ ERROR_RESULTS_WITH_ERRORS("error.results_with_errors", Unit.OPERATION, "The number of queries with error payload"),
+ ERROR_UNSPECIFIED("error.unspecified", Unit.OPERATION, "Requests that failed for an unspecified reason"),
+ ERROR_UNHANDLED_EXCEPTION("error.unhandled_exception", Unit.OPERATION, "Requests that failed due to an unhandled exception");
+
private final String name;
private final Unit unit;
diff --git a/container-core/src/main/java/com/yahoo/metrics/Unit.java b/container-core/src/main/java/com/yahoo/metrics/Unit.java
index d69b8446bd5..58960170325 100644
--- a/container-core/src/main/java/com/yahoo/metrics/Unit.java
+++ b/container-core/src/main/java/com/yahoo/metrics/Unit.java
@@ -17,6 +17,8 @@ public enum Unit {
OPERATION_PER_SECOND(BaseUnit.OPERATION, BaseUnit.SECOND),
QUERY(BaseUnit.QUERY),
QUERY_PER_SECOND(BaseUnit.QUERY, BaseUnit.SECOND),
+ QUERY_ITEM(BaseUnit.QUERY_ITEM),
+ RELEVANCE(BaseUnit.RELEVANCE),
REQUEST(BaseUnit.REQUEST),
RESPONSE(BaseUnit.RESPONSE),
RESPONSE_PER_SECOND(BaseUnit.RESPONSE, BaseUnit.SECOND),
@@ -58,6 +60,8 @@ public enum Unit {
MILLISECOND("millisecond", "ms"),
OPERATION("operation"),
QUERY("query"),
+ QUERY_ITEM("query-item"),
+ RELEVANCE("relevance"),
REQUEST("request"),
RESPONSE("response"),
SECOND("second", "s"),
diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
index ecbc451ead1..bdcc3f9e40a 100644
--- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
+++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
@@ -28,7 +28,8 @@ reuseAddress bool default=true
# The maximum idle time for a connection, which roughly translates to the Socket.setSoTimeout(int).
idleTimeout double default=180.0
-# Whether or not to have socket keep alive turned on.
+# TODO Vespa 9 Remove
+# Has no effect since Jetty 11 upgrade
tcpKeepAliveEnabled bool default=false
# Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
index f34fd523207..c15cb6b2cc4 100644
--- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
+++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
@@ -4,7 +4,8 @@ namespace=jdisc.http
# Whether to enable developer mode, where stack traces etc are visible in response bodies.
developerMode bool default=false
-# The gzip compression level to use, if compression is enabled in a request.
+# TODO Vespa 9 Remove
+# Has no effect since Jetty 11 upgrade
responseCompressionLevel int default=6
# Whether the request body of POSTed forms should be removed (form parameters are available as request parameters).
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
index 1ff2783cc53..ce205b1a893 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
@@ -5,6 +5,8 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.ServerConfig;
import com.yahoo.jdisc.http.ssl.impl.ConfiguredSslContextFactoryProvider;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
@@ -12,8 +14,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
index 8b18c8cf09d..fdb9f2226de 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
@@ -2,9 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
+import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
index a23a3505bcb..e4b82db5b9f 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
@@ -8,15 +8,17 @@ import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.service.CurrentContainer;
+import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Steinar Knutsen
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
index 165659389ec..502702ccf35 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
@@ -2,6 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.http.server.jetty.HttpResponseStatisticsCollector.StatisticsEntry;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
@@ -10,6 +13,7 @@ import org.eclipse.jetty.http.MetaData.Response;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpChannelOverHttp;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.server.Request;
@@ -19,9 +23,6 @@ import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
@@ -164,8 +165,8 @@ public class HttpResponseStatisticsCollectorTest {
}
private Request testRequest(String scheme, int responseCode, String httpMethod, String path,
com.yahoo.jdisc.Request.RequestType explicitRequestType) {
- HttpChannel channel = new HttpChannel(connector, new HttpConfiguration(), null, new DummyTransport());
- MetaData.Request metaData = new MetaData.Request(httpMethod, new HttpURI(scheme + "://" + path), HttpVersion.HTTP_1_1, new HttpFields());
+ HttpChannel channel = new HttpChannelOverHttp(null, connector, new HttpConfiguration(), null, new DummyTransport());
+ MetaData.Request metaData = new MetaData.Request(httpMethod, HttpURI.build(scheme + "://" + path), HttpVersion.HTTP_1_1, HttpFields.build());
Request req = channel.getRequest();
if (explicitRequestType != null)
req.setAttribute("requestType", explicitRequestType);
@@ -192,7 +193,7 @@ public class HttpResponseStatisticsCollectorTest {
private final class DummyTransport implements HttpTransport {
@Override
- public void send(Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) {
+ public void send(MetaData.Request request, Response response, ByteBuffer byteBuffer, boolean b, Callback callback) {
callback.succeeded();
}
@@ -202,11 +203,6 @@ public class HttpResponseStatisticsCollectorTest {
}
@Override
- public boolean isOptimizedForDirectBuffers() {
- return false;
- }
-
- @Override
public void push(MetaData.Request request) {
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
index 7cce9f2a9ff..ae1a6494acd 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
@@ -807,6 +807,7 @@ public class HttpServerConformanceTest extends ServerProviderConformanceTest {
post.setProtocolVersion(HttpVersion.HTTP_1_1);
request = post;
}
+ request.addHeader("Connection", "close");
return executorService.submit(() -> httpClient.execute(request));
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
index 318067ac634..39b6dcdc6d5 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
@@ -186,9 +186,10 @@ public class HttpServerTest {
@Test
void requireThatServerCanEchoCompressed() throws Exception {
final JettyTestDriver driver = JettyTestDriver.newInstance(new EchoRequestHandler());
- SimpleHttpClient client = driver.newClient(true);
- client.get("/status.html")
- .expectStatusCode(is(OK));
+ try (SimpleHttpClient client = driver.newClient(true)) {
+ client.get("/status.html")
+ .expectStatusCode(is(OK));
+ }
assertTrue(driver.close());
}
@@ -532,9 +533,9 @@ public class HttpServerTest {
.withTrustStore(certificateFile)
.build();
- new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)
- .get("/dummy.html")
- .expectStatusCode(is(UNAUTHORIZED));
+ try (var c = new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)) {
+ c.get("/dummy.html").expectStatusCode(is(UNAUTHORIZED));
+ }
assertTrue(driver.close());
}
@@ -550,9 +551,9 @@ public class HttpServerTest {
.withTrustStore(certificateFile)
.build();
- new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)
- .get("/status.html")
- .expectStatusCode(is(OK));
+ try (var c = new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)) {
+ c.get("/status.html").expectStatusCode(is(OK));
+ }
assertTrue(driver.close());
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
index d4d6dcee957..6cd6f05933a 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
@@ -12,6 +12,8 @@ import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.assertj.core.api.Assertions;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -185,14 +187,15 @@ class ProxyProtocolTest {
// Using Jetty's http client as Apache httpclient does not support the proxy-protocol v1/v2.
private static HttpClient createJettyHttpClient(Path certificateFile) throws Exception {
- SslContextFactory.Client clientSslCtxFactory = new SslContextFactory.Client();
- clientSslCtxFactory.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
- clientSslCtxFactory.setSslContext(new SslContextBuilder().withTrustStore(certificateFile).build());
-
- HttpClient client = new HttpClient(clientSslCtxFactory);
- client.setConnectTimeout(60*1000);
- client.setStopTimeout(60*1000);
- client.setIdleTimeout(60*1000);
+ var ssl = new SslContextFactory.Client();
+ ssl.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
+ ssl.setSslContext(new SslContextBuilder().withTrustStore(certificateFile).build());
+ var connector = new ClientConnector();
+ connector.setSslContextFactory(ssl);
+ HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(connector));
+ int timeout = 60 * 1000;
+ client.setConnectTimeout(timeout);
+ client.setIdleTimeout(timeout);
client.start();
return client;
}
diff --git a/container-dev/pom.xml b/container-dev/pom.xml
index f62cc69a428..c327b73d953 100644
--- a/container-dev/pom.xml
+++ b/container-dev/pom.xml
@@ -105,8 +105,8 @@
<!-- START JETTY embedded jars -->
<exclusion>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -118,11 +118,19 @@
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
@@ -138,7 +146,11 @@
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</exclusion>
<!-- END JETTY embedded jars -->
</exclusions>
diff --git a/container-test/pom.xml b/container-test/pom.xml
index d2806bb0330..d4da20cf9fe 100644
--- a/container-test/pom.xml
+++ b/container-test/pom.xml
@@ -116,8 +116,8 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -129,11 +129,19 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@@ -149,7 +157,11 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</dependency>
<!-- END JETTY embedded jars -->
</dependencies>
diff --git a/fat-model-dependencies/pom.xml b/fat-model-dependencies/pom.xml
index 7d00f9ba58e..bbac77d9c0b 100644
--- a/fat-model-dependencies/pom.xml
+++ b/fat-model-dependencies/pom.xml
@@ -152,6 +152,10 @@
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>*</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
diff --git a/fileacquirer/abi-spec.json b/fileacquirer/abi-spec.json
index 560d1fb7a16..63e3ba71f2d 100644
--- a/fileacquirer/abi-spec.json
+++ b/fileacquirer/abi-spec.json
@@ -25,17 +25,6 @@
],
"fields" : [ ]
},
- "com.yahoo.filedistribution.fileacquirer.FileReferenceDoesNotExistException" : {
- "superClass" : "java.lang.RuntimeException",
- "interfaces" : [ ],
- "attributes" : [
- "public"
- ],
- "methods" : [ ],
- "fields" : [
- "public final java.lang.String fileReference"
- ]
- },
"com.yahoo.filedistribution.fileacquirer.MockFileAcquirer" : {
"superClass" : "java.lang.Object",
"interfaces" : [
diff --git a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirer.java b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirer.java
index 03650963f96..3f25273334a 100644
--- a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirer.java
+++ b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirer.java
@@ -2,6 +2,7 @@
package com.yahoo.filedistribution.fileacquirer;
import com.yahoo.config.FileReference;
+import com.yahoo.vespa.config.FileReferenceDoesNotExistException;
import java.io.File;
import java.util.concurrent.TimeUnit;
diff --git a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirerImpl.java b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirerImpl.java
index 5d6477cd927..9fe876d358a 100644
--- a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirerImpl.java
+++ b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/FileAcquirerImpl.java
@@ -2,18 +2,23 @@
package com.yahoo.filedistribution.fileacquirer;
import com.yahoo.cloud.config.filedistribution.FiledistributorrpcConfig;
-import com.yahoo.config.subscription.ConfigSubscriber;
import com.yahoo.config.FileReference;
-import com.yahoo.jrt.*;
-
+import com.yahoo.config.subscription.ConfigSubscriber;
+import com.yahoo.jrt.ErrorCode;
+import com.yahoo.jrt.Request;
+import com.yahoo.jrt.Spec;
+import com.yahoo.jrt.StringValue;
+import com.yahoo.jrt.Supervisor;
+import com.yahoo.jrt.Target;
+import com.yahoo.jrt.Transport;
+import com.yahoo.vespa.config.FileReferenceDoesNotExistException;
+import java.io.File;
import java.time.Duration;
-import java.util.logging.Level;
-
-import java.util.logging.Logger;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
-import java.io.File;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Retrieves the path to a file or directory on the local file system
diff --git a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/MockFileAcquirer.java b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/MockFileAcquirer.java
index 744c49629e9..e393cf7bc4e 100644
--- a/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/MockFileAcquirer.java
+++ b/fileacquirer/src/main/java/com/yahoo/filedistribution/fileacquirer/MockFileAcquirer.java
@@ -2,6 +2,7 @@
package com.yahoo.filedistribution.fileacquirer;
import com.yahoo.config.FileReference;
+import com.yahoo.vespa.config.FileReferenceDoesNotExistException;
import java.io.File;
import java.util.Map;
import java.util.concurrent.TimeUnit;
diff --git a/fileacquirer/src/test/java/MockFileAcquirerTest.java b/fileacquirer/src/test/java/MockFileAcquirerTest.java
index 9a505118c31..dc8908249e0 100644
--- a/fileacquirer/src/test/java/MockFileAcquirerTest.java
+++ b/fileacquirer/src/test/java/MockFileAcquirerTest.java
@@ -1,11 +1,11 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
import com.yahoo.config.FileReference;
import com.yahoo.filedistribution.fileacquirer.FileAcquirer;
-import com.yahoo.filedistribution.fileacquirer.FileReferenceDoesNotExistException;
import com.yahoo.filedistribution.fileacquirer.MockFileAcquirer;
import com.yahoo.filedistribution.fileacquirer.TimeoutException;
+import com.yahoo.vespa.config.FileReferenceDoesNotExistException;
import org.junit.Test;
-
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.HashMap;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
index 742b39e97c1..246a02aa441 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeList.java
@@ -9,13 +9,17 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.node.ClusterId;
+import com.yahoo.vespa.hosted.provision.node.IP;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.EnumSet;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -30,13 +34,22 @@ import static java.util.stream.Collectors.collectingAndThen;
*/
public class NodeList extends AbstractFilteringList<Node, NodeList> {
+ private static final NodeList EMPTY = new NodeList(List.of(), false);
+
+ /**
+ * A lazily populated cache of parent-child relationships. This exists to improve the speed of parent<->child
+ * lookup which is a frequent operation
+ */
+ private final AtomicReference<Map<String, NodeFamily>> nodeCache = new AtomicReference<>(null);
+ private final AtomicReference<Set<String>> ipCache = new AtomicReference<>(null);
+
protected NodeList(List<Node> nodes, boolean negate) {
super(nodes, negate, NodeList::new);
}
/** Returns the node with the given hostname from this list, or empty if it is not present */
public Optional<Node> node(String hostname) {
- return matching(node -> node.hostname().equals(hostname)).first();
+ return get(hostname).map(NodeFamily::node);
}
/** Returns the subset of nodes which are retired */
@@ -189,7 +202,9 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
/** Returns the child nodes of the given parent node */
public NodeList childrenOf(String hostname) {
- return matching(node -> node.hasParent(hostname));
+ NodeList children = get(hostname).map(NodeFamily::children).map(NodeList::copyOf).orElse(EMPTY);
+ // Fallback, in case the parent itself is not in this list
+ return children.isEmpty() ? matching(node -> node.hasParent(hostname)) : children;
}
public NodeList childrenOf(Node parent) {
@@ -221,24 +236,21 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
public NodeList parentsOf(NodeList children) {
return children.stream()
.map(this::parentOf)
- .filter(Optional::isPresent)
.flatMap(Optional::stream)
.collect(collectingAndThen(Collectors.toList(), NodeList::copyOf));
}
+ /** Returns the parent node of the given child node */
+ public Optional<Node> parentOf(Node child) {
+ return child.parentHostname().flatMap(this::get).map(NodeFamily::node);
+ }
+
/** Returns the nodes contained in the group identified by given index */
public NodeList group(int index) {
return matching(n -> n.allocation().isPresent() &&
n.allocation().get().membership().cluster().group().equals(Optional.of(ClusterSpec.Group.from(index))));
}
- /** Returns the parent node of the given child node */
- public Optional<Node> parentOf(Node child) {
- return child.parentHostname()
- .flatMap(parentHostname -> stream().filter(node -> node.hostname().equals(parentHostname))
- .findFirst());
- }
-
/** Returns the hostnames of nodes in this */
public Set<String> hostnames() {
return stream().map(Node::hostname).collect(Collectors.toUnmodifiableSet());
@@ -316,6 +328,31 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
});
}
+ /**
+ * Returns the number of unused IP addresses in the pool, assuming any and all unaccounted for hostnames
+ * in the pool are resolved to exactly 1 IP address (or 2 with {@link IP.IpAddresses.Protocol#dualStack}).
+ */
+ public int eventuallyUnusedIpAddressCount(Node host) {
+ // The count in this method relies on the size of the IP address pool if that's non-empty,
+ // otherwise fall back to the address/hostname pool.
+ if (host.ipConfig().pool().ipSet().isEmpty()) {
+ Set<String> allHostnames = cache().keySet();
+ return (int) host.ipConfig().pool().getAddressList().stream()
+ .filter(address -> !allHostnames.contains(address.hostname()))
+ .count();
+ }
+ Set<String> allIps = ipCache.updateAndGet((old) -> {
+ if (old != null) {
+ return old;
+ }
+ return stream().flatMap(node -> node.ipConfig().primary().stream())
+ .collect(Collectors.toUnmodifiableSet());
+ });
+ return (int) host.ipConfig().pool().ipSet().stream()
+ .filter(address -> !allIps.contains(address))
+ .count();
+ }
+
private void ensureSingleCluster() {
if (isEmpty()) return;
@@ -336,6 +373,7 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
}
public static NodeList copyOf(List<Node> nodes) {
+ if (nodes.isEmpty()) return EMPTY;
return new NodeList(nodes, false);
}
@@ -354,4 +392,36 @@ public class NodeList extends AbstractFilteringList<Node, NodeList> {
return this.asList().equals(((NodeList) other).asList());
}
+ /** Get node family, by given hostname */
+ private Optional<NodeFamily> get(String hostname) {
+ return Optional.ofNullable(cache().get(hostname));
+ }
+
+ private Map<String, NodeFamily> cache() {
+ return nodeCache.updateAndGet((oldValue) -> {
+ if (oldValue != null) {
+ return oldValue;
+ }
+ Map<String, NodeFamily> newValue = new HashMap<>();
+ for (var node : this) {
+ NodeFamily family;
+ if (node.parentHostname().isEmpty()) {
+ family = new NodeFamily(node, new ArrayList<>());
+ for (var child : this) {
+ if (child.hasParent(node.hostname())) {
+ family.children.add(child);
+ }
+ }
+ } else {
+ family = new NodeFamily(node, List.of());
+ }
+ newValue.put(node.hostname(), family);
+ }
+ return newValue;
+ });
+ }
+
+ /** A node and its children, if any */
+ private record NodeFamily(Node node, List<Node> children) {}
+
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java
deleted file mode 100644
index 6e7fc340231..00000000000
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.provision;
-
-import com.yahoo.vespa.hosted.provision.node.IP;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Wraps a NodeList and builds a host to children mapping for faster access
- * as that is done very frequently.
- *
- * @author baldersheim
- */
-public class NodesAndHosts<NL extends NodeList> {
- private final NL nodes;
- private final Map<String, HostAndNodes> host2Nodes = new HashMap<>();
- private final Set<String> allPrimaryIps = new HashSet<>();
- private final Set<String> allHostNames;
-
- public static <L extends NodeList> NodesAndHosts<L> create(L nodes) {
- return new NodesAndHosts<L>(nodes);
- }
-
- private NodesAndHosts(NL nodes) {
- this.nodes = nodes;
- nodes.forEach(node -> allPrimaryIps.addAll(node.ipConfig().primary()));
- allHostNames = nodes.stream().map(Node::hostname).collect(Collectors.toSet());
- nodes.forEach(node -> {
- node.parentHostname().ifPresentOrElse(
- parent -> host2Nodes.computeIfAbsent(parent, key -> new HostAndNodes()).add(node),
- () -> host2Nodes.computeIfAbsent(node.hostname(), key -> new HostAndNodes()).setHost(node));
- });
-
- }
-
- /// Return the NodeList used for construction
- public NL nodes() { return nodes; }
-
- public NodeList childrenOf(Node host) {
- return childrenOf(host.hostname());
- }
- public NodeList childrenOf(String hostname) {
- HostAndNodes hostAndNodes = host2Nodes.get(hostname);
- return hostAndNodes != null ? NodeList.copyOf(hostAndNodes.children) : NodeList.of();
- }
-
- public Optional<Node> parentOf(Node node) {
- if (node.parentHostname().isEmpty()) return Optional.empty();
-
- HostAndNodes hostAndNodes = host2Nodes.get(node.parentHostname().get());
- return hostAndNodes != null ? Optional.ofNullable(hostAndNodes.host) : Optional.empty();
- }
-
- /**
- * Returns the number of unused IP addresses in the pool, assuming any and all unaccounted for hostnames
- * in the pool are resolved to exactly 1 IP address (or 2 with {@link IP.IpAddresses.Protocol#dualStack}).
- */
- public int eventuallyUnusedIpAddressCount(Node host) {
- // The count in this method relies on the size of the IP address pool if that's non-empty,
- // otherwise fall back to the address/hostname pool.
- return (int) (host.ipConfig().pool().ipSet().isEmpty()
- ? host.ipConfig().pool().getAddressList().stream().filter(address -> !allHostNames.contains(address.hostname())).count()
- : host.ipConfig().pool().ipSet().stream().filter(address -> !allPrimaryIps.contains(address)).count());
- }
-
- private static class HostAndNodes {
- private Node host;
- private final List<Node> children;
- HostAndNodes() {
- this.host = null;
- children = new ArrayList<>();
- }
- void setHost(Node host) { this.host = host; }
- void add(Node child) { children.add(child); }
- }
-}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
index 5769f978089..1d5581b511d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java
@@ -22,7 +22,6 @@ import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeMutex;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner;
@@ -31,6 +30,7 @@ import com.yahoo.vespa.hosted.provision.provisioning.NodeCandidate;
import com.yahoo.vespa.hosted.provision.provisioning.NodePrioritizer;
import com.yahoo.vespa.hosted.provision.provisioning.NodeSpec;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionedHost;
+
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
@@ -222,8 +222,8 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer {
ArrayList<Node> mutableNodes) {
for (int clusterIndex = 0; clusterIndex < preprovisionCapacity.size(); ++clusterIndex) {
ClusterCapacity clusterCapacity = preprovisionCapacity.get(clusterIndex);
- NodesAndHosts<LockedNodeList> nodesAndHosts = NodesAndHosts.create(new LockedNodeList(mutableNodes, () -> {}));
- List<Node> candidates = findCandidates(clusterCapacity, clusterIndex, nodesAndHosts);
+ LockedNodeList allNodes = new LockedNodeList(mutableNodes, () -> {});
+ List<Node> candidates = findCandidates(clusterCapacity, clusterIndex, allNodes);
int deficit = Math.max(0, clusterCapacity.count() - candidates.size());
if (deficit > 0) {
return Optional.of(clusterCapacity.withCount(deficit));
@@ -236,7 +236,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer {
return Optional.empty();
}
- private List<Node> findCandidates(ClusterCapacity clusterCapacity, int clusterIndex, NodesAndHosts<LockedNodeList> nodesAndHosts) {
+ private List<Node> findCandidates(ClusterCapacity clusterCapacity, int clusterIndex, LockedNodeList allNodes) {
NodeResources nodeResources = toNodeResources(clusterCapacity);
// We'll allocate each ClusterCapacity as a unique cluster in a dummy application
@@ -249,7 +249,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer {
NodeSpec nodeSpec = NodeSpec.from(clusterCapacity.count(), nodeResources, false, true, nodeRepository().zone().cloud().account());
int wantedGroups = 1;
- NodePrioritizer prioritizer = new NodePrioritizer(nodesAndHosts, applicationId, clusterSpec, nodeSpec, wantedGroups,
+ NodePrioritizer prioritizer = new NodePrioritizer(allNodes, applicationId, clusterSpec, nodeSpec, wantedGroups,
true, nodeRepository().nameResolver(), nodeRepository().nodes(), nodeRepository().resourcesCalculator(),
nodeRepository().spareCount(), nodeSpec.cloudAccount().isEnclave(nodeRepository().zone()));
List<NodeCandidate> nodeCandidates = prioritizer.collect(List.of());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
index 552db84748d..fcc8e904a47 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
@@ -9,7 +9,6 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.provisioning.HostCapacity;
import java.time.Duration;
@@ -40,7 +39,7 @@ public abstract class NodeMover<MOVE> extends NodeRepositoryMaintainer {
}
/** Returns a suggested move for given node */
- protected abstract MOVE suggestedMove(Node node, Node fromHost, Node toHost, NodesAndHosts<? extends NodeList> allNodes);
+ protected abstract MOVE suggestedMove(Node node, Node fromHost, Node toHost, NodeList allNodes);
private static class HostWithResources {
private final Node node;
@@ -56,17 +55,17 @@ public abstract class NodeMover<MOVE> extends NodeRepositoryMaintainer {
}
/** Find the best possible move */
- protected final MOVE findBestMove(NodesAndHosts<? extends NodeList> allNodes) {
+ protected final MOVE findBestMove(NodeList allNodes) {
HostCapacity capacity = new HostCapacity(allNodes, nodeRepository().resourcesCalculator());
MOVE bestMove = emptyMove;
// Shuffle nodes to not get stuck if the chosen move is consistently discarded. Node moves happen through
// a soft request to retire (preferToRetire), which node allocation can disregard
- NodeList activeNodes = allNodes.nodes().nodeType(NodeType.tenant)
+ NodeList activeNodes = allNodes.nodeType(NodeType.tenant)
.state(Node.State.active)
.shuffle(random);
- Set<Node> spares = capacity.findSpareHosts(allNodes.nodes().asList(), nodeRepository().spareCount());
+ Set<Node> spares = capacity.findSpareHosts(allNodes.asList(), nodeRepository().spareCount());
List<HostWithResources> hostResources = new ArrayList<>();
- allNodes.nodes().matching(nodeRepository().nodes()::canAllocateTenantNodeTo).forEach(host -> hostResources.add(new HostWithResources(host, capacity.availableCapacityOf(host))));
+ allNodes.matching(nodeRepository().nodes()::canAllocateTenantNodeTo).forEach(host -> hostResources.add(new HostWithResources(host, capacity.availableCapacityOf(host))));
for (Node node : activeNodes) {
if (node.parentHostname().isEmpty()) continue;
ApplicationId applicationId = node.allocation().get().owner();
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java
index c853bfa2abe..3649f921480 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/Rebalancer.java
@@ -8,7 +8,6 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.HostCapacity;
@@ -42,15 +41,15 @@ public class Rebalancer extends NodeMover<Rebalancer.Move> {
if (nodeRepository().zone().system().isCd()) return 1.0; // CD tests assert on # of nodes, avoid rebalnacing as it make tests unstable
// Work with an unlocked snapshot as this can take a long time and full consistency is not needed
- NodesAndHosts<NodeList> allNodes = NodesAndHosts.create(nodeRepository().nodes().list());
+ NodeList allNodes = nodeRepository().nodes().list();
updateSkewMetric(allNodes);
- if ( ! zoneIsStable(allNodes.nodes())) return 1.0;
+ if ( ! zoneIsStable(allNodes)) return 1.0;
findBestMove(allNodes).execute(true, Agent.Rebalancer, deployer, metric, nodeRepository());
return 1.0;
}
@Override
- protected Move suggestedMove(Node node, Node fromHost, Node toHost, NodesAndHosts<? extends NodeList> allNodes) {
+ protected Move suggestedMove(Node node, Node fromHost, Node toHost, NodeList allNodes) {
HostCapacity capacity = new HostCapacity(allNodes, nodeRepository().resourcesCalculator());
double skewReductionAtFromHost = skewReductionByRemoving(node, fromHost, capacity);
double skewReductionAtToHost = skewReductionByAdding(node, toHost, capacity);
@@ -65,11 +64,11 @@ public class Rebalancer extends NodeMover<Rebalancer.Move> {
}
/** We do this here rather than in MetricsReporter because it is expensive and frequent updates are unnecessary */
- private void updateSkewMetric(NodesAndHosts<? extends NodeList> allNodes) {
+ private void updateSkewMetric(NodeList allNodes) {
HostCapacity capacity = new HostCapacity(allNodes, nodeRepository().resourcesCalculator());
double totalSkew = 0;
int hostCount = 0;
- for (Node host : allNodes.nodes().nodeType(NodeType.host).state(Node.State.active)) {
+ for (Node host : allNodes.nodeType(NodeType.host).state(Node.State.active)) {
hostCount++;
totalSkew += Node.skew(host.flavor().resources(), capacity.unusedCapacityOf(host));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
index d5b0c3baf19..5ce88346178 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
@@ -9,7 +9,6 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.maintenance.MaintenanceDeployment.Move;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.HostCapacity;
@@ -117,13 +116,13 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer {
if (nodeWhichCantMove.isEmpty()) return List.of();
Node node = nodeWhichCantMove.get();
- NodesAndHosts<NodeList> allNodes = NodesAndHosts.create(nodeRepository().nodes().list());
+ NodeList allNodes = nodeRepository().nodes().list();
// Allocation will assign the spareCount most empty nodes as "spares", which will not be allocated on
// unless needed for node failing. Our goal here is to make room on these spares for the given node
HostCapacity hostCapacity = new HostCapacity(allNodes, nodeRepository().resourcesCalculator());
- Set<Node> spareHosts = hostCapacity.findSpareHosts(allNodes.nodes().hosts().satisfies(node.resources()).asList(),
+ Set<Node> spareHosts = hostCapacity.findSpareHosts(allNodes.hosts().satisfies(node.resources()).asList(),
nodeRepository().spareCount());
- List<Node> hosts = allNodes.nodes().hosts().except(spareHosts).asList();
+ List<Node> hosts = allNodes.hosts().except(spareHosts).asList();
CapacitySolver capacitySolver = new CapacitySolver(hostCapacity, maxIterations);
List<Move> shortestMitigation = null;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
index f01e8ecd301..9f009b47983 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SwitchRebalancer.java
@@ -8,7 +8,6 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.maintenance.MaintenanceDeployment.Move;
import com.yahoo.vespa.hosted.provision.node.Agent;
@@ -40,8 +39,8 @@ public class SwitchRebalancer extends NodeMover<Move> {
protected double maintain() {
if (!nodeRepository().nodes().isWorking()) return 0.0;
if (!nodeRepository().zone().environment().isProduction()) return 1.0;
- NodesAndHosts<NodeList> allNodes = NodesAndHosts.create(nodeRepository().nodes().list()); // Lockless as strong consistency is not needed
- if (!zoneIsStable(allNodes.nodes())) return 1.0;
+ NodeList allNodes = nodeRepository().nodes().list(); // Lockless as strong consistency is not needed
+ if (!zoneIsStable(allNodes)) return 1.0;
Move bestMove = findBestMove(allNodes);
if (!bestMove.isEmpty()) {
@@ -53,9 +52,9 @@ public class SwitchRebalancer extends NodeMover<Move> {
}
@Override
- protected Move suggestedMove(Node node, Node fromHost, Node toHost, NodesAndHosts<? extends NodeList> allNodes) {
- NodeList clusterNodes = clusterOf(node, allNodes.nodes());
- NodeList clusterHosts = allNodes.nodes().parentsOf(clusterNodes);
+ protected Move suggestedMove(Node node, Node fromHost, Node toHost, NodeList allNodes) {
+ NodeList clusterNodes = clusterOf(node, allNodes);
+ NodeList clusterHosts = allNodes.parentsOf(clusterNodes);
if (onExclusiveSwitch(node, clusterHosts)) return Move.empty();
if (!increasesExclusiveSwitches(clusterNodes, clusterHosts, toHost)) return Move.empty();
return new Move(node, fromHost, toHost);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
index 46cc32c7156..07f9c439fe2 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
@@ -11,7 +11,6 @@ import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing;
@@ -37,17 +36,8 @@ public class GroupPreparer {
private final NodeRepository nodeRepository;
private final Optional<HostProvisioner> hostProvisioner;
- /**
- * Contains list of prepared nodes and the NodesAndHost object to use for next prepare call.
- */
- public static class PrepareResult {
- public final List<Node> prepared;
- public final NodesAndHosts<LockedNodeList> allNodesAndHosts;
- PrepareResult(List<Node> prepared, NodesAndHosts<LockedNodeList> allNodesAndHosts) {
- this.prepared = prepared;
- this.allNodesAndHosts = allNodesAndHosts;
- }
- }
+ /** Contains list of prepared nodes and the {@link LockedNodeList} object to use for next prepare call */
+ record PrepareResult(List<Node> prepared, LockedNodeList allNodes) {}
public GroupPreparer(NodeRepository nodeRepository, Optional<HostProvisioner> hostProvisioner) {
this.nodeRepository = nodeRepository;
@@ -64,8 +54,8 @@ public class GroupPreparer {
* This method will remove from this list if it finds it needs additional nodes
* @param indices the next available node indices for this cluster.
* This method will consume these when it allocates new nodes to the cluster.
- * @param allNodesAndHosts list of all nodes and hosts. Use createNodesAndHostUnlocked to create param for
- * first invocation. Then use previous PrepareResult.allNodesAndHosts for the following.
+ * @param allNodes list of all nodes and hosts. Use {@link #createUnlockedNodeList()} to create param for
+ * first invocation. Then use previous {@link PrepareResult#allNodes()} for the following.
* @return the list of nodes this cluster group will have allocated if activated, and
*/
// Note: This operation may make persisted changes to the set of reserved and inactive nodes,
@@ -73,37 +63,37 @@ public class GroupPreparer {
// active config model which is changed on activate
public PrepareResult prepare(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups,
- NodesAndHosts<LockedNodeList> allNodesAndHosts) {
+ LockedNodeList allNodes) {
log.log(Level.FINE, () -> "Preparing " + cluster.type().name() + " " + cluster.id() + " with requested resources " +
requestedNodes.resources().orElse(NodeResources.unspecified()));
// Try preparing in memory without global unallocated lock. Most of the time there should be no changes,
// and we can return nodes previously allocated.
NodeAllocation probeAllocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
- indices::probeNext, wantedGroups, allNodesAndHosts);
+ indices::probeNext, wantedGroups, allNodes);
if (probeAllocation.fulfilledAndNoChanges()) {
List<Node> acceptedNodes = probeAllocation.finalNodes();
surplusActiveNodes.removeAll(acceptedNodes);
indices.commitProbe();
- return new PrepareResult(acceptedNodes, allNodesAndHosts);
+ return new PrepareResult(acceptedNodes, allNodes);
} else {
// There were some changes, so re-do the allocation with locks
indices.resetProbe();
List<Node> prepared = prepareWithLocks(application, cluster, requestedNodes, surplusActiveNodes, indices, wantedGroups);
- return new PrepareResult(prepared, createNodesAndHostUnlocked());
+ return new PrepareResult(prepared, createUnlockedNodeList());
}
}
- // Use this to create allNodesAndHosts param to prepare method for first invocation of prepare
- public NodesAndHosts<LockedNodeList> createNodesAndHostUnlocked() { return NodesAndHosts.create(nodeRepository.nodes().list(PROBE_LOCK)); }
+ // Use this to create allNodes param to prepare method for first invocation of prepare
+ LockedNodeList createUnlockedNodeList() { return nodeRepository.nodes().list(PROBE_LOCK); }
/// Note that this will write to the node repo.
private List<Node> prepareWithLocks(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups) {
try (Mutex lock = nodeRepository.applications().lock(application);
Mutex allocationLock = nodeRepository.nodes().lockUnallocated()) {
- NodesAndHosts<LockedNodeList> allNodesAndHosts = NodesAndHosts.create(nodeRepository.nodes().list(allocationLock));
+ LockedNodeList allNodes = nodeRepository.nodes().list(allocationLock);
NodeAllocation allocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
- indices::next, wantedGroups, allNodesAndHosts);
+ indices::next, wantedGroups, allNodes);
NodeType hostType = allocation.nodeType().hostType();
if (canProvisionDynamically(hostType) && allocation.hostDeficit().isPresent()) {
HostSharing sharing = hostSharing(cluster, hostType);
@@ -156,10 +146,10 @@ public class GroupPreparer {
private NodeAllocation prepareAllocation(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
List<Node> surplusActiveNodes, Supplier<Integer> nextIndex, int wantedGroups,
- NodesAndHosts<LockedNodeList> allNodesAndHosts) {
+ LockedNodeList allNodes) {
- NodeAllocation allocation = new NodeAllocation(allNodesAndHosts, application, cluster, requestedNodes, nextIndex, nodeRepository);
- NodePrioritizer prioritizer = new NodePrioritizer(allNodesAndHosts,
+ NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requestedNodes, nextIndex, nodeRepository);
+ NodePrioritizer prioritizer = new NodePrioritizer(allNodes,
application,
cluster,
requestedNodes,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacity.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacity.java
index f29bf61149c..991bc22402d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacity.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/HostCapacity.java
@@ -5,7 +5,6 @@ import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import java.util.ArrayList;
import java.util.List;
@@ -23,18 +22,15 @@ import java.util.stream.Collectors;
*/
public class HostCapacity {
- private final NodesAndHosts<? extends NodeList> allNodes;
+ private final NodeList allNodes;
private final HostResourcesCalculator hostResourcesCalculator;
public HostCapacity(NodeList allNodes, HostResourcesCalculator hostResourcesCalculator) {
- this(NodesAndHosts.create(Objects.requireNonNull(allNodes, "allNodes must be non-null")), hostResourcesCalculator);
- }
- public HostCapacity(NodesAndHosts<? extends NodeList> allNodes, HostResourcesCalculator hostResourcesCalculator) {
this.allNodes = Objects.requireNonNull(allNodes, "allNodes must be non-null");
this.hostResourcesCalculator = Objects.requireNonNull(hostResourcesCalculator, "hostResourcesCalculator must be non-null");
}
- public NodeList allNodes() { return allNodes.nodes(); }
+ public NodeList allNodes() { return allNodes; }
/**
* Spare hosts are the hosts in the system with the most free capacity. A zone may reserve a minimum number of spare
@@ -97,9 +93,9 @@ public class HostCapacity {
/** Returns the number of available IP addresses on given host */
int freeIps(Node host) {
if (host.type() == NodeType.host) {
- return (allNodes.eventuallyUnusedIpAddressCount(host));
+ return allNodes.eventuallyUnusedIpAddressCount(host);
}
- return host.ipConfig().pool().findUnusedIpAddresses(allNodes.nodes()).size();
+ return host.ipConfig().pool().findUnusedIpAddresses(allNodes).size();
}
/** Returns the capacity of given host that is both free and usable */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index 63d5db09380..bf3ad5f15fb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -14,7 +14,6 @@ import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
@@ -43,7 +42,7 @@ class NodeAllocation {
private static final Logger LOG = Logger.getLogger(NodeAllocation.class.getName());
/** List of all nodes in node-repository */
- private final NodesAndHosts<? extends NodeList> allNodesAndHosts;
+ private final NodeList allNodes;
/** The application this list is for */
private final ApplicationId application;
@@ -86,9 +85,9 @@ class NodeAllocation {
private List<NodeCandidate> lastOffered;
- NodeAllocation(NodesAndHosts<? extends NodeList> allNodesAndHosts, ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
+ NodeAllocation(NodeList allNodes, ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
Supplier<Integer> nextIndex, NodeRepository nodeRepository) {
- this.allNodesAndHosts = allNodesAndHosts;
+ this.allNodes = allNodes;
this.application = application;
this.cluster = cluster;
this.requestedNodes = requestedNodes;
@@ -214,7 +213,7 @@ class NodeAllocation {
// In zones with shared hosts we require that if either of the nodes on the host requires exclusivity,
// then all the nodes on the host must have the same owner
- for (Node nodeOnHost : allNodesAndHosts.childrenOf(candidate.parentHostname().get())) {
+ for (Node nodeOnHost : allNodes.childrenOf(candidate.parentHostname().get())) {
if (nodeOnHost.allocation().isEmpty()) continue;
if (requestedNodes.isExclusive() || nodeOnHost.allocation().get().membership().cluster().isExclusive()) {
if ( ! nodeOnHost.allocation().get().owner().equals(application)) return true;
@@ -289,7 +288,7 @@ class NodeAllocation {
}
private Node resize(Node node) {
- NodeResources hostResources = allNodesAndHosts.parentOf(node).get().flavor().resources();
+ NodeResources hostResources = allNodes.parentOf(node).get().flavor().resources();
return node.with(new Flavor(requestedNodes.resources().get()
.with(hostResources.diskSpeed())
.with(hostResources.storageType())
@@ -341,7 +340,7 @@ class NodeAllocation {
if (hostType == NodeType.host) return nodeRepository.database().readProvisionIndices(count);
// Infrastructure hosts have fixed indices, starting at 1
- Set<Integer> currentIndices = allNodesAndHosts.nodes().nodeType(hostType)
+ Set<Integer> currentIndices = allNodes.nodeType(hostType)
.hostnames()
.stream()
// TODO(mpolden): Use cluster index instead of parsing hostname, once all
@@ -441,7 +440,7 @@ class NodeAllocation {
if (nodeType() == NodeType.tenant) return accepted;
// Infrastructure nodes are always allocated by type. Count all nodes as accepted so that we never exceed
// the wanted number of nodes for the type.
- return allNodesAndHosts.nodes().nodeType(nodeType()).size();
+ return allNodes.nodeType(nodeType()).size();
}
/** Prefer to retire nodes we want the least */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
index 79d05ce5c97..5e95d36fcfb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
@@ -7,7 +7,6 @@ import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Nodes;
import com.yahoo.vespa.hosted.provision.persistence.NameResolver;
@@ -31,7 +30,7 @@ import java.util.stream.Collectors;
public class NodePrioritizer {
private final List<NodeCandidate> candidates = new ArrayList<>();
- private final NodesAndHosts<LockedNodeList> allNodesAndHosts;
+ private final LockedNodeList allNodes;
private final HostCapacity capacity;
private final NodeSpec requestedNodes;
private final ApplicationId application;
@@ -47,23 +46,23 @@ public class NodePrioritizer {
private final Set<Node> spareHosts;
private final boolean enclave;
- public NodePrioritizer(NodesAndHosts<LockedNodeList> allNodesAndHosts, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
+ public NodePrioritizer(LockedNodeList allNodes, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
int wantedGroups, boolean dynamicProvisioning, NameResolver nameResolver, Nodes nodes,
HostResourcesCalculator hostResourcesCalculator, int spareCount, boolean enclave) {
- this.allNodesAndHosts = allNodesAndHosts;
- this.capacity = new HostCapacity(this.allNodesAndHosts, hostResourcesCalculator);
+ this.allNodes = allNodes;
+ this.capacity = new HostCapacity(this.allNodes, hostResourcesCalculator);
this.requestedNodes = nodeSpec;
this.clusterSpec = clusterSpec;
this.application = application;
this.dynamicProvisioning = dynamicProvisioning;
this.spareHosts = dynamicProvisioning ?
- capacity.findSpareHostsInDynamicallyProvisionedZones(this.allNodesAndHosts.nodes().asList()) :
- capacity.findSpareHosts(this.allNodesAndHosts.nodes().asList(), spareCount);
+ capacity.findSpareHostsInDynamicallyProvisionedZones(this.allNodes.asList()) :
+ capacity.findSpareHosts(this.allNodes.asList(), spareCount);
this.nameResolver = nameResolver;
this.nodes = nodes;
this.enclave = enclave;
- NodeList nodesInCluster = this.allNodesAndHosts.nodes().owner(application).type(clusterSpec.type()).cluster(clusterSpec.id());
+ NodeList nodesInCluster = this.allNodes.owner(application).type(clusterSpec.type()).cluster(clusterSpec.id());
NodeList nonRetiredNodesInCluster = nodesInCluster.not().retired();
long currentGroups = nonRetiredNodesInCluster.state(Node.State.active).stream()
.flatMap(node -> node.allocation()
@@ -139,7 +138,7 @@ public class NodePrioritizer {
private void addCandidatesOnExistingHosts() {
if ( !canAllocateNew) return;
- for (Node host : allNodesAndHosts.nodes()) {
+ for (Node host : allNodes) {
if ( ! nodes.canAllocateTenantNodeTo(host, dynamicProvisioning)) continue;
if (host.reservedTo().isPresent() && !host.reservedTo().get().equals(application.tenant())) continue;
if (host.reservedTo().isPresent() && application.instance().isTester()) continue;
@@ -147,13 +146,13 @@ public class NodePrioritizer {
if ( ! host.exclusiveToClusterType().map(clusterSpec.type()::equals).orElse(true)) continue;
if (spareHosts.contains(host) && !canAllocateToSpareHosts) continue;
if ( ! capacity.hasCapacity(host, requestedNodes.resources().get())) continue;
- if ( ! allNodesAndHosts.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue;
+ if ( ! allNodes.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue;
candidates.add(NodeCandidate.createNewChild(requestedNodes.resources().get(),
capacity.availableCapacityOf(host),
host,
spareHosts.contains(host),
- allNodesAndHosts.nodes(),
+ allNodes,
nameResolver,
!enclave));
}
@@ -162,7 +161,7 @@ public class NodePrioritizer {
/** Add existing nodes allocated to the application */
private void addApplicationNodes() {
EnumSet<Node.State> legalStates = EnumSet.of(Node.State.active, Node.State.inactive, Node.State.reserved);
- allNodesAndHosts.nodes().stream()
+ allNodes.stream()
.filter(node -> node.type() == requestedNodes.type())
.filter(node -> legalStates.contains(node.state()))
.filter(node -> node.allocation().isPresent())
@@ -175,7 +174,7 @@ public class NodePrioritizer {
/** Add nodes already provisioned, but not allocated to any application */
private void addReadyNodes() {
- allNodesAndHosts.nodes().stream()
+ allNodes.stream()
.filter(node -> node.type() == requestedNodes.type())
.filter(node -> node.state() == Node.State.ready)
.map(node -> candidateFrom(node, false))
@@ -185,7 +184,7 @@ public class NodePrioritizer {
/** Create a candidate from given pre-existing node */
private NodeCandidate candidateFrom(Node node, boolean isSurplus) {
- Optional<Node> optionalParent = allNodesAndHosts.parentOf(node);
+ Optional<Node> optionalParent = allNodes.parentOf(node);
if (optionalParent.isPresent()) {
Node parent = optionalParent.get();
return NodeCandidate.createChild(node,
@@ -223,7 +222,7 @@ public class NodePrioritizer {
*/
private boolean canStillAllocate(Node node) {
if (node.type() != NodeType.tenant || node.parentHostname().isEmpty()) return true;
- Optional<Node> parent = allNodesAndHosts.parentOf(node);
+ Optional<Node> parent = allNodes.parentOf(node);
return parent.isPresent() && nodes.canAllocateTenantNodeTo(parent.get(), dynamicProvisioning);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
index 139e8848ab1..b6c7324c75c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
@@ -9,13 +9,11 @@ import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* Performs preparation of node activation changes for an application.
@@ -58,8 +56,8 @@ class Preparer {
// active config model which is changed on activate
private List<Node> prepareNodes(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
int wantedGroups) {
- NodesAndHosts<LockedNodeList> allNodesAndHosts = groupPreparer.createNodesAndHostUnlocked();
- NodeList appNodes = allNodesAndHosts.nodes().owner(application);
+ LockedNodeList allNodes = groupPreparer.createUnlockedNodeList();
+ NodeList appNodes = allNodes.owner(application);
List<Node> surplusNodes = findNodesInRemovableGroups(appNodes, cluster, wantedGroups);
List<Integer> usedIndices = appNodes.cluster(cluster.id()).mapToList(node -> node.allocation().get().membership().index());
@@ -71,11 +69,11 @@ class Preparer {
GroupPreparer.PrepareResult result = groupPreparer.prepare(application, clusterGroup,
requestedNodes.fraction(wantedGroups),
surplusNodes, indices, wantedGroups,
- allNodesAndHosts);
- allNodesAndHosts = result.allNodesAndHosts; // Might have changed
- List<Node> accepted = result.prepared;
+ allNodes);
+ allNodes = result.allNodes(); // Might have changed
+ List<Node> accepted = result.prepared();
if (requestedNodes.rejectNonActiveParent()) {
- NodeList activeHosts = allNodesAndHosts.nodes().state(Node.State.active).parents().nodeType(requestedNodes.type().hostType());
+ NodeList activeHosts = allNodes.state(Node.State.active).parents().nodeType(requestedNodes.type().hostType());
accepted = accepted.stream()
.filter(node -> node.parentHostname().isEmpty() || activeHosts.parentOf(node).isPresent())
.toList();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
index 2327b40885f..23c2d0fc47a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicAllocationTest.java
@@ -547,7 +547,7 @@ public class DynamicAllocationTest {
}
private List<Node> findSpareCapacity(ProvisioningTester tester) {
- NodeList nodes = tester.nodeRepository().nodes().list(State.values());
+ NodeList nodes = tester.nodeRepository().nodes().list();
return nodes.nodeType(NodeType.host)
.matching(host -> nodes.childrenOf(host).size() == 0) // Hosts without children
.asList();
diff --git a/parent/pom.xml b/parent/pom.xml
index d1fc3e4f76a..a9c3cfa82f8 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -900,9 +900,9 @@
<version>${eclipse-collections.version}</version>
</dependency>
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
- <version>${jetty-alpn.version}</version>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
+ <version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -916,12 +916,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-client</artifactId>
+ <artifactId>jetty-alpn-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-client</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
@@ -931,22 +931,22 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-server</artifactId>
+ <artifactId>jetty-io</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlet</artifactId>
+ <artifactId>jetty-jmx</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-jmx</artifactId>
+ <artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
@@ -955,6 +955,11 @@
<version>${jetty.version}</version>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
+ <version>${jetty-servlet-api.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version> <!-- 2.3.3 has a BROKEN manifest -->
@@ -1117,8 +1122,8 @@
<felix.log.version>1.0.1</felix.log.version>
<findbugs.version>3.0.2</findbugs.version> <!-- Should be kept in sync with guava -->
<hdrhistogram.version>2.1.12</hdrhistogram.version>
- <jetty.version>9.4.49.v20220914</jetty.version>
- <jetty-alpn.version>1.1.3.v20160715</jetty-alpn.version>
+ <jetty.version>11.0.13</jetty.version>
+ <jetty-servlet-api.version>5.0.2</jetty-servlet-api.version>
<jjwt.version>0.11.2</jjwt.version>
<jna.version>5.11.0</jna.version>
<junit.version>5.8.1</junit.version>
diff --git a/screwdriver.yaml b/screwdriver.yaml
index 182abb95968..d918078b80e 100644
--- a/screwdriver.yaml
+++ b/screwdriver.yaml
@@ -128,6 +128,7 @@ jobs:
# Set correct version in pom.xml files
(cd vespa && screwdriver/replace-vespa-version-in-poms.sh $VESPA_VERSION $(pwd) )
(cd sample-apps && find . -name "pom.xml" -exec sed -i -e "s,<vespa_version>.*</vespa_version>,<vespa_version>$VESPA_VERSION</vespa_version>," {} \;)
+ (cd sample-apps && find . -name "pom.xml" -exec sed -i -e "s:<version>[[]8,9[)]</version>:<version>$VESPA_VERSION</version>:" {} \;)
- make-srpm: |
make -C $WORKDIR/vespa -f .copr/Makefile srpm outdir=$WORKDIR
- *restore-cache
diff --git a/searchcore/src/tests/proton/matching/index_environment/index_environment_test.cpp b/searchcore/src/tests/proton/matching/index_environment/index_environment_test.cpp
index 9acc6eed669..60c60f0a37e 100644
--- a/searchcore/src/tests/proton/matching/index_environment/index_environment_test.cpp
+++ b/searchcore/src/tests/proton/matching/index_environment/index_environment_test.cpp
@@ -17,6 +17,7 @@ using search::index::schema::DataType;
using vespalib::eval::ConstantValue;
using SAF = Schema::AttributeField;
using SIAF = Schema::ImportedAttributeField;
+using SIF = Schema::IndexField;
const vespalib::string my_expr_ref(
"this is my reference ranking expression.\n"
@@ -157,21 +158,26 @@ Schema::UP schema_with_virtual_fields() {
result->addAttributeField(SAF("person_map.value.year", DataType::INT32, CollectionType::ARRAY));
result->addImportedAttributeField(SAF("int_map.key", DataType::INT32, CollectionType::ARRAY));
result->addImportedAttributeField(SAF("int_map.value", DataType::INT32, CollectionType::ARRAY));
+ // Index fields do not represent virtual fields:
+ result->addIndexField(SIF("url.hostname", DataType::STRING, CollectionType::SINGLE));
+ result->addIndexField(SIF("url.port", DataType::STRING, CollectionType::SINGLE));
return result;
}
TEST_F("virtual fields are extracted in index environment", Fixture(schema_with_virtual_fields()))
{
- ASSERT_EQUAL(9u, f.env.getNumFields());
+ ASSERT_EQUAL(11u, f.env.getNumFields());
TEST_DO(f.assertAttributeField(0, "person_map.key", DataType::INT32, CollectionType::ARRAY));
TEST_DO(f.assertAttributeField(1, "person_map.value.name", DataType::STRING, CollectionType::ARRAY));
TEST_DO(f.assertAttributeField(2, "person_map.value.year", DataType::INT32, CollectionType::ARRAY));
- TEST_DO(f.assertAttributeField(3, "int_map.key", DataType::INT32, CollectionType::ARRAY));
- TEST_DO(f.assertAttributeField(4, "int_map.value", DataType::INT32, CollectionType::ARRAY));
- EXPECT_EQUAL("[documentmetastore]", f.env.getField(5)->name());
- TEST_DO(f.assert_virtual_field(6, "int_map"));
- TEST_DO(f.assert_virtual_field(7, "person_map"));
- TEST_DO(f.assert_virtual_field(8, "person_map.value"));
+ TEST_DO(f.assertField(3, "url.hostname", DataType::STRING, CollectionType::SINGLE));
+ TEST_DO(f.assertField(4, "url.port", DataType::STRING, CollectionType::SINGLE));
+ TEST_DO(f.assertAttributeField(5, "int_map.key", DataType::INT32, CollectionType::ARRAY));
+ TEST_DO(f.assertAttributeField(6, "int_map.value", DataType::INT32, CollectionType::ARRAY));
+ EXPECT_EQUAL("[documentmetastore]", f.env.getField(7)->name());
+ TEST_DO(f.assert_virtual_field(8, "int_map"));
+ TEST_DO(f.assert_virtual_field(9, "person_map"));
+ TEST_DO(f.assert_virtual_field(10, "person_map.value"));
}
TEST_F("require that onnx model config can be obtained", Fixture(buildEmptySchema())) {
diff --git a/searchcore/src/vespa/searchcore/proton/matching/indexenvironment.cpp b/searchcore/src/vespa/searchcore/proton/matching/indexenvironment.cpp
index 6638b238e03..6fceb0db87f 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/indexenvironment.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/indexenvironment.cpp
@@ -32,7 +32,9 @@ extract_virtual_fields(const std::vector<search::fef::FieldInfo>& fields)
// These attributes have '.' in their names, example: my_map.key and my_map.value represent a map<int, string>.
StringSet result;
for (const auto& field : fields) {
- consider_field_for_extraction(field.name(), result);
+ if (field.hasAttribute()) {
+ consider_field_for_extraction(field.name(), result);
+ }
}
return result;
}
diff --git a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
index d00342d0e51..2f51459ebfa 100644
--- a/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
+++ b/searchlib/src/tests/attribute/tensorattribute/tensorattribute_test.cpp
@@ -887,6 +887,7 @@ public:
}
void test_setup();
void test_save_load(bool multi_node);
+ void test_address_space_usage();
};
template <HnswIndexType type>
@@ -935,6 +936,23 @@ TensorAttributeHnswIndex<type>::test_save_load(bool multi_node)
expect_level_0(1, index_b.get_node(2));
}
+template <HnswIndexType type>
+void
+TensorAttributeHnswIndex<type>::test_address_space_usage()
+{
+ bool dense = type == HnswIndexType::SINGLE;
+ search::AddressSpaceUsage usage = _attr->getAddressSpaceUsage();
+ const auto& all = usage.get_all();
+ EXPECT_EQUAL(dense ? 3u : 5u, all.size());
+ EXPECT_EQUAL(1u, all.count("tensor-store"));
+ EXPECT_EQUAL(1u, all.count("hnsw-levels-store"));
+ EXPECT_EQUAL(1u, all.count("hnsw-links-store"));
+ if (!dense) {
+ EXPECT_EQUAL(1u, all.count("hnsw-nodeid-mapping"));
+ EXPECT_EQUAL(1u, all.count("shared-string-repo"));
+ }
+}
+
class DenseTensorAttributeHnswIndex : public TensorAttributeHnswIndex<HnswIndexType::SINGLE> {
public:
DenseTensorAttributeHnswIndex() : TensorAttributeHnswIndex<HnswIndexType::SINGLE>(vec_2d_spec, FixtureTraits().hnsw()) {}
@@ -970,16 +988,15 @@ TEST_F("Hnsw index is integrated in mixed tensor attribute and can be saved and
f.test_save_load(true);
}
-TEST_F("Populates address space usage", DenseTensorAttributeHnswIndex)
+TEST_F("Populates address space usage in dense tensor attribute with hnsw index", DenseTensorAttributeHnswIndex)
{
- search::AddressSpaceUsage usage = f._attr->getAddressSpaceUsage();
- const auto& all = usage.get_all();
- EXPECT_EQUAL(3u, all.size());
- EXPECT_EQUAL(1u, all.count("tensor-store"));
- EXPECT_EQUAL(1u, all.count("hnsw-levels-store"));
- EXPECT_EQUAL(1u, all.count("hnsw-links-store"));
+ f.test_address_space_usage();
}
+TEST_F("Populates address space usage in mixed tensor attribute with hnsw index", MixedTensorAttributeHnswIndex)
+{
+ f.test_address_space_usage();
+}
class DenseTensorAttributeMockIndex : public Fixture {
public:
diff --git a/searchlib/src/vespa/searchlib/attribute/address_space_components.cpp b/searchlib/src/vespa/searchlib/attribute/address_space_components.cpp
index 244e01a3874..75c198f71e2 100644
--- a/searchlib/src/vespa/searchlib/attribute/address_space_components.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/address_space_components.cpp
@@ -21,5 +21,6 @@ const vespalib::string AddressSpaceComponents::tensor_store = "tensor-store";
const vespalib::string AddressSpaceComponents::shared_string_repo = "shared-string-repo";
const vespalib::string AddressSpaceComponents::hnsw_levels_store = "hnsw-levels-store";
const vespalib::string AddressSpaceComponents::hnsw_links_store = "hnsw-links-store";
+const vespalib::string AddressSpaceComponents::hnsw_nodeid_mapping = "hnsw-nodeid-mapping";
}
diff --git a/searchlib/src/vespa/searchlib/attribute/address_space_components.h b/searchlib/src/vespa/searchlib/attribute/address_space_components.h
index a8a41a024f8..20302a51f0d 100644
--- a/searchlib/src/vespa/searchlib/attribute/address_space_components.h
+++ b/searchlib/src/vespa/searchlib/attribute/address_space_components.h
@@ -20,6 +20,7 @@ public:
static const vespalib::string shared_string_repo;
static const vespalib::string hnsw_levels_store;
static const vespalib::string hnsw_links_store;
+ static const vespalib::string hnsw_nodeid_mapping;
};
}
diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
index 5483a0d2de4..1529611753b 100644
--- a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
@@ -706,6 +706,9 @@ HnswIndex<type>::populate_address_space_usage(search::AddressSpaceUsage& usage)
{
usage.set(AddressSpaceComponents::hnsw_levels_store, _graph.levels_store.addressSpaceUsage());
usage.set(AddressSpaceComponents::hnsw_links_store, _graph.links_store.addressSpaceUsage());
+ if constexpr (type == HnswIndexType::MULTI) {
+ usage.set(AddressSpaceComponents::hnsw_nodeid_mapping, _id_mapping.address_space_usage());
+ }
}
template <HnswIndexType type>
diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_nodeid_mapping.h b/searchlib/src/vespa/searchlib/tensor/hnsw_nodeid_mapping.h
index 8adf621b9b3..b544eb6f09f 100644
--- a/searchlib/src/vespa/searchlib/tensor/hnsw_nodeid_mapping.h
+++ b/searchlib/src/vespa/searchlib/tensor/hnsw_nodeid_mapping.h
@@ -55,7 +55,7 @@ public:
void assign_generation(generation_t current_gen);
void reclaim_memory(generation_t oldest_used_gen);
void on_load(vespalib::ConstArrayRef<HnswNode> nodes);
- // TODO: Add support for compaction
+ vespalib::AddressSpace address_space_usage() const { return _nodeids.addressSpaceUsage(); }
vespalib::MemoryUsage memory_usage() const;
vespalib::MemoryUsage update_stat(const vespalib::datastore::CompactionStrategy& compaction_strategy);
bool consider_compact() const noexcept { return _nodeids.consider_compact(); }
diff --git a/vespa-dependencies-enforcer/allowed-maven-dependencies.txt b/vespa-dependencies-enforcer/allowed-maven-dependencies.txt
index 1e38b6029ba..5a29ad22c51 100644
--- a/vespa-dependencies-enforcer/allowed-maven-dependencies.txt
+++ b/vespa-dependencies-enforcer/allowed-maven-dependencies.txt
@@ -2,8 +2,8 @@
#[non-test]
# Contains dependencies that are not used exclusively in 'test' scope
-ai.djl.huggingface:tokenizers:0.20.0
ai.djl:api:0.20.0
+ai.djl.huggingface:tokenizers:0.20.0
aopalliance:aopalliance:1.0
backport-util-concurrent:backport-util-concurrent:3.1
biz.aQute.bnd:biz.aQute.bnd.util:6.1.0
@@ -146,23 +146,21 @@ org.codehaus.plexus:plexus-sec-dispatcher:2.0
org.codehaus.plexus:plexus-utils:3.3.1
org.eclipse.collections:eclipse-collections:11.0.0
org.eclipse.collections:eclipse-collections-api:11.0.0
-org.eclipse.jetty:jetty-alpn-java-server:9.4.49.v20220914
-org.eclipse.jetty:jetty-alpn-server:9.4.49.v20220914
-org.eclipse.jetty:jetty-client:9.4.49.v20220914
-org.eclipse.jetty:jetty-continuation:9.4.49.v20220914
-org.eclipse.jetty:jetty-http:9.4.49.v20220914
-org.eclipse.jetty:jetty-io:9.4.49.v20220914
-org.eclipse.jetty:jetty-jmx:9.4.49.v20220914
-org.eclipse.jetty:jetty-security:9.4.49.v20220914
-org.eclipse.jetty:jetty-server:9.4.49.v20220914
-org.eclipse.jetty:jetty-servlet:9.4.49.v20220914
-org.eclipse.jetty:jetty-servlets:9.4.49.v20220914
-org.eclipse.jetty:jetty-util:9.4.49.v20220914
-org.eclipse.jetty:jetty-util-ajax:9.4.49.v20220914
-org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715
-org.eclipse.jetty.http2:http2-common:9.4.49.v20220914
-org.eclipse.jetty.http2:http2-hpack:9.4.49.v20220914
-org.eclipse.jetty.http2:http2-server:9.4.49.v20220914
+org.eclipse.jetty:jetty-alpn-client:11.0.13
+org.eclipse.jetty:jetty-alpn-java-server:11.0.13
+org.eclipse.jetty:jetty-alpn-server:11.0.13
+org.eclipse.jetty:jetty-client:11.0.13
+org.eclipse.jetty:jetty-http:11.0.13
+org.eclipse.jetty:jetty-io:11.0.13
+org.eclipse.jetty:jetty-jmx:11.0.13
+org.eclipse.jetty:jetty-security:11.0.13
+org.eclipse.jetty:jetty-server:11.0.13
+org.eclipse.jetty:jetty-servlet:11.0.13
+org.eclipse.jetty:jetty-util:11.0.13
+org.eclipse.jetty.http2:http2-common:11.0.13
+org.eclipse.jetty.http2:http2-hpack:11.0.13
+org.eclipse.jetty.http2:http2-server:11.0.13
+org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api:5.0.2
org.eclipse.sisu:org.eclipse.sisu.inject:0.3.5
org.eclipse.sisu:org.eclipse.sisu.plexus:0.3.5
org.fusesource.jansi:jansi:1.18
diff --git a/vespalib/src/tests/coro/async_io/async_io_test.cpp b/vespalib/src/tests/coro/async_io/async_io_test.cpp
index a506a5dd0d4..f5098e30086 100644
--- a/vespalib/src/tests/coro/async_io/async_io_test.cpp
+++ b/vespalib/src/tests/coro/async_io/async_io_test.cpp
@@ -4,14 +4,22 @@
#include <vespa/vespalib/coro/detached.h>
#include <vespa/vespalib/coro/completion.h>
#include <vespa/vespalib/coro/async_io.h>
+#include <vespa/vespalib/coro/async_crypto_socket.h>
#include <vespa/vespalib/net/socket_spec.h>
#include <vespa/vespalib/net/server_socket.h>
#include <vespa/vespalib/net/socket_handle.h>
#include <vespa/vespalib/net/socket_address.h>
+#include <vespa/vespalib/net/crypto_engine.h>
+#include <vespa/vespalib/util/require.h>
+#include <vespa/vespalib/util/classname.h>
+#include <vespa/vespalib/test/make_tls_options_for_testing.h>
+#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
+#include <vespa/vespalib/net/tls/maybe_tls_crypto_engine.h>
#include <vespa/vespalib/gtest/gtest.h>
using namespace vespalib;
using namespace vespalib::coro;
+using namespace vespalib::test;
Detached self_exiting_run_loop(AsyncIo::SP async) {
for (size_t i = 0; co_await async->schedule(); ++i) {
@@ -53,11 +61,11 @@ TEST(AsyncIoTest, shutdown_with_self_exiting_coroutine) {
f2.wait();
}
-Lazy<size_t> write_msg(AsyncIo &async, SocketHandle &socket, const vespalib::string &msg) {
+Lazy<size_t> write_msg(AsyncCryptoSocket &socket, const vespalib::string &msg) {
size_t written = 0;
while (written < msg.size()) {
size_t write_size = (msg.size() - written);
- ssize_t write_result = co_await async.write(socket, msg.data() + written, write_size);
+ ssize_t write_result = co_await socket.write(msg.data() + written, write_size);
if (write_result <= 0) {
co_return written;
}
@@ -66,12 +74,12 @@ Lazy<size_t> write_msg(AsyncIo &async, SocketHandle &socket, const vespalib::str
co_return written;
}
-Lazy<vespalib::string> read_msg(AsyncIo &async, SocketHandle &socket, size_t wanted_bytes) {
+Lazy<vespalib::string> read_msg(AsyncCryptoSocket &socket, size_t wanted_bytes) {
char tmp[64];
vespalib::string result;
while (result.size() < wanted_bytes) {
size_t read_size = std::min(sizeof(tmp), wanted_bytes - result.size());
- ssize_t read_result = co_await async.read(socket, tmp, read_size);
+ ssize_t read_result = co_await socket.read(tmp, read_size);
if (read_result <= 0) {
co_return result;
}
@@ -80,50 +88,78 @@ Lazy<vespalib::string> read_msg(AsyncIo &async, SocketHandle &socket, size_t wan
co_return result;
}
-Work verify_socket_io(AsyncIo &async, SocketHandle &socket, bool is_server) {
+Work verify_socket_io(AsyncCryptoSocket &socket, bool is_server) {
vespalib::string server_message = "hello, this is the server speaking";
vespalib::string client_message = "please pick up, I need to talk to you";
if (is_server) {
- vespalib::string read = co_await read_msg(async, socket, client_message.size());
+ vespalib::string read = co_await read_msg(socket, client_message.size());
EXPECT_EQ(client_message, read);
- size_t written = co_await write_msg(async, socket, server_message);
+ size_t written = co_await write_msg(socket, server_message);
EXPECT_EQ(written, ssize_t(server_message.size()));
} else {
- size_t written = co_await write_msg(async, socket, client_message);
+ size_t written = co_await write_msg(socket, client_message);
EXPECT_EQ(written, ssize_t(client_message.size()));
- vespalib::string read = co_await read_msg(async, socket, server_message.size());
+ vespalib::string read = co_await read_msg(socket, server_message.size());
EXPECT_EQ(server_message, read);
}
co_return Done{};
}
-Work async_server(AsyncIo &async, ServerSocket &server_socket) {
+Work async_server(AsyncIo &async, CryptoEngine &engine, ServerSocket &server_socket) {
auto server_addr = server_socket.address();
auto server_spec = server_addr.spec();
fprintf(stderr, "listening at '%s' (fd = %d)\n", server_spec.c_str(), server_socket.get_fd());
- auto socket = co_await async.accept(server_socket);
- fprintf(stderr, "server fd: %d\n", socket.get());
- co_return co_await verify_socket_io(async, socket, true);
+ auto raw_socket = co_await async.accept(server_socket);
+ fprintf(stderr, "server fd: %d\n", raw_socket.get());
+ auto socket = co_await AsyncCryptoSocket::accept(async, engine, std::move(raw_socket));
+ EXPECT_TRUE(socket);
+ REQUIRE(socket);
+ fprintf(stderr, "server socket type: %s\n", getClassName(*socket).c_str());
+ co_return co_await verify_socket_io(*socket, true);
}
-Work async_client(AsyncIo &async, ServerSocket &server_socket) {
+Work async_client(AsyncIo &async, CryptoEngine &engine, ServerSocket &server_socket) {
auto server_addr = server_socket.address();
- auto server_spec = server_addr.spec();
- fprintf(stderr, "connecting to '%s'\n", server_spec.c_str());
- auto client_addr = SocketSpec(server_spec).client_address();
- auto socket = co_await async.connect(client_addr);
- fprintf(stderr, "client fd: %d\n", socket.get());
- co_return co_await verify_socket_io(async, socket, false);
+ auto server_spec = SocketSpec(server_addr.spec());
+ fprintf(stderr, "connecting to '%s'\n", server_spec.spec().c_str());
+ auto client_addr = server_spec.client_address();
+ auto raw_socket = co_await async.connect(client_addr);
+ fprintf(stderr, "client fd: %d\n", raw_socket.get());
+ auto socket = co_await AsyncCryptoSocket::connect(async, engine, std::move(raw_socket), server_spec);
+ EXPECT_TRUE(socket);
+ REQUIRE(socket);
+ fprintf(stderr, "client socket type: %s\n", getClassName(*socket).c_str());
+ co_return co_await verify_socket_io(*socket, false);
}
-TEST(AsyncIoTest, raw_socket_io) {
+void verify_socket_io(CryptoEngine &engine) {
ServerSocket server_socket("tcp/0");
server_socket.set_blocking(false);
auto async = AsyncIo::create();
- auto f1 = make_future(async_server(async, server_socket));
- auto f2 = make_future(async_client(async, server_socket));
- f1.wait();
- f2.wait();
+ auto f1 = make_future(async_server(async, engine, server_socket));
+ auto f2 = make_future(async_client(async, engine, server_socket));
+ (void) f1.get();
+ (void) f2.get();
+}
+
+TEST(AsyncIoTest, raw_socket_io) {
+ NullCryptoEngine engine;
+ verify_socket_io(engine);
+}
+
+TEST(AsyncIoTest, tls_socket_io) {
+ TlsCryptoEngine engine(make_tls_options_for_testing());
+ verify_socket_io(engine);
+}
+
+TEST(AsyncIoTest, maybe_tls_true_socket_io) {
+ MaybeTlsCryptoEngine engine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), true);
+ verify_socket_io(engine);
+}
+
+TEST(AsyncIoTest, maybe_tls_false_socket_io) {
+ MaybeTlsCryptoEngine engine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), false);
+ verify_socket_io(engine);
}
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/vespalib/src/vespa/vespalib/btree/btreeaggregator.h b/vespalib/src/vespa/vespalib/btree/btreeaggregator.h
index 8a15d1ca34f..13109f5ffae 100644
--- a/vespalib/src/vespa/vespalib/btree/btreeaggregator.h
+++ b/vespalib/src/vespa/vespalib/btree/btreeaggregator.h
@@ -34,7 +34,7 @@ public:
static void recalc(InternalNodeType &node, const NodeAllocatorType &allocator, const AggrCalcT &aggrCalc);
static AggregatedType recalc(LeafNodeType &node, LeafNodeType &splitNode, const AggrCalcT &aggrCalc);
-
+
static AggregatedType recalc(InternalNodeType &node, InternalNodeType &splitNode,
const NodeAllocatorType &allocator, const AggrCalcT &aggrCalc);
};
diff --git a/vespalib/src/vespa/vespalib/btree/btreeinserter.h b/vespalib/src/vespa/vespalib/btree/btreeinserter.h
index 2a4985b04b8..947213ab7e6 100644
--- a/vespalib/src/vespa/vespalib/btree/btreeinserter.h
+++ b/vespalib/src/vespa/vespalib/btree/btreeinserter.h
@@ -8,7 +8,7 @@
#include "btreeaggregator.h"
#include "noaggrcalc.h"
#include "minmaxaggrcalc.h"
-#include "btreeiterator.h"
+#include "btreeiterator.h"
namespace vespalib::btree {
diff --git a/vespalib/src/vespa/vespalib/btree/btreeiterator.h b/vespalib/src/vespa/vespalib/btree/btreeiterator.h
index 15061a536ef..4b99edf592a 100644
--- a/vespalib/src/vespa/vespalib/btree/btreeiterator.h
+++ b/vespalib/src/vespa/vespalib/btree/btreeiterator.h
@@ -297,7 +297,7 @@ protected:
BTreeIteratorBase(const BTreeIteratorBase &other);
BTreeIteratorBase &operator=(const BTreeIteratorBase &other);
-
+
/**
* Set new tree height and clear portions of path that are now
* beyond new tree height. For internal use only.
@@ -414,7 +414,7 @@ public:
size_t
size() const;
-
+
/**
* Return the current position in the tree.
*/
@@ -485,7 +485,7 @@ public:
rbegin();
/*
- * Get aggregated values for the current tree.
+ * Get aggregated values for the current tree.
*/
const AggrT &
getAggregated() const;
@@ -697,7 +697,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than or equal to the key argument. Original
* position must be valid with a key that is less than the key argument.
- *
+ *
* Tree traits determine if binary or linear search is performed within
* each tree node.
*
@@ -711,7 +711,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than or equal to the key argument. Original
* position must be valid with a key that is less than the key argument.
- *
+ *
* Binary search is performed within each tree node.
*
* @param key Key to search for
@@ -724,7 +724,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than or equal to the key argument. Original
* position must be valid with a key that is less than the key argument.
- *
+ *
* Linear search is performed within each tree node.
*
* @param key Key to search for
@@ -737,7 +737,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than the key argument. Original position must
* be valid with a key that is less than or equal to the key argument.
- *
+ *
* Tree traits determine if binary or linear search is performed within
* each tree node.
*
@@ -751,7 +751,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than the key argument. Original position must
* be valid with a key that is less than or equal to the key argument.
- *
+ *
* Binary search is performed within each tree node.
*
* @param key Key to search for
@@ -764,7 +764,7 @@ public:
* Step iterator forwards until it is at a position with a key
* that is greater than the key argument. Original position must
* be valid with a key that is less than or equal to the key argument.
- *
+ *
* Linear search is performed within each tree node.
*
* @param key Key to search for
@@ -868,7 +868,7 @@ public:
{
return const_cast<NodeAllocatorType &>(*_allocator);
}
-
+
BTreeNode::Ref
moveFirstLeafNode(BTreeNode::Ref rootRef);
diff --git a/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h b/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
index 38739f03798..3fa5f1188cd 100644
--- a/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
+++ b/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
@@ -42,7 +42,7 @@ private:
using RefVector = vespalib::Array<BTreeNode::Ref>;
using BTreeRootBaseTypeVector = vespalib::Array<BTreeRootBaseType *>;
-
+
// Nodes that might not be frozen.
RefVector _internalToFreeze;
RefVector _leafToFreeze;
diff --git a/vespalib/src/vespa/vespalib/btree/btreenodestore.h b/vespalib/src/vespa/vespalib/btree/btreenodestore.h
index 3b37be33924..8fef0185674 100644
--- a/vespalib/src/vespa/vespalib/btree/btreenodestore.h
+++ b/vespalib/src/vespa/vespalib/btree/btreenodestore.h
@@ -189,7 +189,7 @@ public:
bool has_held_buffers() const {
return _store.has_held_buffers();
}
-
+
template <typename FunctionType>
void foreach_key(EntryRef ref, FunctionType func) const {
if (!ref.valid())
diff --git a/vespalib/src/vespa/vespalib/btree/btreeremover.h b/vespalib/src/vespa/vespalib/btree/btreeremover.h
index 33ecc0be88b..852a8aa2104 100644
--- a/vespalib/src/vespa/vespalib/btree/btreeremover.h
+++ b/vespalib/src/vespa/vespalib/btree/btreeremover.h
@@ -8,7 +8,7 @@
#include "btreeaggregator.h"
#include "noaggrcalc.h"
#include "minmaxaggrcalc.h"
-#include "btreeiterator.h"
+#include "btreeiterator.h"
namespace vespalib::btree {
@@ -56,7 +56,7 @@ class BTreeRemover : public BTreeRemoverBase<KeyT, DataT, AggrT,
TraitsT::INTERNAL_SLOTS,
TraitsT::LEAF_SLOTS,
AggrCalcT>
-
+
{
public:
using ParentType = BTreeRemoverBase<KeyT, DataT, AggrT,
diff --git a/vespalib/src/vespa/vespalib/btree/btreerootbase.h b/vespalib/src/vespa/vespalib/btree/btreerootbase.h
index 6b57dda7660..8589f43d909 100644
--- a/vespalib/src/vespa/vespalib/btree/btreerootbase.h
+++ b/vespalib/src/vespa/vespalib/btree/btreerootbase.h
@@ -54,7 +54,7 @@ public:
// entry for _root is owned by new copy of BTreeRootBase.
_root = BTreeNode::Ref();
}
-
+
void setRoots(BTreeNode::Ref newRoot) {
_root = newRoot;
_frozenRoot = newRoot.ref();
diff --git a/vespalib/src/vespa/vespalib/btree/btreestore.h b/vespalib/src/vespa/vespalib/btree/btreestore.h
index 5250cfa4535..c228c084e6d 100644
--- a/vespalib/src/vespa/vespalib/btree/btreestore.h
+++ b/vespalib/src/vespa/vespalib/btree/btreestore.h
@@ -55,7 +55,7 @@ public:
using BufferState = datastore::BufferState;
static constexpr uint32_t clusterLimit = 8;
-
+
enum BufferTypes
{
BUFFERTYPE_ARRAY1 = 0,
@@ -209,13 +209,13 @@ public:
applyNewArray(EntryRef &ref,
AddIter aOrg,
AddIter ae);
-
+
void
applyNewTree(EntryRef &ref,
AddIter a,
AddIter ae,
CompareT comp);
-
+
void
applyNew(EntryRef &ref,
AddIter a,
diff --git a/vespalib/src/vespa/vespalib/btree/minmaxaggregated.h b/vespalib/src/vespa/vespalib/btree/minmaxaggregated.h
index 4b7a8a85db3..802f9822d71 100644
--- a/vespalib/src/vespa/vespalib/btree/minmaxaggregated.h
+++ b/vespalib/src/vespa/vespalib/btree/minmaxaggregated.h
@@ -11,7 +11,7 @@ class MinMaxAggregated
{
int32_t _min;
int32_t _max;
-
+
public:
MinMaxAggregated()
: _min(std::numeric_limits<int32_t>::max()),
diff --git a/vespalib/src/vespa/vespalib/coro/CMakeLists.txt b/vespalib/src/vespa/vespalib/coro/CMakeLists.txt
index 0fbb94e8255..8a7a0ade049 100644
--- a/vespalib/src/vespa/vespalib/coro/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/coro/CMakeLists.txt
@@ -1,6 +1,7 @@
# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
vespa_add_library(vespalib_vespalib_coro OBJECT
SOURCES
+ async_crypto_socket.cpp
async_io.cpp
DEPENDS
)
diff --git a/vespalib/src/vespa/vespalib/coro/async_crypto_socket.cpp b/vespalib/src/vespa/vespalib/coro/async_crypto_socket.cpp
new file mode 100644
index 00000000000..4f862b48690
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/coro/async_crypto_socket.cpp
@@ -0,0 +1,261 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "async_crypto_socket.h"
+#include <vespa/vespalib/net/tls/protocol_snooping.h>
+#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
+#include <vespa/vespalib/net/tls/crypto_codec.h>
+#include <vespa/vespalib/data/smart_buffer.h>
+
+namespace vespalib::coro {
+
+namespace {
+
+using net::tls::CryptoCodec;
+using net::tls::HandshakeResult;
+using net::tls::EncodeResult;
+using net::tls::DecodeResult;
+
+struct InvalidSocket : AsyncCryptoSocket {
+ Lazy<ssize_t> read(char *, size_t) override { co_return -EINVAL; }
+ Lazy<ssize_t> write(const char *, size_t) override { co_return -EINVAL; }
+};
+
+struct RawSocket : AsyncCryptoSocket {
+ AsyncIo::SP async;
+ SocketHandle handle;
+ RawSocket(AsyncIo &async_in, SocketHandle handle_in)
+ : async(async_in.shared_from_this()), handle(std::move(handle_in)) {}
+ Lazy<ssize_t> read(char *buf, size_t len) override {
+ return async->read(handle, buf, len);
+ }
+ Lazy<ssize_t> write(const char *buf, size_t len) override {
+ return async->write(handle, buf, len);
+ }
+};
+
+struct SnoopedRawSocket : AsyncCryptoSocket {
+ AsyncIo::SP async;
+ SocketHandle handle;
+ SmartBuffer data;
+ SnoopedRawSocket(AsyncIo &async_in, SocketHandle handle_in)
+ : async(async_in.shared_from_this()), handle(std::move(handle_in)), data(0) {}
+ void inject_data(const char *buf, size_t len) {
+ if (len > 0) {
+ auto dst = data.reserve(len);
+ memcpy(dst.data, buf, len);
+ data.commit(len);
+ }
+ }
+ Lazy<ssize_t> read_from_buffer(char *buf, size_t len) {
+ auto src = data.obtain();
+ size_t frame = std::min(len, src.size);
+ if (frame > 0) {
+ memcpy(buf, src.data, frame);
+ data.evict(frame);
+ data.drop_if_empty();
+ }
+ co_return frame;
+ }
+ Lazy<ssize_t> read(char *buf, size_t len) override {
+ if (data.empty()) {
+ return async->read(handle, buf, len);
+ } else {
+ return read_from_buffer(buf, len);
+ }
+ }
+ Lazy<ssize_t> write(const char *buf, size_t len) override {
+ return async->write(handle, buf, len);
+ }
+};
+
+struct TlsSocket : AsyncCryptoSocket {
+ AsyncIo::SP async;
+ SocketHandle handle;
+ std::unique_ptr<CryptoCodec> codec;
+ SmartBuffer app_input;
+ SmartBuffer enc_input;
+ SmartBuffer enc_output;
+ TlsSocket(AsyncIo &async_in, SocketHandle handle_in, std::unique_ptr<CryptoCodec> codec_in)
+ : async(async_in.shared_from_this()), handle(std::move(handle_in)), codec(std::move(codec_in)),
+ app_input(0), enc_input(0), enc_output(0) {}
+ void inject_enc_input(const char *buf, size_t len) {
+ if (len > 0) {
+ auto dst = enc_input.reserve(len);
+ memcpy(dst.data, buf, len);
+ enc_input.commit(len);
+ }
+ }
+ Lazy<bool> flush_enc_output() {
+ while (!enc_output.empty()) {
+ auto pending = enc_output.obtain();
+ auto res = co_await async->write(handle, pending.data, pending.size);
+ if (res > 0) {
+ enc_output.evict(res);
+ } else {
+ co_return false;
+ }
+ }
+ co_return true;
+ }
+ Lazy<bool> fill_enc_input() {
+ auto dst = enc_input.reserve(codec->min_encode_buffer_size());
+ ssize_t res = co_await async->read(handle, dst.data, dst.size);
+ if (res > 0) {
+ enc_input.commit(res);
+ co_return true;
+ } else {
+ co_return false;
+ }
+ }
+ Lazy<bool> handshake() {
+ for (;;) {
+ auto in = enc_input.obtain();
+ auto out = enc_output.reserve(codec->min_encode_buffer_size());
+ auto hs_res = codec->handshake(in.data, in.size, out.data, out.size);
+ enc_input.evict(hs_res.bytes_consumed);
+ enc_output.commit(hs_res.bytes_produced);
+ switch (hs_res.state) {
+ case ::vespalib::net::tls::HandshakeResult::State::Failed: co_return false;
+ case ::vespalib::net::tls::HandshakeResult::State::Done: co_return co_await flush_enc_output();
+ case ::vespalib::net::tls::HandshakeResult::State::NeedsWork:
+ codec->do_handshake_work();
+ break;
+ case ::vespalib::net::tls::HandshakeResult::State::NeedsMorePeerData:
+ bool flush_ok = co_await flush_enc_output();
+ if (!flush_ok) {
+ co_return false;
+ }
+ bool fill_ok = co_await fill_enc_input();
+ if (!fill_ok) {
+ co_return false;
+ }
+ }
+ }
+ }
+ Lazy<ssize_t> read(char *buf, size_t len) override {
+ while (app_input.empty()) {
+ auto src = enc_input.obtain();
+ auto dst = app_input.reserve(codec->min_decode_buffer_size());
+ auto res = codec->decode(src.data, src.size, dst.data, dst.size);
+ app_input.commit(res.bytes_produced);
+ enc_input.evict(res.bytes_consumed);
+ if (res.failed()) {
+ co_return -EIO;
+ }
+ if (res.closed()) {
+ co_return 0;
+ }
+ if (app_input.empty()) {
+ bool fill_ok = co_await fill_enc_input();
+ if (!fill_ok) {
+ co_return -EIO;
+ }
+ }
+ }
+ auto src = app_input.obtain();
+ size_t frame = std::min(len, src.size);
+ if (frame > 0) {
+ memcpy(buf, src.data, frame);
+ app_input.evict(frame);
+ }
+ co_return frame;
+ }
+ Lazy<ssize_t> write(const char *buf, size_t len) override {
+ auto dst = enc_output.reserve(codec->min_encode_buffer_size());
+ auto res = codec->encode(buf, len, dst.data, dst.size);
+ if (res.failed) {
+ co_return -EIO;
+ }
+ enc_output.commit(res.bytes_produced);
+ bool flush_ok = co_await flush_enc_output();
+ if (!flush_ok) {
+ co_return -EIO;
+ }
+ co_return res.bytes_consumed;
+ }
+};
+
+Lazy<AsyncCryptoSocket::UP> try_handshake(std::unique_ptr<TlsSocket> tls_socket) {
+ bool hs_ok = co_await tls_socket->handshake();
+ if (hs_ok) {
+ co_return std::move(tls_socket);
+ } else {
+ co_return std::make_unique<InvalidSocket>();
+ }
+}
+
+Lazy<AsyncCryptoSocket::UP> accept_tls(AsyncIo &async, AbstractTlsCryptoEngine &crypto, SocketHandle handle) {
+ auto tls_codec = crypto.create_tls_server_crypto_codec(handle);
+ auto tls_socket = std::make_unique<TlsSocket>(async, std::move(handle), std::move(tls_codec));
+ co_return co_await try_handshake(std::move(tls_socket));
+}
+
+Lazy<AsyncCryptoSocket::UP> accept_maybe_tls(AsyncIo &async, AbstractTlsCryptoEngine &crypto, SocketHandle handle) {
+ char buf[net::tls::snooping::min_header_bytes_to_observe()];
+ memset(buf, 0, sizeof(buf));
+ size_t snooped = 0;
+ while (snooped < sizeof(buf)) {
+ auto res = co_await async.read(handle, buf + snooped, sizeof(buf) - snooped);
+ if (res <= 0) {
+ co_return std::make_unique<InvalidSocket>();
+ }
+ snooped += res;
+ }
+ if (net::tls::snooping::snoop_client_hello_header(buf) == net::tls::snooping::TlsSnoopingResult::ProbablyTls) {
+ auto tls_codec = crypto.create_tls_server_crypto_codec(handle);
+ auto tls_socket = std::make_unique<TlsSocket>(async, std::move(handle), std::move(tls_codec));
+ tls_socket->inject_enc_input(buf, snooped);
+ co_return co_await try_handshake(std::move(tls_socket));
+ } else {
+ auto plain_socket = std::make_unique<SnoopedRawSocket>(async, std::move(handle));
+ plain_socket->inject_data(buf, snooped);
+ co_return std::move(plain_socket);
+ }
+}
+
+Lazy<AsyncCryptoSocket::UP> connect_tls(AsyncIo &async, AbstractTlsCryptoEngine &crypto, SocketHandle handle, SocketSpec spec) {
+ auto tls_codec = crypto.create_tls_client_crypto_codec(handle, spec);
+ auto tls_socket = std::make_unique<TlsSocket>(async, std::move(handle), std::move(tls_codec));
+ co_return co_await try_handshake(std::move(tls_socket));
+}
+
+}
+
+AsyncCryptoSocket::~AsyncCryptoSocket() = default;
+
+Lazy<AsyncCryptoSocket::UP>
+AsyncCryptoSocket::accept(AsyncIo &async, CryptoEngine &crypto,
+ SocketHandle handle)
+{
+ if (dynamic_cast<NullCryptoEngine*>(&crypto)) {
+ co_return std::make_unique<RawSocket>(async, std::move(handle));
+ }
+ if (auto *tls_engine = dynamic_cast<AbstractTlsCryptoEngine*>(&crypto)) {
+ if (tls_engine->always_use_tls_when_server()) {
+ co_return co_await accept_tls(async, *tls_engine, std::move(handle));
+ } else {
+ co_return co_await accept_maybe_tls(async, *tls_engine, std::move(handle));
+ }
+ }
+ co_return std::make_unique<InvalidSocket>();
+}
+
+Lazy<AsyncCryptoSocket::UP>
+AsyncCryptoSocket::connect(AsyncIo &async, CryptoEngine &crypto,
+ SocketHandle handle, SocketSpec spec)
+{
+ if (dynamic_cast<NullCryptoEngine*>(&crypto)) {
+ (void) spec; // no SNI for plaintext sockets
+ co_return std::make_unique<RawSocket>(async, std::move(handle));
+ }
+ if (auto *tls_engine = dynamic_cast<AbstractTlsCryptoEngine*>(&crypto)) {
+ if (tls_engine->use_tls_when_client()) {
+ co_return co_await connect_tls(async, *tls_engine, std::move(handle), spec);
+ } else {
+ co_return std::make_unique<RawSocket>(async, std::move(handle));
+ }
+ }
+ co_return std::make_unique<InvalidSocket>();
+}
+
+}
diff --git a/vespalib/src/vespa/vespalib/coro/async_crypto_socket.h b/vespalib/src/vespa/vespalib/coro/async_crypto_socket.h
new file mode 100644
index 00000000000..7d792994a80
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/coro/async_crypto_socket.h
@@ -0,0 +1,31 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "lazy.h"
+#include "async_io.h"
+
+#include <vespa/vespalib/net/socket_spec.h>
+#include <vespa/vespalib/net/socket_handle.h>
+#include <vespa/vespalib/net/crypto_engine.h>
+
+#include <memory>
+
+namespace vespalib::coro {
+
+// A socket endpoint supporting async read/write with encryption
+
+struct AsyncCryptoSocket {
+ using UP = std::unique_ptr<AsyncCryptoSocket>;
+
+ virtual Lazy<ssize_t> read(char *buf, size_t len) = 0;
+ virtual Lazy<ssize_t> write(const char *buf, size_t len) = 0;
+ virtual ~AsyncCryptoSocket();
+
+ static Lazy<AsyncCryptoSocket::UP> accept(AsyncIo &async, CryptoEngine &crypto,
+ SocketHandle handle);
+ static Lazy<AsyncCryptoSocket::UP> connect(AsyncIo &async, CryptoEngine &crypto,
+ SocketHandle handle, SocketSpec spec);
+};
+
+}
diff --git a/vespalib/src/vespa/vespalib/coro/async_io.h b/vespalib/src/vespa/vespalib/coro/async_io.h
index 72e2ef3a312..56d2aae7fdf 100644
--- a/vespalib/src/vespa/vespalib/coro/async_io.h
+++ b/vespalib/src/vespa/vespalib/coro/async_io.h
@@ -25,7 +25,7 @@ struct AsyncIo : std::enable_shared_from_this<AsyncIo> {
AsyncIo &operator=(AsyncIo &&) = delete;
virtual ~AsyncIo();
using SP = std::shared_ptr<AsyncIo>;
-
+
// thin wrapper used by the owner to handle lifetime
class Owner {
private:
@@ -44,13 +44,13 @@ struct AsyncIo : std::enable_shared_from_this<AsyncIo> {
void fini_shutdown();
~Owner();
};
-
+
// create an async_io 'runtime'
static Owner create();
// implementation tag
virtual vespalib::string get_impl_spec() = 0;
-
+
// api for async io used by coroutines
virtual Lazy<SocketHandle> accept(ServerSocket &server_socket) = 0;
virtual Lazy<SocketHandle> connect(const SocketAddress &addr) = 0;
diff --git a/vespalib/src/vespa/vespalib/coro/generator.h b/vespalib/src/vespa/vespalib/coro/generator.h
index 1f1468d1d19..a28cba47e53 100644
--- a/vespalib/src/vespa/vespalib/coro/generator.h
+++ b/vespalib/src/vespa/vespalib/coro/generator.h
@@ -53,7 +53,7 @@ public:
copy_awaiter(const copy_awaiter&) = delete;
cpy_type value_cpy;
};
-
+
public:
promise_type(promise_type &&) = delete;
promise_type(const promise_type &) = delete;
@@ -105,10 +105,10 @@ public:
return _handle.promise().result();
}
};
-
+
private:
Handle _handle;
-
+
public:
Generator(const Generator &) = delete;
Generator &operator=(const Generator &) = delete;
diff --git a/vespalib/src/vespa/vespalib/data/slime/external_memory.h b/vespalib/src/vespa/vespalib/data/slime/external_memory.h
index 1a7dd85d15b..25b5c2765d7 100644
--- a/vespalib/src/vespa/vespalib/data/slime/external_memory.h
+++ b/vespalib/src/vespa/vespalib/data/slime/external_memory.h
@@ -15,7 +15,7 @@ namespace vespalib::slime {
**/
struct ExternalMemory {
using UP = std::unique_ptr<ExternalMemory>;
- virtual Memory get() const = 0;
+ virtual Memory get() const = 0;
virtual ~ExternalMemory() = default;
};
diff --git a/vespalib/src/vespa/vespalib/data/smart_buffer.h b/vespalib/src/vespa/vespalib/data/smart_buffer.h
index fc7042c5eea..5266e0f1c75 100644
--- a/vespalib/src/vespa/vespalib/data/smart_buffer.h
+++ b/vespalib/src/vespa/vespalib/data/smart_buffer.h
@@ -22,7 +22,7 @@ private:
size_t _write_pos;
const char *read_ptr() const { return (const char *)(_data.get()) + _read_pos; }
- size_t read_len() const { return (_write_pos - _read_pos); }
+ size_t read_len() const { return (_write_pos - _read_pos); }
char *write_ptr() { return (char *)(_data.get()) + _write_pos; }
size_t write_len() const { return (_data.size() - _write_pos); }
size_t unused() const { return (_data.size() - read_len()); }
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_btree_dictionary_read_snapshot.h b/vespalib/src/vespa/vespalib/datastore/unique_store_btree_dictionary_read_snapshot.h
index b38c49ccab4..fc91c6fa292 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_btree_dictionary_read_snapshot.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_btree_dictionary_read_snapshot.h
@@ -17,7 +17,7 @@ private:
using BTreeDictionaryType = BTreeDictionaryT;
using FrozenView = typename BTreeDictionaryType::FrozenView;
FrozenView _frozen_view;
-
+
public:
UniqueStoreBTreeDictionaryReadSnapshot(FrozenView frozen_view);
void fill() override;
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h b/vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h
index f91ebf64257..fa0e5630b74 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h
@@ -11,7 +11,7 @@
namespace vespalib::datastore {
/**
- * Helper class for comparing elements in unique store.
+ * Helper class for comparing elements in unique store.
*/
template <typename EntryT>
class UniqueStoreComparatorHelper {
@@ -81,7 +81,7 @@ class UniqueStoreComparatorHelper<float> : public UniqueStoreFloatingPointCompar
template <>
class UniqueStoreComparatorHelper<double> : public UniqueStoreFloatingPointComparatorHelper<double> {
};
-
+
/**
* Compare two entries based on entry refs.
*
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h b/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
index 8977fd1cce8..265478fbaf5 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
@@ -36,7 +36,7 @@ public:
: UniqueStoreEntryBase(),
_value()
{ }
-
+
UniqueStoreSmallStringEntry(const char *value, size_t value_len, size_t array_size)
: UniqueStoreEntryBase()
{
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_value_filter.h b/vespalib/src/vespa/vespalib/datastore/unique_store_value_filter.h
index 28c7a5ff001..5b4c078ab48 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_value_filter.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_value_filter.h
@@ -30,7 +30,7 @@ public:
};
template <typename EntryT>
-const EntryT UniqueStoreFloatingPointValueFilter<EntryT>::normalized_nan = -std::numeric_limits<EntryT>::quiet_NaN();
+const EntryT UniqueStoreFloatingPointValueFilter<EntryT>::normalized_nan = -std::numeric_limits<EntryT>::quiet_NaN();
/*
* Specialized helper class for normalizing float values inserted into unique store.
diff --git a/vespalib/src/vespa/vespalib/geo/zcurve.h b/vespalib/src/vespa/vespalib/geo/zcurve.h
index 2efcc50d1ed..2f92b3a019b 100644
--- a/vespalib/src/vespa/vespalib/geo/zcurve.h
+++ b/vespalib/src/vespa/vespalib/geo/zcurve.h
@@ -32,9 +32,9 @@ public:
~BoundingBox() = default;
- int64_t getzMinx() const { return _zMinx; }
- int64_t getzMaxx() const { return _zMaxx; }
- int64_t getzMiny() const { return _zMiny; }
+ int64_t getzMinx() const { return _zMinx; }
+ int64_t getzMaxx() const { return _zMaxx; }
+ int64_t getzMiny() const { return _zMiny; }
int64_t getzMaxy() const { return _zMaxy; }
/**
diff --git a/vespalib/src/vespa/vespalib/net/selector.h b/vespalib/src/vespa/vespalib/net/selector.h
index 9b278189215..6b40053abe1 100644
--- a/vespalib/src/vespa/vespalib/net/selector.h
+++ b/vespalib/src/vespa/vespalib/net/selector.h
@@ -13,7 +13,7 @@
namespace vespalib {
/**
- * Simple class used to hold events extracted from a call to epoll_wait.
+ * Simple class used to hold events extracted from a call to epoll_wait.
**/
class EpollEvents
{
@@ -44,7 +44,7 @@ public:
Selector()
: _epoll(), _wakeup_pipe(), _events(4096)
{
- _epoll.add(_wakeup_pipe.get_read_fd(), nullptr, true, false);
+ _epoll.add(_wakeup_pipe.get_read_fd(), nullptr, true, false);
}
~Selector() {
_epoll.remove(_wakeup_pipe.get_read_fd());
diff --git a/vespalib/src/vespa/vespalib/stllike/hashtable.h b/vespalib/src/vespa/vespalib/stllike/hashtable.h
index 55b055cddaf..4dbb138f63d 100644
--- a/vespalib/src/vespa/vespalib/stllike/hashtable.h
+++ b/vespalib/src/vespa/vespalib/stllike/hashtable.h
@@ -306,7 +306,7 @@ public:
// This will insert unconditionally, without checking presence, and might cause duplicates.
// Use at you own risk.
void force_insert(Value && value);
-
+
/// This gives faster iteration than can be achieved by the iterators.
template <typename Func>
void for_each(Func func) const;
diff --git a/vespalib/src/vespa/vespalib/test/datastore/buffer_stats.h b/vespalib/src/vespa/vespalib/test/datastore/buffer_stats.h
index 110d2354bd5..9fe77a853a8 100644
--- a/vespalib/src/vespa/vespalib/test/datastore/buffer_stats.h
+++ b/vespalib/src/vespa/vespalib/test/datastore/buffer_stats.h
@@ -12,7 +12,7 @@ namespace vespalib::datastore::test {
*/
struct BufferStats
{
- // elements
+ // elements
size_t _used;
size_t _hold;
size_t _dead;
@@ -25,7 +25,7 @@ struct BufferStats
BufferStats &dead(size_t val) { _dead += val; return *this; }
BufferStats &extra_used(size_t val) { _extra_used += val; return *this; }
BufferStats &extra_hold(size_t val) { _extra_hold += val; return *this; }
-
+
BufferStats &hold_to_dead(size_t val) {
dec_hold(val);
_dead += val;
diff --git a/vespalib/src/vespa/vespalib/util/benchmark_timer.h b/vespalib/src/vespa/vespalib/util/benchmark_timer.h
index d91d58069fa..b49b03a7787 100644
--- a/vespalib/src/vespa/vespalib/util/benchmark_timer.h
+++ b/vespalib/src/vespa/vespalib/util/benchmark_timer.h
@@ -81,7 +81,7 @@ private:
for (size_t i = 0; i < 3; ++i) {
timer.before();
loop.perform(loop_cnt);
- timer.after();
+ timer.after();
}
if (timer.min_time() > 0.010) {
return loop_cnt;
@@ -89,12 +89,12 @@ private:
}
}
- static double do_benchmark(const Loop &loop, size_t loop_cnt, double budget) {
+ static double do_benchmark(const Loop &loop, size_t loop_cnt, double budget) {
vespalib::BenchmarkTimer timer(budget);
while (timer.has_budget()) {
timer.before();
loop.perform(loop_cnt);
- timer.after();
+ timer.after();
}
return (timer.min_time() / double(loop_cnt));
}
diff --git a/vespalib/src/vespa/vespalib/util/binary_hamming_distance.h b/vespalib/src/vespa/vespalib/util/binary_hamming_distance.h
index ce8c8dacdf9..89e8e58ca1c 100644
--- a/vespalib/src/vespa/vespalib/util/binary_hamming_distance.h
+++ b/vespalib/src/vespa/vespalib/util/binary_hamming_distance.h
@@ -4,7 +4,7 @@
namespace vespalib {
/**
* Compute Hamming distance between two binary blobs
- *
+ *
* @param lhs a blob (to interpret as a bitvector with sz*8 bits)
* @param rhs a blob (to interpret as a bitvector with sz*8 bits)
* @param sz number of bytes in each blob
diff --git a/vespalib/src/vespa/vespalib/util/exceptions.h b/vespalib/src/vespa/vespalib/util/exceptions.h
index 8c470d25a5b..5d880ccf0ac 100644
--- a/vespalib/src/vespa/vespalib/util/exceptions.h
+++ b/vespalib/src/vespa/vespalib/util/exceptions.h
@@ -157,7 +157,7 @@ private:
/**
* NOTE: This function must only be called from within a catch block,
* and the parameter must reference the caught exception.
- *
+ *
* Based on the run-time type of the exception, determine if it is
* safe to handle this exception and continue normal program
* operation. If the exception is considered safe, no additional
diff --git a/vespalib/src/vespa/vespalib/util/mmap_file_allocator.h b/vespalib/src/vespa/vespalib/util/mmap_file_allocator.h
index 0a83bfb4e60..9d6eb096162 100644
--- a/vespalib/src/vespa/vespalib/util/mmap_file_allocator.h
+++ b/vespalib/src/vespa/vespalib/util/mmap_file_allocator.h
@@ -42,7 +42,7 @@ public:
PtrAndSize alloc(size_t sz) const override;
void free(PtrAndSize alloc) const override;
size_t resize_inplace(PtrAndSize, size_t) const override;
-
+
// For unit test
size_t get_end_offset() const noexcept { return _end_offset; }
};
diff --git a/vespalib/src/vespa/vespalib/util/mmap_file_allocator_factory.h b/vespalib/src/vespa/vespalib/util/mmap_file_allocator_factory.h
index ffa2b0929ca..3f4180fc7b9 100644
--- a/vespalib/src/vespa/vespalib/util/mmap_file_allocator_factory.h
+++ b/vespalib/src/vespa/vespalib/util/mmap_file_allocator_factory.h
@@ -24,7 +24,7 @@ class MmapFileAllocatorFactory {
public:
void setup(const vespalib::string &dir_name);
std::unique_ptr<MemoryAllocator> make_memory_allocator(const vespalib::string& name);
-
+
static MmapFileAllocatorFactory& instance();
};
diff --git a/vespalib/src/vespa/vespalib/util/thread_bundle.h b/vespalib/src/vespa/vespalib/util/thread_bundle.h
index 252e8976544..1a78b82c1f3 100644
--- a/vespalib/src/vespa/vespalib/util/thread_bundle.h
+++ b/vespalib/src/vespa/vespalib/util/thread_bundle.h
@@ -68,7 +68,7 @@ struct ThreadBundle {
// a thread bundle that can only run things in the current thread.
static ThreadBundle &trivial();
-
+
private:
Runnable *resolve(Runnable *target) { return target; }
Runnable *resolve(Runnable &target) { return &target; }
diff --git a/vespalog/src/test/bufferedlogskiptest.cpp b/vespalog/src/test/bufferedlogskiptest.cpp
index ac0bb585be9..8b7f1982678 100644
--- a/vespalog/src/test/bufferedlogskiptest.cpp
+++ b/vespalog/src/test/bufferedlogskiptest.cpp
@@ -75,7 +75,7 @@ main(int argc, char **argv)
}
ns_log::Logger::fakePid = true;
uint64_t timer;
- logger.setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
+ ns_log_logger.setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
ns_log::BufferedLogger::instance().setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
reset(timer);
diff --git a/vespalog/src/test/bufferedlogtest.cpp b/vespalog/src/test/bufferedlogtest.cpp
index 8399fa81dfa..365f8fb85a7 100644
--- a/vespalog/src/test/bufferedlogtest.cpp
+++ b/vespalog/src/test/bufferedlogtest.cpp
@@ -386,7 +386,7 @@ main(int argc, char **argv)
ns_log::Logger::fakePid = true;
ns_log::BufferedLogger::instance().setMaxCacheSize(10);
uint64_t timer;
- logger.setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
+ ns_log_logger.setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
ns_log::BufferedLogger::instance().setTimer(std::unique_ptr<ns_log::Timer>(new ns_log::TestTimer(timer)));
reset(timer);
diff --git a/vespalog/src/vespa/log/bufferedlogger.h b/vespalog/src/vespa/log/bufferedlogger.h
index 373f81b5160..8baa32445a5 100644
--- a/vespalog/src/vespa/log/bufferedlogger.h
+++ b/vespalog/src/vespa/log/bufferedlogger.h
@@ -91,13 +91,13 @@
#ifdef VESPA_LOG_USELOGBUFFERFORREGULARLOG
#define LOG(level, ...) \
do { \
- if (logger.wants(ns_log::Logger::level)) { \
- if (logger.wants(ns_log::Logger::debug)) { \
- logger.doLog(ns_log::Logger::level, \
+ if (LOG_WOULD_LOG(level)) { \
+ if (LOG_WOULD_LOG(debug)) { \
+ ns_log_logger.doLog(ns_log::Logger::level, \
__FILE__, __LINE__, __VA_ARGS__); \
ns_log::BufferedLogger::instance().trimCache(); \
} else { \
- ns_log::BufferedLogger::instance().doLog(logger, \
+ ns_log::BufferedLogger::instance().doLog(ns_log_logger, \
ns_log::Logger::level, __FILE__, __LINE__, \
"", __VA_ARGS__); \
} \
@@ -110,13 +110,13 @@
// VESPA_LOG_USELOGBUFFERFORREGULARLOG is defined.
#define LOGBM(level, ...) \
do { \
- if (logger.wants(ns_log::Logger::level)) { \
- if (logger.wants(ns_log::Logger::debug)) { \
- logger.doLog(ns_log::Logger::level, \
+ if (LOG_WOULD_LOG(level)) { \
+ if (LOG_WOULD_LOG(debug)) { \
+ ns_log_logger.doLog(ns_log::Logger::level, \
__FILE__, __LINE__, __VA_ARGS__); \
ns_log::BufferedLogger::instance().trimCache(); \
} else { \
- ns_log::BufferedLogger::instance().doLog(logger, \
+ ns_log::BufferedLogger::instance().doLog(ns_log_logger, \
ns_log::Logger::level, __FILE__, __LINE__, \
"", __VA_ARGS__); \
} \
@@ -127,15 +127,15 @@
// (File/line of macro caller)
#define LOGBP(level, ARGS...) \
do { \
- if (logger.wants(ns_log::Logger::level)) { \
- if (logger.wants(ns_log::Logger::debug)) { \
- logger.doLog(ns_log::Logger::level, \
+ if (LOG_WOULD_LOG(level)) { \
+ if (LOG_WOULD_LOG(debug)) { \
+ ns_log_logger.doLog(ns_log::Logger::level, \
__FILE__, __LINE__, ##ARGS); \
ns_log::BufferedLogger::instance().trimCache(); \
} else { \
std::ostringstream ost123; \
ost123 << __FILE__ << ":" << __LINE__; \
- ns_log::BufferedLogger::instance().doLog(logger, \
+ ns_log::BufferedLogger::instance().doLog(ns_log_logger, \
ns_log::Logger::level, \
__FILE__, __LINE__, ost123.str(), ##ARGS); \
} \
@@ -145,13 +145,13 @@
// Define LOGT calls for using the buffer specifically stating token
#define LOGBT(level, token, ...) \
do { \
- if (logger.wants(ns_log::Logger::level)) { \
- if (logger.wants(ns_log::Logger::debug)) { \
- logger.doLog(ns_log::Logger::level, \
+ if (LOG_WOULD_LOG(level)) { \
+ if (LOG_WOULD_LOG(debug)) { \
+ ns_log_logger.doLog(ns_log::Logger::level, \
__FILE__, __LINE__, __VA_ARGS__); \
ns_log::BufferedLogger::instance().trimCache(); \
} else { \
- ns_log::BufferedLogger::instance().doLog(logger, \
+ ns_log::BufferedLogger::instance().doLog(ns_log_logger, \
ns_log::Logger::level, \
__FILE__, __LINE__, token, __VA_ARGS__); \
} \
diff --git a/vespalog/src/vespa/log/log.cpp b/vespalog/src/vespa/log/log.cpp
index 7f2668a97ce..69d69b97874 100644
--- a/vespalog/src/vespa/log/log.cpp
+++ b/vespalog/src/vespa/log/log.cpp
@@ -175,19 +175,19 @@ Logger::Logger(const char *name, const char *rcsId)
Logger::~Logger()
{
- _numInstances--;
- if (_numInstances == 1) {
- if (logger != nullptr) {
- logger->~Logger();
- free(logger);
- logger = nullptr;
+ _numInstances--;
+ if (_numInstances == 1) {
+ if (ns_log_indirect_logger != nullptr) {
+ ns_log_indirect_logger->~Logger();
+ free(ns_log_indirect_logger);
+ ns_log_indirect_logger = nullptr;
+ }
+ } else if (_numInstances == 0) {
+ delete _controlFile;
+ logInitialised = false;
+ delete _target;
+ _target = nullptr;
}
- } else if (_numInstances == 0) {
- delete _controlFile;
- logInitialised = false;
- delete _target;
- _target = nullptr;
- }
}
@@ -406,4 +406,13 @@ Logger::doEventState(const char *name, const char *value)
doLog(event, "", 0, "state/1 name=\"%s\" value=\"%s\"", name, value);
}
+LogTarget *
+Logger::getCurrentTarget()
+{
+ if (_target == nullptr) {
+ throwInvalid("No current log target");
+ }
+ return _target;
+}
+
} // end namespace ns_log
diff --git a/vespalog/src/vespa/log/log.h b/vespalog/src/vespa/log/log.h
index 5b73aef5083..22b6a720bd2 100644
--- a/vespalog/src/vespa/log/log.h
+++ b/vespalog/src/vespa/log/log.h
@@ -21,31 +21,37 @@
// Used to use anonymous namespaces, but they fail miserably in gdb 5.3
#define LOG_SETUP(...) \
-static ns_log::Logger logger(__VA_ARGS__) // NOLINT
+static ns_log::Logger ns_log_logger(__VA_ARGS__) // NOLINT
-#define LOG_SETUP_INDIRECT(x, id) \
-static ns_log::Logger *logger=NULL; \
-static bool logInitialised = false; \
-static const char *logName = x; \
+#define LOG_SETUP_INDIRECT(x, id) \
+static ns_log::Logger *ns_log_indirect_logger=NULL; \
+static bool logInitialised = false; \
+static const char *logName = x; \
static const char *indirectRcsId = id
+#define LOG_WOULD_LOG(level) ns_log_logger.wants(ns_log::Logger::level)
+#define LOG_WOULD_VLOG(level) ns_log_logger.wants(level)
+#define LOG_INDIRECT_WOULD_LOG(levelName) \
+ ns_log_indirect_logger->wants(ns_log::Logger::levelName)
#define LOG_RCSID(x) \
-static int log_dummmy __attribute__((unused)) = logger.setRcsId(x)
-
+static int log_dummmy __attribute__((unused)) = ns_log_logger.setRcsId(x)
// Define LOG if not using log buffer. Otherwise log buffer will define them
#ifndef VESPA_LOG_USELOGBUFFERFORREGULARLOG
-#define LOG(level, ...) \
-do { \
- if (__builtin_expect(logger.wants(ns_log::Logger::level), false)) { \
- logger.doLog(ns_log::Logger::level, __FILE__, __LINE__, __VA_ARGS__); \
- } \
+#define LOG(level, ...) \
+do { \
+ if (__builtin_expect(LOG_WOULD_LOG(level), false)) { \
+ ns_log_logger.doLog(ns_log::Logger::level, \
+ __FILE__, __LINE__, __VA_ARGS__); \
+ } \
} while (false)
+
#define VLOG(level, ...) \
do { \
- if (__builtin_expect(logger.wants(level), false)) { \
- logger.doLog(level, __FILE__, __LINE__, __VA_ARGS__); \
+ if (__builtin_expect(LOG_WOULD_VLOG(level), false)) { \
+ ns_log_logger.doLog(level, \
+ __FILE__, __LINE__, __VA_ARGS__); \
} \
} while (false)
#endif
@@ -53,84 +59,85 @@ do { \
// Must use placement new in the following definition, since the variable
// "logger" must be a valid logger object DURING the construction of the
// logger object itself.
-#define LOG_INDIRECT_MUST \
- if (!logInitialised) { \
- logInitialised = true; \
- logger = static_cast<Logger *>(malloc(sizeof *logger)); \
- new (logger) Logger(logName, indirectRcsId); \
- }
-#define LOG_INDIRECT(level, ...) \
-do { \
- LOG_INDIRECT_MUST \
- if (logger->wants(ns_log::Logger::level)) { \
- logger->doLog(ns_log::Logger::level, __FILE__, __LINE__, __VA_ARGS__); \
- } \
+#define LOG_INDIRECT(level, ...) \
+do { \
+ if (!logInitialised) { \
+ logInitialised = true; \
+ ns_log_indirect_logger = \
+ static_cast<Logger *>( \
+ malloc(sizeof *ns_log_indirect_logger)); \
+ new (ns_log_indirect_logger) Logger(logName, indirectRcsId); \
+ } \
+ if (LOG_INDIRECT_WOULD_LOG(level)) { \
+ ns_log_indirect_logger->doLog(ns_log::Logger::level, \
+ __FILE__, __LINE__, __VA_ARGS__); \
+ } \
} while (false)
-#define LOG_WOULD_LOG(level) logger.wants(ns_log::Logger::level)
-#define LOG_WOULD_VLOG(level) logger.wants(level)
-#define EV_STARTING(name) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventStarting(name); \
- } \
+#define EV_STARTING(name) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventStarting(name); \
+ } \
} while (false)
-#define EV_STOPPING(name,why) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventStopping(name, why); \
- } \
+#define EV_STOPPING(name,why) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventStopping(name, why); \
+ } \
} while (false)
#define EV_STARTED(name) \
do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventStarted(name); \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventStarted(name); \
} \
} while (false)
-#define EV_STOPPED(name,pid,exitcode) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventStopped(name, pid, exitcode); \
- } \
-} while (false)
-
-#define EV_CRASH(name,pid,signal) \
+#define EV_STOPPED(name,pid,exitcode) \
do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventCrash(name, pid, signal); \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventStopped(name, pid, \
+ exitcode); \
} \
} while (false)
-#define EV_PROGRESS(name, ...) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventProgress(name, __VA_ARGS__); \
- } \
+#define EV_CRASH(name,pid,signal) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventCrash(name, pid, signal); \
+ } \
} while (false)
-#define EV_COUNT(name,value) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventCount(name, value); \
- } \
+#define EV_PROGRESS(name, ...) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventProgress(name, \
+ __VA_ARGS__); \
+ } \
} while (false)
-#define EV_VALUE(name,value) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventValue(name, value); \
- } \
+#define EV_COUNT(name,value) \
+ do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventCount(name, value); \
+ } \
} while (false)
-#define EV_STATE(name,value) \
-do { \
- if (logger.wants(ns_log::Logger::event)) { \
- logger.doEventState(name, value); \
- } \
+#define EV_VALUE(name,value) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventValue(name, value); \
+ } \
+} while (false)
+
+#define EV_STATE(name,value) \
+do { \
+ if (LOG_WOULD_LOG(event)) { \
+ ns_log_logger.doEventState(name, value); \
+ } \
} while (false)
namespace ns_log {
@@ -228,6 +235,9 @@ public:
// Only for unit testing
void setTimer(std::unique_ptr<Timer> timer) { _timer = std::move(timer); }
+
+ // Only for internal use
+ static LogTarget *getCurrentTarget();
};