-
Notifications
You must be signed in to change notification settings - Fork 2
Storage layer
Using the FactoryStorageCacheService and CacheType to build the kind of ExoCache and FutureExoCache.
FactoryStorageCacheService: The Factory which uses the CacheService to create the region caching for management in itself.
CacheType: Initialize the FutureCache from eXoCache but, it is also create the CacheLoader in the FutureCache. When you need to load data from the data source. You only invoke the cacheLoader.retrieve(ServiceContext) method such as the decorator more functions into the FutureCache.
(Visitor DP). and then the ServiceContext.execute() method will execute to load the data from data source.
FooKey: which keeps in the eXoCache such as Key
FooFilterKey: which keeps in the FutureCache with the ServiceContext for next time when you want to query by fooFilter.
ListFoosKey: which keeps in the FutureCache with the ServiceContext for next time when you want to query by fooFilter, offset and limit.
FoodData: which wraps the Foo model such as Value in the eXoCache.
Using the eXoCache to keep the FooKey, FooData
Using the FutureExoCache<ServiceContext, Key, Value>
Key: FooKey, FooFilterKey, ListFoosKey.
Data: FooData, ListFoosData.
In CachedFooStorage:
private final ExoCache<FooKey, FooData> etkFooCache;
private final FutureETKCache<FooKey, FooData, ServiceContext<FooData>> fooCache;
public CachedFooStorage(final FooStorageImpl storage, final FactoryStorageCacheService cacheService) {
this.etkFooCache = cacheService.getFooCache();
//Initializes the EtkFutureCache which executes for caching ServiceContext
this.fooCache = CacheType.FOO.createFutureCache(etkFooCache);
}
FutureETKCache:
public <K extends CacheKey, V extends Serializable> FutureETKCache<K, V, ServiceContext<V>> createFutureCache(ExoCache<K,V> cache) {
return new FutureETKCache<K, V, ServiceContext<V>>(new CacheLoader<K, V>(), cache);
}
And ClassLoader class:
public class CacheLoader<K extends CacheKey, V> implements Loader<K, V, ServiceContext<V>> {
@Override
public V retrieve(ServiceContext<V> context, K key) throws Exception {
return context.execute();
}
}
CachedFooStorage which is middle layer to communicate with Service layer and Database layer. It executes following the priority: first check in caching and second check in database and delegate the task to FutureCache.get() method.
public final V get(final C context, final K key) {
// First we try a simple cache get
V value = get(key);
// If it does not succeed then we go through a process that will avoid to
// load
// the same resource concurrently
if (value == null) {
// Create our future
FutureTask<V> future = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
// Retrieve the value from the loader
V value = loader.retrieve(context, key);//CacheLoader.retrieve() invokes, pass ServiceContext params
//
if (value != null) {
// Cache it, it is made available to other threads (unless someone
// removes it)
put(key, value);
// Return value
return value;
} else {
return null;
}
}
});
// This boolean means we inserted in the local
boolean inserted = true;
//
try {
FutureTask<V> phantom = futureEntries.putIfAbsent(key, future);
// Use the value that could have been inserted by another thread
if (phantom != null) {
future = phantom;
inserted = false;
} else {
future.run();
}
// Returns the value
value = future.get();
} catch (ExecutionException e) {
if (e.getCause() != null) {
throw new UndeclaredThrowableException(e.getCause());
} else {
log.error("Computing of resource " + key + " threw an exception", e.getCause());
}
} catch (Exception e) {
log.error("Retrieval of resource " + key + " threw an exception", e);
} finally {
// Clean up the per key map but only if our insertion succeeded and with
// our future
if (inserted) {
futureEntries.remove(key, future);
}
}
}
//
return value;
}