diff options
3 files changed, 88 insertions, 13 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index 6eaad63251c..94d60432337 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -14,6 +14,7 @@ import com.yahoo.slime.Slime; import com.yahoo.slime.SlimeUtils; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.curator.Lock; +import com.yahoo.vespa.curator.MultiplePathsLock; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveBucket; @@ -143,20 +144,21 @@ public class CuratorDb { return curator.lock(lockPath(name), defaultLockTimeout.multipliedBy(2)); } + // TODO: Remove MultiplePathsLock and use of legacyLockPath() methods after 7.752 has been rolled out public Lock lock(TenantAndApplicationId id) { - return curator.lock(lockPath(id), defaultLockTimeout.multipliedBy(2)); + return new MultiplePathsLock(lockPath(id), legacyLockPath(id), defaultLockTimeout.multipliedBy(2),curator); } public Lock lockForDeployment(ApplicationId id, ZoneId zone) { - return curator.lock(lockPath(id, zone), deployLockTimeout); + return new MultiplePathsLock(lockPath(id, zone), legacyLockPath(id, zone), deployLockTimeout, curator); } public Lock lock(ApplicationId id, JobType type) { - return curator.lock(lockPath(id, type), defaultLockTimeout); + return new MultiplePathsLock(lockPath(id, type), legacyLockPath(id, type), defaultLockTimeout, curator); } public Lock lock(ApplicationId id, JobType type, Step step) throws TimeoutException { - return tryLock(lockPath(id, type, step)); + return tryLock(lockPath(id, type, step), legacyLockPath(id, type, step)); } public Lock lockRotations() { @@ -239,6 +241,19 @@ public class CuratorDb { } } + /** Try locking with a low timeout, meaning it is OK to fail lock acquisition. + * + * Useful for maintenance jobs, where there is no point in running the jobs back to back. + */ + private Lock tryLock(Path path, Path path2) throws TimeoutException { + try { + return new MultiplePathsLock(path, path2, tryLockTimeout, curator); + } + catch (UncheckedTimeoutException e) { + throw new TimeoutException(e.getMessage()); + } + } + private <T> Optional<T> read(Path path, Function<byte[], T> mapper) { return curator.getData(path).filter(data -> data.length > 0).map(mapper); } @@ -667,32 +682,48 @@ public class CuratorDb { .append(tenant.value()); } - private Path lockPath(TenantAndApplicationId application) { + private Path legacyLockPath(TenantAndApplicationId application) { return lockPath(application.tenant()) .append(application.application().value()); } - private Path lockPath(ApplicationId instance) { - return lockPath(TenantAndApplicationId.from(instance)) + private Path legacyLockPath(ApplicationId instance) { + return legacyLockPath(TenantAndApplicationId.from(instance)) .append(instance.instance().value()); } - private Path lockPath(ApplicationId instance, ZoneId zone) { - return lockPath(instance) + private Path legacyLockPath(ApplicationId instance, ZoneId zone) { + return legacyLockPath(instance) .append(zone.environment().value()) .append(zone.region().value()); } - private Path lockPath(ApplicationId instance, JobType type) { - return lockPath(instance) + private Path legacyLockPath(ApplicationId instance, JobType type) { + return legacyLockPath(instance) .append(type.jobName()); } - private Path lockPath(ApplicationId instance, JobType type, Step step) { - return lockPath(instance, type) + private Path legacyLockPath(ApplicationId instance, JobType type, Step step) { + return legacyLockPath(instance, type) .append(step.name()); } + private Path lockPath(TenantAndApplicationId application) { + return lockRoot.append(application.tenant().value() + ":" + application.application().value()); + } + + private Path lockPath(ApplicationId instance, ZoneId zone) { + return lockRoot.append(instance.serializedForm() + ":" + zone.region().value()); + } + + private Path lockPath(ApplicationId instance, JobType type) { + return lockRoot.append(instance.serializedForm() + ":" + type.jobName()); + } + + private Path lockPath(ApplicationId instance, JobType type, Step step) { + return lockRoot.append(instance.serializedForm() + ":" + type.jobName() + ":" + step.name()); + } + private Path lockPath(String provisionId) { return lockRoot .append(provisionStatePath()) diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/Lock.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/Lock.java index 56ae65bb317..3f9c52594a3 100644 --- a/zkfacade/src/main/java/com/yahoo/vespa/curator/Lock.java +++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/Lock.java @@ -69,6 +69,9 @@ public class Lock implements Mutex { throw new RuntimeException("Exception releasing lock '" + lockPath + "'"); } } + + protected String lockPath() { return lockPath; } + } diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/MultiplePathsLock.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/MultiplePathsLock.java new file mode 100644 index 00000000000..65ae77c8ffa --- /dev/null +++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/MultiplePathsLock.java @@ -0,0 +1,41 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.curator; + +import com.yahoo.concurrent.UncheckedTimeoutException; +import com.yahoo.path.Path; + +import java.time.Duration; + +/** + * Class that holds two locks, originally used for transitioning from one lock to + * another, where you need to hold both the old lock and the new lock in the + * transition period. + * + * @author hmusum + */ +public class MultiplePathsLock extends Lock { + + private final Lock oldLock; + private final Lock newLock; + + public MultiplePathsLock(Path newLockPath, Path oldLockPath, Duration timeout, Curator curator) { + super(newLockPath.getAbsolute(), curator); + this.newLock = curator.lock(newLockPath, timeout); + this.oldLock = curator.lock(oldLockPath, timeout);; + } + + @Override + public void acquire(Duration timeout) throws UncheckedTimeoutException { + oldLock.acquire(timeout); + newLock.acquire(timeout); + } + + @Override + public void close() { + oldLock.close(); + newLock.close(); + } + +} + + |