summaryrefslogtreecommitdiffstats
path: root/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java
diff options
context:
space:
mode:
Diffstat (limited to 'dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java')
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java74
1 files changed, 61 insertions, 13 deletions
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java
index 1efc72d4..8b549800 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/cache/CacheBase.java
@@ -1,8 +1,13 @@
package org.openslx.bwlp.sat.thrift.cache;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
+import org.openslx.util.QuickTimer;
+import org.openslx.util.QuickTimer.Task;
/**
* Class that caches an instance of a given class for 10 minutes.
@@ -15,28 +20,71 @@ public abstract class CacheBase<T> {
private static final Logger LOGGER = LogManager.getLogger(CacheBase.class);
- private static final int TIMEOUT = 10 * 60 * 1000;
+ /** Keep cached data for 10 minutes at a time */
+ private static final int TIMEOUT = 600_000;
private T cachedInstance = null;
+ /** Deadline after which cache is considered stale */
private long cacheTimeout = 0;
+ /** For timed waiting on new data */
+ private CountDownLatch latch = null;
+
protected abstract T getCallback() throws TException;
- protected synchronized T getInternal() {
- final long now = System.currentTimeMillis();
- if (cachedInstance == null || now > cacheTimeout) {
- try {
- T freshInstance = getCallback();
- if (freshInstance != null) {
- cachedInstance = freshInstance;
- cacheTimeout = now + TIMEOUT;
- }
- } catch (TException e) {
- LOGGER.warn("Could not retrieve fresh instance of " + getClass().getSimpleName(), e);
+ protected T getInternal() {
+ boolean doFetch = false;
+ final CountDownLatch localLatch;
+ synchronized (this) {
+ if (cachedInstance != null && System.currentTimeMillis() < cacheTimeout)
+ return cachedInstance;
+ if (latch == null) {
+ latch = new CountDownLatch(1);
+ doFetch = true;
}
+ localLatch = latch; // Fetch a local reference while still synchronized
+ }
+ // Need update
+ if (doFetch) {
+ // This invocation found latch == null, which means it is
+ // responsible for triggering the actual update.
+ QuickTimer.scheduleOnce(new Task() {
+ @Override
+ public void fire() {
+ T freshInstance = null;
+ try {
+ freshInstance = getCallback();
+ } catch (TException e) {
+ LOGGER.warn("Could not retrieve fresh instance of " + getClass().getSimpleName(), e);
+ } finally {
+ synchronized (CacheBase.this) {
+ if (freshInstance != null) {
+ cachedInstance = freshInstance;
+ cacheTimeout = System.currentTimeMillis() + TIMEOUT;
+ }
+ latch = null;
+ }
+ localLatch.countDown();
+ }
+ }
+ });
+ }
+ // Now just wait for latch, regardless of whether we triggered the update or not
+ boolean ok = false;
+ try {
+ // In case the cache is still empty, we wait for long. Otherwise, bail out after
+ // one second so we'll rather use stale data than blocking the caller for too long.
+ int waitTime = cachedInstance == null ? 600 : 1;
+ ok = localLatch.await(waitTime, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ }
+ if (!ok) {
+ LOGGER.warn("CacheUpdate for " + getClass().getSimpleName() + " timed out, using old data.");
+ }
+ synchronized (this) {
+ return cachedInstance;
}
- return cachedInstance;
}
}