aboutsummaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java
diff options
context:
space:
mode:
authorbjormel <bjormel@yahooinc.com>2023-10-01 12:23:12 +0000
committerbjormel <bjormel@yahooinc.com>2023-10-01 12:23:12 +0000
commite9058b555d4dfea2f6c872d9a677e8678b569569 (patch)
treefa1b67c6e39712c1e0d9f308b0dd55573b43f913 /configserver/src/main/java
parent0ad931fa86658904fe9212b014d810236b0e00e4 (diff)
parent16030193ec04ee41e98779a3d7ee6a6c1d0d0d6f (diff)
Merge branch 'master' into bjormel/aws-main-controller
Diffstat (limited to 'configserver/src/main/java')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java28
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/FallbackOnnxModelCostProvider.java16
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprints.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java123
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java145
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/DeployHandlerLogger.java15
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java41
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java56
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java14
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java9
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java12
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationFile.java9
17 files changed, 318 insertions, 213 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 9533f04107d..e675e00b642 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -41,16 +41,18 @@ import com.yahoo.slime.Slime;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.applicationmodel.InfrastructureApplication;
+import com.yahoo.vespa.config.server.application.ActiveTokenFingerprints.Token;
+import com.yahoo.vespa.config.server.application.ActiveTokenFingerprintsClient;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.application.ApplicationCuratorDatabase;
import com.yahoo.vespa.config.server.application.ApplicationData;
import com.yahoo.vespa.config.server.application.ApplicationReindexing;
-import com.yahoo.vespa.config.server.application.ApplicationReindexing.Status;
import com.yahoo.vespa.config.server.application.ApplicationVersions;
import com.yahoo.vespa.config.server.application.ClusterReindexing;
import com.yahoo.vespa.config.server.application.ClusterReindexingStatusClient;
import com.yahoo.vespa.config.server.application.CompressedApplicationInputStream;
import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker;
+import com.yahoo.vespa.config.server.application.ActiveTokenFingerprints;
import com.yahoo.vespa.config.server.application.DefaultClusterReindexingStatusClient;
import com.yahoo.vespa.config.server.application.FileDistributionStatus;
import com.yahoo.vespa.config.server.application.HttpProxy;
@@ -129,7 +131,6 @@ import static com.yahoo.vespa.config.server.tenant.TenantRepository.HOSTED_VESPA
import static com.yahoo.vespa.curator.Curator.CompletionWaiter;
import static com.yahoo.yolean.Exceptions.uncheck;
import static java.nio.file.Files.readAttributes;
-import static java.util.Comparator.naturalOrder;
/**
* The API for managing applications.
@@ -159,6 +160,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
private final Metric metric;
private final SecretStoreValidator secretStoreValidator;
private final ClusterReindexingStatusClient clusterReindexingStatusClient;
+ private final ActiveTokenFingerprints activeTokenFingerprints;
private final FlagSource flagSource;
@Inject
@@ -188,6 +190,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
metric,
new SecretStoreValidator(secretStore),
new DefaultClusterReindexingStatusClient(),
+ new ActiveTokenFingerprintsClient(),
flagSource);
}
@@ -205,6 +208,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
Metric metric,
SecretStoreValidator secretStoreValidator,
ClusterReindexingStatusClient clusterReindexingStatusClient,
+ ActiveTokenFingerprints activeTokenFingerprints,
FlagSource flagSource) {
this.tenantRepository = Objects.requireNonNull(tenantRepository);
this.hostProvisioner = Objects.requireNonNull(hostProvisioner);
@@ -219,7 +223,8 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
this.testerClient = Objects.requireNonNull(testerClient);
this.metric = Objects.requireNonNull(metric);
this.secretStoreValidator = Objects.requireNonNull(secretStoreValidator);
- this.clusterReindexingStatusClient = clusterReindexingStatusClient;
+ this.clusterReindexingStatusClient = Objects.requireNonNull(clusterReindexingStatusClient);
+ this.activeTokenFingerprints = Objects.requireNonNull(activeTokenFingerprints);
this.flagSource = flagSource;
}
@@ -237,6 +242,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
private SecretStoreValidator secretStoreValidator = new SecretStoreValidator(new SecretStoreProvider().get());
private FlagSource flagSource = new InMemoryFlagSource();
private ConfigConvergenceChecker configConvergenceChecker = new ConfigConvergenceChecker();
+ private Map<String, List<Token>> activeTokens = Map.of();
public Builder withTenantRepository(TenantRepository tenantRepository) {
this.tenantRepository = tenantRepository;
@@ -298,6 +304,11 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return this;
}
+ public Builder withActiveTokens(Map<String, List<Token>> tokens) {
+ this.activeTokens = tokens;
+ return this;
+ }
+
public ApplicationRepository build() {
return new ApplicationRepository(tenantRepository,
tenantRepository.hostProvisionerProvider().getHostProvisioner(),
@@ -313,6 +324,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
metric,
secretStoreValidator,
ClusterReindexingStatusClient.DUMMY_INSTANCE,
+ __ -> activeTokens,
flagSource);
}
@@ -612,6 +624,10 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return uncheck(() -> clusterReindexingStatusClient.getReindexingStatus(getApplication(applicationId)));
}
+ public Map<String, List<Token>> activeTokenFingerprints(ApplicationId applicationId) {
+ return activeTokenFingerprints.get(getApplication(applicationId));
+ }
+
public Long getApplicationGeneration(ApplicationId applicationId) {
return getApplication(applicationId).getApplicationGeneration();
}
@@ -1030,21 +1046,21 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
private Session validateThatLocalSessionIsNotActive(Tenant tenant, long sessionId) {
Session session = getLocalSession(tenant, sessionId);
if (Session.Status.ACTIVATE.equals(session.getStatus())) {
- throw new IllegalArgumentException("Session is active: " + sessionId);
+ throw new IllegalArgumentException("Session " + sessionId + " for '" + tenant.getName() + "' is active");
}
return session;
}
private Session getLocalSession(Tenant tenant, long sessionId) {
Session session = tenant.getSessionRepository().getLocalSession(sessionId);
- if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
+ if (session == null) throw new NotFoundException("Local session " + sessionId + " for '" + tenant.getName() + "' was not found");
return session;
}
private RemoteSession getRemoteSession(Tenant tenant, long sessionId) {
RemoteSession session = tenant.getSessionRepository().getRemoteSession(sessionId);
- if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
+ if (session == null) throw new NotFoundException("Remote session " + sessionId + " for '" + tenant.getName() + "' was not found");
return session;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/FallbackOnnxModelCostProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/FallbackOnnxModelCostProvider.java
new file mode 100644
index 00000000000..57cfb1cd43b
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/FallbackOnnxModelCostProvider.java
@@ -0,0 +1,16 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.config.server;
+
+import com.yahoo.config.model.api.OnnxModelCost;
+import com.yahoo.container.di.componentgraph.Provider;
+
+/**
+ * Default provider that provides a disabled {@link OnnxModelCost} instance.
+ *
+ * @author bjorncs
+ */
+public class FallbackOnnxModelCostProvider implements Provider<OnnxModelCost> {
+ @Override public OnnxModelCost get() { return OnnxModelCost.disabled(); }
+ @Override public void deconstruct() {}
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprints.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprints.java
new file mode 100644
index 00000000000..9cde5e38302
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprints.java
@@ -0,0 +1,18 @@
+package com.yahoo.vespa.config.server.application;
+
+import com.yahoo.vespa.config.server.modelfactory.ModelResult;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author jonmv
+ */
+public interface ActiveTokenFingerprints {
+
+ /** Lists all active tokens and their fingerprints for each token-enabled container host in the application, that is currently up. */
+ Map<String, List<Token>> get(ModelResult application);
+
+ record Token(String id, List<String> fingerprints) { }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java
new file mode 100644
index 00000000000..4e9eac7a9a6
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ActiveTokenFingerprintsClient.java
@@ -0,0 +1,123 @@
+package com.yahoo.vespa.config.server.application;
+
+import ai.vespa.http.DomainName;
+import ai.vespa.http.HttpURL;
+import ai.vespa.http.HttpURL.Path;
+import ai.vespa.http.HttpURL.Scheme;
+import ai.vespa.util.http.hc5.VespaAsyncHttpClientBuilder;
+import com.yahoo.config.model.api.ApplicationClusterEndpoint.AuthMethod;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.slime.Inspector;
+import com.yahoo.vespa.config.server.modelfactory.ModelResult;
+import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
+import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Phaser;
+
+import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER;
+import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER;
+import static com.yahoo.slime.SlimeUtils.entriesStream;
+import static com.yahoo.slime.SlimeUtils.jsonToSlime;
+import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * @author jonmv
+ */
+public class ActiveTokenFingerprintsClient implements ActiveTokenFingerprints, AutoCloseable {
+
+ private final CloseableHttpAsyncClient httpClient = createHttpClient();
+
+ public ActiveTokenFingerprintsClient() {
+ httpClient.start();
+ }
+
+ @Override
+ public Map<String, List<Token>> get(ModelResult application) {
+ Set<String> containersWithTokenFilter = application.getModel().applicationClusterInfo().stream()
+ .flatMap(cluster -> cluster.endpoints().stream())
+ .filter(endpoint -> endpoint.authMethod() == AuthMethod.token)
+ .flatMap(endpoint -> endpoint.hostNames().stream())
+ .collect(toSet());
+ return getFingerprints(application.getModel().getHosts().stream()
+ .filter(host -> containersWithTokenFilter.contains(host.getHostname()))
+ .flatMap(host -> host.getServices().stream())
+ .filter(service -> service.getServiceType().equals(CONTAINER.serviceName)
+ || service.getServiceType().equals(QRSERVER.serviceName))
+ .toList());
+ }
+
+ private Map<String, List<Token>> getFingerprints(List<ServiceInfo> services) {
+ Map<String, List<Token>> tokens = new ConcurrentHashMap<>();
+ Phaser phaser = new Phaser(services.size() + 1);
+ for (ServiceInfo service : services) getFingerprints(tokens, service, phaser);
+ phaser.arriveAndAwaitAdvance();
+ return tokens;
+ }
+
+ // A container may be unable to provide its fingerprints for a number of reasons, which may be OK, so
+ // we only track those containers which return an OK response, but we do require at least one such response.
+ private void getFingerprints(Map<String, List<Token>> hostTokens, ServiceInfo service, Phaser phaser) {
+ URI uri = HttpURL.create(Scheme.http,
+ DomainName.of(service.getHostName()),
+ service.getPorts().stream().filter(port -> port.getTags().stream().anyMatch("http"::equals)).findAny().get().getPort(),
+ Path.parse("/data-plane-tokens/v1"))
+ .asURI();
+ httpClient.execute(SimpleRequestBuilder.get(uri).build(), new FutureCallback<>() {
+ @Override public void completed(SimpleHttpResponse result) {
+ if (result.getCode() == 200) hostTokens.put(service.getHostName(), parseTokens(result));
+ phaser.arrive();
+ }
+ @Override public void failed(Exception ex) { phaser.arrive(); }
+ @Override public void cancelled() { phaser.arrive(); }
+ });
+ }
+
+ private static List<Token> parseTokens(SimpleHttpResponse response) {
+ return entriesStream(jsonToSlime(response.getBodyBytes()).get().field("tokens"))
+ .map(entry -> new Token(entry.field("id").asString(),
+ entriesStream(entry.field("fingerprints")).map(Inspector::asString).toList()))
+ .toList();
+ }
+
+ private static CloseableHttpAsyncClient createHttpClient() {
+ return VespaAsyncHttpClientBuilder
+ .create(tlsStrategy -> PoolingAsyncClientConnectionManagerBuilder.create()
+ .setTlsStrategy(tlsStrategy)
+ .setDefaultConnectionConfig(ConnectionConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(2))
+ .build())
+ .build())
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(2))
+ .build())
+ .setDefaultRequestConfig(
+ RequestConfig.custom()
+ .setConnectionRequestTimeout(Timeout.ofSeconds(2))
+ .setResponseTimeout(Timeout.ofSeconds(2))
+ .build())
+ .setUserAgent("data-plane-token-client")
+ .build();
+ }
+
+ @Override
+ public void close() throws Exception {
+ httpClient.close(CloseMode.GRACEFUL);
+ httpClient.awaitShutdown(TimeValue.ofSeconds(10));
+ }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
index 693252da43a..ff2c137c11c 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/TenantApplications.java
@@ -23,7 +23,6 @@ import com.yahoo.vespa.config.server.monitoring.MetricUpdater;
import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
-import com.yahoo.vespa.curator.CompletionTimeoutException;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
@@ -37,7 +36,6 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Clock;
import java.time.Duration;
-import java.time.Instant;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
@@ -62,6 +60,8 @@ import static java.util.stream.Collectors.toSet;
public class TenantApplications implements RequestHandler, HostValidator {
private static final Logger log = Logger.getLogger(TenantApplications.class.getName());
+ /* Time to wait for all config servers to get event when an application is removed */
+ private static final Duration waitForAll = Duration.ofSeconds(5);
private final Curator curator;
private final ApplicationCuratorDatabase database;
@@ -430,146 +430,17 @@ public class TenantApplications implements RequestHandler, HostValidator {
public TenantFileSystemDirs getTenantFileSystemDirs() { return tenantFileSystemDirs; }
public CompletionWaiter createRemoveApplicationWaiter(ApplicationId applicationId) {
- return RemoveApplicationWaiter.createAndInitialize(curator, applicationId, serverId);
+ return curator.createCompletionWaiter(barrierPath(applicationId), serverId, waitForAll);
}
public CompletionWaiter getRemoveApplicationWaiter(ApplicationId applicationId) {
- return RemoveApplicationWaiter.create(curator, applicationId, serverId);
+ return curator.getCompletionWaiter(barrierPath(applicationId), serverId, waitForAll);
}
- /**
- * Waiter for removing application. Will wait for some time for all servers to remove application,
- * but will accept the majority of servers to have removed app if it takes a long time.
- */
- // TODO: Merge with CuratorCompletionWaiter
- static class RemoveApplicationWaiter implements CompletionWaiter {
-
- private static final java.util.logging.Logger log = Logger.getLogger(RemoveApplicationWaiter.class.getName());
- private static final Duration waitForAllDefault = Duration.ofSeconds(5);
-
- private final Curator curator;
- private final Path barrierPath;
- private final Path waiterNode;
- private final Duration waitForAll;
- private final Clock clock = Clock.systemUTC();
-
- RemoveApplicationWaiter(Curator curator, ApplicationId applicationId, String serverId) {
- this(curator, applicationId, serverId, waitForAllDefault);
- }
-
- RemoveApplicationWaiter(Curator curator, ApplicationId applicationId, String serverId, Duration waitForAll) {
- this.barrierPath = TenantRepository.getBarriersPath().append(applicationId.tenant().value())
- .append("delete-application")
- .append(applicationId.serializedForm());
- this.waiterNode = barrierPath.append(serverId);
- this.curator = curator;
- this.waitForAll = waitForAll;
- }
-
- @Override
- public void awaitCompletion(Duration timeout) {
- List<String> respondents;
- try {
- respondents = awaitInternal(timeout);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- if (respondents.size() < barrierMemberCount()) {
- throw new CompletionTimeoutException("Timed out waiting for peer config servers to remove application " +
- "(waited for barrier " + barrierPath + ")." +
- "Got response from " + respondents + ", but need response from " +
- "at least " + barrierMemberCount() + " server(s). " +
- "Timeout passed as argument was " + timeout.toMillis() + " ms");
- }
- }
-
- private List<String> awaitInternal(Duration timeout) throws Exception {
- Instant startTime = clock.instant();
- Instant endTime = startTime.plus(timeout);
- Instant gotQuorumTime = Instant.EPOCH;
- List<String> respondents;
- do {
- respondents = curator.framework().getChildren().forPath(barrierPath.getAbsolute());
- if (log.isLoggable(Level.FINE)) {
- log.log(Level.FINE, respondents.size() + "/" + curator.zooKeeperEnsembleCount() + " responded: " +
- respondents + ", all participants: " + curator.zooKeeperEnsembleConnectionSpec());
- }
-
- // If all config servers responded, return
- if (respondents.size() == curator.zooKeeperEnsembleCount()) {
- logBarrierCompleted(respondents, startTime);
- break;
- }
-
- // If some are missing, quorum is enough, but wait for all up to 5 seconds before returning
- if (respondents.size() >= barrierMemberCount()) {
- if (gotQuorumTime.isBefore(startTime))
- gotQuorumTime = clock.instant();
-
- // Give up if more than some time has passed since we got quorum, otherwise continue
- if (Duration.between(clock.instant(), gotQuorumTime.plus(waitForAll)).isNegative()) {
- logBarrierCompleted(respondents, startTime);
- break;
- }
- }
-
- Thread.sleep(100);
- } while (clock.instant().isBefore(endTime));
-
- return respondents;
- }
-
- private void logBarrierCompleted(List<String> respondents, Instant startTime) {
- Duration duration = Duration.between(startTime, Instant.now());
- Level level = (duration.minus(Duration.ofSeconds(5))).isNegative() ? Level.FINE : Level.INFO;
- log.log(level, () -> barrierCompletedMessage(respondents, duration));
- }
-
- private String barrierCompletedMessage(List<String> respondents, Duration duration) {
- return barrierPath + " completed in " + duration.toString() +
- ", " + respondents.size() + "/" + curator.zooKeeperEnsembleCount() + " responded: " + respondents;
- }
-
- @Override
- public void notifyCompletion() {
- try {
- curator.framework().create().forPath(waiterNode.getAbsolute());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String toString() { return "'" + barrierPath + "', " + barrierMemberCount() + " members"; }
-
- public static CompletionWaiter create(Curator curator, ApplicationId applicationId, String serverId) {
- return new RemoveApplicationWaiter(curator, applicationId, serverId);
- }
-
- public static CompletionWaiter create(Curator curator, ApplicationId applicationId, String serverId, Duration waitForAll) {
- return new RemoveApplicationWaiter(curator, applicationId, serverId, waitForAll);
- }
-
- public static CompletionWaiter createAndInitialize(Curator curator, ApplicationId applicationId, String serverId) {
- return createAndInitialize(curator, applicationId, serverId, waitForAllDefault);
- }
-
- public static CompletionWaiter createAndInitialize(Curator curator, ApplicationId applicationId, String serverId, Duration waitForAll) {
- RemoveApplicationWaiter waiter = new RemoveApplicationWaiter(curator, applicationId, serverId, waitForAll);
-
- // Cleanup and create a new barrier path
- Path barrierPath = waiter.barrierPath();
- curator.delete(barrierPath);
- curator.create(barrierPath.getParentPath());
- curator.createAtomically(barrierPath);
-
- return waiter;
- }
-
- private int barrierMemberCount() { return (curator.zooKeeperEnsembleCount() / 2) + 1; /* majority */ }
-
- private Path barrierPath() { return barrierPath; }
-
+ private static Path barrierPath(ApplicationId applicationId) {
+ return TenantRepository.getBarriersPath().append(applicationId.tenant().value())
+ .append("delete-application")
+ .append(applicationId.serializedForm());
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/DeployHandlerLogger.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/DeployHandlerLogger.java
index 154d2d0f2f0..042aa2423f3 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/DeployHandlerLogger.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/DeployHandlerLogger.java
@@ -11,6 +11,7 @@ import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.server.session.PrepareParams;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
+import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -35,15 +36,17 @@ public class DeployHandlerLogger implements DeployLogger {
this.logroot = slime.setObject().setArray("log");
}
+ @Override public void log(Level level, String message) { log(level, () -> message); }
+ @Override public void log(Level level, Supplier<String> message) { log(level, message, null); }
+
@Override
@SuppressWarnings("deprecation")
- public void log(Level level, String message) {
- if (level.intValue() <= LogLevel.DEBUG.intValue() && !verbose)
- return;
+ public void log(Level level, Supplier<String> supplier, Throwable throwable) {
+ // Also tee to a normal log, Vespa log for example, but use level fine
+ log.log(Level.FINE, throwable, () -> prefix + supplier.get());
- logJson(level, message);
- // Also tee to a normal log, Vespa log for example, but use level fine
- log.log(Level.FINE, () -> prefix + message);
+ if (level.intValue() <= LogLevel.DEBUG.intValue() && !verbose) return;
+ logJson(level, supplier.get());
}
@Override
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 142f98e13e3..96b0b03c832 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -13,6 +13,7 @@ import com.yahoo.config.model.api.EndpointCertificateSecrets;
import com.yahoo.config.model.api.HostProvisioner;
import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.api.Provisioned;
import com.yahoo.config.model.api.Quota;
import com.yahoo.config.model.api.Reindexing;
@@ -28,6 +29,7 @@ import com.yahoo.config.provision.Zone;
import com.yahoo.container.jdisc.secretstore.SecretStore;
import com.yahoo.vespa.config.server.tenant.SecretStoreExternalIdRetriever;
import com.yahoo.vespa.flags.FetchVector;
+import com.yahoo.vespa.flags.Flag;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.PermanentFlags;
@@ -66,6 +68,7 @@ public class ModelContextImpl implements ModelContext {
private final Optional<? extends Reindexing> reindexing;
private final ModelContext.Properties properties;
private final Optional<File> appDir;
+ private final OnnxModelCost onnxModelCost;
private final Optional<DockerImage> wantedDockerImageRepository;
@@ -92,6 +95,7 @@ public class ModelContextImpl implements ModelContext {
Provisioned provisioned,
ModelContext.Properties properties,
Optional<File> appDir,
+ OnnxModelCost onnxModelCost,
Optional<DockerImage> wantedDockerImageRepository,
Version modelVespaVersion,
Version wantedNodeVespaVersion) {
@@ -109,6 +113,7 @@ public class ModelContextImpl implements ModelContext {
this.wantedDockerImageRepository = wantedDockerImageRepository;
this.modelVespaVersion = modelVespaVersion;
this.wantedNodeVespaVersion = wantedNodeVespaVersion;
+ this.onnxModelCost = onnxModelCost;
}
@Override
@@ -150,6 +155,8 @@ public class ModelContextImpl implements ModelContext {
@Override
public Optional<File> appDir() { return appDir; }
+ @Override public OnnxModelCost onnxModelCost() { return onnxModelCost; }
+
@Override
public Optional<DockerImage> wantedDockerImageRepo() { return wantedDockerImageRepository; }
@@ -201,6 +208,8 @@ public class ModelContextImpl implements ModelContext {
private final boolean enableNestedMultivalueGrouping;
private final boolean useReconfigurableDispatcher;
private final int contentLayerMetadataFeatureLevel;
+ private final boolean dynamicHeapSize;
+ private final String unknownConfigDefinition;
public FeatureFlags(FlagSource source, ApplicationId appId, Version version) {
this.defaultTermwiseLimit = flagValue(source, appId, version, Flags.DEFAULT_TERM_WISE_LIMIT);
@@ -243,6 +252,8 @@ public class ModelContextImpl implements ModelContext {
this.enableNestedMultivalueGrouping = flagValue(source, appId, version, Flags.ENABLE_NESTED_MULTIVALUE_GROUPING);
this.useReconfigurableDispatcher = flagValue(source, appId, version, Flags.USE_RECONFIGURABLE_DISPATCHER);
this.contentLayerMetadataFeatureLevel = flagValue(source, appId, version, Flags.CONTENT_LAYER_METADATA_FEATURE_LEVEL);
+ this.dynamicHeapSize = flagValue(source, appId, version, Flags.DYNAMIC_HEAP_SIZE);
+ this.unknownConfigDefinition = flagValue(source, appId, version, Flags.UNKNOWN_CONFIG_DEFINITION);
}
@Override public int heapSizePercentage() { return heapPercentage; }
@@ -293,10 +304,13 @@ public class ModelContextImpl implements ModelContext {
@Override public boolean enableNestedMultivalueGrouping() { return enableNestedMultivalueGrouping; }
@Override public boolean useReconfigurableDispatcher() { return useReconfigurableDispatcher; }
@Override public int contentLayerMetadataFeatureLevel() { return contentLayerMetadataFeatureLevel; }
+ @Override public boolean dynamicHeapSize() { return dynamicHeapSize; }
+ @Override public String unknownConfigDefinition() { return unknownConfigDefinition; }
private static <V> V flagValue(FlagSource source, ApplicationId appId, Version vespaVersion, UnboundFlag<? extends V, ?, ?> flag) {
return flag.bindTo(source)
.with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm())
+ .with(FetchVector.Dimension.APPLICATION_ID, appId.toSerializedFormWithoutInstance())
.with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString())
.with(FetchVector.Dimension.TENANT_ID, appId.tenant().value())
.boxedValue();
@@ -309,6 +323,7 @@ public class ModelContextImpl implements ModelContext {
UnboundFlag<? extends V, ?, ?> flag) {
return flag.bindTo(source)
.with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm())
+ .with(FetchVector.Dimension.APPLICATION_ID, appId.toSerializedFormWithoutInstance())
.with(FetchVector.Dimension.CLUSTER_TYPE, clusterType.name())
.with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString())
.boxedValue();
@@ -321,6 +336,7 @@ public class ModelContextImpl implements ModelContext {
UnboundFlag<? extends V, ?, ?> flag) {
return flag.bindTo(source)
.with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm())
+ .with(FetchVector.Dimension.APPLICATION_ID, appId.toSerializedFormWithoutInstance())
.with(FetchVector.Dimension.CLUSTER_ID, clusterId.value())
.with(FetchVector.Dimension.VESPA_VERSION, vespaVersion.toFullString())
.boxedValue();
@@ -397,21 +413,16 @@ public class ModelContextImpl implements ModelContext {
this.tenantSecretStores = tenantSecretStores;
this.secretStore = secretStore;
this.jvmGCOptionsFlag = PermanentFlags.JVM_GC_OPTIONS.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm());
- this.allowDisableMtls = PermanentFlags.ALLOW_DISABLE_MTLS.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
+ .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm())
+ .with(FetchVector.Dimension.APPLICATION_ID, applicationId.toSerializedFormWithoutInstance());
+ this.allowDisableMtls = flagValue(flagSource, applicationId, PermanentFlags.ALLOW_DISABLE_MTLS);
this.operatorCertificates = operatorCertificates;
- this.tlsCiphersOverride = PermanentFlags.TLS_CIPHERS_OVERRIDE.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
+ this.tlsCiphersOverride = flagValue(flagSource, applicationId, PermanentFlags.TLS_CIPHERS_OVERRIDE);
this.zoneDnsSuffixes = configserverConfig.zoneDnsSuffixes();
- this.environmentVariables = PermanentFlags.ENVIRONMENT_VARIABLES.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
+ this.environmentVariables = flagValue(flagSource, applicationId, PermanentFlags.ENVIRONMENT_VARIABLES);
this.cloudAccount = cloudAccount;
- this.allowUserFilters = PermanentFlags.ALLOW_USER_FILTERS.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
- this.endpointConnectionTtl = Duration.ofSeconds(
- PermanentFlags.ENDPOINT_CONNECTION_TTL.bindTo(flagSource)
- .with(FetchVector.Dimension.INSTANCE_ID, applicationId.serializedForm()).value());
+ this.allowUserFilters = flagValue(flagSource, applicationId, PermanentFlags.ALLOW_USER_FILTERS);
+ this.endpointConnectionTtl = Duration.ofSeconds(flagValue(flagSource, applicationId, PermanentFlags.ENDPOINT_CONNECTION_TTL));
this.dataplaneTokens = dataplaneTokens;
}
@@ -512,4 +523,10 @@ public class ModelContextImpl implements ModelContext {
@Override public Duration endpointConnectionTtl() { return endpointConnectionTtl; }
}
+ private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) {
+ return flag.bindTo(source)
+ .with(FetchVector.Dimension.INSTANCE_ID, appId.serializedForm())
+ .with(FetchVector.Dimension.APPLICATION_ID, appId.toSerializedFormWithoutInstance())
+ .boxedValue();
+ }
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
index bd6e0f90b54..f39feceeeb1 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
@@ -95,9 +95,11 @@ public class ApplicationHandler extends HttpHandler {
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}")) return getApplicationResponse(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/content/{*}")) return content(applicationId(path), path.getRest(), request);
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/filedistributionstatus")) return filedistributionStatus(applicationId(path), request);
+ if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/active-token-fingerprints")) return activeTokenFingerprints(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/logs")) return logs(applicationId(path), request);
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/metrics/deployment")) return deploymentMetrics(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/metrics/searchnode")) return searchNodeMetrics(applicationId(path));
+ if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/quota")) return quotaUsage(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/reindexing")) return getReindexingStatus(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/service/{service}/{hostname}/status/{*}")) return serviceStatusPage(applicationId(path), path.get("service"), path.get("hostname"), path.getRest(), request);
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/service/{service}/{hostname}/state/v1/{*}")) return serviceStateV1(applicationId(path), path.get("service"), path.get("hostname"), path.getRest(), request);
@@ -105,7 +107,6 @@ public class ApplicationHandler extends HttpHandler {
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/serviceconverge/{hostAndPort}")) return checkServiceConverge(applicationId(path), path.get("hostAndPort"), request);
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/suspended")) return isSuspended(applicationId(path));
if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/tester/{command}")) return testerRequest(applicationId(path), path.get("command"), request);
- if (path.matches("/application/v2/tenant/{tenant}/application/{application}/environment/{ignore}/region/{ignore}/instance/{instance}/quota")) return quotaUsage(applicationId(path));
return ErrorResponse.notFoundError("Nothing at " + path);
}
@@ -150,18 +151,11 @@ public class ApplicationHandler extends HttpHandler {
}
private HttpResponse serviceStatusPage(ApplicationId applicationId, String service, String hostname, HttpURL.Path pathSuffix, HttpRequest request) {
- HttpURL.Path pathPrefix = HttpURL.Path.empty();
- switch (service) {
- case "container-clustercontroller":
- pathPrefix = pathPrefix.append("clustercontroller-status").append("v1");
- break;
- case "distributor":
- case "storagenode":
- pathPrefix = pathPrefix.append("contentnode-status").append("v1");
- break;
- default:
- throw new com.yahoo.vespa.config.server.NotFoundException("No status page for service: " + service);
- }
+ HttpURL.Path pathPrefix = switch (service) {
+ case "container-clustercontroller" -> HttpURL.Path.empty().append("clustercontroller-status").append("v1");
+ case "distributor", "storagenode" -> HttpURL.Path.empty().append("contentnode-status").append("v1");
+ default -> throw new NotFoundException("No status page for service: " + service);
+ };
return applicationRepository.proxyServiceHostnameRequest(applicationId, hostname, service, pathPrefix.append(pathSuffix), Query.empty().add(request.getJDiscRequest().parameters()), null);
}
@@ -194,6 +188,22 @@ public class ApplicationHandler extends HttpHandler {
return applicationRepository.fileDistributionStatus(applicationId, getTimeoutFromRequest(request));
}
+ private HttpResponse activeTokenFingerprints(ApplicationId applicationId) {
+ Slime slime = new Slime();
+ Cursor hostsArray = slime.setObject().setArray("hosts");
+ applicationRepository.activeTokenFingerprints(applicationId).forEach((host, tokens) -> {
+ Cursor hostObject = hostsArray.addObject();
+ hostObject.setString("host", host);
+ Cursor tokensArray = hostObject.setArray("tokens");
+ tokens.forEach(token -> {
+ Cursor tokenObject = tokensArray.addObject();
+ tokenObject.setString("id", token.id());
+ token.fingerprints().forEach(tokenObject.setArray("fingerprints")::addString);
+ });
+ });
+ return new SlimeJsonResponse(slime);
+ }
+
private HttpResponse logs(ApplicationId applicationId, HttpRequest request) {
Optional<DomainName> hostname = Optional.ofNullable(request.getProperty("hostname")).map(DomainName::of);
String apiParams = Optional.ofNullable(request.getUri().getQuery()).map(q -> "?" + q).orElse("");
@@ -213,19 +223,13 @@ public class ApplicationHandler extends HttpHandler {
}
private HttpResponse testerRequest(ApplicationId applicationId, String command, HttpRequest request) {
- switch (command) {
- case "status":
- return applicationRepository.getTesterStatus(applicationId);
- case "log":
- Long after = Long.valueOf(request.getProperty("after"));
- return applicationRepository.getTesterLog(applicationId, after);
- case "ready":
- return applicationRepository.isTesterReady(applicationId);
- case "report":
- return applicationRepository.getTestReport(applicationId);
- default:
- throw new IllegalArgumentException("Unknown tester command in request " + request.getUri().toString());
- }
+ return switch (command) {
+ case "status" -> applicationRepository.getTesterStatus(applicationId);
+ case "log" -> applicationRepository.getTesterLog(applicationId, Long.valueOf(request.getProperty("after")));
+ case "ready" -> applicationRepository.isTesterReady(applicationId);
+ case "report" -> applicationRepository.getTestReport(applicationId);
+ default -> throw new IllegalArgumentException("Unknown tester command in request " + request.getUri().toString());
+ };
}
private HttpResponse quotaUsage(ApplicationId applicationId) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
index 328bd143d81..d302e0e8008 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
@@ -9,6 +9,7 @@ import com.yahoo.config.model.api.ConfigDefinitionRepo;
import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelFactory;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.api.Provisioned;
import com.yahoo.config.model.application.provider.MockFileRegistry;
import com.yahoo.config.provision.ApplicationId;
@@ -58,6 +59,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
private final FlagSource flagSource;
private final SecretStore secretStore;
private final ExecutorService executor;
+ private final OnnxModelCost onnxModelCost;
public ActivatedModelsBuilder(TenantName tenant,
long applicationGeneration,
@@ -72,7 +74,8 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
ConfigserverConfig configserverConfig,
Zone zone,
ModelFactoryRegistry modelFactoryRegistry,
- ConfigDefinitionRepo configDefinitionRepo) {
+ ConfigDefinitionRepo configDefinitionRepo,
+ OnnxModelCost onnxModelCost) {
super(modelFactoryRegistry, configserverConfig, zone, hostProvisionerProvider, new SilentDeployLogger());
this.tenant = tenant;
this.applicationGeneration = applicationGeneration;
@@ -84,6 +87,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
this.flagSource = flagSource;
this.secretStore = secretStore;
this.executor = executor;
+ this.onnxModelCost = onnxModelCost;
}
@Override
@@ -108,6 +112,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
provisioned,
modelContextProperties,
Optional.empty(),
+ onnxModelCost,
wantedDockerImageRepository,
modelFactory.version(),
wantedNodeVespaVersion);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
index 4faa475fa08..57c766bb9c2 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
@@ -207,11 +207,12 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> {
builtModelVersions.add(modelVersion);
} catch (RuntimeException e) {
// allow failure to create old config models if there is a validation override that allow skipping old
- // config models or we're manually deploying
+ // config models, or we're manually deploying
if (builtModelVersions.size() > 0 &&
( builtModelVersions.get(0).getModel().skipOldConfigModels(now) || zone().environment().isManuallyDeployed()))
- log.log(Level.INFO, applicationId + ": Failed to build version " + version +
- ", but allow failure due to validation override or manual deployment");
+ log.log(Level.WARNING, applicationId + ": Failed to build version " + version +
+ ", but allow failure due to validation override or manual deployment:"
+ + Exceptions.toMessageString(e));
else {
log.log(Level.SEVERE, applicationId + ": Failed to build version " + version);
throw e;
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java
index af611b131f6..a3f0284890c 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java
@@ -16,6 +16,7 @@ import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelCreateResult;
import com.yahoo.config.model.api.ModelFactory;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.api.Provisioned;
import com.yahoo.config.model.api.ValidationParameters;
import com.yahoo.config.model.api.ValidationParameters.IgnoreValidationErrors;
@@ -69,6 +70,7 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P
private final Optional<ApplicationVersions> activeApplicationVersions;
private final Curator curator;
private final ExecutorService executor;
+ private final OnnxModelCost onnxModelCost;
public PreparedModelsBuilder(ModelFactoryRegistry modelFactoryRegistry,
FlagSource flagSource,
@@ -85,7 +87,8 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P
PrepareParams params,
Optional<ApplicationVersions> activeApplicationVersions,
ConfigserverConfig configserverConfig,
- Zone zone) {
+ Zone zone,
+ OnnxModelCost onnxModelCost) {
super(modelFactoryRegistry, configserverConfig, zone, hostProvisionerProvider, deployLogger);
this.flagSource = flagSource;
this.secretStore = secretStore;
@@ -98,6 +101,7 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P
this.params = params;
this.activeApplicationVersions = activeApplicationVersions;
this.executor = executor;
+ this.onnxModelCost = onnxModelCost;
}
@Override
@@ -123,6 +127,7 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P
provisioned,
createModelContextProperties(modelFactory.version(), applicationPackage),
getAppDir(applicationPackage),
+ onnxModelCost,
wantedDockerImageRepository,
modelVersion,
wantedNodeVespaVersion);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
index aeff97169f4..67872865106 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
@@ -18,6 +18,7 @@ import com.yahoo.config.model.api.ContainerEndpoint;
import com.yahoo.config.model.api.EndpointCertificateMetadata;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
import com.yahoo.config.model.api.FileDistribution;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.api.Quota;
import com.yahoo.config.model.api.TenantSecretStore;
import com.yahoo.config.provision.AllocatedHosts;
@@ -93,6 +94,7 @@ public class SessionPreparer {
private final FlagSource flagSource;
private final ExecutorService executor;
private final BooleanFlag writeSessionData;
+ private final OnnxModelCost onnxModelCost;
public SessionPreparer(ModelFactoryRegistry modelFactoryRegistry,
FileDistributionFactory fileDistributionFactory,
@@ -103,7 +105,8 @@ public class SessionPreparer {
Curator curator,
Zone zone,
FlagSource flagSource,
- SecretStore secretStore) {
+ SecretStore secretStore,
+ OnnxModelCost onnxModelCost) {
this.modelFactoryRegistry = modelFactoryRegistry;
this.fileDistributionFactory = fileDistributionFactory;
this.hostProvisionerProvider = hostProvisionerProvider;
@@ -115,6 +118,7 @@ public class SessionPreparer {
this.flagSource = flagSource;
this.executor = executor;
this.writeSessionData = Flags.WRITE_CONFIG_SERVER_SESSION_DATA_AS_ONE_BLOB.bindTo(flagSource);
+ this.onnxModelCost = onnxModelCost;
}
ExecutorService getExecutor() { return executor; }
@@ -134,7 +138,8 @@ public class SessionPreparer {
ApplicationId applicationId = params.getApplicationId();
Preparation preparation = new Preparation(hostValidator, logger, params, activeApplicationVersions,
TenantRepository.getTenantPath(applicationId.tenant()),
- serverDbSessionDir, applicationPackage, sessionZooKeeperClient);
+ serverDbSessionDir, applicationPackage, sessionZooKeeperClient,
+ onnxModelCost);
preparation.preprocess();
try {
AllocatedHosts allocatedHosts = preparation.buildModels(now);
@@ -186,7 +191,7 @@ public class SessionPreparer {
Preparation(HostValidator hostValidator, DeployLogger logger, PrepareParams params,
Optional<ApplicationVersions> activeApplicationVersions, Path tenantPath,
File serverDbSessionDir, ApplicationPackage applicationPackage,
- SessionZooKeeperClient sessionZooKeeperClient) {
+ SessionZooKeeperClient sessionZooKeeperClient, OnnxModelCost onnxModelCost) {
this.logger = logger;
this.params = params;
this.applicationPackage = applicationPackage;
@@ -219,7 +224,8 @@ public class SessionPreparer {
params,
activeApplicationVersions,
configserverConfig,
- zone);
+ zone,
+ onnxModelCost);
}
void checkTimeout(String step) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
index 3b57945b21d..eb07e3010c6 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
@@ -9,6 +9,7 @@ import com.yahoo.concurrent.StripedExecutor;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.application.provider.DeployData;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
import com.yahoo.config.provision.ApplicationId;
@@ -118,6 +119,7 @@ public class SessionRepository {
private final SessionPreparer sessionPreparer;
private final Path sessionsPath;
private final TenantName tenantName;
+ private final OnnxModelCost onnxModelCost;
private final SessionCounter sessionCounter;
private final SecretStore secretStore;
private final HostProvisionerProvider hostProvisionerProvider;
@@ -147,8 +149,10 @@ public class SessionRepository {
Clock clock,
ModelFactoryRegistry modelFactoryRegistry,
ConfigDefinitionRepo configDefinitionRepo,
- int maxNodeSize) {
+ int maxNodeSize,
+ OnnxModelCost onnxModelCost) {
this.tenantName = tenantName;
+ this.onnxModelCost = onnxModelCost;
sessionCounter = new SessionCounter(curator, tenantName);
this.sessionsPath = TenantRepository.getSessionsPath(tenantName);
this.clock = clock;
@@ -553,7 +557,8 @@ public class SessionRepository {
configserverConfig,
zone,
modelFactoryRegistry,
- configDefinitionRepo);
+ configDefinitionRepo,
+ onnxModelCost);
return ApplicationVersions.fromList(builder.buildModels(session.getApplicationId(),
session.getDockerImageRepository(),
session.getVespaVersion(),
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
index 2bc8cb5bc0a..378cd9bdb8c 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
@@ -118,21 +118,21 @@ public class SessionZooKeeperClient {
public long sessionId() { return sessionId; }
- public CompletionWaiter createActiveWaiter() { return createCompletionWaiter(getWaiterPath(ACTIVE_BARRIER)); }
+ public CompletionWaiter createActiveWaiter() { return createCompletionWaiter(barrierPath(ACTIVE_BARRIER)); }
- CompletionWaiter createPrepareWaiter() { return createCompletionWaiter(getWaiterPath(PREPARE_BARRIER)); }
+ CompletionWaiter createPrepareWaiter() { return createCompletionWaiter(barrierPath(PREPARE_BARRIER)); }
- CompletionWaiter getPrepareWaiter() { return getCompletionWaiter(getWaiterPath(PREPARE_BARRIER)); }
+ CompletionWaiter getPrepareWaiter() { return getCompletionWaiter(barrierPath(PREPARE_BARRIER)); }
- CompletionWaiter getActiveWaiter() { return getCompletionWaiter(getWaiterPath(ACTIVE_BARRIER)); }
+ CompletionWaiter getActiveWaiter() { return getCompletionWaiter(barrierPath(ACTIVE_BARRIER)); }
- CompletionWaiter getUploadWaiter() { return getCompletionWaiter(getWaiterPath(UPLOAD_BARRIER)); }
+ CompletionWaiter getUploadWaiter() { return getCompletionWaiter(barrierPath(UPLOAD_BARRIER)); }
private static final String PREPARE_BARRIER = "prepareBarrier";
private static final String ACTIVE_BARRIER = "activeBarrier";
private static final String UPLOAD_BARRIER = "uploadBarrier";
- private Path getWaiterPath(String barrierName) {
+ private Path barrierPath(String barrierName) {
return sessionPath.append(barrierName);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
index ba09b3de365..ea53c8aa2bb 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
@@ -11,6 +11,7 @@ import com.yahoo.concurrent.Locks;
import com.yahoo.concurrent.StripedExecutor;
import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Zone;
@@ -119,6 +120,7 @@ public class TenantRepository {
new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("check for removed applications"));
private final Curator.DirectoryCache directoryCache;
private final ZookeeperServerConfig zookeeperServerConfig;
+ private final OnnxModelCost onnxModelCost;
/**
* Creates a new tenant repository
@@ -138,7 +140,8 @@ public class TenantRepository {
ConfigActivationListener configActivationListener,
TenantListener tenantListener,
ZookeeperServerConfig zookeeperServerConfig,
- FileDirectory fileDirectory) {
+ FileDirectory fileDirectory,
+ OnnxModelCost onnxModelCost) {
this(hostRegistry,
curator,
metrics,
@@ -157,7 +160,8 @@ public class TenantRepository {
configDefinitionRepo,
configActivationListener,
tenantListener,
- zookeeperServerConfig);
+ zookeeperServerConfig,
+ onnxModelCost);
}
public TenantRepository(HostRegistry hostRegistry,
@@ -178,7 +182,8 @@ public class TenantRepository {
ConfigDefinitionRepo configDefinitionRepo,
ConfigActivationListener configActivationListener,
TenantListener tenantListener,
- ZookeeperServerConfig zookeeperServerConfig) {
+ ZookeeperServerConfig zookeeperServerConfig,
+ OnnxModelCost onnxModelCost) {
this.hostRegistry = hostRegistry;
this.configserverConfig = configserverConfig;
this.curator = curator;
@@ -201,6 +206,7 @@ public class TenantRepository {
this.zookeeperServerConfig = zookeeperServerConfig;
// This we should control with a feature flag.
this.deployHelperExecutor = createModelBuilderExecutor();
+ this.onnxModelCost = onnxModelCost;
curator.framework().getConnectionStateListenable().addListener(this::stateChanged);
@@ -353,7 +359,8 @@ public class TenantRepository {
curator,
zone,
flagSource,
- secretStore);
+ secretStore,
+ onnxModelCost);
SessionRepository sessionRepository = new SessionRepository(tenantName,
applicationRepo,
sessionPreparer,
@@ -371,7 +378,8 @@ public class TenantRepository {
clock,
modelFactoryRegistry,
configDefinitionRepo,
- zookeeperServerConfig.juteMaxBuffer());
+ zookeeperServerConfig.juteMaxBuffer(),
+ onnxModelCost);
log.log(Level.FINE, "Adding tenant '" + tenantName + "'" + ", created " + created +
". Bootstrapping in " + Duration.between(start, clock.instant()));
Tenant tenant = new Tenant(tenantName, sessionRepository, applicationRepo, created);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java
index 4c262379c35..1288b63cadd 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplication.java
@@ -111,6 +111,12 @@ public class ZKApplication {
return getBytesInternal(getFullPath(path));
}
+ public long getSize(Path path) {
+ return curator.getStat(path).map(stat -> (long)stat.getDataLength())
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Could not get size from '" + path + "' in zookeeper"));
+ }
+
void putData(Path path, String data) {
byte[] bytes = Utf8.toBytes(data);
ensureDataIsNotTooLarge(bytes, path);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationFile.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationFile.java
index 6bc29331efb..e51f8627de2 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationFile.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationFile.java
@@ -3,8 +3,9 @@ package com.yahoo.vespa.config.server.zookeeper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.config.application.api.ApplicationFile;
-import com.yahoo.path.Path;
import com.yahoo.io.IOUtils;
+import com.yahoo.path.Path;
+import com.yahoo.vespa.config.util.ConfigUtils;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
@@ -13,11 +14,9 @@ import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
-import java.util.logging.Level;
-import com.yahoo.vespa.config.util.ConfigUtils;
-
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Level;
import java.util.logging.Logger;
import static com.yahoo.vespa.config.server.zookeeper.ZKApplication.USERAPP_ZK_SUBPATH;
@@ -184,6 +183,8 @@ class ZKApplicationFile extends ApplicationFile {
}
}
+ @Override public long getSize() { return zkApp.getSize(getZKPath(path)); }
+
@Override
public int compareTo(ApplicationFile other) {
if (other == this) return 0;