All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openstreetmap.atlas.utilities.caching.ConcurrentResourceCache Maven / Gradle / Ivy

The newest version!
package org.openstreetmap.atlas.utilities.caching;

import java.net.URI;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;

import org.openstreetmap.atlas.streaming.resource.Resource;
import org.openstreetmap.atlas.utilities.caching.strategies.CachingStrategy;
import org.openstreetmap.atlas.utilities.caching.strategies.NamespaceCachingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* The threadsafe {@link ResourceCache} implementation. There is a caveat, related to the fact that * some caching strategies utilize system-wide global state e.g. {@link NamespaceCachingStrategy} * uses the tmp filesystem. In doing so it becomes impossible to guarantee concurrency safety from * within the {@link ConcurrentResourceCache} alone.
* {@link ConcurrentResourceCache} needs a specified {@link CachingStrategy} and default fetching * {@link Function} at creation time. The cache then loads a resource using a given {@link URI}. * Since using {@link URI} objects can often be cumbersome, users of this class are encouraged to * extend it and overload the {@link ConcurrentResourceCache#get} method to take more convenient * parameters. *

* * @author lcram */ public class ConcurrentResourceCache implements ResourceCache { private static final Logger logger = LoggerFactory.getLogger(ConcurrentResourceCache.class); private final CachingStrategy cachingStrategy; private final Function> fetcher; private final UUID cacheID; /** * Create a new {@link ConcurrentResourceCache} with the given fetcher and strategy. * * @param cachingStrategy * the caching strategy * @param fetcher * the default fetcher */ public ConcurrentResourceCache(final CachingStrategy cachingStrategy, final Function> fetcher) { this.cachingStrategy = cachingStrategy; this.fetcher = fetcher; this.cacheID = UUID.randomUUID(); logger.info("Initialized cache {} with ID {}", this.getClass().getName(), this.cacheID); } @Override public Optional get(final URI resourceURI) { Optional cachedResource; // We must synchronize the application of the caching strategy since we cannot guarantee // that the strategy does not utilize internal global state. synchronized (this) { cachedResource = this.cachingStrategy.attemptFetch(resourceURI, this.fetcher); } if (cachedResource.isEmpty()) { logger.warn("CacheID {}: cache fetch of {} failed, falling back to default fetcher...", this.cacheID, resourceURI); // We must also synchronize the application of the fetcher, since it may rely on state // shared by the calling threads. synchronized (this) { cachedResource = this.fetcher.apply(resourceURI); } } return cachedResource; } /** * Get the name of the backing {@link CachingStrategy}. * * @return the name */ public String getStrategyName() { return this.cachingStrategy.getName(); } @Override public void invalidate() { logger.info("CacheID {}: invalidating cache", this.cacheID); // Synchronize invalidation with the same lock used to fetch and cache. This prevents // invalidation corruption. synchronized (this) { this.cachingStrategy.invalidate(); } } @Override public void invalidate(final URI resourceURI) { logger.info("CacheID {}: invalidating resource {}", this.cacheID, resourceURI); // Synchronize invalidation with the same lock used to fetch and cache. This prevents // invalidation corruption. synchronized (this) { this.cachingStrategy.invalidate(resourceURI); } } /** * Get a {@link UUID} for this cache instance. This is useful for logging. * * @return The cache instance {@link UUID} */ protected UUID getCacheID() { return this.cacheID; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy