summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2023-03-10 18:33:07 +0100
committerGitHub <noreply@github.com>2023-03-10 18:33:07 +0100
commit7ddc151bec7b736db6d3f15f1c32f77d0115784c (patch)
tree2dafbc776fdd43ecdaf1d67b9fd668e570c33645
parent315c1feec1ac67f97419d910550f4aebfe9290a7 (diff)
parent88b39d0d00f453b6406fc19b60cb6423af5d2933 (diff)
Merge branch 'master' into bratseth/autoscaling-completion
-rw-r--r--config-model/src/main/java/com/yahoo/schema/expressiontransforms/InputRecorder.java6
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/LoggingRequestHandler.java76
-rw-r--r--model-integration/src/main/java/ai/vespa/modelintegration/evaluator/TensorConverter.java23
-rw-r--r--model-integration/src/main/java/ai/vespa/rankingexpression/importer/onnx/TypeConverter.java36
-rw-r--r--model-integration/src/main/protobuf/onnx.proto6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java24
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java22
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ExpeditedChangeApplicationMaintainer.java37
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java28
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java63
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java78
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java37
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java4
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumattributesaver.cpp7
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumattributesaver.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumstore.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/enumstore.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/i_enum_store.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multienumattributesaver.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multienumattributesaver.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.cpp6
-rw-r--r--searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.h4
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.cpp13
-rw-r--r--searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.h2
-rw-r--r--searchlib/src/vespa/searchlib/bitcompression/compression.h4
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/feature_store.h8
-rw-r--r--vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java8
-rw-r--r--vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java15
-rw-r--r--vespalib/src/tests/datastore/array_store/array_store_test.cpp6
-rw-r--r--vespalib/src/tests/datastore/unique_store_string_allocator/unique_store_string_allocator_test.cpp6
-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/btreestore.h255
-rw-r--r--vespalib/src/vespa/vespalib/btree/btreestore.hpp2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/array_store.hpp2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/bufferstate.h32
-rw-r--r--vespalib/src/vespa/vespalib/datastore/datastore.h2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/datastorebase.cpp51
-rw-r--r--vespalib/src/vespa/vespalib/datastore/datastorebase.h30
-rw-r--r--vespalib/src/vespa/vespalib/datastore/entryref.h4
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store.h5
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store.hpp2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.h4
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp8
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h4
-rw-r--r--vespalib/src/vespa/vespalib/datastore/unique_store_string_comparator.h6
54 files changed, 452 insertions, 526 deletions
diff --git a/config-model/src/main/java/com/yahoo/schema/expressiontransforms/InputRecorder.java b/config-model/src/main/java/com/yahoo/schema/expressiontransforms/InputRecorder.java
index 515745cb6bc..7124628be0c 100644
--- a/config-model/src/main/java/com/yahoo/schema/expressiontransforms/InputRecorder.java
+++ b/config-model/src/main/java/com/yahoo/schema/expressiontransforms/InputRecorder.java
@@ -13,6 +13,7 @@ import com.yahoo.searchlib.rankingexpression.rule.ReferenceNode;
import com.yahoo.searchlib.rankingexpression.transform.ExpressionTransformer;
import java.io.StringReader;
+import java.util.HashSet;
import java.util.Set;
/**
@@ -23,6 +24,7 @@ import java.util.Set;
public class InputRecorder extends ExpressionTransformer<RankProfileTransformContext> {
private final Set<String> neededInputs;
+ private final Set<String> handled = new HashSet<>();
public InputRecorder(Set<String> target) {
this.neededInputs = target;
@@ -52,9 +54,13 @@ public class InputRecorder extends ExpressionTransformer<RankProfileTransformCon
simpleFunctionOrIdentifier = true;
}
if (simpleFunctionOrIdentifier) {
+ if (handled.contains(name)) {
+ return;
+ }
var f = context.rankProfile().getFunctions().get(name);
if (f != null && f.function().arguments().size() == 0) {
transform(f.function().getBody().getRoot(), context);
+ handled.add(name);
return;
}
neededInputs.add(feature.toString());
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/LoggingRequestHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/LoggingRequestHandler.java
index d608977a7ff..bacceac9d76 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/LoggingRequestHandler.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/LoggingRequestHandler.java
@@ -3,7 +3,6 @@ package com.yahoo.container.jdisc;
import com.yahoo.component.annotation.Inject;
import com.yahoo.container.handler.Timing;
-import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.AccessLogEntry;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.Response;
@@ -102,54 +101,54 @@ public abstract class LoggingRequestHandler extends ThreadedHttpRequestHandler {
private void logTimes(long startTime, String sourceIP,
long renderStartTime, long commitStartTime, long endTime,
- String req, String normalizedQuery, Timing t) {
+ String req, ExtendedResponse response) {
// note: intentionally only taking time since request was received
long totalTime = endTime - startTime;
- long timeoutInterval = Long.MAX_VALUE;
- long requestOverhead = 0;
- long summaryStartTime = 0;
+ long timeoutInterval;
+ long requestOverhead;
+ long summaryStartTime;
+ Timing t = response.getTiming();
if (t != null) {
timeoutInterval = t.getTimeout();
long queryStartTime = t.getQueryStartTime();
- if (queryStartTime > 0) {
- requestOverhead = queryStartTime - startTime;
- }
+ requestOverhead = (queryStartTime > 0) ? queryStartTime - startTime : 0;
summaryStartTime = t.getSummaryStartTime();
- }
-
- if (totalTime <= timeoutInterval) {
- return;
- }
-
- StringBuilder b = new StringBuilder();
- b.append(normalizedQuery);
- b.append(" from ").append(sourceIP).append(". ");
-
- if (requestOverhead > 0) {
- b.append("Time from HTTP connection open to request reception ");
- b.append(requestOverhead).append(" ms. ");
- }
- if (summaryStartTime != 0) {
- b.append("Request time: ");
- b.append(summaryStartTime - startTime).append(" ms. ");
- b.append("Summary fetch time: ");
- b.append(renderStartTime - summaryStartTime).append(" ms. ");
} else {
- long spentSearching = renderStartTime - startTime;
- b.append("Processing time: ").append(spentSearching).append(" ms. ");
+ requestOverhead = 0;
+ summaryStartTime = 0;
+ timeoutInterval = Long.MAX_VALUE;
}
- b.append("Result rendering/transfer: ");
- b.append(commitStartTime - renderStartTime).append(" ms. ");
- b.append("End transaction: ");
- b.append(endTime - commitStartTime).append(" ms. ");
- b.append("Total: ").append(totalTime).append(" ms. ");
- b.append("Timeout: ").append(timeoutInterval).append(" ms. ");
- b.append("Request string: ").append(req);
+ if (totalTime <= timeoutInterval) return;
- log.log(Level.WARNING, "Slow execution. " + b);
+ log.log(Level.FINE, () -> {
+ StringBuilder b = new StringBuilder();
+ b.append(response.getParsedQuery());
+ b.append(" from ").append(sourceIP).append(". ");
+ if (requestOverhead > 0) {
+ b.append("Time from HTTP connection open to request reception ");
+ b.append(requestOverhead).append(" ms. ");
+ }
+ if (summaryStartTime != 0) {
+ b.append("Request time: ");
+ b.append(summaryStartTime - startTime).append(" ms. ");
+ b.append("Summary fetch time: ");
+ b.append(renderStartTime - summaryStartTime).append(" ms. ");
+ } else {
+ long spentSearching = renderStartTime - startTime;
+ b.append("Processing time: ").append(spentSearching).append(" ms. ");
+ }
+ b.append("Result rendering/transfer: ");
+ b.append(commitStartTime - renderStartTime).append(" ms. ");
+ b.append("End transaction: ");
+ b.append(endTime - commitStartTime).append(" ms. ");
+ b.append("Total: ").append(totalTime).append(" ms. ");
+ b.append("Timeout: ").append(timeoutInterval).append(" ms. ");
+ b.append("Request string: ").append(req);
+ return b.toString();
+ });
}
private static class NullResponse extends ExtendedResponse {
@@ -224,8 +223,7 @@ public abstract class LoggingRequestHandler extends ThreadedHttpRequestHandler {
commitStartTime,
endTime,
getUri(jdiscRequest),
- extendedResponse.getParsedQuery(),
- extendedResponse.getTiming());
+ extendedResponse);
Optional<AccessLogEntry> jdiscRequestAccessLogEntry =
AccessLoggingRequestHandler.getAccessLogEntry(jdiscRequest);
diff --git a/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/TensorConverter.java b/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/TensorConverter.java
index 9c79961eddf..eef75a32c0a 100644
--- a/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/TensorConverter.java
+++ b/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/TensorConverter.java
@@ -180,12 +180,25 @@ class TensorConverter {
}
static private TensorType.Value toVespaValueType(TensorInfo.OnnxTensorType onnxType) {
+ // NOTE:
+ // should match best_cell_type in onnx_wrapper.cpp
switch (onnxType) {
- case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: return TensorType.Value.INT8;
- case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: return TensorType.Value.BFLOAT16;
- case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return TensorType.Value.FLOAT;
- case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: return TensorType.Value.DOUBLE;
- }
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL:
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
+ return TensorType.Value.INT8;
+
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16:
+ return TensorType.Value.BFLOAT16;
+
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16:
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16:
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
+ return TensorType.Value.FLOAT;
+
+ case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE:
+ return TensorType.Value.DOUBLE;
+ }
return TensorType.Value.DOUBLE;
}
diff --git a/model-integration/src/main/java/ai/vespa/rankingexpression/importer/onnx/TypeConverter.java b/model-integration/src/main/java/ai/vespa/rankingexpression/importer/onnx/TypeConverter.java
index 35ec1d8c54a..2c008dbb922 100644
--- a/model-integration/src/main/java/ai/vespa/rankingexpression/importer/onnx/TypeConverter.java
+++ b/model-integration/src/main/java/ai/vespa/rankingexpression/importer/onnx/TypeConverter.java
@@ -56,21 +56,27 @@ class TypeConverter {
tensor.getDimsList());
}
- private static TensorType.Value toValueType(Onnx.TensorProto.DataType dataType) {
- switch (dataType) {
- case FLOAT: return TensorType.Value.FLOAT;
- case DOUBLE: return TensorType.Value.DOUBLE;
- // Imperfect conversion, for now:
- case BOOL: return TensorType.Value.FLOAT;
- case INT8: return TensorType.Value.FLOAT;
- case INT16: return TensorType.Value.FLOAT;
- case INT32: return TensorType.Value.FLOAT;
- case INT64: return TensorType.Value.FLOAT;
- case UINT8: return TensorType.Value.FLOAT;
- case UINT16: return TensorType.Value.FLOAT;
- case UINT32: return TensorType.Value.FLOAT;
- case UINT64: return TensorType.Value.FLOAT;
- default: throw new IllegalArgumentException("A ONNX tensor with data type " + dataType +
+ private static TensorType.Value toValueType(Onnx.TensorProto.DataType onnxType) {
+ // NOTE:
+ // should match best_cell_type in onnx_wrapper.cpp
+ switch (onnxType) {
+ case BOOL: // Imperfect conversion fallthrough
+ case INT8:
+ return TensorType.Value.INT8;
+ case BFLOAT16:
+ return TensorType.Value.BFLOAT16;
+ case UINT8: // Imperfect conversion fallthrough
+ case INT16: // Imperfect conversion fallthrough
+ case UINT16: // Imperfect conversion fallthrough
+ case FLOAT:
+ return TensorType.Value.FLOAT;
+ case INT32: // Imperfect conversion fallthrough
+ case INT64: // Imperfect conversion fallthrough
+ case UINT32: // Imperfect conversion fallthrough
+ case UINT64: // Imperfect conversion fallthrough
+ case DOUBLE:
+ return TensorType.Value.DOUBLE;
+ default: throw new IllegalArgumentException("A ONNX tensor with data type " + onnxType +
" cannot be converted to a Vespa tensor type");
}
}
diff --git a/model-integration/src/main/protobuf/onnx.proto b/model-integration/src/main/protobuf/onnx.proto
index dc6542867e0..27f1fdef4b3 100644
--- a/model-integration/src/main/protobuf/onnx.proto
+++ b/model-integration/src/main/protobuf/onnx.proto
@@ -298,6 +298,10 @@ message TensorProto {
UINT64 = 13;
COMPLEX64 = 14; // complex with float32 real and imaginary components
COMPLEX128 = 15; // complex with float64 real and imaginary components
+ // Non-IEEE floating-point format based on IEEE754 single-precision
+ // floating-point number truncated to 16 bits.
+ // This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits.
+ BFLOAT16 = 16;
// Future extensions go here.
}
@@ -461,4 +465,4 @@ message OperatorSetIdProto {
// The version of the operator set being identified.
// This field MUST be present in this version of the IR.
optional int64 version = 2;
-} \ No newline at end of file
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java
index 9cfed5d046c..8daac029c7b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java
@@ -73,4 +73,9 @@ public class Applications {
return db.lock(application, timeout);
}
+ /** Create a lock which provides exclusive rights to perform a maintenance deployment */
+ public Mutex lockMaintenance(ApplicationId application) {
+ return db.lockMaintenance(application);
+ }
+
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
index b3ff0c42547..50eee9e33b3 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java
@@ -46,15 +46,18 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer {
return 1.0;
}
+ protected final Deployer deployer() { return deployer; }
+
/** Returns the number of deployments that are pending execution */
public int pendingDeployments() {
return pendingDeployments.size();
}
/** Returns whether given application should be deployed at this moment in time */
- protected boolean canDeployNow(ApplicationId application) {
- return true;
- }
+ protected abstract boolean canDeployNow(ApplicationId application);
+
+ /** Returns the applications that should be maintained by this now. */
+ protected abstract Map<ApplicationId, String> applicationsNeedingMaintenance();
/**
* Redeploy this application.
@@ -64,19 +67,14 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer {
*/
protected void deploy(ApplicationId application, String reason) {
if (pendingDeployments.addIfAbsent(application)) { // Avoid queuing multiple deployments for same application
- deploymentExecutor.execute(() -> deployWithLock(application, reason));
+ deploymentExecutor.execute(() -> deployNow(application, reason));
}
}
- protected Deployer deployer() { return deployer; }
-
- /** Returns the applications that should be maintained by this now. */
- protected abstract Map<ApplicationId, String> applicationsNeedingMaintenance();
-
/**
* Redeploy this application. A lock will be taken for the duration of the deployment activation
*/
- protected final void deployWithLock(ApplicationId application, String reason) {
+ protected final void deployNow(ApplicationId application, String reason) {
try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) {
if ( ! deployment.isValid()) return; // this will be done at another config server
if ( ! canDeployNow(application)) return; // redeployment is no longer needed
@@ -97,7 +95,7 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer {
@Override
public void shutdown() {
super.shutdown();
- this.deploymentExecutor.shutdownNow();
+ deploymentExecutor.shutdownNow();
}
@Override
@@ -105,7 +103,9 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer {
super.awaitShutdown();
try {
// Give deployments in progress some time to complete
- this.deploymentExecutor.awaitTermination(1, TimeUnit.MINUTES);
+ if (!deploymentExecutor.awaitTermination(1, TimeUnit.MINUTES)) {
+ log.log(Level.WARNING, "Failed to shut down deployment executor within deadline");
+ }
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
index 9fffdcf34e1..4c9fab748d1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainer.java
@@ -6,7 +6,6 @@ import com.yahoo.config.provision.ApplicationLockException;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Deployer;
-import com.yahoo.config.provision.Environment;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
@@ -19,6 +18,7 @@ import com.yahoo.vespa.hosted.provision.autoscale.Autoscaler;
import com.yahoo.vespa.hosted.provision.autoscale.Autoscaling;
import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricSnapshot;
import com.yahoo.vespa.hosted.provision.node.History;
+
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
@@ -68,6 +68,7 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
* @return true if an autoscaling decision was made or nothing should be done, false if there was an error
*/
private boolean autoscale(ApplicationId applicationId, ClusterSpec.Id clusterId) {
+ boolean redeploy = false;
try (var lock = nodeRepository().applications().lock(applicationId)) {
Optional<Application> application = nodeRepository().applications().get(applicationId);
if (application.isEmpty()) return true;
@@ -93,16 +94,10 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
applications().put(application.get().with(cluster), lock);
// Attempt to perform the autoscaling immediately, and log it regardless
- if (autoscaling != null
- && autoscaling.resources().isPresent()
- && !current.equals(autoscaling.resources().get())) {
- try (MaintenanceDeployment deployment = new MaintenanceDeployment(applicationId, deployer, metric, nodeRepository())) {
- if (deployment.isValid())
- deployment.activate();
- logAutoscaling(current, autoscaling.resources().get(), applicationId, clusterNodes.not().retired());
- }
+ if (autoscaling != null && autoscaling.resources().isPresent() && !current.equals(autoscaling.resources().get())) {
+ redeploy = true;
+ logAutoscaling(current, autoscaling.resources().get(), applicationId, clusterNodes.not().retired());
}
- return true;
}
catch (ApplicationLockException e) {
return false;
@@ -110,6 +105,13 @@ public class AutoscalingMaintainer extends NodeRepositoryMaintainer {
catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Illegal arguments for " + applicationId + " cluster " + clusterId, e);
}
+ if (redeploy) {
+ try (MaintenanceDeployment deployment = new MaintenanceDeployment(applicationId, deployer, metric, nodeRepository())) {
+ if (deployment.isValid())
+ deployment.activate();
+ }
+ }
+ return true;
}
private Applications applications() {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ExpeditedChangeApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ExpeditedChangeApplicationMaintainer.java
index d048f43973a..ffa125230a8 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ExpeditedChangeApplicationMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ExpeditedChangeApplicationMaintainer.java
@@ -16,7 +16,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* This maintainer detects changes to nodes that must be expedited, and redeploys affected applications.
@@ -40,25 +39,21 @@ public class ExpeditedChangeApplicationMaintainer extends ApplicationMaintainer
@Override
protected Map<ApplicationId, String> applicationsNeedingMaintenance() {
- var applications = new HashMap<ApplicationId, String>();
-
- nodeRepository().nodes()
- .list()
- .nodeType(NodeType.tenant, NodeType.proxy)
- .matching(node -> node.allocation().isPresent())
- .groupingBy(node -> node.allocation().get().owner())
- .forEach((applicationId, nodes) -> {
- hasNodesWithChanges(applicationId, nodes)
- .ifPresent(reason -> applications.put(applicationId, reason));
- });
-
+ NodeList allNodes = nodeRepository().nodes().list();
+ Map<ApplicationId, String> applications = new HashMap<>();
+ allNodes.nodeType(NodeType.tenant, NodeType.proxy)
+ .matching(node -> node.allocation().isPresent())
+ .groupingBy(node -> node.allocation().get().owner())
+ .forEach((applicationId, nodes) -> {
+ hasNodesWithChanges(applicationId, nodes)
+ .ifPresent(reason -> applications.put(applicationId, reason));
+ });
// A ready proxy node should trigger a redeployment as it will activate the node.
- if (!nodeRepository().nodes().list(Node.State.ready, Node.State.reserved).nodeType(NodeType.proxy).isEmpty()) {
+ if (!allNodes.state(Node.State.ready, Node.State.reserved).nodeType(NodeType.proxy).isEmpty()) {
applications.merge(ApplicationId.from("hosted-vespa", "routing", "default"),
"nodes being ready",
(oldValue, newValue) -> oldValue + ", " + newValue);
}
-
return applications;
}
@@ -68,7 +63,7 @@ public class ExpeditedChangeApplicationMaintainer extends ApplicationMaintainer
*/
@Override
protected void deploy(ApplicationId application, String reason) {
- deployWithLock(application, reason);
+ deployNow(application, reason);
}
/** Returns the reason for doing an expedited deploy. */
@@ -78,11 +73,11 @@ public class ExpeditedChangeApplicationMaintainer extends ApplicationMaintainer
List<String> reasons = nodes.stream()
.flatMap(node -> node.history()
- .events()
- .stream()
- .filter(event -> expediteChangeBy(event.agent()))
- .filter(event -> lastDeployTime.get().isBefore(event.at()))
- .map(event -> event.type() + (event.agent() == Agent.system ? "" : " by " + event.agent())))
+ .events()
+ .stream()
+ .filter(event -> expediteChangeBy(event.agent()))
+ .filter(event -> lastDeployTime.get().isBefore(event.at()))
+ .map(event -> event.type() + (event.agent() == Agent.system ? "" : " by " + event.agent())))
.sorted()
.distinct()
.toList();
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
index bcc571355e3..189238a1c11 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MaintenanceDeployment.java
@@ -1,8 +1,8 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.maintenance;
+import com.yahoo.concurrent.UncheckedTimeoutException;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.ApplicationLockException;
import com.yahoo.config.provision.Deployer;
import com.yahoo.config.provision.Deployment;
import com.yahoo.config.provision.TransientException;
@@ -16,7 +16,6 @@ import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.yolean.Exceptions;
import java.io.Closeable;
-import java.time.Duration;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -63,18 +62,12 @@ class MaintenanceDeployment implements Closeable {
return deployment.isPresent();
}
- /**
- * Returns the application lock held by this, or empty if it is not held.
- *
- * @throws IllegalStateException id this is called when closed
- */
- public Optional<Mutex> applicationLock() {
- if (closed) throw new IllegalStateException(this + " is closed");
- return lock;
- }
-
+ /** Prepare this deployment. Returns whether prepare was successful */
public boolean prepare() {
- return doStep(() -> { deployment.get().prepare(); return 0L; }).isPresent();
+ return doStep(() -> {
+ deployment.get().prepare();
+ return 0L;
+ }).isPresent();
}
/**
@@ -104,13 +97,10 @@ class MaintenanceDeployment implements Closeable {
}
private Optional<Mutex> tryLock(ApplicationId application, NodeRepository nodeRepository) {
- Duration timeout = Duration.ofSeconds(3);
try {
- // Use a short lock to avoid interfering with change deployments
- return Optional.of(nodeRepository.applications().lock(application, timeout));
- }
- catch (ApplicationLockException e) {
- log.log(Level.INFO, () -> "Could not lock " + application + " for maintenance deployment within " + timeout);
+ return Optional.of(nodeRepository.applications().lockMaintenance(application));
+ } catch (UncheckedTimeoutException e) {
+ log.log(Level.INFO, () -> "Could not lock " + application + " for maintenance deployment within timeout");
return Optional.empty();
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
index 84a45de39d7..afea08711fa 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
@@ -182,27 +182,26 @@ public class NodeFailer extends NodeRepositoryMaintainer {
* Called when a node should be moved to the failed state: Do that if it seems safe,
* which is when the node repo has available capacity to replace the node (and all its tenant nodes if host).
* Otherwise not replacing the node ensures (by Orchestrator check) that no further action will be taken.
- *
- * @return whether node was successfully failed
*/
- private boolean failActive(FailingNode failing) {
+ private void failActive(FailingNode failing) {
Optional<Deployment> deployment =
deployer.deployFromLocalActive(failing.node().allocation().get().owner(), Duration.ofMinutes(5));
- if (deployment.isEmpty()) return false;
+ if (deployment.isEmpty()) return;
// If the active node that we are trying to fail is of type host, we need to successfully fail all
// the children nodes running on it before we fail the host. Failing a child node in a dynamically
// provisioned zone may require provisioning new hosts that require the host application lock to be held,
// so we must release ours before failing the children.
List<FailingNode> activeChildrenToFail = new ArrayList<>();
+ boolean redeploy = false;
try (NodeMutex lock = nodeRepository().nodes().lockAndGetRequired(failing.node())) {
// Now that we have gotten the node object under the proper lock, sanity-check it still makes sense to fail
if (!Objects.equals(failing.node().allocation().map(Allocation::owner), lock.node().allocation().map(Allocation::owner)))
- return false;
+ return;
if (lock.node().state() == Node.State.failed)
- return true;
+ return;
if (!Objects.equals(failing.node().state(), lock.node().state()))
- return false;
+ return;
failing = new FailingNode(lock.node(), failing.reason);
String reasonForChildFailure = "Failing due to parent host " + failing.node().hostname() + " failure: " + failing.reason();
@@ -216,36 +215,46 @@ public class NodeFailer extends NodeRepositoryMaintainer {
if (activeChildrenToFail.isEmpty()) {
log.log(Level.INFO, "Failing out " + failing.node + ": " + failing.reason);
- wantToFail(failing.node(), true, lock);
- try {
- deployment.get().activate();
- return true;
- } catch (TransientException | UncheckedTimeoutException e) {
- log.log(Level.INFO, "Failed to redeploy " + failing.node().allocation().get().owner() +
- " with a transient error, will be retried by application maintainer: " +
- Exceptions.toMessageString(e));
- return true;
- } catch (RuntimeException e) {
- // Reset want to fail: We'll retry failing unless it heals in the meantime
- nodeRepository().nodes().node(failing.node().hostname())
- .ifPresent(n -> wantToFail(n, false, lock));
- log.log(Level.WARNING, "Could not fail " + failing.node() + " for " + failing.node().allocation().get().owner() +
- " for " + failing.reason() + ": " + Exceptions.toMessageString(e));
- return false;
- }
+ markWantToFail(failing.node(), true, lock);
+ redeploy = true;
}
}
+ // Redeploy to replace failing node
+ if (redeploy) {
+ redeploy(deployment.get(), failing);
+ return;
+ }
+
// In a dynamically provisioned zone the failing of the first child may require a new host to be provisioned,
// so failActive() may take a long time to complete, but the remaining children should be fast.
activeChildrenToFail.forEach(this::failActive);
- return false;
}
- private void wantToFail(Node node, boolean wantToFail, Mutex lock) {
- if (!node.status().wantToFail())
+ private void redeploy(Deployment deployment, FailingNode failing) {
+ try {
+ deployment.activate();
+ } catch (TransientException | UncheckedTimeoutException e) {
+ log.log(Level.INFO, "Failed to redeploy " + failing.node().allocation().get().owner() +
+ " with a transient error, will be retried by application maintainer: " +
+ Exceptions.toMessageString(e));
+ } catch (RuntimeException e) {
+ // Reset want to fail: We'll retry failing unless it heals in the meantime
+ Optional<NodeMutex> optionalNodeMutex = nodeRepository().nodes().lockAndGet(failing.node());
+ if (optionalNodeMutex.isEmpty()) return;
+ try (var nodeMutex = optionalNodeMutex.get()) {
+ markWantToFail(nodeMutex.node(), false, nodeMutex);
+ log.log(Level.WARNING, "Could not fail " + failing.node() + " for " + failing.node().allocation().get().owner() +
+ " for " + failing.reason() + ": " + Exceptions.toMessageString(e));
+ }
+ }
+ }
+
+ private void markWantToFail(Node node, boolean wantToFail, Mutex lock) {
+ if (node.status().wantToFail() != wantToFail) {
nodeRepository().nodes().write(node.withWantToFail(wantToFail, Agent.NodeFailer, clock().instant()), lock);
+ }
}
/** Returns true if node failing should be throttled */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
index 036c46479d1..10a828c887a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainer.java
@@ -47,13 +47,12 @@ public class PeriodicApplicationMaintainer extends ApplicationMaintainer {
.orElse(false);
}
- // Returns the applications that need to be redeployed by this config server at this point in time.
@Override
protected Map<ApplicationId, String> applicationsNeedingMaintenance() {
if (deployer().bootstrapping()) return Map.of();
// Collect all deployment times before sorting as deployments may happen while we build the set, breaking
- // the comparable contract. Stale times are fine as the time is rechecked in ApplicationMaintainer#deployWithLock
+ // the comparable contract. Stale times are fine as the time is rechecked in ApplicationMaintainer#deployNow
Map<ApplicationId, Instant> deploymentTimes = nodesNeedingMaintenance().stream()
.map(node -> node.allocation().get().owner())
.distinct()
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java
index 87af8c05b14..1ae9b00d794 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/RetiredExpirer.java
@@ -14,9 +14,10 @@ import com.yahoo.vespa.orchestrator.OrchestrationException;
import com.yahoo.yolean.Exceptions;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.OptionalLong;
/**
* Maintenance job which deactivates retired nodes, if given permission by orchestrator, or
@@ -47,40 +48,55 @@ public class RetiredExpirer extends NodeRepositoryMaintainer {
protected double maintain() {
int attempts = 0;
int successes = 0;
+ List<ApplicationId> applicationsWithRetiredNodes = nodeRepository().nodes().list(Node.State.active)
+ .retired()
+ .stream()
+ .map(node -> node.allocation().get().owner())
+ .distinct()
+ .toList();
+ for (var application : applicationsWithRetiredNodes) {
+ attempts++;
+ if (removeRetiredNodes(application)) {
+ successes++;
+ }
+ }
+ return attempts == 0 ? 1.0 : ((double)successes / attempts);
+ }
- NodeList activeNodes = nodeRepository().nodes().list(Node.State.active);
- Map<ApplicationId, NodeList> retiredNodesByApplication = activeNodes.retired().groupingBy(node -> node.allocation().get().owner());
- for (Map.Entry<ApplicationId, NodeList> entry : retiredNodesByApplication.entrySet()) {
- ApplicationId application = entry.getKey();
- NodeList retiredNodes = entry.getValue();
- Map<Removal, NodeList> nodesByRemovalReason = retiredNodes.groupingBy(node -> removalOf(node, activeNodes));
- if (nodesByRemovalReason.isEmpty()) continue;
-
- for (var kv : nodesByRemovalReason.entrySet()) {
- Removal removal = kv.getKey();
- if (removal.equals(Removal.none())) continue;
-
- NodeList nodes = kv.getValue();
- attempts++;
- try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) {
- if (!deployment.isValid()) {
- log.info("Skipping invalid deployment for " + application);
- continue;
- }
-
- nodeRepository().nodes().setRemovable(application, nodes.asList(), removal.isReusable());
- Optional<Long> session = deployment.activate();
- String nodeList = String.join(", ", nodes.mapToList(Node::hostname));
- if (session.isEmpty()) {
- log.info("Failed to redeploy " + application);
- continue;
- }
- log.info("Redeployed " + application + " at session " + session.get() + " to deactivate retired nodes: " + nodeList);
- successes++;
+ /** Mark retired nodes as removable and redeploy application */
+ private boolean removeRetiredNodes(ApplicationId application) {
+ try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) {
+ if (!deployment.isValid()) {
+ log.info("Skipping invalid deployment for " + application);
+ return false;
+ }
+ boolean redeploy = false;
+ List<String> nodesToDeactivate = new ArrayList<>();
+ try (var lock = nodeRepository().applications().lock(application)) {
+ NodeList activeNodes = nodeRepository().nodes().list(Node.State.active);
+ Map<Removal, NodeList> nodesByRemovalReason = activeNodes.owner(application)
+ .retired()
+ .groupingBy(node -> removalOf(node, activeNodes));
+ for (var kv : nodesByRemovalReason.entrySet()) {
+ Removal reason = kv.getKey();
+ if (reason.equals(Removal.none())) continue;
+ redeploy = true;
+ nodesToDeactivate.addAll(kv.getValue().hostnames());
+ nodeRepository().nodes().setRemovable(kv.getValue(), reason.isReusable());
}
}
+ if (!redeploy) {
+ return true;
+ }
+ Optional<Long> session = deployment.activate();
+ String nodeList = String.join(", ", nodesToDeactivate);
+ if (session.isEmpty()) {
+ log.info("Failed to redeploy " + application);
+ return false;
+ }
+ log.info("Redeployed " + application + " at session " + session.get() + " to deactivate retired nodes: " + nodeList);
+ return true;
}
- return attempts == 0 ? 1.0 : ((double)successes / attempts);
}
/**
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 5ce88346178..dcdcbf09175 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
@@ -8,6 +8,7 @@ import com.yahoo.config.provision.NodeResources;
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.NodeMutex;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.maintenance.MaintenanceDeployment.Move;
import com.yahoo.vespa.hosted.provision.node.Agent;
@@ -49,9 +50,7 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer {
NodeRepository nodeRepository,
Metric metric,
Duration interval) {
- this(deployer, nodeRepository, metric, interval,
- 10_000 // Should take less than a few minutes
- );
+ this(deployer, nodeRepository, metric, interval, 10_000 /* Should take less than a few minutes */);
}
public SpareCapacityMaintainer(Deployer deployer,
@@ -160,22 +159,32 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer {
.filter(node -> node.state() == Node.State.active)
.min(this::retireOvercomittedComparator);
if (nodeToRetire.isEmpty()) return;
+ retire(nodeToRetire.get());
+ }
- ApplicationId application = nodeToRetire.get().allocation().get().owner();
- try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, metric, nodeRepository())) {
- if ( ! deployment.isValid()) return;
-
- Optional<Node> nodeWithWantToRetire = nodeRepository().nodes().node(nodeToRetire.get().hostname())
- .map(node -> node.withWantToRetire(true, Agent.SpareCapacityMaintainer, nodeRepository().clock().instant()));
- if (nodeWithWantToRetire.isEmpty()) return;
-
- nodeRepository().nodes().write(nodeWithWantToRetire.get(), deployment.applicationLock().get());
- log.log(Level.INFO, String.format("Redeploying %s to move %s from overcommitted host",
- application, nodeToRetire.get().hostname()));
+ /** Mark node for retirement and redeploy its application */
+ private void retire(Node node) {
+ ApplicationId owner = node.allocation().get().owner();
+ try (MaintenanceDeployment deployment = new MaintenanceDeployment(owner, deployer, metric, nodeRepository())) {
+ if (!deployment.isValid()) return;
+ if (!markWantToRetire(node.hostname())) return;
+ log.log(Level.INFO, String.format("Redeploying %s to move %s from over-committed host",
+ owner, node.hostname()));
deployment.activate();
}
}
+ private boolean markWantToRetire(String hostname) {
+ Optional<NodeMutex> optionalNodeMutex = nodeRepository().nodes().lockAndGet(hostname);
+ if (optionalNodeMutex.isEmpty()) return false;
+ try (var nodeMutex = optionalNodeMutex.get()) {
+ Node retiredNode = nodeMutex.node().withWantToRetire(true, Agent.SpareCapacityMaintainer,
+ nodeRepository().clock().instant());
+ nodeRepository().nodes().write(retiredNode, nodeMutex);
+ return true;
+ }
+ }
+
private static class CapacitySolver {
private final HostCapacity hostCapacity;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
index bb3d288e555..10f0c8aa554 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
@@ -203,17 +203,12 @@ public class Nodes {
/**
* Sets a list of nodes to have their allocation removable (active to inactive) in the node repository.
*
- * @param application the application the nodes belong to
* @param nodes the nodes to make removable. These nodes MUST be in the active state
* @param reusable move the node directly to {@link Node.State#dirty} after removal
*/
- public void setRemovable(ApplicationId application, List<Node> nodes, boolean reusable) {
- try (Mutex lock = applications.lock(application)) {
- List<Node> removableNodes = nodes.stream()
- .map(node -> node.with(node.allocation().get().removable(true, reusable)))
- .toList();
- write(removableNodes, lock);
- }
+ public void setRemovable(NodeList nodes, boolean reusable) {
+ performOn(nodes, (node, mutex) -> write(node.with(node.allocation().get().removable(true, reusable)),
+ mutex));
}
/**
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
index c1ab8489f40..cec413cf4e3 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
@@ -391,6 +391,11 @@ public class CuratorDb {
return db.lock(lockPath.append("archiveUris"), defaultLockTimeout);
}
+ public Lock lockMaintenance(ApplicationId application) {
+ return db.lock(lockPath.append("maintenanceDeployment").append(application.serializedForm()),
+ Duration.ofSeconds(3));
+ }
+
// Load balancers -----------------------------------------------------------
public List<LoadBalancerId> readLoadBalancerIds() {
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
index 880a69b61e5..e075995c89e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java
@@ -402,8 +402,8 @@ public class HostCapacityMaintainerTest {
// Config server becomes removable (done by RetiredExpirer in a real system) and redeployment moves it
// to parked
int removedIndex = nodeToRemove.get().allocation().get().membership().index();
- tester.nodeRepository().nodes().setRemovable(configSrvApp, List.of(nodeToRemove.get()), true);
- tester.nodeRepository().nodes().setRemovable(hostApp, List.of(hostToRemove.get()), true);
+ tester.nodeRepository().nodes().setRemovable(NodeList.of(nodeToRemove.get()), true);
+ tester.nodeRepository().nodes().setRemovable(NodeList.of(hostToRemove.get()), true);
tester.prepareAndActivateInfraApplication(configSrvApp, hostType.childNodeType());
tester.prepareAndActivateInfraApplication(hostApp, hostType);
tester.nodeRepository().nodes().markNodeAvailableForNewAllocation(nodeToRemove.get().hostname(), Agent.operator, "Readied by host-admin");
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
index b5735cfae84..98c17eb4d5e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
@@ -515,9 +515,9 @@ public class OsVersionsTest {
private void replaceNodes(ApplicationId application) {
// Deploy to retire nodes
deployApplication(application);
- List<Node> retired = tester.nodeRepository().nodes().list().owner(application).retired().asList();
+ NodeList retired = tester.nodeRepository().nodes().list().owner(application).retired();
assertFalse("At least one node is retired", retired.isEmpty());
- tester.nodeRepository().nodes().setRemovable(application, retired, false);
+ tester.nodeRepository().nodes().setRemovable(retired, false);
// Redeploy to deactivate removable nodes and allocate new ones
deployApplication(application);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java
index 9a38cbbba44..9cd5adef5f4 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/InfraDeployerImplTest.java
@@ -10,8 +10,8 @@ import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Provisioner;
import com.yahoo.config.provision.Zone;
-import com.yahoo.vespa.flags.InMemoryFlagSource;
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.NodeRepositoryTester;
import com.yahoo.vespa.hosted.provision.maintenance.InfrastructureVersions;
@@ -122,7 +122,7 @@ public class InfraDeployerImplTest {
addNode(5, Node.State.dirty, Optional.empty());
addNode(6, Node.State.ready, Optional.empty());
Node node7 = addNode(7, Node.State.active, Optional.of(target));
- nodeRepository.nodes().setRemovable(application.getApplicationId(), List.of(node7), false);
+ nodeRepository.nodes().setRemovable(NodeList.of(node7), false);
infraDeployer.getDeployment(application.getApplicationId()).orElseThrow().activate();
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
index c1c4630f431..fb773f19b8a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/VirtualNodeProvisioningTest.java
@@ -636,7 +636,7 @@ public class VirtualNodeProvisioningTest {
tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, r)));
// Deactivate any retired nodes - usually done by the RetiredExpirer
- tester.nodeRepository().nodes().setRemovable(app1, tester.getNodes(app1).retired().asList(), false);
+ tester.nodeRepository().nodes().setRemovable(tester.getNodes(app1).retired(), false);
tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, r)));
if (expectedReuse) {
diff --git a/searchlib/src/vespa/searchlib/attribute/enumattributesaver.cpp b/searchlib/src/vespa/searchlib/attribute/enumattributesaver.cpp
index 74a37ca8394..a2090185158 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumattributesaver.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/enumattributesaver.cpp
@@ -8,16 +8,13 @@
namespace search {
-EnumAttributeSaver::
-EnumAttributeSaver(const IEnumStore &enumStore)
+EnumAttributeSaver::EnumAttributeSaver(IEnumStore &enumStore)
: _enumStore(enumStore),
_enumerator(enumStore.make_enumerator())
{
}
-EnumAttributeSaver::~EnumAttributeSaver()
-{
-}
+EnumAttributeSaver::~EnumAttributeSaver() = default;
void
EnumAttributeSaver::writeUdat(IAttributeSaveTarget &saveTarget)
diff --git a/searchlib/src/vespa/searchlib/attribute/enumattributesaver.h b/searchlib/src/vespa/searchlib/attribute/enumattributesaver.h
index d6dceb4772a..47af8c0452e 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumattributesaver.h
+++ b/searchlib/src/vespa/searchlib/attribute/enumattributesaver.h
@@ -24,7 +24,7 @@ private:
std::unique_ptr<Enumerator> _enumerator;
public:
- EnumAttributeSaver(const IEnumStore &enumStore);
+ EnumAttributeSaver(IEnumStore &enumStore);
~EnumAttributeSaver();
void writeUdat(IAttributeSaveTarget &saveTarget);
diff --git a/searchlib/src/vespa/searchlib/attribute/enumstore.h b/searchlib/src/vespa/searchlib/attribute/enumstore.h
index df3a595ae34..59524f3788a 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumstore.h
+++ b/searchlib/src/vespa/searchlib/attribute/enumstore.h
@@ -212,7 +212,7 @@ public:
void inc_compaction_count() override {
_store.get_allocator().get_data_store().inc_compaction_count();
}
- std::unique_ptr<Enumerator> make_enumerator() const override;
+ std::unique_ptr<Enumerator> make_enumerator() override;
std::unique_ptr<EntryComparator> allocate_comparator() const override;
// Methods below are only relevant for strings, and are templated to only be instantiated on demand.
diff --git a/searchlib/src/vespa/searchlib/attribute/enumstore.hpp b/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
index b863e56fb4a..bc767a296eb 100644
--- a/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/enumstore.hpp
@@ -259,7 +259,7 @@ EnumStoreT<EntryT>::consider_compact_dictionary(const CompactionStrategy& compac
template <typename EntryT>
std::unique_ptr<IEnumStore::Enumerator>
-EnumStoreT<EntryT>::make_enumerator() const
+EnumStoreT<EntryT>::make_enumerator()
{
return std::make_unique<Enumerator>(*_dict, _store.get_data_store(), false);
}
diff --git a/searchlib/src/vespa/searchlib/attribute/i_enum_store.h b/searchlib/src/vespa/searchlib/attribute/i_enum_store.h
index 57886511221..2157db3e5ed 100644
--- a/searchlib/src/vespa/searchlib/attribute/i_enum_store.h
+++ b/searchlib/src/vespa/searchlib/attribute/i_enum_store.h
@@ -72,7 +72,7 @@ public:
enumstore::EnumeratedLoader make_enumerated_loader();
enumstore::EnumeratedPostingsLoader make_enumerated_postings_loader();
- virtual std::unique_ptr<Enumerator> make_enumerator() const = 0;
+ virtual std::unique_ptr<Enumerator> make_enumerator() = 0;
virtual std::unique_ptr<vespalib::datastore::EntryComparator> allocate_comparator() const = 0;
};
diff --git a/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.cpp b/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.cpp
index 083f0409821..87326f3628f 100644
--- a/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.cpp
@@ -80,7 +80,7 @@ MultiValueEnumAttributeSaver<MultiValueT>::
MultiValueEnumAttributeSaver(GenerationHandler::Guard &&guard,
const attribute::AttributeHeader &header,
const MultiValueMapping &mvMapping,
- const IEnumStore &enumStore)
+ IEnumStore &enumStore)
: Parent(std::move(guard), header, mvMapping),
_mvMapping(mvMapping),
_enumSaver(enumStore),
diff --git a/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.h b/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.h
index 44c45567733..7c127ac0781 100644
--- a/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.h
+++ b/searchlib/src/vespa/searchlib/attribute/multienumattributesaver.h
@@ -35,7 +35,7 @@ public:
MultiValueEnumAttributeSaver(GenerationHandler::Guard &&guard,
const attribute::AttributeHeader &header,
const MultiValueMapping &mvMapping,
- const IEnumStore &enumStore);
+ IEnumStore &enumStore);
~MultiValueEnumAttributeSaver() override;
};
diff --git a/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.cpp b/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.cpp
index 0c3180875a3..a8f13df0a85 100644
--- a/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.cpp
@@ -16,7 +16,7 @@ namespace search::attribute {
ReferenceAttributeSaver::ReferenceAttributeSaver(GenerationHandler::Guard &&guard,
const AttributeHeader &header,
EntryRefVector&& indices,
- const Store &store)
+ Store &store)
: AttributeSaver(std::move(guard), header),
_indices(std::move(indices)),
_store(store),
@@ -25,9 +25,7 @@ ReferenceAttributeSaver::ReferenceAttributeSaver(GenerationHandler::Guard &&guar
}
-ReferenceAttributeSaver::~ReferenceAttributeSaver()
-{
-}
+ReferenceAttributeSaver::~ReferenceAttributeSaver() = default;
namespace {
diff --git a/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.h b/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.h
index c413d01c386..fa3fafc3254 100644
--- a/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.h
+++ b/searchlib/src/vespa/searchlib/attribute/reference_attribute_saver.h
@@ -41,9 +41,9 @@ public:
ReferenceAttributeSaver(vespalib::GenerationHandler::Guard &&guard,
const AttributeHeader &header,
EntryRefVector&& indices,
- const Store &store);
+ Store &store);
- virtual ~ReferenceAttributeSaver();
+ ~ReferenceAttributeSaver() override;
};
}
diff --git a/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.cpp b/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.cpp
index 1857e942136..1f3f3e104d1 100644
--- a/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.cpp
@@ -4,7 +4,6 @@
#include "iattributesavetarget.h"
#include <vespa/searchlib/util/bufferwriter.h>
-
using search::attribute::EntryRefVector;
using vespalib::GenerationHandler;
@@ -14,25 +13,20 @@ SingleValueEnumAttributeSaver::
SingleValueEnumAttributeSaver(GenerationHandler::Guard &&guard,
const attribute::AttributeHeader &header,
EntryRefVector &&indices,
- const IEnumStore &enumStore)
+ IEnumStore &enumStore)
: AttributeSaver(std::move(guard), header),
_indices(std::move(indices)),
_enumSaver(enumStore)
{
}
-
-SingleValueEnumAttributeSaver::~SingleValueEnumAttributeSaver()
-{
-}
-
+SingleValueEnumAttributeSaver::~SingleValueEnumAttributeSaver() = default;
bool
SingleValueEnumAttributeSaver::onSave(IAttributeSaveTarget &saveTarget)
{
_enumSaver.writeUdat(saveTarget);
- std::unique_ptr<search::BufferWriter> datWriter(saveTarget.datWriter().
- allocBufferWriter());
+ std::unique_ptr<search::BufferWriter> datWriter(saveTarget.datWriter().allocBufferWriter());
assert(saveTarget.getEnumerated());
auto &enumerator = _enumSaver.get_enumerator();
enumerator.enumerateValues();
@@ -49,5 +43,4 @@ SingleValueEnumAttributeSaver::onSave(IAttributeSaveTarget &saveTarget)
return true;
}
-
} // namespace search
diff --git a/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.h b/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.h
index af83d36cbbb..7f1c62c7720 100644
--- a/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.h
+++ b/searchlib/src/vespa/searchlib/attribute/singleenumattributesaver.h
@@ -22,7 +22,7 @@ public:
SingleValueEnumAttributeSaver(vespalib::GenerationHandler::Guard &&guard,
const attribute::AttributeHeader &header,
attribute::EntryRefVector &&indices,
- const IEnumStore &enumStore);
+ IEnumStore &enumStore);
~SingleValueEnumAttributeSaver() override;
};
diff --git a/searchlib/src/vespa/searchlib/bitcompression/compression.h b/searchlib/src/vespa/searchlib/bitcompression/compression.h
index 7c5ba3e94ca..a77d82d9e8f 100644
--- a/searchlib/src/vespa/searchlib/bitcompression/compression.h
+++ b/searchlib/src/vespa/searchlib/bitcompression/compression.h
@@ -1248,9 +1248,7 @@ public:
void setReadContext(search::ComprFileReadContext *readContext) {
_readContext = readContext;
}
- search::ComprFileReadContext *getReadContext() const {
- return _readContext;
- }
+
void readComprBuffer() {
_readContext->readComprBuffer();
}
diff --git a/searchlib/src/vespa/searchlib/memoryindex/feature_store.h b/searchlib/src/vespa/searchlib/memoryindex/feature_store.h
index 5f5e782a382..53588fa2894 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/feature_store.h
+++ b/searchlib/src/vespa/searchlib/memoryindex/feature_store.h
@@ -154,12 +154,8 @@ public:
void setupForReadFeatures(vespalib::datastore::EntryRef ref, DecodeContextCooked &decoder) const {
const uint8_t * bits = getBits(ref);
decoder.setByteCompr(bits);
- uint32_t bufferId = RefType(ref).bufferId();
- const vespalib::datastore::BufferState &state = _store.getBufferState(bufferId);
- decoder.setEnd(
- ((_store.getEntryArray<uint8_t>(RefType(0, bufferId), buffer_array_size) + state.size() -
- bits) + 7) / 8,
- false);
+ constexpr uint32_t maxOffset = RefType::offsetSize() * buffer_array_size;
+ decoder.setEnd(maxOffset, false);
}
/**
diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java
index 373928a3e22..fe1e2b46830 100644
--- a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java
+++ b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java
@@ -171,6 +171,8 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler {
private static final String SLICES = "slices";
private static final String SLICE_ID = "sliceId";
private static final String DRY_RUN = "dryRun";
+ private static final String FROM_TIMESTAMP = "fromTimestamp";
+ private static final String TO_TIMESTAMP = "toTimestamp";
private final Clock clock;
private final Duration handlerTimeout;
@@ -1227,6 +1229,12 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler {
getProperty(request, CONTINUATION).map(ProgressToken::fromSerializedString).ifPresent(parameters::setResumeToken);
parameters.setPriority(DocumentProtocol.Priority.NORMAL_4);
+ getProperty(request, FROM_TIMESTAMP, unsignedLongParser).ifPresent(parameters::setFromTimestamp);
+ getProperty(request, TO_TIMESTAMP, unsignedLongParser).ifPresent(parameters::setToTimestamp);
+ if (Long.compareUnsigned(parameters.getFromTimestamp(), parameters.getToTimestamp()) > 0) {
+ throw new IllegalArgumentException("toTimestamp must be greater than, or equal to, fromTimestamp");
+ }
+
StorageCluster storageCluster = resolveCluster(cluster, clusters);
parameters.setRoute(storageCluster.name());
parameters.setBucketSpace(resolveBucket(storageCluster,
diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java
index b6ad7ba5570..851a0949266 100644
--- a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java
+++ b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java
@@ -223,6 +223,8 @@ public class DocumentV1ApiTest {
assertEquals("(all the things)", parameters.getDocumentSelection());
assertEquals(6000, parameters.getSessionTimeoutMs());
assertEquals(9, parameters.getTraceLevel());
+ assertEquals(1_000_000, parameters.getFromTimestamp());
+ assertEquals(2_000_000, parameters.getToTimestamp());
// Put some documents in the response
parameters.getLocalDataHandler().onMessage(new PutDocumentMessage(new DocumentPut(doc1)), tokens.get(0));
parameters.getLocalDataHandler().onMessage(new PutDocumentMessage(new DocumentPut(doc2)), tokens.get(1));
@@ -234,7 +236,7 @@ public class DocumentV1ApiTest {
parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.TIMEOUT, "timeout is OK");
});
response = driver.sendRequest("http://localhost/document/v1?cluster=content&bucketSpace=default&wantedDocumentCount=1025&concurrency=123" +
- "&selection=all%20the%20things&fieldSet=[id]&timeout=6&tracelevel=9");
+ "&selection=all%20the%20things&fieldSet=[id]&timeout=6&tracelevel=9&fromTimestamp=1000000&toTimestamp=2000000");
assertSameJson("""
{
"pathId": "/document/v1",
@@ -284,6 +286,8 @@ public class DocumentV1ApiTest {
assertEquals(6000, parameters.getTimeoutMs());
assertEquals(4, parameters.getSlices());
assertEquals(1, parameters.getSliceId());
+ assertEquals(0, parameters.getFromTimestamp()); // not set; 0 is default
+ assertEquals(0, parameters.getToTimestamp()); // not set; 0 is default
// Put some documents in the response
parameters.getLocalDataHandler().onMessage(new PutDocumentMessage(new DocumentPut(doc1)), tokens.get(0));
parameters.getLocalDataHandler().onMessage(new PutDocumentMessage(new DocumentPut(doc2)), tokens.get(1));
@@ -500,6 +504,15 @@ public class DocumentV1ApiTest {
"}", response.readAll());
assertEquals(200, response.getStatus());
+ // GET with from timestamp > to timestamp is an error
+ access.expect(parameters -> { fail("unreachable"); });
+ response = driver.sendRequest("http://localhost/document/v1/?cluster=content&fromTimestamp=100&toTimestamp=99");
+ assertSameJson("{" +
+ " \"pathId\": \"/document/v1/\"," +
+ " \"message\": \"toTimestamp must be greater than, or equal to, fromTimestamp\"" +
+ "}", response.readAll());
+ assertEquals(400, response.getStatus());
+
// GET with full document ID is a document get operation which returns 404 when no document is found
access.session.expect((id, parameters) -> {
assertEquals(doc1.getId(), id);
diff --git a/vespalib/src/tests/datastore/array_store/array_store_test.cpp b/vespalib/src/tests/datastore/array_store/array_store_test.cpp
index 3ebe8fdba1a..97e1ddb985d 100644
--- a/vespalib/src/tests/datastore/array_store/array_store_test.cpp
+++ b/vespalib/src/tests/datastore/array_store/array_store_test.cpp
@@ -97,13 +97,13 @@ struct ArrayStoreTest : public TestT
uint32_t getBufferId(EntryRef ref) const {
return EntryRefType(ref).bufferId();
}
- void assertBufferState(EntryRef ref, const MemStats& expStats) const {
+ void assertBufferState(EntryRef ref, const MemStats& expStats) {
EXPECT_EQ(expStats._used, store.bufferState(ref).size());
EXPECT_EQ(expStats._hold, store.bufferState(ref).stats().hold_elems());
EXPECT_EQ(expStats._dead, store.bufferState(ref).stats().dead_elems());
}
- void assert_buffer_stats(EntryRef ref, const TestBufferStats& exp_stats) const {
- auto& state = store.bufferState(ref);
+ void assert_buffer_stats(EntryRef ref, const TestBufferStats& exp_stats) {
+ const auto& state = store.bufferState(ref);
EXPECT_EQ(exp_stats._used, state.size());
EXPECT_EQ(exp_stats._hold, state.stats().hold_elems());
EXPECT_EQ(exp_stats._dead, state.stats().dead_elems());
diff --git a/vespalib/src/tests/datastore/unique_store_string_allocator/unique_store_string_allocator_test.cpp b/vespalib/src/tests/datastore/unique_store_string_allocator/unique_store_string_allocator_test.cpp
index 64e0c1599bd..7d4451556c8 100644
--- a/vespalib/src/tests/datastore/unique_store_string_allocator/unique_store_string_allocator_test.cpp
+++ b/vespalib/src/tests/datastore/unique_store_string_allocator/unique_store_string_allocator_test.cpp
@@ -56,11 +56,11 @@ struct TestBase : public ::testing::Test {
uint32_t get_buffer_id(EntryRef ref) const {
return EntryRefType(ref).bufferId();
}
- const BufferState &buffer_state(EntryRef ref) const {
+ BufferState &buffer_state(EntryRef ref) {
return allocator.get_data_store().getBufferState(get_buffer_id(ref));
}
- void assert_buffer_state(EntryRef ref, const TestBufferStats expStats) const {
- const auto & stats = buffer_state(ref).stats();
+ void assert_buffer_state(EntryRef ref, const TestBufferStats expStats) {
+ auto & stats = buffer_state(ref).stats();
EXPECT_EQ(expStats._used, buffer_state(ref).size());
EXPECT_EQ(expStats._hold, stats.hold_elems());
EXPECT_EQ(expStats._dead, stats.dead_elems());
diff --git a/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h b/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
index 3fa5f1188cd..784e95e3817 100644
--- a/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
+++ b/vespalib/src/vespa/vespalib/btree/btreenodeallocator.h
@@ -163,7 +163,7 @@ public:
vespalib::string toString(BTreeNode::Ref ref) const;
vespalib::string toString(const BTreeNode * node) const;
- bool getCompacting(EntryRef ref) const { return _nodeStore.getCompacting(ref); }
+ bool getCompacting(EntryRef ref) { return _nodeStore.getCompacting(ref); }
std::unique_ptr<vespalib::datastore::CompactingBuffers> start_compact_worst(const CompactionStrategy& compaction_strategy) { return _nodeStore.start_compact_worst(compaction_strategy); }
diff --git a/vespalib/src/vespa/vespalib/btree/btreenodestore.h b/vespalib/src/vespa/vespalib/btree/btreenodestore.h
index 8fef0185674..73e68c3579f 100644
--- a/vespalib/src/vespa/vespalib/btree/btreenodestore.h
+++ b/vespalib/src/vespa/vespalib/btree/btreenodestore.h
@@ -182,7 +182,7 @@ public:
}
// Inherit doc from DataStoreT
- bool getCompacting(EntryRef ref) const {
+ bool getCompacting(EntryRef ref) {
return _store.getCompacting(ref);
}
diff --git a/vespalib/src/vespa/vespalib/btree/btreestore.h b/vespalib/src/vespa/vespalib/btree/btreestore.h
index c228c084e6d..9d98a9ca514 100644
--- a/vespalib/src/vespa/vespalib/btree/btreestore.h
+++ b/vespalib/src/vespa/vespalib/btree/btreestore.h
@@ -95,202 +95,90 @@ protected:
public:
BTreeStore();
-
BTreeStore(bool init);
-
~BTreeStore();
const NodeAllocatorType &getAllocator() const { return _allocator; }
- void
- disableFreeLists() {
+ void disableFreeLists() {
_store.disableFreeLists();
_allocator.disableFreeLists();
}
- void
- disableElemHoldList()
- {
+ void disableElemHoldList() {
_store.disableElemHoldList();
_allocator.disableElemHoldList();
}
- BTreeTypeRefPair
- allocNewBTree() {
+ BTreeTypeRefPair allocNewBTree() {
return _store.allocator<BTreeType>(BUFFERTYPE_BTREE).alloc();
}
- BTreeTypeRefPair
- allocBTree() {
+ BTreeTypeRefPair allocBTree() {
return _store.freeListAllocator<BTreeType, TreeReclaimer>(BUFFERTYPE_BTREE).alloc();
}
- BTreeTypeRefPair
- allocNewBTreeCopy(const BTreeType &rhs) {
+ BTreeTypeRefPair allocNewBTreeCopy(const BTreeType &rhs) {
return _store.allocator<BTreeType>(BUFFERTYPE_BTREE).alloc(rhs);
}
- BTreeTypeRefPair
- allocBTreeCopy(const BTreeType &rhs) {
+ BTreeTypeRefPair allocBTreeCopy(const BTreeType &rhs) {
return _store.freeListAllocator<BTreeType, datastore::DefaultReclaimer<BTreeType> >(BUFFERTYPE_BTREE).alloc(rhs);
}
- KeyDataTypeRefPair
- allocNewKeyData(uint32_t clusterSize);
-
- KeyDataTypeRefPair
- allocKeyData(uint32_t clusterSize);
-
- KeyDataTypeRefPair
- allocNewKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);
-
- KeyDataTypeRefPair
- allocKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);
-
- const KeyDataType *
- lower_bound(const KeyDataType *b, const KeyDataType *e,
- const KeyType &key, CompareT comp);
-
- void
- makeTree(EntryRef &ref,
- const KeyDataType *array, uint32_t clusterSize);
-
- void
- makeArray(EntryRef &ref, EntryRef leafRef, LeafNodeType *leafNode);
-
- bool
- insert(EntryRef &ref,
- const KeyType &key, const DataType &data,
- CompareT comp = CompareT());
-
- bool
- remove(EntryRef &ref,
- const KeyType &key,
- CompareT comp = CompareT());
-
- uint32_t
- getNewClusterSize(const KeyDataType *o,
- const KeyDataType *oe,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
- void
- applyCluster(const KeyDataType *o,
- const KeyDataType *oe,
- KeyDataType *d,
- const KeyDataType *de,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
-
- void
- applyModifyTree(BTreeType *tree,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
- void
- applyBuildTree(BTreeType *tree,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
- void
- applyNewArray(EntryRef &ref,
- AddIter aOrg,
- AddIter ae);
-
- void
- applyNewTree(EntryRef &ref,
- AddIter a,
- AddIter ae,
- CompareT comp);
-
- void
- applyNew(EntryRef &ref,
- AddIter a,
- AddIter ae,
- CompareT comp);
-
-
- bool
- applyCluster(EntryRef &ref,
- uint32_t clusterSize,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
- void
- applyTree(BTreeType *tree,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp);
-
- void
- normalizeTree(EntryRef &ref,
- BTreeType *tree,
- bool wasArray);
+ KeyDataTypeRefPair allocNewKeyData(uint32_t clusterSize);
+ KeyDataTypeRefPair allocKeyData(uint32_t clusterSize);
+ KeyDataTypeRefPair allocNewKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);
+ KeyDataTypeRefPair allocKeyDataCopy(const KeyDataType *rhs, uint32_t clusterSize);
+
+ const KeyDataType * lower_bound(const KeyDataType *b, const KeyDataType *e, const KeyType &key, CompareT comp);
+
+ void makeTree(EntryRef &ref, const KeyDataType *array, uint32_t clusterSize);
+ void makeArray(EntryRef &ref, EntryRef leafRef, LeafNodeType *leafNode);
+ bool insert(EntryRef &ref, const KeyType &key, const DataType &data, CompareT comp = CompareT());
+
+ bool remove(EntryRef &ref, const KeyType &key,CompareT comp = CompareT());
+
+ uint32_t getNewClusterSize(const KeyDataType *o, const KeyDataType *oe, AddIter a, AddIter ae,
+ RemoveIter r, RemoveIter re, CompareT comp);
+
+ void applyCluster(const KeyDataType *o, const KeyDataType *oe, KeyDataType *d, const KeyDataType *de,
+ AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
+
+ void applyModifyTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
+ void applyBuildTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
+ void applyNewArray(EntryRef &ref, AddIter aOrg, AddIter ae);
+ void applyNewTree(EntryRef &ref, AddIter a, AddIter ae, CompareT comp);
+ void applyNew(EntryRef &ref, AddIter a, AddIter ae, CompareT comp);
+
+ bool applyCluster(EntryRef &ref, uint32_t clusterSize, AddIter a, AddIter ae,
+ RemoveIter r, RemoveIter re, CompareT comp);
+
+ void applyTree(BTreeType *tree, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp);
+
+ void normalizeTree(EntryRef &ref, BTreeType *tree, bool wasArray);
/**
* Apply multiple changes at once.
*
* additions and removals should be sorted on key without duplicates.
* Overlap between additions and removals indicates updates.
*/
- void
- apply(EntryRef &ref,
- AddIter a,
- AddIter ae,
- RemoveIter r,
- RemoveIter re,
- CompareT comp = CompareT());
-
- void
- clear(const EntryRef ref);
-
- size_t
- size(const EntryRef ref) const;
+ void apply(EntryRef &ref, AddIter a, AddIter ae, RemoveIter r, RemoveIter re, CompareT comp = CompareT());
- size_t
- frozenSize(const EntryRef ref) const;
+ void clear(const EntryRef ref);
+ size_t size(const EntryRef ref) const;
+ size_t frozenSize(const EntryRef ref) const;
+ Iterator begin(const EntryRef ref) const;
+ ConstIterator beginFrozen(const EntryRef ref) const;
- Iterator
- begin(const EntryRef ref) const;
+ void beginFrozen(const EntryRef ref, std::vector<ConstIterator> &where) const;
- ConstIterator
- beginFrozen(const EntryRef ref) const;
-
- void
- beginFrozen(const EntryRef ref, std::vector<ConstIterator> &where) const;
-
- uint32_t
- getTypeId(RefType ref) const
- {
- return _store.getBufferState(ref.bufferId()).getTypeId();
+ uint32_t getTypeId(RefType ref) const {
+ return _store.getBufferMeta(ref.bufferId()).getTypeId();
}
- static bool
- isSmallArray(uint32_t typeId)
- {
- return typeId < clusterLimit;
- }
-
- bool
- isSmallArray(const EntryRef ref) const;
-
+ static bool isSmallArray(uint32_t typeId) { return typeId < clusterLimit; }
+ bool isSmallArray(const EntryRef ref) const;
static bool isBTree(uint32_t typeId) { return typeId == BUFFERTYPE_BTREE; }
bool isBTree(RefType ref) const { return isBTree(getTypeId(ref)); }
@@ -299,9 +187,7 @@ public:
* Cluster size == 0 means we have a tree for the given reference.
* The reference must be valid.
**/
- static uint32_t
- getClusterSize(uint32_t typeId)
- {
+ static uint32_t getClusterSize(uint32_t typeId) {
return (typeId < clusterLimit) ? typeId + 1 : 0;
}
@@ -310,11 +196,7 @@ public:
* Cluster size == 0 means we have a tree for the given reference.
* The reference must be valid.
**/
- uint32_t
- getClusterSize(RefType ref) const
- {
- return getClusterSize(getTypeId(ref));
- }
+ uint32_t getClusterSize(RefType ref) const { return getClusterSize(getTypeId(ref)); }
const BTreeType * getTreeEntry(RefType ref) const {
return _store.getEntry<BTreeType>(ref);
@@ -329,24 +211,18 @@ public:
}
// Inherit doc from DataStoreBase
- void
- reclaim_memory(generation_t oldest_used_gen)
- {
+ void reclaim_memory(generation_t oldest_used_gen) {
_allocator.reclaim_memory(oldest_used_gen);
_store.reclaim_memory(oldest_used_gen);
}
// Inherit doc from DataStoreBase
- void
- assign_generation(generation_t current_gen)
- {
+ void assign_generation(generation_t current_gen) {
_allocator.assign_generation(current_gen);
_store.assign_generation(current_gen);
}
- void
- reclaim_all_memory()
- {
+ void reclaim_all_memory() {
_allocator.reclaim_all_memory();
_store.reclaim_all_memory();
}
@@ -360,30 +236,23 @@ public:
return usage;
}
- void
- clearBuilder()
- {
+ void clearBuilder() {
_builder.clear();
}
- AggregatedType
- getAggregated(const EntryRef ref) const;
+ AggregatedType getAggregated(const EntryRef ref) const;
template <typename FunctionType>
- void
- foreach_unfrozen_key(EntryRef ref, FunctionType func) const;
+ void foreach_unfrozen_key(EntryRef ref, FunctionType func) const;
template <typename FunctionType>
- void
- foreach_frozen_key(EntryRef ref, FunctionType func) const;
+ void foreach_frozen_key(EntryRef ref, FunctionType func) const;
template <typename FunctionType>
- void
- foreach_unfrozen(EntryRef ref, FunctionType func) const;
+ void foreach_unfrozen(EntryRef ref, FunctionType func) const;
template <typename FunctionType>
- void
- foreach_frozen(EntryRef ref, FunctionType func) const;
+ void foreach_frozen(EntryRef ref, FunctionType func) const;
std::unique_ptr<vespalib::datastore::CompactingBuffers> start_compact_worst_btree_nodes(const CompactionStrategy& compaction_strategy);
void move_btree_nodes(const std::vector<EntryRef>& refs);
@@ -394,12 +263,10 @@ public:
private:
static constexpr size_t MIN_BUFFER_ARRAYS = 128u;
template <typename FunctionType, bool Frozen>
- void
- foreach_key(EntryRef ref, FunctionType func) const;
+ void foreach_key(EntryRef ref, FunctionType func) const;
template <typename FunctionType, bool Frozen>
- void
- foreach(EntryRef ref, FunctionType func) const;
+ void foreach(EntryRef ref, FunctionType func) const;
};
template <typename KeyT, typename DataT, typename AggrT, typename CompareT,
diff --git a/vespalib/src/vespa/vespalib/btree/btreestore.hpp b/vespalib/src/vespa/vespalib/btree/btreestore.hpp
index 6b2c4d924cd..a19d0b34aa6 100644
--- a/vespalib/src/vespa/vespalib/btree/btreestore.hpp
+++ b/vespalib/src/vespa/vespalib/btree/btreestore.hpp
@@ -850,7 +850,7 @@ isSmallArray(const EntryRef ref) const
if (!ref.valid())
return true;
RefType iRef(ref);
- uint32_t typeId(_store.getBufferState(iRef.bufferId()).getTypeId());
+ uint32_t typeId(_store.getBufferMeta(iRef.bufferId()).getTypeId());
return typeId < clusterLimit;
}
diff --git a/vespalib/src/vespa/vespalib/datastore/array_store.h b/vespalib/src/vespa/vespalib/datastore/array_store.h
index 43bd469fca4..dd786e5f2e2 100644
--- a/vespalib/src/vespa/vespalib/datastore/array_store.h
+++ b/vespalib/src/vespa/vespalib/datastore/array_store.h
@@ -139,7 +139,7 @@ public:
static DataStoreBase& get_data_store_base(ArrayStore &self) { return self._store; }
// Should only be used for unit testing
- const BufferState &bufferState(EntryRef ref) const;
+ const BufferState &bufferState(EntryRef ref);
bool has_free_lists_enabled() const { return _store.has_free_lists_enabled(); }
bool has_held_buffers() const noexcept { return _store.has_held_buffers(); }
diff --git a/vespalib/src/vespa/vespalib/datastore/array_store.hpp b/vespalib/src/vespa/vespalib/datastore/array_store.hpp
index 64aed0bd541..301cff1e414 100644
--- a/vespalib/src/vespa/vespalib/datastore/array_store.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/array_store.hpp
@@ -197,7 +197,7 @@ ArrayStore<EntryT, RefT, TypeMapperT>::update_stat(const CompactionStrategy& com
template <typename EntryT, typename RefT, typename TypeMapperT>
const BufferState &
-ArrayStore<EntryT, RefT, TypeMapperT>::bufferState(EntryRef ref) const
+ArrayStore<EntryT, RefT, TypeMapperT>::bufferState(EntryRef ref)
{
RefT internalRef(ref);
return _store.getBufferState(internalRef.bufferId());
diff --git a/vespalib/src/vespa/vespalib/datastore/bufferstate.h b/vespalib/src/vespa/vespalib/datastore/bufferstate.h
index 3f023b41c51..aa7f6dfdfa4 100644
--- a/vespalib/src/vespa/vespalib/datastore/bufferstate.h
+++ b/vespalib/src/vespa/vespalib/datastore/bufferstate.h
@@ -40,14 +40,14 @@ public:
private:
InternalBufferStats _stats;
- BufferFreeList _free_list;
+ BufferFreeList _free_list;
std::atomic<BufferTypeBase*> _typeHandler;
- Alloc _buffer;
- uint32_t _arraySize;
- uint16_t _typeId;
+ Alloc _buffer;
+ uint32_t _arraySize;
+ uint16_t _typeId;
std::atomic<State> _state;
- bool _disableElemHoldList : 1;
- bool _compacting : 1;
+ bool _disableElemHoldList : 1;
+ bool _compacting : 1;
public:
/**
@@ -130,7 +130,27 @@ public:
BufferTypeBase *getTypeHandler() { return _typeHandler.load(std::memory_order_relaxed); }
void resume_primary_buffer(uint32_t buffer_id);
+};
+class BufferAndMeta {
+public:
+ BufferAndMeta() : BufferAndMeta(nullptr, 0, 0) { }
+ BufferAndMeta(void* buffer, uint32_t typeId, uint32_t arraySize)
+ : _buffer(buffer),
+ _typeId(typeId),
+ _arraySize(arraySize)
+ { }
+ std::atomic<void*>& get_atomic_buffer() noexcept { return _buffer; }
+ void* get_buffer_relaxed() noexcept { return _buffer.load(std::memory_order_relaxed); }
+ const void* get_buffer_acquire() const noexcept { return _buffer.load(std::memory_order_acquire); }
+ uint32_t getTypeId() const { return _typeId; }
+ uint32_t getArraySize() const { return _arraySize; }
+ void setTypeId(uint32_t typeId) { _typeId = typeId; }
+ void setArraySize(uint32_t arraySize) { _arraySize = arraySize; }
+private:
+ std::atomic<void*> _buffer;
+ uint32_t _typeId;
+ uint32_t _arraySize;
};
}
diff --git a/vespalib/src/vespa/vespalib/datastore/datastore.h b/vespalib/src/vespa/vespalib/datastore/datastore.h
index f0ca9c90700..01b81d0fa58 100644
--- a/vespalib/src/vespa/vespalib/datastore/datastore.h
+++ b/vespalib/src/vespa/vespalib/datastore/datastore.h
@@ -49,7 +49,7 @@ public:
void reclaim_all_entry_refs() override;
- bool getCompacting(EntryRef ref) const {
+ bool getCompacting(EntryRef ref) {
return getBufferState(RefType(ref).bufferId()).getCompacting();
}
diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
index 42234194040..99bdb19576f 100644
--- a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
+++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp
@@ -106,15 +106,8 @@ DataStoreBase::~DataStoreBase()
void
DataStoreBase::switch_primary_buffer(uint32_t typeId, size_t elemsNeeded)
{
- size_t buffer_id = primary_buffer_id(typeId);
- for (size_t i = 0; i < getNumBuffers(); ++i) {
- // start using next buffer
- buffer_id = nextBufferId(buffer_id);
- if (getBufferState(buffer_id).isFree()) {
- break;
- }
- }
- if (!getBufferState(buffer_id).isFree()) {
+ size_t buffer_id = getFirstFreeBufferId();
+ if ((buffer_id < _states.size()) && !getBufferState(buffer_id).isFree()) {
LOG_ABORT(vespalib::make_string("switch_primary_buffer(%u, %zu): did not find a free buffer",
typeId, elemsNeeded).c_str());
}
@@ -164,6 +157,23 @@ DataStoreBase::consider_grow_active_buffer(uint32_t type_id, size_t elems_needed
return true;
}
+uint32_t
+DataStoreBase::getFirstFreeBufferId() {
+ for (uint32_t buffer_id = 0; buffer_id < _states.size(); buffer_id++) {
+ if (getBufferState(buffer_id).isFree()) {
+ return buffer_id;
+ }
+ }
+ // Need next(new) buffer
+ return _states.size();
+}
+
+BufferState &
+DataStoreBase::getBufferState(uint32_t buffer_id) noexcept {
+ assert(buffer_id < _states.size());
+ return _states[buffer_id];
+}
+
void
DataStoreBase::switch_or_grow_primary_buffer(uint32_t typeId, size_t elemsNeeded)
{
@@ -191,15 +201,8 @@ DataStoreBase::init_primary_buffers()
{
uint32_t numTypes = _primary_buffer_ids.size();
for (uint32_t typeId = 0; typeId < numTypes; ++typeId) {
- size_t buffer_id = 0;
- for (size_t i = 0; i < getNumBuffers(); ++i) {
- if (getBufferState(buffer_id).isFree()) {
- break;
- }
- // start using next buffer
- buffer_id = nextBufferId(buffer_id);
- }
- assert(getBufferState(buffer_id).isFree());
+ size_t buffer_id = getFirstFreeBufferId();
+ assert((buffer_id == _states.size()) || getBufferState(buffer_id).isFree());
onActive(buffer_id, typeId, 0u);
_primary_buffer_ids[typeId] = buffer_id;
}
@@ -273,14 +276,14 @@ vespalib::MemoryUsage
DataStoreBase::getMemoryUsage() const {
auto usage = getDynamicMemoryUsage();
size_t extra_allocated = 0;
- extra_allocated += _buffers.capacity() * sizeof(BufferAndTypeId);
+ extra_allocated += _buffers.capacity() * sizeof(BufferAndMeta);
extra_allocated += _primary_buffer_ids.capacity() * sizeof(uint32_t);
extra_allocated += _states.capacity() * sizeof(BufferState);
extra_allocated += _typeHandlers.capacity() * sizeof(BufferTypeBase *);
extra_allocated += _free_lists.capacity() * sizeof(FreeList);
size_t extra_used = 0;
- extra_used += _buffers.size() * sizeof(BufferAndTypeId);
+ extra_used += _buffers.size() * sizeof(BufferAndMeta);
extra_used += _primary_buffer_ids.size() * sizeof(uint32_t);
extra_used += _states.size() * sizeof(BufferState);
extra_used += _typeHandlers.size() * sizeof(BufferTypeBase *);
@@ -398,9 +401,11 @@ DataStoreBase::onActive(uint32_t bufferId, uint32_t typeId, size_t elemsNeeded)
{
assert(typeId < _typeHandlers.size());
assert(bufferId < _numBuffers);
- _buffers[bufferId].setTypeId(typeId);
BufferState &state = getBufferState(bufferId);
- state.onActive(bufferId, typeId, _typeHandlers[typeId], elemsNeeded, _buffers[bufferId].get_atomic_buffer());
+ BufferAndMeta & bufferMeta = _buffers[bufferId];
+ state.onActive(bufferId, typeId, _typeHandlers[typeId], elemsNeeded, bufferMeta.get_atomic_buffer());
+ bufferMeta.setTypeId(typeId);
+ bufferMeta.setArraySize(state.getArraySize());
enableFreeList(bufferId);
}
@@ -461,7 +466,7 @@ DataStoreBase::start_compact_worst_buffers(CompactionSpec compaction_spec, const
compaction_strategy.get_active_buffers_ratio(),
compaction_strategy.getMaxDeadAddressSpaceRatio() / 2,
CompactionStrategy::DEAD_ADDRESS_SPACE_SLACK);
- uint32_t free_buffers = 0;
+ uint32_t free_buffers = _buffers.size() - _states.size();
for (uint32_t bufferId = 0; bufferId < _numBuffers; ++bufferId) {
const auto &state = getBufferState(bufferId);
if (state.isActive()) {
diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.h b/vespalib/src/vespa/vespalib/datastore/datastorebase.h
index 950e1967ee2..8749f2a27e6 100644
--- a/vespalib/src/vespa/vespalib/datastore/datastorebase.h
+++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.h
@@ -73,8 +73,8 @@ public:
* Get the primary buffer id for the given type id.
*/
uint32_t primary_buffer_id(uint32_t typeId) const { return _primary_buffer_ids[typeId]; }
- const BufferState &getBufferState(uint32_t bufferId) const { return _states[bufferId]; }
- BufferState &getBufferState(uint32_t bufferId) { return _states[bufferId]; }
+ BufferState &getBufferState(uint32_t buffer_id) noexcept;
+ const BufferAndMeta & getBufferMeta(uint32_t buffer_id) const { return _buffers[buffer_id]; }
uint32_t getNumBuffers() const { return _numBuffers; }
/**
@@ -211,15 +211,6 @@ private:
class BufferHold;
- /**
- * Get the next buffer id after the given buffer id.
- */
- uint32_t nextBufferId(uint32_t bufferId) {
- uint32_t ret = bufferId + 1;
- if (ret == _numBuffers)
- ret = 0;
- return ret;
- }
bool consider_grow_active_buffer(uint32_t type_id, size_t elems_needed);
void switch_or_grow_primary_buffer(uint32_t typeId, size_t elemsNeeded);
void markCompacting(uint32_t bufferId);
@@ -243,24 +234,11 @@ private:
void inc_hold_buffer_count();
void fallbackResize(uint32_t bufferId, size_t elementsNeeded);
+ uint32_t getFirstFreeBufferId();
virtual void reclaim_all_entry_refs() = 0;
- class BufferAndTypeId {
- public:
- BufferAndTypeId() : BufferAndTypeId(nullptr, 0) { }
- BufferAndTypeId(void* buffer, uint32_t typeId) : _buffer(buffer), _typeId(typeId) { }
- std::atomic<void*>& get_atomic_buffer() noexcept { return _buffer; }
- void* get_buffer_relaxed() noexcept { return _buffer.load(std::memory_order_relaxed); }
- const void* get_buffer_acquire() const noexcept { return _buffer.load(std::memory_order_acquire); }
- uint32_t getTypeId() const { return _typeId; }
- void setTypeId(uint32_t typeId) { _typeId = typeId; }
- private:
- std::atomic<void*> _buffer;
- uint32_t _typeId;
- };
-
- std::vector<BufferAndTypeId> _buffers; // For fast mapping with known types
+ std::vector<BufferAndMeta> _buffers; // For fast mapping with known types
// Provides a mapping from typeId -> primary buffer for that type.
// The primary buffer is used for allocations of new element(s) if no available slots are found in free lists.
diff --git a/vespalib/src/vespa/vespalib/datastore/entryref.h b/vespalib/src/vespa/vespalib/datastore/entryref.h
index a0016f4fdcb..752d660a097 100644
--- a/vespalib/src/vespa/vespalib/datastore/entryref.h
+++ b/vespalib/src/vespa/vespalib/datastore/entryref.h
@@ -38,8 +38,8 @@ public:
EntryRefT(const EntryRef & ref_) noexcept : EntryRef(ref_.ref()) {}
size_t offset() const noexcept { return _ref & (offsetSize() - 1); }
uint32_t bufferId() const noexcept { return _ref >> OffsetBits; }
- static size_t offsetSize() noexcept { return 1ul << OffsetBits; }
- static uint32_t numBuffers() noexcept { return 1 << BufferBits; }
+ static constexpr size_t offsetSize() noexcept { return 1ul << OffsetBits; }
+ static constexpr uint32_t numBuffers() noexcept { return 1 << BufferBits; }
};
vespalib::asciistream& operator<<(vespalib::asciistream& os, const EntryRef& ref);
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store.h b/vespalib/src/vespa/vespalib/datastore/unique_store.h
index 1313d57fbab..f2d62020ab4 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store.h
@@ -67,7 +67,8 @@ public:
Allocator& get_allocator() { return _allocator; }
const Allocator& get_allocator() const { return _allocator; }
IUniqueStoreDictionary& get_dictionary() { return *_dict; }
- inline const DataStoreType& get_data_store() const noexcept { return _allocator.get_data_store(); }
+ const DataStoreType& get_data_store() const noexcept { return _allocator.get_data_store(); }
+ DataStoreType& get_data_store() noexcept { return _allocator.get_data_store(); }
// Pass on hold list management to underlying store
void assign_generation(generation_t current_gen);
@@ -78,7 +79,7 @@ public:
uint32_t getNumUniques() const;
Builder getBuilder(uint32_t uniqueValuesHint);
- Enumerator getEnumerator(bool sort_unique_values) const;
+ Enumerator getEnumerator(bool sort_unique_values);
// Should only be used for unit testing
const BufferState &bufferState(EntryRef ref) const;
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store.hpp b/vespalib/src/vespa/vespalib/datastore/unique_store.hpp
index d9d5f9fee7f..aef6ea07290 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store.hpp
@@ -221,7 +221,7 @@ UniqueStore<EntryT, RefT, Compare, Allocator>::getBuilder(uint32_t uniqueValuesH
template <typename EntryT, typename RefT, typename Compare, typename Allocator>
typename UniqueStore<EntryT, RefT, Compare, Allocator>::Enumerator
-UniqueStore<EntryT, RefT, Compare, Allocator>::getEnumerator(bool sort_unique_values) const
+UniqueStore<EntryT, RefT, Compare, Allocator>::getEnumerator(bool sort_unique_values)
{
return Enumerator(*_dict, _store, sort_unique_values);
}
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.h b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.h
index c4baff2206b..a6e7c2c974e 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.h
@@ -30,9 +30,9 @@ private:
EnumValues _enumValues;
uint32_t _next_enum_val;
- void allocate_enum_values();
+ void allocate_enum_values(DataStoreBase &store);
public:
- UniqueStoreEnumerator(const IUniqueStoreDictionary &dict, const DataStoreBase &store, bool sort_unique_values);
+ UniqueStoreEnumerator(const IUniqueStoreDictionary &dict, DataStoreBase &store, bool sort_unique_values);
~UniqueStoreEnumerator();
void enumerateValue(EntryRef ref);
void enumerateValues();
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp
index 52437fc765c..6d08a027bf1 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp
@@ -9,7 +9,7 @@
namespace vespalib::datastore {
template <typename RefT>
-UniqueStoreEnumerator<RefT>::UniqueStoreEnumerator(const IUniqueStoreDictionary &dict, const DataStoreBase &store, bool sort_unique_values)
+UniqueStoreEnumerator<RefT>::UniqueStoreEnumerator(const IUniqueStoreDictionary &dict, DataStoreBase &store, bool sort_unique_values)
: _dict_snapshot(dict.get_read_snapshot()),
_store(store),
_enumValues(),
@@ -19,7 +19,7 @@ UniqueStoreEnumerator<RefT>::UniqueStoreEnumerator(const IUniqueStoreDictionary
if (sort_unique_values) {
_dict_snapshot->sort();
}
- allocate_enum_values();
+ allocate_enum_values(store);
}
template <typename RefT>
@@ -40,11 +40,11 @@ UniqueStoreEnumerator<RefT>::enumerateValue(EntryRef ref)
template <typename RefT>
void
-UniqueStoreEnumerator<RefT>::allocate_enum_values()
+UniqueStoreEnumerator<RefT>::allocate_enum_values(DataStoreBase & store)
{
_enumValues.resize(RefType::numBuffers());
for (uint32_t bufferId = 0; bufferId < RefType::numBuffers(); ++bufferId) {
- const BufferState &state = _store.getBufferState(bufferId);
+ const BufferState &state = store.getBufferState(bufferId);
if (state.isActive()) {
_enumValues[bufferId].resize(state.get_used_arrays());
}
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 265478fbaf5..a85b73f423d 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_string_allocator.h
@@ -114,7 +114,7 @@ public:
EntryRef move_on_compact(EntryRef ref) override;
const UniqueStoreEntryBase& get_wrapped(EntryRef ref) const {
RefType iRef(ref);
- auto &state = _store.getBufferState(iRef.bufferId());
+ auto &state = _store.getBufferMeta(iRef.bufferId());
auto type_id = state.getTypeId();
if (type_id != 0) {
return *reinterpret_cast<const UniqueStoreEntryBase *>(_store.template getEntryArray<char>(iRef, state.getArraySize()));
@@ -124,7 +124,7 @@ public:
}
const char *get(EntryRef ref) const {
RefType iRef(ref);
- auto &state = _store.getBufferState(iRef.bufferId());
+ auto &state = _store.getBufferMeta(iRef.bufferId());
auto type_id = state.getTypeId();
if (type_id != 0) {
return reinterpret_cast<const UniqueStoreSmallStringEntry *>(_store.template getEntryArray<char>(iRef, state.getArraySize()))->value();
diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_string_comparator.h b/vespalib/src/vespa/vespalib/datastore/unique_store_string_comparator.h
index 73a812ccd0b..e507132a085 100644
--- a/vespalib/src/vespa/vespalib/datastore/unique_store_string_comparator.h
+++ b/vespalib/src/vespa/vespalib/datastore/unique_store_string_comparator.h
@@ -25,10 +25,10 @@ protected:
const char *get(EntryRef ref) const {
if (ref.valid()) {
RefType iRef(ref);
- auto &state = _store.getBufferState(iRef.bufferId());
- auto type_id = state.getTypeId();
+ const auto &meta = _store.getBufferMeta(iRef.bufferId());
+ auto type_id = meta.getTypeId();
if (type_id != 0) {
- return reinterpret_cast<const UniqueStoreSmallStringEntry *>(_store.template getEntryArray<char>(iRef, state.getArraySize()))->value();
+ return reinterpret_cast<const UniqueStoreSmallStringEntry *>(_store.template getEntryArray<char>(iRef, meta.getArraySize()))->value();
} else {
return _store.template getEntry<WrappedExternalEntryType>(iRef)->value().c_str();
}