mirror of
https://github.com/google/nomulus.git
synced 2025-07-24 03:30:46 +02:00
Begin migration from Guava Cache to Caffeine (#1590)
* Begin migration from Guava Cache to Caffeine Caffeine is apparently strictly superior to the older Guava Cache (and is even recommended in lieu of Guava Cache on Guava Cache's own documentation). This adds the relevant dependencies and switch over just a single call site to use the new Caffeine cache. It also implements a new pattern, asynchronously refreshing the cache value starting from half of our configuration time. For frequently accessed entities this will allow us to NEVER block on a load, as it will be asynchronously refreshed in the background long before it ever expires synchronously during a read operation.
This commit is contained in:
parent
9ec303bd71
commit
a3b8ad4cfc
67 changed files with 218 additions and 134 deletions
|
@ -1438,8 +1438,8 @@ public final class RegistryConfig {
|
|||
}
|
||||
|
||||
/** Returns the amount of time a singleton should be cached, before expiring. */
|
||||
public static Duration getSingletonCacheRefreshDuration() {
|
||||
return Duration.standardSeconds(CONFIG_SETTINGS.get().caching.singletonCacheRefreshSeconds);
|
||||
public static java.time.Duration getSingletonCacheRefreshDuration() {
|
||||
return java.time.Duration.ofSeconds(CONFIG_SETTINGS.get().caching.singletonCacheRefreshSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,10 +17,10 @@ package google.registry.model;
|
|||
import static com.google.common.base.Suppliers.memoizeWithExpiration;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.joda.time.Duration.ZERO;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.common.base.Supplier;
|
||||
import org.joda.time.Duration;
|
||||
import java.time.Duration;
|
||||
|
||||
/** Utility methods related to caching Datastore entities. */
|
||||
public class CacheUtils {
|
||||
|
@ -41,8 +41,36 @@ public class CacheUtils {
|
|||
*/
|
||||
public static <T> Supplier<T> tryMemoizeWithExpiration(
|
||||
Duration expiration, Supplier<T> original) {
|
||||
return expiration.isEqual(ZERO)
|
||||
return expiration.isZero()
|
||||
? original
|
||||
: memoizeWithExpiration(original, expiration.getMillis(), MILLISECONDS);
|
||||
: memoizeWithExpiration(original, expiration.toMillis(), MILLISECONDS);
|
||||
}
|
||||
|
||||
/** Creates and returns a new {@link Caffeine} builder. */
|
||||
public static Caffeine<Object, Object> newCacheBuilder() {
|
||||
return Caffeine.newBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new {@link Caffeine} builder with the specified cache expiration.
|
||||
*
|
||||
* <p>This also sets the refresh duration to half of the cache expiration. The resultant behavior
|
||||
* is that a cache entry is eligible to be asynchronously refreshed after access once more than
|
||||
* half of its cache duration has elapsed, and then it is synchronously refreshed (blocking the
|
||||
* read) once its full cache duration has elapsed. So you will never get data older than the cache
|
||||
* expiration, but for frequently accessed keys it will be refreshed more often than that and the
|
||||
* cost of the load will never be incurred during the read.
|
||||
*/
|
||||
public static Caffeine<Object, Object> newCacheBuilder(Duration expireAfterWrite) {
|
||||
Duration refreshAfterWrite = expireAfterWrite.dividedBy(2);
|
||||
Caffeine<Object, Object> caffeine = Caffeine.newBuilder().expireAfterWrite(expireAfterWrite);
|
||||
// In tests, the cache duration is usually set to 0, which means the cache load synchronously
|
||||
// blocks every time it is called anyway because of the expireAfterWrite() above. Thus, setting
|
||||
// the refreshAfterWrite won't do anything, plus it's not legal to call it with a zero value
|
||||
// anyway (Caffeine allows expireAfterWrite to be zero but not refreshAfterWrite).
|
||||
if (!refreshAfterWrite.isZero()) {
|
||||
caffeine = caffeine.refreshAfterWrite(refreshAfterWrite);
|
||||
}
|
||||
return caffeine;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,8 +264,7 @@ public class Registry extends ImmutableObject
|
|||
/** A cache that loads the {@link Registry} for a given tld. */
|
||||
private static final LoadingCache<String, Optional<Registry>> CACHE =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getSingletonCacheRefreshDuration().getMillis()))
|
||||
.expireAfterWrite(getSingletonCacheRefreshDuration())
|
||||
.build(
|
||||
new CacheLoader<String, Optional<Registry>>() {
|
||||
@Override
|
||||
|
|
|
@ -17,11 +17,11 @@ package google.registry.tmch;
|
|||
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PILOT;
|
||||
import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PRODUCTION;
|
||||
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
|
||||
import static google.registry.model.CacheUtils.newCacheBuilder;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
|
||||
|
@ -76,9 +76,7 @@ public final class TmchCertificateAuthority {
|
|||
* persist the correct one for this given environment.
|
||||
*/
|
||||
private static final LoadingCache<TmchCaMode, X509CRL> CRL_CACHE =
|
||||
CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(
|
||||
java.time.Duration.ofMillis(getSingletonCacheRefreshDuration().getMillis()))
|
||||
newCacheBuilder(getSingletonCacheRefreshDuration())
|
||||
.build(
|
||||
new CacheLoader<TmchCaMode, X509CRL>() {
|
||||
@Override
|
||||
|
|
|
@ -54,13 +54,10 @@ class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, HostResource>
|
|||
@RegisterExtension
|
||||
final ReplayExtension replayExtension = ReplayExtension.createWithDoubleReplay(clock);
|
||||
|
||||
HostInfoFlowTest() {
|
||||
setEppInput("host_info.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void initHostTest() {
|
||||
createTld("foobar");
|
||||
setEppInput("host_info.xml", ImmutableMap.of("HOSTNAME", "ns1.example.tld"));
|
||||
}
|
||||
|
||||
private HostResource persistHostResource() throws Exception {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue