aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ContainerImages.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FirmwareChecks.java17
-rw-r--r--vespajlib/src/main/java/com/yahoo/lang/CachedSupplier.java52
-rw-r--r--vespajlib/src/test/java/com/yahoo/lang/CachedSupplierTest.java39
4 files changed, 100 insertions, 23 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ContainerImages.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ContainerImages.java
index b4cb9158a5c..953ccaacb6b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ContainerImages.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/ContainerImages.java
@@ -1,10 +1,9 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.provisioning;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.lang.CachedSupplier;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient;
@@ -12,7 +11,6 @@ import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
@@ -34,17 +32,12 @@ public class ContainerImages {
* unnecessary ZK reads. When images change, some nodes may need to wait for TTL until they see the new image,
* this is fine.
*/
- private volatile Supplier<Map<NodeType, DockerImage>> images;
+ private final CachedSupplier<Map<NodeType, DockerImage>> images;
public ContainerImages(CuratorDatabaseClient db, DockerImage defaultImage) {
this.db = db;
this.defaultImage = defaultImage;
- createCache();
- }
-
- private void createCache() {
- this.images = Suppliers.memoizeWithExpiration(() -> Collections.unmodifiableMap(db.readContainerImages()),
- cacheTtl.toMillis(), TimeUnit.MILLISECONDS);
+ this.images = new CachedSupplier<>(() -> Collections.unmodifiableMap(db.readContainerImages()), cacheTtl);
}
/** Returns the current images for each node type */
@@ -72,7 +65,7 @@ public class ContainerImages {
image.ifPresentOrElse(img -> images.put(nodeType, img),
() -> images.remove(nodeType));
db.writeContainerImages(images);
- createCache(); // Throw away current cache
+ this.images.refresh(); // Throw away current cache
log.info("Set container image for " + nodeType + " nodes to " + image.map(DockerImage::asString).orElse(null));
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FirmwareChecks.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FirmwareChecks.java
index 25fcfecc9b8..ef66891af7c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FirmwareChecks.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/FirmwareChecks.java
@@ -1,15 +1,13 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.provisioning;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
+import com.yahoo.lang.CachedSupplier;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
-import java.util.concurrent.TimeUnit;
/**
* Keeps cached data about when to do a firmware check on the hosts managed by a node repository.
@@ -28,13 +26,12 @@ public class FirmwareChecks {
private final CuratorDatabaseClient database;
private final Clock clock;
-
- private volatile Supplier<Optional<Instant>> checkAfter;
+ private final CachedSupplier<Optional<Instant>> checkAfter;
public FirmwareChecks(CuratorDatabaseClient database, Clock clock) {
this.database = database;
this.clock = clock;
- createCache();
+ this.checkAfter = new CachedSupplier<>(database::readFirmwareCheck, cacheExpiry);
}
/** Returns the instant after which a firmware check is required, or empty if none currently are. */
@@ -45,17 +42,13 @@ public class FirmwareChecks {
/** Requests a firmware check for all hosts managed by this node repository. */
public void request() {
database.writeFirmwareCheck(Optional.of(clock.instant()));
- createCache();
+ checkAfter.refresh();
}
/** Clears any outstanding firmware checks for this node repository. */
public void cancel() {
database.writeFirmwareCheck(Optional.empty());
- createCache();
- }
-
- private void createCache() {
- checkAfter = Suppliers.memoizeWithExpiration(database::readFirmwareCheck, cacheExpiry.toMillis(), TimeUnit.MILLISECONDS);
+ checkAfter.refresh();
}
}
diff --git a/vespajlib/src/main/java/com/yahoo/lang/CachedSupplier.java b/vespajlib/src/main/java/com/yahoo/lang/CachedSupplier.java
new file mode 100644
index 00000000000..07ce1250855
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/lang/CachedSupplier.java
@@ -0,0 +1,52 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.lang;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.function.Supplier;
+
+/**
+ * Supplier that caches the value for a given duration with ability to invalidate at demand.
+ * Is thread safe.
+ *
+ * @author freva
+ */
+public class CachedSupplier<T> implements Supplier<T> {
+
+ private final Supplier<T> delegate;
+ private final Duration period;
+ private final Clock clock;
+
+ private Instant nextRefresh;
+ private volatile T value;
+
+ public CachedSupplier(Supplier<T> delegate, Duration period) {
+ this(delegate, period, Clock.systemUTC());
+ }
+
+ CachedSupplier(Supplier<T> delegate, Duration period, Clock clock) {
+ this.delegate = delegate;
+ this.period = period;
+ this.clock = clock;
+ this.nextRefresh = Instant.MIN;
+ }
+
+ @Override
+ public T get() {
+ synchronized (this) {
+ if (clock.instant().isAfter(nextRefresh))
+ refresh();
+ }
+
+ return value;
+ }
+
+ public void refresh() {
+ synchronized (this) {
+ this.value = delegate.get();
+ this.nextRefresh = clock.instant().plus(period);
+ }
+ }
+
+}
diff --git a/vespajlib/src/test/java/com/yahoo/lang/CachedSupplierTest.java b/vespajlib/src/test/java/com/yahoo/lang/CachedSupplierTest.java
new file mode 100644
index 00000000000..b0dc1262ebc
--- /dev/null
+++ b/vespajlib/src/test/java/com/yahoo/lang/CachedSupplierTest.java
@@ -0,0 +1,39 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.lang;
+
+import com.yahoo.test.ManualClock;
+import org.junit.Test;
+
+import java.time.Duration;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author freva
+ */
+public class CachedSupplierTest {
+
+ @Test
+ public void test() {
+ ManualClock clock = new ManualClock();
+ MutableInteger integer = new MutableInteger(0);
+ CachedSupplier<Integer> supplier = new CachedSupplier<>(() -> integer.add(1), Duration.ofMinutes(1), clock);
+
+ assertEquals(1, supplier.get().intValue());
+ assertEquals(1, supplier.get().intValue());
+
+ clock.advance(Duration.ofSeconds(30));
+ assertEquals(1, supplier.get().intValue());
+
+ clock.advance(Duration.ofSeconds(31));
+ assertEquals(2, supplier.get().intValue());
+ assertEquals(2, supplier.get().intValue());
+
+ supplier.refresh();
+ assertEquals(3, supplier.get().intValue());
+ assertEquals(3, supplier.get().intValue());
+
+ clock.advance(Duration.ofSeconds(61));
+ assertEquals(4, supplier.get().intValue());
+ }
+}