aboutsummaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo/vespa/config
diff options
context:
space:
mode:
authorHarald Musum <musum@verizonmedia.com>2020-10-21 08:25:26 +0200
committerGitHub <noreply@github.com>2020-10-21 08:25:26 +0200
commit0a0dd27fa223bf7a06e03a1760b4c592aae5b136 (patch)
tree4a932487ac3ab2afaa7c3b1e9bd20aaacca43907 /configserver/src/main/java/com/yahoo/vespa/config
parent33c66735b26b168281d4f515742921ef43392725 (diff)
Revert "Reapply "Merge LocalSession and RemoteSession""
Diffstat (limited to 'configserver/src/main/java/com/yahoo/vespa/config')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java46
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java8
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java12
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java28
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java61
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java37
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java212
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionStateWatcher.java10
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SilentDeployLogger.java2
10 files changed, 285 insertions, 133 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 b454e5b063d..157e1bd838c 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
@@ -50,7 +50,9 @@ import com.yahoo.vespa.config.server.http.v2.ProtonMetricsResponse;
import com.yahoo.vespa.config.server.metrics.DeploymentMetricsRetriever;
import com.yahoo.vespa.config.server.metrics.ProtonMetricsRetriever;
import com.yahoo.vespa.config.server.provision.HostProvisionerProvider;
+import com.yahoo.vespa.config.server.session.LocalSession;
import com.yahoo.vespa.config.server.session.PrepareParams;
+import com.yahoo.vespa.config.server.session.RemoteSession;
import com.yahoo.vespa.config.server.session.Session;
import com.yahoo.vespa.config.server.session.SessionRepository;
import com.yahoo.vespa.config.server.session.SilentDeployLogger;
@@ -480,10 +482,10 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
Optional<Long> activeSession = tenantApplications.activeSessionOf(applicationId);
if (activeSession.isEmpty()) return false;
- // Deleting an application is done by deleting the session, other config
+ // Deleting an application is done by deleting the remote session, other config
// servers will pick this up and clean up through the watcher in this class
try {
- Session session = getSession(tenant, activeSession.get());
+ Session session = getRemoteSession(tenant, activeSession.get());
tenant.getSessionRepository().delete(session);
} catch (NotFoundException e) {
log.log(Level.INFO, TenantRepository.logPre(applicationId) + "Active session exists, but has not been deleted properly. Trying to cleanup");
@@ -607,7 +609,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
Tenant tenant = getTenant(applicationId);
if (tenant == null) throw new NotFoundException("Tenant '" + applicationId.tenant() + "' not found");
long sessionId = getSessionIdForApplication(tenant, applicationId);
- Session session = getSession(tenant, sessionId);
+ RemoteSession session = getRemoteSession(tenant, sessionId);
SessionRepository sessionRepository = tenant.getSessionRepository();
return sessionRepository.ensureApplicationLoaded(session).getForVersionOrLatest(version, clock.instant());
} catch (NotFoundException e) {
@@ -759,7 +761,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
*
* @return the active session, or null if there is no active session for the given application id.
*/
- public Session getActiveRemoteSession(ApplicationId applicationId) {
+ public RemoteSession getActiveRemoteSession(ApplicationId applicationId) {
Tenant tenant = getTenant(applicationId);
if (tenant == null) throw new IllegalArgumentException("Could not find any tenant for '" + applicationId + "'");
return getActiveSession(tenant, applicationId);
@@ -779,14 +781,14 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
}
public void validateThatSessionIsNotActive(Tenant tenant, long sessionId) {
- Session session = getSession(tenant, sessionId);
+ Session session = getRemoteSession(tenant, sessionId);
if (Session.Status.ACTIVATE.equals(session.getStatus())) {
throw new IllegalStateException("Session is active: " + sessionId);
}
}
public void validateThatSessionIsPrepared(Tenant tenant, long sessionId) {
- Session session = getSession(tenant, sessionId);
+ Session session = getRemoteSession(tenant, sessionId);
if ( ! Session.Status.PREPARE.equals(session.getStatus()))
throw new IllegalStateException("Session not prepared: " + sessionId);
}
@@ -817,9 +819,9 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return session.getSessionId();
}
- public void deleteExpiredSessions() {
- Map<Tenant, Collection<Session>> sessionsPerTenant = new HashMap<>();
- tenantRepository.getAllTenants().forEach(tenant -> sessionsPerTenant.put(tenant, tenant.getSessionRepository().getSessions()));
+ public void deleteExpiredLocalSessions() {
+ Map<Tenant, Collection<LocalSession>> sessionsPerTenant = new HashMap<>();
+ tenantRepository.getAllTenants().forEach(tenant -> sessionsPerTenant.put(tenant, tenant.getSessionRepository().getLocalSessions()));
Set<ApplicationId> applicationIds = new HashSet<>();
sessionsPerTenant.values()
@@ -837,6 +839,18 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
sessionsPerTenant.keySet().forEach(tenant -> tenant.getSessionRepository().deleteExpiredSessions(activeSessions));
}
+ public int deleteExpiredRemoteSessions(Duration expiryTime) {
+ return deleteExpiredRemoteSessions(clock, expiryTime);
+ }
+
+ public int deleteExpiredRemoteSessions(Clock clock, Duration expiryTime) {
+ return tenantRepository.getAllTenants()
+ .stream()
+ .map(tenant -> tenant.getSessionRepository().deleteExpiredRemoteSessions(clock, expiryTime))
+ .mapToInt(i -> i)
+ .sum();
+ }
+
// ---------------- Tenant operations ----------------------------------------------------------------
@@ -909,14 +923,14 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
}
private Session getLocalSession(Tenant tenant, long sessionId) {
- Session session = tenant.getSessionRepository().getSession(sessionId);
+ Session session = tenant.getSessionRepository().getLocalSession(sessionId);
if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
return session;
}
- private Session getSession(Tenant tenant, long sessionId) {
- Session session = tenant.getSessionRepository().getSession(sessionId);
+ private RemoteSession getRemoteSession(Tenant tenant, long sessionId) {
+ RemoteSession session = tenant.getSessionRepository().getRemoteSession(sessionId);
if (session == null) throw new NotFoundException("Session " + sessionId + " was not found");
return session;
@@ -952,13 +966,13 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
// TODO: Merge this and getActiveSession(), they are almost identical
private Session getExistingSession(Tenant tenant, ApplicationId applicationId) {
TenantApplications applicationRepo = tenant.getApplicationRepo();
- return getSession(tenant, applicationRepo.requireActiveSessionOf(applicationId));
+ return getRemoteSession(tenant, applicationRepo.requireActiveSessionOf(applicationId));
}
- public Session getActiveSession(Tenant tenant, ApplicationId applicationId) {
+ public RemoteSession getActiveSession(Tenant tenant, ApplicationId applicationId) {
TenantApplications applicationRepo = tenant.getApplicationRepo();
if (applicationRepo.activeApplications().contains(applicationId)) {
- return tenant.getSessionRepository().getSession(applicationRepo.requireActiveSessionOf(applicationId));
+ return tenant.getSessionRepository().getRemoteSession(applicationRepo.requireActiveSessionOf(applicationId));
}
return null;
}
@@ -966,7 +980,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
public Session getActiveLocalSession(Tenant tenant, ApplicationId applicationId) {
TenantApplications applicationRepo = tenant.getApplicationRepo();
if (applicationRepo.activeApplications().contains(applicationId)) {
- return tenant.getSessionRepository().getSession(applicationRepo.requireActiveSessionOf(applicationId));
+ return tenant.getSessionRepository().getLocalSession(applicationRepo.requireActiveSessionOf(applicationId));
}
return null;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
index 3c22c05ae2d..7d58682947f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
@@ -94,7 +94,7 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
PrepareParams params = this.params.get();
ApplicationId applicationId = params.getApplicationId();
try (ActionTimer timer = applicationRepository.timerFor(applicationId, "deployment.prepareMillis")) {
- this.configChangeActions = tenant.getSessionRepository().prepareSession(session, deployLogger, params, clock.instant());
+ this.configChangeActions = tenant.getSessionRepository().prepareLocalSession(session, deployLogger, params, clock.instant());
this.prepared = true;
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
index f73afc7c711..aa709b3bf37 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java
@@ -70,7 +70,7 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer {
continue;
}
}
- createSessionIfMissing(applicationId, sessionId);
+ createLocalSessionIfMissing(applicationId, sessionId);
}
}
}
@@ -83,11 +83,11 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer {
super.close();
}
- private void createSessionIfMissing(ApplicationId applicationId, long sessionId) {
+ private void createLocalSessionIfMissing(ApplicationId applicationId, long sessionId) {
Tenant tenant = applicationRepository.getTenant(applicationId);
SessionRepository sessionRepository = tenant.getSessionRepository();
- if (sessionRepository.getSession(sessionId) == null)
- sessionRepository.createSessionFromDistributedApplicationPackage(sessionId);
+ if (sessionRepository.getLocalSession(sessionId) == null)
+ sessionRepository.createLocalSessionFromDistributedApplicationPackage(sessionId);
}
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
index 32b067b5731..19534bba810 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/SessionsMaintainer.java
@@ -1,6 +1,7 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.maintenance;
+import com.yahoo.log.LogLevel;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.flags.FlagSource;
@@ -15,14 +16,23 @@ import java.time.Duration;
* @author hmusum
*/
public class SessionsMaintainer extends ConfigServerMaintainer {
+ private final boolean hostedVespa;
SessionsMaintainer(ApplicationRepository applicationRepository, Curator curator, Duration interval, FlagSource flagSource) {
super(applicationRepository, curator, flagSource, Duration.ofMinutes(1), interval);
+ this.hostedVespa = applicationRepository.configserverConfig().hostedVespa();
}
@Override
protected boolean maintain() {
- applicationRepository.deleteExpiredSessions();
+ applicationRepository.deleteExpiredLocalSessions();
+
+ if (hostedVespa) {
+ Duration expiryTime = Duration.ofMinutes(90);
+ int deleted = applicationRepository.deleteExpiredRemoteSessions(expiryTime);
+ log.log(LogLevel.FINE, () -> "Deleted " + deleted + " expired remote sessions older than " + expiryTime);
+ }
+
return true;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java
new file mode 100644
index 00000000000..f842578b657
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java
@@ -0,0 +1,28 @@
+// 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.TenantName;
+
+/**
+ * A LocalSession is a session that has been created locally on this configserver. A local session can be edited and
+ * prepared. Deleting a local session will ensure that the local filesystem state and global zookeeper state is
+ * cleaned for this session.
+ *
+ * @author Ulf Lilleengen
+ */
+// This is really the store of an application, whether it is active or in an edit session
+// TODO: Separate the "application store" and "session" aspects - the latter belongs in the HTTP layer -bratseth
+public class LocalSession extends Session {
+
+ /**
+ * Creates a session. This involves loading the application, validating it and distributing it.
+ *
+ * @param sessionId The session id for this session.
+ */
+ public LocalSession(TenantName tenant, long sessionId, ApplicationPackage applicationPackage,
+ SessionZooKeeperClient sessionZooKeeperClient) {
+ super(tenant, sessionId, sessionZooKeeperClient, applicationPackage);
+ }
+
+}
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
new file mode 100644
index 00000000000..de5f1392242
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
@@ -0,0 +1,61 @@
+// Copyright Verizon Media. 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.provision.TenantName;
+import com.yahoo.vespa.config.server.application.ApplicationSet;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A RemoteSession represents a session created on another config server. This session can
+ * be regarded as read only, and this interface only allows reading information about a session.
+ *
+ * @author Ulf Lilleengen
+ */
+public class RemoteSession extends Session {
+
+ private final Optional<ApplicationSet> applicationSet;
+
+ /**
+ * 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 zooKeeperClient a SessionZooKeeperClient instance
+ */
+ RemoteSession(TenantName tenant, long sessionId, SessionZooKeeperClient zooKeeperClient) {
+ this(tenant, sessionId, zooKeeperClient, Optional.empty());
+ }
+
+ /**
+ * 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
+ * @param applicationSet current application set for this session
+ */
+ RemoteSession(TenantName tenant, long sessionId, SessionZooKeeperClient zooKeeperClient, Optional<ApplicationSet> applicationSet) {
+ super(tenant, sessionId, zooKeeperClient);
+ this.applicationSet = applicationSet;
+ }
+
+ @Override
+ Optional<ApplicationSet> applicationSet() { return applicationSet; }
+
+ public synchronized RemoteSession activated(ApplicationSet applicationSet) {
+ Objects.requireNonNull(applicationSet, "applicationSet cannot be null");
+ return new RemoteSession(tenant, sessionId, sessionZooKeeperClient, Optional.of(applicationSet));
+ }
+
+ public synchronized RemoteSession deactivated() {
+ return new RemoteSession(tenant, sessionId, sessionZooKeeperClient, Optional.empty());
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ",application set=" + applicationSet;
+ }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
index d5e158cd9ac..69dfc4d627d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
@@ -17,34 +17,38 @@ import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
import java.time.Instant;
-import java.util.Objects;
import java.util.Optional;
/**
- * A session represents an instance of an application that can be edited, prepared and activated.
+ * A session represents an instance of an application that can be edited, prepared and activated. This
+ * class represents the common stuff between sessions working on the local file
+ * system ({@link LocalSession}s) and sessions working on zookeeper ({@link RemoteSession}s).
*
* @author Ulf Lilleengen
* @author hmusum
*/
-public class Session implements Comparable<Session> {
+public abstract class Session implements Comparable<Session> {
protected final long sessionId;
protected final TenantName tenant;
protected final SessionZooKeeperClient sessionZooKeeperClient;
protected final Optional<ApplicationPackage> applicationPackage;
- private final Optional<ApplicationSet> applicationSet;
- public Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient, ApplicationPackage applicationPackage) {
- this(tenant, sessionId, sessionZooKeeperClient, Optional.of(applicationPackage), Optional.empty());
+ protected Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient) {
+ this(tenant, sessionId, sessionZooKeeperClient, Optional.empty());
}
- public Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient,
- Optional<ApplicationPackage> applicationPackage, Optional<ApplicationSet> applicationSet) {
+ protected Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient,
+ ApplicationPackage applicationPackage) {
+ this(tenant, sessionId, sessionZooKeeperClient, Optional.of(applicationPackage));
+ }
+
+ private Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient,
+ Optional<ApplicationPackage> applicationPackage) {
this.tenant = tenant;
this.sessionId = sessionId;
this.sessionZooKeeperClient = sessionZooKeeperClient;
this.applicationPackage = applicationPackage;
- this.applicationSet = applicationSet;
}
public final long getSessionId() {
@@ -59,18 +63,9 @@ public class Session implements Comparable<Session> {
return sessionZooKeeperClient;
}
- public synchronized Session activated(ApplicationSet applicationSet) {
- Objects.requireNonNull(applicationSet, "applicationSet cannot be null");
- return new Session(tenant, sessionId, sessionZooKeeperClient, applicationPackage, Optional.of(applicationSet));
- }
-
- public synchronized Session deactivated() {
- return new Session(tenant, sessionId, sessionZooKeeperClient, applicationPackage, Optional.empty());
- }
-
@Override
public String toString() {
- return "Session,id=" + sessionId + ",application set=" + applicationSet + ",application package=" + applicationPackage;
+ return "Session,id=" + sessionId;
}
public long getActiveSessionAtCreate() {
@@ -186,14 +181,14 @@ public class Session implements Comparable<Session> {
return applicationPackage.orElseThrow(() -> new RuntimeException("No application package found for " + this));
}
- public ApplicationFile getApplicationFile(Path relativePath, Session.Mode mode) {
+ public ApplicationFile getApplicationFile(Path relativePath, LocalSession.Mode mode) {
if (mode.equals(Session.Mode.WRITE)) {
markSessionEdited();
}
return getApplicationPackage().getFile(relativePath);
}
- Optional<ApplicationSet> applicationSet() { return applicationSet; }
+ Optional<ApplicationSet> applicationSet() { return Optional.empty(); };
private void markSessionEdited() {
setStatus(Session.Status.NEW);
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 0348ba9f150..59146c339d3 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
@@ -73,7 +73,8 @@ public class SessionRepository {
private static final FilenameFilter sessionApplicationsFilter = (dir, name) -> name.matches("\\d+");
private static final long nonExistingActiveSessionId = 0;
- private final Map<Long, Session> sessionCache = new ConcurrentHashMap<>();
+ private final Map<Long, LocalSession> localSessionCache = new ConcurrentHashMap<>();
+ private final Map<Long, RemoteSession> remoteSessionCache = new ConcurrentHashMap<>();
private final Map<Long, SessionStateWatcher> sessionStateWatchers = new HashMap<>();
private final Duration sessionLifetime;
private final Clock clock;
@@ -103,27 +104,36 @@ public class SessionRepository {
this.applicationRepo = applicationRepo;
this.sessionPreparer = sessionPreparer;
this.metrics = componentRegistry.getMetrics().getOrCreateMetricUpdater(Metrics.createDimensions(tenantName));
- loadAll(); // Needs to be done before creating cache below
+ loadSessions(); // Needs to be done before creating cache below
this.directoryCache = curator.createDirectoryCache(sessionsPath.getAbsolute(), false, false, componentRegistry.getZkCacheExecutor());
this.directoryCache.addListener(this::childEvent);
this.directoryCache.start();
}
- private void loadAll() {
- loadSessionsFromFileSystem();
- loadSessions();
+ private void loadSessions() {
+ loadLocalSessions();
+ loadRemoteSessions();
}
- public synchronized void addSession(Session session) {
+ // ---------------- Local sessions ----------------------------------------------------------------
+
+ public synchronized void addLocalSession(LocalSession session) {
long sessionId = session.getSessionId();
- sessionCache.put(sessionId, session);
+ localSessionCache.put(sessionId, session);
+ if (remoteSessionCache.get(sessionId) == null) {
+ createRemoteSession(sessionId);
+ }
+ }
+
+ public LocalSession getLocalSession(long sessionId) {
+ return localSessionCache.get(sessionId);
}
- public Collection<Session> getSessions() {
- return sessionCache.values();
+ public Collection<LocalSession> getLocalSessions() {
+ return localSessionCache.values();
}
- private void loadSessionsFromFileSystem() {
+ private void loadLocalSessions() {
File[] sessions = tenantFileSystemDirs.sessionsPath().listFiles(sessionApplicationsFilter);
if (sessions == null) return;
@@ -137,7 +147,7 @@ public class SessionRepository {
}
}
- public ConfigChangeActions prepareSession(Session session, DeployLogger logger, PrepareParams params, Instant now) {
+ public ConfigChangeActions prepareLocalSession(Session session, DeployLogger logger, PrepareParams params, Instant now) {
applicationRepo.createApplication(params.getApplicationId()); // TODO jvenstad: This is wrong, but it has to be done now, since preparation can change the application ID of a session :(
logger.log(Level.FINE, "Created application " + params.getApplicationId());
long sessionId = session.getSessionId();
@@ -161,10 +171,10 @@ public class SessionRepository {
* @param timeoutBudget timeout for creating session and waiting for other servers.
* @return a new session
*/
- public Session createSessionFromExisting(Session existingSession, boolean internalRedeploy, TimeoutBudget timeoutBudget) {
+ public LocalSession createSessionFromExisting(Session existingSession, boolean internalRedeploy, TimeoutBudget timeoutBudget) {
ApplicationId existingApplicationId = existingSession.getApplicationId();
File existingApp = getSessionAppDir(existingSession.getSessionId());
- Session session = createSessionFromApplication(existingApp, existingApplicationId, internalRedeploy, timeoutBudget);
+ LocalSession session = createSessionFromApplication(existingApp, existingApplicationId, internalRedeploy, timeoutBudget);
// Note: Setters below need to be kept in sync with calls in SessionPreparer.writeStateToZooKeeper()
session.setApplicationId(existingApplicationId);
session.setApplicationPackageReference(existingSession.getApplicationPackageReference());
@@ -182,59 +192,93 @@ public class SessionRepository {
* @param timeoutBudget Timeout for creating session and waiting for other servers.
* @return a new session
*/
- public Session createSessionFromApplicationPackage(File applicationDirectory, ApplicationId applicationId, TimeoutBudget timeoutBudget) {
+ public LocalSession createSessionFromApplicationPackage(File applicationDirectory, ApplicationId applicationId, TimeoutBudget timeoutBudget) {
applicationRepo.createApplication(applicationId);
return createSessionFromApplication(applicationDirectory, applicationId, false, timeoutBudget);
}
+ /**
+ * This method is used when creating a session based on a remote session and the distributed application package
+ * It does not wait for session being created on other servers
+ */
+ private void createLocalSession(File applicationFile, ApplicationId applicationId, long sessionId) {
+ try {
+ ApplicationPackage applicationPackage = createApplicationPackage(applicationFile, applicationId, sessionId, false);
+ createLocalSession(sessionId, applicationPackage);
+ } catch (Exception e) {
+ throw new RuntimeException("Error creating session " + sessionId, e);
+ }
+ }
+
// Will delete session data in ZooKeeper and file system
- public void deleteLocalSession(Session session) {
+ public void deleteLocalSession(LocalSession session) {
long sessionId = session.getSessionId();
- log.log(Level.FINE, () -> "Deleting session " + sessionId);
+ log.log(Level.FINE, () -> "Deleting local session " + sessionId);
SessionStateWatcher watcher = sessionStateWatchers.remove(sessionId);
if (watcher != null) watcher.close();
- sessionCache.remove(sessionId);
+ localSessionCache.remove(sessionId);
NestedTransaction transaction = new NestedTransaction();
transaction.add(FileTransaction.from(FileOperations.delete(getSessionAppDir(sessionId).getAbsolutePath())));
transaction.commit();
}
private void deleteAllSessions() {
- List<Session> sessions = new ArrayList<>(sessionCache.values());
- for (Session session : sessions) {
+ List<LocalSession> sessions = new ArrayList<>(localSessionCache.values());
+ for (LocalSession session : sessions) {
deleteLocalSession(session);
}
}
- public Session getSession(long sessionId) {
- return sessionCache.get(sessionId);
+ // ---------------- Remote sessions ----------------------------------------------------------------
+
+ public RemoteSession getRemoteSession(long sessionId) {
+ return remoteSessionCache.get(sessionId);
}
public List<Long> getRemoteSessionsFromZooKeeper() {
return getSessionList(curator.getChildren(sessionsPath));
}
- public synchronized Session createSession(long sessionId) {
+ public synchronized RemoteSession createRemoteSession(long sessionId) {
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
- Session session = new Session(tenantName, sessionId, sessionZKClient, Optional.empty(), Optional.empty());
- sessionCache.put(sessionId, session);
+ RemoteSession session = new RemoteSession(tenantName, sessionId, sessionZKClient);
+ remoteSessionCache.put(sessionId, session);
loadSessionIfActive(session);
updateSessionStateWatcher(sessionId, session);
return session;
}
- public void deactivateAndUpdateCache(Session session) {
- Session deactivated = session.deactivated();
- sessionCache.put(deactivated.getSessionId(), deactivated);
+ public int deleteExpiredRemoteSessions(Clock clock, Duration expiryTime) {
+ int deleted = 0;
+ for (long sessionId : getRemoteSessionsFromZooKeeper()) {
+ Session session = remoteSessionCache.get(sessionId);
+ if (session == null) continue; // Internal sessions not in sync with zk, continue
+ if (session.getStatus() == Session.Status.ACTIVATE) continue;
+ if (sessionHasExpired(session.getCreateTime(), expiryTime, clock)) {
+ log.log(Level.FINE, () -> "Remote session " + sessionId + " for " + tenantName + " has expired, deleting it");
+ deleteRemoteSessionFromZooKeeper(session);
+ deleted++;
+ }
+ }
+ return deleted;
+ }
+
+ public void deactivateAndUpdateCache(RemoteSession remoteSession) {
+ RemoteSession session = remoteSession.deactivated();
+ remoteSessionCache.put(session.getSessionId(), session);
}
- public void deleteSessionFromZooKeeper(Session session) {
+ public void deleteRemoteSessionFromZooKeeper(Session session) {
SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(session.getSessionId());
Transaction transaction = sessionZooKeeperClient.deleteTransaction();
transaction.commit();
transaction.close();
}
+ private boolean sessionHasExpired(Instant created, Duration expiryTime, Clock clock) {
+ return (created.plus(expiryTime).isBefore(clock.instant()));
+ }
+
private List<Long> getSessionListFromDirectoryCache(List<ChildData> children) {
return getSessionList(children.stream()
.map(child -> Path.fromString(child.getPath()).getName())
@@ -245,7 +289,7 @@ public class SessionRepository {
return children.stream().map(Long::parseLong).collect(Collectors.toList());
}
- private void loadSessions() throws NumberFormatException {
+ private void loadRemoteSessions() throws NumberFormatException {
getRemoteSessionsFromZooKeeper().forEach(this::sessionAdded);
}
@@ -255,18 +299,16 @@ public class SessionRepository {
* @param sessionId session id for the new session
*/
public synchronized void sessionAdded(long sessionId) {
- if (sessionCache.containsKey(sessionId)) return;
-
- log.log(Level.FINE, () -> "Adding session " + sessionId);
- Session session = createSession(sessionId);
+ log.log(Level.FINE, () -> "Adding remote session " + sessionId);
+ Session session = createRemoteSession(sessionId);
if (session.getStatus() == Session.Status.NEW) {
log.log(Level.FINE, () -> session.logPre() + "Confirming upload for session " + sessionId);
confirmUpload(session);
}
- createSessionFromDistributedApplicationPackage(sessionId);
+ createLocalSessionFromDistributedApplicationPackage(sessionId);
}
- void activate(Session session) {
+ void activate(RemoteSession session) {
long sessionId = session.getSessionId();
Curator.CompletionWaiter waiter = createSessionZooKeeperClient(sessionId).getActiveWaiter();
log.log(Level.FINE, () -> session.logPre() + "Getting session from repo: " + session);
@@ -278,21 +320,28 @@ public class SessionRepository {
log.log(Level.INFO, session.logPre() + "Session activated: " + sessionId);
}
- public void delete(Session session) {
- long sessionId = session.getSessionId();
- deleteSessionFromZooKeeper(session);
- sessionCache.remove(sessionId);
- deleteLocalSession(session);
+ public void delete(Session remoteSession) {
+ long sessionId = remoteSession.getSessionId();
+ // TODO: Change log level to FINE when debugging is finished
+ log.log(Level.INFO, () -> remoteSession.logPre() + "Deactivating and deleting remote session " + sessionId);
+ deleteRemoteSessionFromZooKeeper(remoteSession);
+ remoteSessionCache.remove(sessionId);
+ LocalSession localSession = getLocalSession(sessionId);
+ if (localSession != null) {
+ // TODO: Change log level to FINE when debugging is finished
+ log.log(Level.INFO, () -> localSession.logPre() + "Deleting local session " + sessionId);
+ deleteLocalSession(localSession);
+ }
}
private void sessionRemoved(long sessionId) {
SessionStateWatcher watcher = sessionStateWatchers.remove(sessionId);
if (watcher != null) watcher.close();
- sessionCache.remove(sessionId);
+ remoteSessionCache.remove(sessionId);
metrics.incRemovedSessions();
}
- private void loadSessionIfActive(Session session) {
+ private void loadSessionIfActive(RemoteSession session) {
for (ApplicationId applicationId : applicationRepo.activeApplications()) {
if (applicationRepo.requireActiveSessionOf(applicationId) == session.getSessionId()) {
log.log(Level.FINE, () -> "Found active application for session " + session.getSessionId() + " , loading it");
@@ -303,22 +352,22 @@ public class SessionRepository {
}
}
- void prepare(Session session) {
+ void prepareRemoteSession(RemoteSession session) {
SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(session.getSessionId());
Curator.CompletionWaiter waiter = sessionZooKeeperClient.getPrepareWaiter();
ensureApplicationLoaded(session);
notifyCompletion(waiter, session);
}
- public ApplicationSet ensureApplicationLoaded(Session session) {
+ public ApplicationSet ensureApplicationLoaded(RemoteSession session) {
if (session.applicationSet().isPresent()) {
return session.applicationSet().get();
}
ApplicationSet applicationSet = loadApplication(session);
- Session activated = session.activated(applicationSet);
+ RemoteSession activated = session.activated(applicationSet);
long sessionId = activated.getSessionId();
- sessionCache.put(sessionId, activated);
+ remoteSessionCache.put(sessionId, activated);
updateSessionStateWatcher(sessionId, activated);
return applicationSet;
@@ -378,7 +427,7 @@ public class SessionRepository {
private void nodeChanged() {
zkWatcherExecutor.execute(() -> {
Multiset<Session.Status> sessionMetrics = HashMultiset.create();
- for (Session session : sessionCache.values()) {
+ for (Session session : remoteSessionCache.values()) {
sessionMetrics.add(session.getStatus());
}
metrics.setNewSessions(sessionMetrics.count(Session.Status.NEW));
@@ -409,20 +458,20 @@ public class SessionRepository {
public void deleteExpiredSessions(Map<ApplicationId, Long> activeSessions) {
log.log(Level.FINE, () -> "Purging old sessions for tenant '" + tenantName + "'");
try {
- for (Session candidate : sessionCache.values()) {
+ for (LocalSession candidate : localSessionCache.values()) {
Instant createTime = candidate.getCreateTime();
log.log(Level.FINE, () -> "Candidate session for deletion: " + candidate.getSessionId() + ", created: " + createTime);
// Sessions with state other than ACTIVATE
if (hasExpired(candidate) && !isActiveSession(candidate)) {
- delete(candidate);
+ deleteLocalSession(candidate);
} else if (createTime.plus(Duration.ofDays(1)).isBefore(clock.instant())) {
// Sessions with state ACTIVATE, but which are not actually active
Optional<ApplicationId> applicationId = candidate.getOptionalApplicationId();
if (applicationId.isEmpty()) continue;
Long activeSession = activeSessions.get(applicationId.get());
if (activeSession == null || activeSession != candidate.getSessionId()) {
- delete(candidate);
+ deleteLocalSession(candidate);
log.log(Level.INFO, "Deleted inactive session " + candidate.getSessionId() + " created " +
createTime + " for '" + applicationId + "'");
}
@@ -435,11 +484,11 @@ public class SessionRepository {
log.log(Level.FINE, () -> "Done purging old sessions");
}
- private boolean hasExpired(Session candidate) {
- return candidate.getCreateTime().plus(sessionLifetime).isBefore(clock.instant());
+ private boolean hasExpired(LocalSession candidate) {
+ return (candidate.getCreateTime().plus(sessionLifetime).isBefore(clock.instant()));
}
- private boolean isActiveSession(Session candidate) {
+ private boolean isActiveSession(LocalSession candidate) {
return candidate.getStatus() == Session.Status.ACTIVATE;
}
@@ -466,10 +515,10 @@ public class SessionRepository {
return FilesApplicationPackage.fromFileWithDeployData(configApplicationDir, deployData);
}
- private Session createSessionFromApplication(File applicationFile,
- ApplicationId applicationId,
- boolean internalRedeploy,
- TimeoutBudget timeoutBudget) {
+ private LocalSession createSessionFromApplication(File applicationFile,
+ ApplicationId applicationId,
+ boolean internalRedeploy,
+ TimeoutBudget timeoutBudget) {
long sessionId = getNextSessionId();
try {
ensureSessionPathDoesNotExist(sessionId);
@@ -478,9 +527,9 @@ public class SessionRepository {
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
sessionZKClient.createNewSession(clock.instant());
Curator.CompletionWaiter waiter = sessionZKClient.getUploadWaiter();
- Session session = new Session(tenantName, sessionId, sessionZKClient, app);
+ LocalSession session = new LocalSession(tenantName, sessionId, app, sessionZKClient);
waiter.awaitCompletion(timeoutBudget.timeLeft());
- addSession(session);
+ addLocalSession(session);
return session;
} catch (Exception e) {
throw new RuntimeException("Error creating session " + sessionId, e);
@@ -506,8 +555,8 @@ public class SessionRepository {
Optional<ApplicationSet> currentActiveApplicationSet = Optional.empty();
try {
long currentActiveSessionId = applicationRepo.requireActiveSessionOf(appId);
- Session activeSession = getSession(currentActiveSessionId);
- currentActiveApplicationSet = Optional.ofNullable(ensureApplicationLoaded(activeSession));
+ RemoteSession currentActiveSession = getRemoteSession(currentActiveSessionId);
+ currentActiveApplicationSet = Optional.ofNullable(ensureApplicationLoaded(currentActiveSession));
} catch (IllegalArgumentException e) {
// Do nothing if we have no currently active session
}
@@ -541,29 +590,29 @@ public class SessionRepository {
void createSessionFromId(long sessionId) {
File sessionDir = getAndValidateExistingSessionAppDir(sessionId);
ApplicationPackage applicationPackage = FilesApplicationPackage.fromFile(sessionDir);
- createSessionWithApplicationPackage(sessionId, applicationPackage);
+ createLocalSession(sessionId, applicationPackage);
}
- void createSessionWithApplicationPackage(long sessionId, ApplicationPackage applicationPackage) {
+ void createLocalSession(long sessionId, ApplicationPackage applicationPackage) {
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
- Session session = new Session(tenantName, sessionId, sessionZKClient, applicationPackage);
- addSession(session);
+ LocalSession session = new LocalSession(tenantName, sessionId, applicationPackage, sessionZKClient);
+ addLocalSession(session);
}
/**
- * Returns a new session for the given session id if it does not already exist.
- * Will also add the session to the session cache if necessary
+ * Returns a new local session for the given session id if it does not already exist.
+ * Will also add the session to the local session cache if necessary
*/
- public void createSessionFromDistributedApplicationPackage(long sessionId) {
+ public void createLocalSessionFromDistributedApplicationPackage(long sessionId) {
if (applicationRepo.sessionExistsInFileSystem(sessionId)) {
- log.log(Level.FINE, () -> "Session " + sessionId + " already exists");
+ log.log(Level.FINE, () -> "Local session for session id " + sessionId + " already exists");
createSessionFromId(sessionId);
return;
}
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
FileReference fileReference = sessionZKClient.readApplicationPackageReference();
- log.log(Level.FINE, () -> "File reference for session " + sessionId + ": " + fileReference);
+ log.log(Level.FINE, () -> "File reference for session id " + sessionId + ": " + fileReference);
if (fileReference != null) {
File rootDir = new File(Defaults.getDefaults().underVespaHome(componentRegistry.getConfigserverConfig().fileReferencesDir()));
File sessionDir;
@@ -573,18 +622,13 @@ public class SessionRepository {
} catch (IllegalArgumentException e) {
// We cannot be guaranteed that the file reference exists (it could be that it has not
// been downloaded yet), and e.g when bootstrapping we cannot throw an exception in that case
- log.log(Level.FINE, "File reference for session " + sessionId + ": " + fileReference + " not found in " + fileDirectory);
+ log.log(Level.FINE, "File reference for session id " + sessionId + ": " + fileReference + " not found in " + fileDirectory);
return;
}
ApplicationId applicationId = sessionZKClient.readApplicationId()
.orElseThrow(() -> new RuntimeException("Could not find application id for session " + sessionId));
- log.log(Level.FINE, () -> "Creating session for tenant '" + tenantName + "' with id " + sessionId);
- try {
- ApplicationPackage applicationPackage = createApplicationPackage(sessionDir, applicationId, sessionId, false);
- createSessionWithApplicationPackage(sessionId, applicationPackage);
- } catch (Exception e) {
- throw new RuntimeException("Error creating session " + sessionId, e);
- }
+ log.log(Level.FINE, () -> "Creating local session for tenant '" + tenantName + "' with session id " + sessionId);
+ createLocalSession(sessionDir, applicationId, sessionId);
}
}
@@ -624,20 +668,20 @@ public class SessionRepository {
return new TenantFileSystemDirs(componentRegistry.getConfigServerDB(), tenantName).getUserApplicationDir(sessionId);
}
- private void updateSessionStateWatcher(long sessionId, Session session) {
+ private void updateSessionStateWatcher(long sessionId, RemoteSession remoteSession) {
SessionStateWatcher sessionStateWatcher = sessionStateWatchers.get(sessionId);
if (sessionStateWatcher == null) {
Curator.FileCache fileCache = curator.createFileCache(getSessionStatePath(sessionId).getAbsolute(), false);
fileCache.addListener(this::nodeChanged);
- sessionStateWatchers.put(sessionId, new SessionStateWatcher(fileCache, session, metrics, zkWatcherExecutor, this));
+ sessionStateWatchers.put(sessionId, new SessionStateWatcher(fileCache, remoteSession, metrics, zkWatcherExecutor, this));
} else {
- sessionStateWatcher.updateRemoteSession(session);
+ sessionStateWatcher.updateRemoteSession(remoteSession);
}
}
@Override
public String toString() {
- return getSessions().toString();
+ return getLocalSessions().toString();
}
public Clock clock() { return clock; }
@@ -663,14 +707,14 @@ public class SessionRepository {
}
private void checkForRemovedSessions(List<Long> sessions) {
- for (Session session : sessionCache.values())
+ for (Session session : remoteSessionCache.values())
if ( ! sessions.contains(session.getSessionId()))
sessionRemoved(session.getSessionId());
}
private void checkForAddedSessions(List<Long> sessions) {
for (Long sessionId : sessions)
- if (sessionCache.get(sessionId) == null)
+ if (remoteSessionCache.get(sessionId) == null)
sessionAdded(sessionId);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionStateWatcher.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionStateWatcher.java
index f1100b37912..0f433f53c77 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionStateWatcher.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionStateWatcher.java
@@ -24,13 +24,13 @@ public class SessionStateWatcher {
private static final Logger log = Logger.getLogger(SessionStateWatcher.class.getName());
private final Curator.FileCache fileCache;
- private volatile Session session;
+ private volatile RemoteSession session;
private final MetricUpdater metrics;
private final Executor zkWatcherExecutor;
private final SessionRepository sessionRepository;
SessionStateWatcher(Curator.FileCache fileCache,
- Session session,
+ RemoteSession session,
MetricUpdater metrics,
Executor zkWatcherExecutor,
SessionRepository sessionRepository) {
@@ -51,7 +51,7 @@ public class SessionStateWatcher {
break;
case PREPARE:
createLocalSession(sessionId);
- sessionRepository.prepare(session);
+ sessionRepository.prepareRemoteSession(session);
break;
case ACTIVATE:
createLocalSession(sessionId);
@@ -66,7 +66,7 @@ public class SessionStateWatcher {
}
private void createLocalSession(long sessionId) {
- sessionRepository.createSessionFromDistributedApplicationPackage(sessionId);
+ sessionRepository.createLocalSessionFromDistributedApplicationPackage(sessionId);
}
public long getSessionId() {
@@ -100,7 +100,7 @@ public class SessionStateWatcher {
});
}
- public synchronized void updateRemoteSession(Session session) {
+ public synchronized void updateRemoteSession(RemoteSession session) {
this.session = session;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SilentDeployLogger.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SilentDeployLogger.java
index e9d5a7da549..9e2e5ddf698 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SilentDeployLogger.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SilentDeployLogger.java
@@ -7,7 +7,7 @@ import java.util.logging.Logger;
import com.yahoo.config.application.api.DeployLogger;
/**
- * The purpose of this is to mute the log messages from model and application building that
+ * The purpose of this is to mute the log messages from model and application building in {@link RemoteSession} that
* is triggered by {@link SessionStateWatcher}, since those messages already have been emitted by the prepare
* handler, for the same prepare operation.
*