summaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java100
1 files changed, 80 insertions, 20 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
index ed401e65f20..36cac87a326 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
@@ -1,11 +1,22 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.session;
+import com.yahoo.config.application.api.ApplicationPackage;
+import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.lang.SettableOptional;
import com.yahoo.transaction.Transaction;
+import com.yahoo.vespa.config.server.GlobalComponentRegistry;
import com.yahoo.vespa.config.server.application.ApplicationSet;
+import com.yahoo.vespa.config.server.modelfactory.ActivatedModelsBuilder;
+import com.yahoo.vespa.curator.Curator;
+import org.apache.zookeeper.KeeperException;
+import java.time.Clock;
import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* A RemoteSession represents a session created on another config server. This session can
@@ -15,46 +26,95 @@ import java.util.Optional;
*/
public class RemoteSession extends Session {
- private final Optional<ApplicationSet> applicationSet;
+ private static final Logger log = Logger.getLogger(RemoteSession.class.getName());
+ private ApplicationSet applicationSet = null;
+ private final ActivatedModelsBuilder applicationLoader;
+ private final Clock clock;
/**
- * Creates a remote session, no application set loaded
+ * Creates a session. This involves loading the application, validating it and distributing it.
*
* @param tenant The name of the tenant creating session
* @param sessionId The session id for this session.
+ * @param componentRegistry a registry of global components
* @param zooKeeperClient a SessionZooKeeperClient instance
*/
public RemoteSession(TenantName tenant,
long sessionId,
+ GlobalComponentRegistry componentRegistry,
SessionZooKeeperClient zooKeeperClient) {
- this(tenant, sessionId, zooKeeperClient, Optional.empty());
+ super(tenant, sessionId, zooKeeperClient);
+ this.applicationLoader = new ActivatedModelsBuilder(tenant, sessionId, zooKeeperClient, componentRegistry);
+ this.clock = componentRegistry.getClock();
}
- /**
- * Creates a remote session, with application set
- *
- * @param tenant The name of the tenant creating session
- * @param sessionId The session id for this session.
- * @param zooKeeperClient a SessionZooKeeperClient instance
- */
- public RemoteSession(TenantName tenant,
- long sessionId,
- SessionZooKeeperClient zooKeeperClient,
- Optional<ApplicationSet> applicationSet) {
- super(tenant, sessionId, zooKeeperClient);
- this.applicationSet = applicationSet;
+ void prepare() {
+ Curator.CompletionWaiter waiter = sessionZooKeeperClient.getPrepareWaiter();
+ ensureApplicationLoaded();
+ notifyCompletion(waiter);
}
- Optional<ApplicationSet> applicationSet() {
- return applicationSet;
+ private ApplicationSet loadApplication() {
+ ApplicationPackage applicationPackage = sessionZooKeeperClient.loadApplicationPackage();
+
+ // Read hosts allocated on the config server instance which created this
+ Optional<AllocatedHosts> allocatedHosts = applicationPackage.getAllocatedHosts();
+
+ return ApplicationSet.fromList(applicationLoader.buildModels(getApplicationId(),
+ sessionZooKeeperClient.readDockerImageRepository(),
+ sessionZooKeeperClient.readVespaVersion(),
+ applicationPackage,
+ new SettableOptional<>(allocatedHosts),
+ clock.instant()));
}
- public synchronized RemoteSession deactivated() {
- return new RemoteSession(tenant, sessionId, sessionZooKeeperClient, Optional.empty());
+ public synchronized ApplicationSet ensureApplicationLoaded() {
+ return applicationSet == null ? applicationSet = loadApplication() : applicationSet;
+ }
+
+ public synchronized void deactivate() {
+ applicationSet = null;
}
public Transaction createDeleteTransaction() {
return sessionZooKeeperClient.createWriteStatusTransaction(Status.DELETE);
}
+
+ void confirmUpload() {
+ Curator.CompletionWaiter waiter = sessionZooKeeperClient.getUploadWaiter();
+ log.log(Level.FINE, "Notifying upload waiter for session " + getSessionId());
+ notifyCompletion(waiter);
+ log.log(Level.FINE, "Done notifying upload for session " + getSessionId());
+ }
+
+ void notifyCompletion(Curator.CompletionWaiter completionWaiter) {
+ try {
+ completionWaiter.notifyCompletion();
+ } catch (RuntimeException e) {
+ // Throw only if we get something else than NoNodeException or NodeExistsException.
+ // NoNodeException might happen when the session is no longer in use (e.g. the app using this session
+ // has been deleted) and this method has not been called yet for the previous session operation on a
+ // minority of the config servers.
+ // NodeExistsException might happen if an event for this node is delivered more than once, in that case
+ // this is a no-op
+ Set<Class<? extends KeeperException>> acceptedExceptions = Set.of(KeeperException.NoNodeException.class,
+ KeeperException.NodeExistsException.class);
+ Class<? extends Throwable> exceptionClass = e.getCause().getClass();
+ if (acceptedExceptions.contains(exceptionClass))
+ log.log(Level.FINE, "Not able to notify completion for session " + getSessionId() +
+ " (" + completionWaiter + ")," +
+ " node " + (exceptionClass.equals(KeeperException.NoNodeException.class)
+ ? "has been deleted"
+ : "already exists"));
+ else
+ throw e;
+ }
+ }
+
+ public void delete() {
+ Transaction transaction = sessionZooKeeperClient.deleteTransaction();
+ transaction.commit();
+ transaction.close();
+ }
}