
sirius.kernel.cache.CacheManager Maven / Gradle / Ivy
Show all versions of sirius-kernel Show documentation
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.kernel.cache;
import sirius.kernel.Stoppable;
import sirius.kernel.di.std.Part;
import sirius.kernel.di.std.Register;
import sirius.kernel.health.Exceptions;
import sirius.kernel.health.Log;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
/**
* Provides access to all managed caches
*
* Is responsible for creating new caches using {@link #createLocalCache(String)} or {@link #createCoherentCache(String)}.
* Also, this class keeps track of all known caches.
*
* Additionally instances of {@link InlineCache} can be created, which can be used to compute a single value,
* which is then cached for a given amount of time.
*/
public class CacheManager {
/**
* Logged used by the caching system
*/
protected static final Log LOG = Log.get("cache");
/**
* Lists all known caches.
*/
private static Map> caches = new ConcurrentHashMap<>();
private static final Duration INLINE_CACHE_DEFAULT_TTL = Duration.ofSeconds(10);
@Part
private static CacheCoherence cacheCoherence;
/**
* This class has only static members and is not intended to be instantiated
*/
private CacheManager() {
}
/**
* Returns a list of all known caches
*
* @return a list of all caches created so far
*/
public static List> getCaches() {
return new ArrayList<>(caches.values());
}
/**
* Creates a cache with the given name which is only managed locally.
*
* The name is used to load the settings from the system configuration, using the extension cache.[name].
* If a value is absent in the cache, the given valueComputer is used to generate the requested value. If
* a value is fetched from the cache, it is verified by the given verifier in certain intervals before it
* is returned to the user.
*
* The system config can provide the following values:
*
* - maxSize: max number of entries in the cache
* - ttl: a duration specifying the max lifetime of a cached entry.
* - verification: a duration specifying in which interval a verification of a value will
* take place (if possible)
*
*
* To create a cache which is maintained across a cluster of nodes, use
* {@link #createCoherentCache(String, ValueComputer, ValueVerifier)}.
*
* @param name the name of the cache, used to load the appropriate extension from the config
* @param valueComputer used to compute a value, if no valid value was found in the cache for the given key. Can
* be null if there is no appropriate way to compute such a value. In this case, the
* cache will simply return null.
* @param verifier used to verify a value before it is returned to the user. Note that the
* value is not verified each time, but in given intervals. If the verifier is null,
* no verification will take place.
* @param the key field used to identify cache entries
* @param the value type used by the cache
* @return a newly created cache according to the given parameters and the settings in the system config
*/
public static Cache createLocalCache(String name,
ValueComputer valueComputer,
ValueVerifier verifier) {
ManagedCache result = new ManagedCache<>(name, valueComputer, verifier);
verifyUniquenessOfName(name);
caches.put(name, result);
return result;
}
private static void verifyUniquenessOfName(String name) {
if (caches.containsKey(name)) {
throw Exceptions.handle()
.to(LOG)
.withSystemErrorMessage("A cache named '%s' has already been created!", name)
.handle();
}
}
/**
* Creates a cache with the given name, for which removals are roamed in the cluster to prevent stale values.
*
* All other settings are exactly the same as for local caches. Also, if no {@link CacheCoherence} is present,
* this will behave like a local cache.
*
* @param name the name of the cache, used to load the appropriate extension from the config
* @param valueComputer used to compute a value, if no valid value was found in the cache for the given key. Can
* be null if there is no appropriate way to compute such a value. In this case, the
* cache will simply return null.
* @param verifier used to verify a value before it is returned to the user. Note that the
* value is not verified each time, but in given intervals. If the verifier is null,
* no verification will take place.
* @param the value type used by the cache
* @return a newly created cache according to the given parameters and the settings in the system config
* @see #createLocalCache(String, ValueComputer, ValueVerifier)
*/
public static Cache createCoherentCache(String name,
ValueComputer valueComputer,
ValueVerifier verifier) {
CoherentCache result = new CoherentCache<>(name, valueComputer, verifier);
verifyUniquenessOfName(name);
caches.put(name, result);
return result;
}
/**
* Creates a locally managed cache with the given name.
*
* This is just a shortcut for {@link #createLocalCache(String, ValueComputer, ValueVerifier)} with neither a
* ValueComputer nor a ValueVerifier supplied.
*
* @param the key field used to identify cache entries
* @param the value type used by the cache
* @param name the name of the cache (used to fetch settings from the system config
* @return the newly created cache
* @see #createLocalCache(String, ValueComputer, ValueVerifier)
*/
public static Cache createLocalCache(String name) {
return createLocalCache(name, null, null);
}
/**
* Creates a coherent cache with the given name.
*
* This is just a shortcut for {@link #createCoherentCache(String, ValueComputer, ValueVerifier)} with neither a
* ValueComputer nor a ValueVerifier supplied.
*
* @param the value type used by the cache
* @param name the name of the cache (used to fetch settings from the system config
* @return the newly created cache
* @see #createLocalCache(String, ValueComputer, ValueVerifier)
*/
public static Cache createCoherentCache(String name) {
return createCoherentCache(name, null, null);
}
/**
* Creates a new {@link InlineCache} with the given TTL and computer.
*
* An inline cache can be used to compute a single value, which is then cached for a certain amount of time.
*
* @param ttl specifies the duration which the computed value will be cached
* @param computer the provider which is used to re-compute the value once it expired
* @param the type of values being cached
* @return an inline cache which keeps a computed value for the given amount of time and then uses the provided
* computer to re-compute the value
*/
public static InlineCache createInlineCache(Duration ttl, Supplier computer) {
return new InlineCache<>(computer, ttl.toMillis());
}
/**
* Boilerplate method for {@link #createInlineCache(Duration, Supplier)}
* which keeps the computed value for up to 10 seconds.
*
* @param computer the provider which is used to re-compute the value once it expired
* @param the type of values being cached
* @return an inline cache which keeps a computed value for ten seconds and then uses the provided
* computer to re-compute the value
*/
public static InlineCache createTenSecondsInlineCache(Supplier computer) {
return createInlineCache(INLINE_CACHE_DEFAULT_TTL, computer);
}
/**
* Used by {@link CoherentCache} to signal that this cache is to be cleared on all nodes.
*
* @param cache the cache to clear
*/
protected static void clearCoherentCache(CoherentCache> cache) {
if (cacheCoherence != null) {
cacheCoherence.clear(cache);
} else {
cache.clearLocal();
}
}
/**
* Clears the coherent cache locally.
*
* @param cacheName the cache to clear
*/
public static void clearCoherentCacheLocally(String cacheName) {
ManagedCache, ?> cache = caches.get(cacheName);
if (cache instanceof CoherentCache) {
((CoherentCache>) cache).clearLocal();
}
}
/**
* Used by {@link CoherentCache} to signal that the given key should be removed from this cache on all nodes.
*
* @param cache the cache to remove the value from
* @param key the key to remove
*/
protected static void removeCoherentCacheKey(CoherentCache> cache, String key) {
if (cacheCoherence != null) {
cacheCoherence.removeKey(cache, key);
} else {
cache.removeLocal(key);
}
}
/**
* Removes the given key from the given cache locally.
*
* @param cacheName the name of the cache to remove the value from
* @param key the key to remove
*/
public static void removeCoherentCacheKeyLocally(String cacheName, String key) {
ManagedCache, ?> cache = caches.get(cacheName);
if (cache instanceof CoherentCache) {
((CoherentCache>) cache).removeLocal(key);
}
}
/**
* Clears the caches when Sirius is shutting down
*/
@Register
public static class CacheManagerLifecycle implements Stoppable {
@Override
public void stopped() {
caches.values().forEach(ManagedCache::clear);
caches.clear();
}
}
}