Skip to content

Commit

Permalink
Reschedule async maintenance immediately if pending work remains (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-manes committed Jun 24, 2018
1 parent d554069 commit e8ff6d3
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 27 deletions.
5 changes: 0 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ allprojects {
subprojects {
apply plugin: 'com.github.ethankhall.semantic-versioning'
apply plugin: 'net.ltgt.errorprone'
apply plugin: 'propdeps-maven'
apply plugin: 'eclipse'
apply plugin: 'java'
apply plugin: 'idea'
Expand All @@ -68,10 +67,6 @@ subprojects {
}
archivesBaseName = path[1..-1].replaceAll(':', '-').toLowerCase()

idea.module {
scopes.PROVIDED.plus += [ configurations.provided ]
}

dependencies {
testCompile libraries.guava
testCompile testLibraries.mockito
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -1108,6 +1109,9 @@ void performCleanUp(@Nullable Runnable task) {
} finally {
evictionLock.unlock();
}
if ((drainStatus() == REQUIRED) && (executor == ForkJoinPool.commonPool())) {
scheduleDrainBuffers();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ public Caffeine<K, V> expireAfterWrite(@NonNull Duration duration) {
* Expired entries may be counted in {@link Cache#estimatedSize()}, but will never be visible to
* read or write operations. Expired entries are cleaned up as part of the routine maintenance
* described in the class javadoc.
* <p>
* If you can represent the duration as a {@link java.time.Duration} (which should be preferred
* when feasible), use {@link #expireAfterWrite(Duration)} instead.
*
* @param duration the length of time after an entry is created that it should be automatically
* removed
Expand Down Expand Up @@ -597,6 +600,9 @@ public Caffeine<K, V> expireAfterAccess(@NonNull Duration duration) {
* Expired entries may be counted in {@link Cache#estimatedSize()}, but will never be visible to
* read or write operations. Expired entries are cleaned up as part of the routine maintenance
* described in the class javadoc.
* <p>
* If you can represent the duration as a {@link java.time.Duration} (which should be preferred
* when feasible), use {@link #expireAfterAccess(Duration)} instead.
*
* @param duration the length of time after an entry is last accessed that it should be
* automatically removed
Expand Down Expand Up @@ -702,6 +708,9 @@ public Caffeine<K, V> refreshAfterWrite(@NonNull Duration duration) {
* return the old value.
* <p>
* <b>Note:</b> <i>all exceptions thrown during refresh will be logged and then swallowed</i>.
* <p>
* If you can represent the duration as a {@link java.time.Duration} (which should be preferred
* when feasible), use {@link #refreshAfterWrite(Duration)} instead.
*
* @param duration the length of time after an entry is created that it should be considered
* stale, and thus eligible for refresh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.ReferenceType;
import com.github.benmanes.caffeine.cache.testing.CacheValidationListener;
import com.github.benmanes.caffeine.testing.Awaits;
import com.github.benmanes.caffeine.testing.ConcurrentTestHarness;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
Expand Down Expand Up @@ -124,6 +123,29 @@ public void scheduleDrainBuffers() {
});
}

@Test
public void rescheduleDrainBuffers() {
AtomicBoolean evicting = new AtomicBoolean();
AtomicBoolean done = new AtomicBoolean();
CacheWriter<Integer, Integer> writer = new CacheWriter<Integer, Integer>() {
@Override public void write(Integer key, Integer value) {}
@Override public void delete(Integer key, Integer value, RemovalCause cause) {
evicting.set(true);
await().untilTrue(done);
}
};
BoundedLocalCache<Integer, Integer> map = asBoundedLocalCache(
Caffeine.newBuilder().writer(writer).maximumSize(0L).build());
map.put(1, 1);
await().untilTrue(evicting);

map.put(2, 2);
assertThat(map.drainStatus, is(PROCESSING_TO_REQUIRED));

done.set(true);
await().until(() -> map.drainStatus, is(IDLE));
}

@Test(dataProvider = "caches")
@CacheSpec(compute = Compute.SYNC, implementation = Implementation.Caffeine,
population = Population.FULL, maximumSize = Maximum.FULL,
Expand Down Expand Up @@ -169,8 +191,8 @@ public void evict_alreadyRemoved(Cache<Integer, Integer> cache, CacheContext con
localCache.put(newEntry.getKey(), newEntry.getValue());
assertThat(localCache.remove(oldEntry.getKey()), is(oldEntry.getValue()));
});
Awaits.await().until(() -> localCache.containsKey(oldEntry.getKey()), is(false));
Awaits.await().until(() -> {
await().until(() -> localCache.containsKey(oldEntry.getKey()), is(false));
await().until(() -> {
synchronized (node) {
return !node.isAlive();
}
Expand All @@ -180,7 +202,7 @@ public void evict_alreadyRemoved(Cache<Integer, Integer> cache, CacheContext con

checkStatus(node, Status.DEAD);
assertThat(localCache.containsKey(newEntry.getKey()), is(true));
Awaits.await().until(() -> cache, hasRemovalNotifications(context, 1, RemovalCause.EXPLICIT));
await().until(() -> cache, hasRemovalNotifications(context, 1, RemovalCause.EXPLICIT));
} finally {
localCache.evictionLock.unlock();
}
Expand Down Expand Up @@ -531,7 +553,7 @@ public void drain_nonblocking(Cache<Integer, Integer> cache, CacheContext contex
localCache.evictionLock.lock();
try {
ConcurrentTestHarness.execute(task);
Awaits.await().untilTrue(done);
await().untilTrue(done);
} finally {
localCache.evictionLock.unlock();
}
Expand Down Expand Up @@ -573,10 +595,10 @@ void checkDrainBlocks(BoundedLocalCache<Integer, Integer> localCache, Runnable t
task.run();
done.set(true);
});
Awaits.await().until(lock::hasQueuedThreads);
await().until(lock::hasQueuedThreads);
} finally {
lock.unlock();
}
Awaits.await().untilTrue(done);
await().untilTrue(done);
}
}
24 changes: 11 additions & 13 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
ext {
versions = [
akka: '2.5.13',
checkerFramework: '2.5.1',
commonsCompress: '1.16.1',
checkerFramework: '2.5.2',
commonsCompress: '1.17',
commonsLang3: '3.7',
config: '1.3.3',
errorProne: '2.3.1',
Expand All @@ -37,7 +37,7 @@ ext {
javapoet: '1.11.1',
jcache: '1.1.0',
jsr330: '1',
univocityParsers: '2.6.3',
univocityParsers: '2.6.4',
ycsb: '0.13.0',
xz: '1.8',
]
Expand All @@ -48,7 +48,7 @@ ext {
jcacheTck: '1.1.0',
jctools: '2.1.2',
junit: '4.12',
mockito: '2.18.3',
mockito: '2.19.0',
paxExam: '4.11.0',
testng: '6.14.3',
truth: '0.24',
Expand All @@ -58,9 +58,9 @@ ext {
collision: '0.3.3',
concurrentlinkedhashmap: '1.4.2',
ehcache3: '3.5.2',
elasticSearch: '6.2.4',
elasticSearch: '6.3.0',
expiringMap: '0.5.8',
jackrabbit: '1.9.2',
jackrabbit: '1.9.4',
jamm: '0.3.2',
javaObjectLayout: '0.9',
jmh: '1.21',
Expand All @@ -70,28 +70,27 @@ ext {
tcache: '1.0.5',
]
pluginVersions = [
apt: '0.15',
buildscan: '1.13.4',
apt: '0.16',
buildscan: '1.14',
checkstyle: '8.10.1',
coveralls: '2.8.2',
coverity: '1.0.10',
errorProne: '0.0.14',
jacoco: '0.8.1',
jmh: '0.4.5',
jmh: '0.4.6',
jmhReport: '0.7.0',
nexus: '2.3.1',
pmd: '6.3.0',
propdeps: '0.0.10.RELEASE',
semanticVersioning: '1.1.0',
shadow: '2.0.4',
sonarqube: '2.6.2',
spotbugs: '3.1.3',
spotbugsPlugin: '1.6.2',
stats: '0.2.2',
versions: '0.17.0',
versions: '0.20.0',
]
annotationProcessorVersions = [
nullaway: '0.4.6',
nullaway: '0.4.7',
]

libraries = [
Expand Down Expand Up @@ -185,7 +184,6 @@ ext {
],
jmhReport: "gradle.plugin.io.morethan.jmhreport:gradle-jmh-report:${pluginVersions.jmhReport}",
nexus: "com.bmuschko:gradle-nexus-plugin:${pluginVersions.nexus}",
propdeps: "io.spring.gradle:propdeps-plugin:${pluginVersions.propdeps}",
semanticVersioning: "io.ehdev:gradle-semantic-versioning:${pluginVersions.semanticVersioning}",
shadow: "com.github.jengelman.gradle.plugins:shadow:${pluginVersions.shadow}",
sonarqube: "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:${pluginVersions.sonarqube}",
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-rc-3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public void setCache(CacheProxy<K, V> cache) {
}

@Override
@SuppressWarnings("NullAway")
public @Nullable Expirable<V> load(K key) {
try {
boolean statsEnabled = statistics.isEnabled();
Expand Down

0 comments on commit e8ff6d3

Please sign in to comment.