#726 - L2 cache returns stale data -> change such that when using "local L2 caching" the changes to L2 cache propagate in foreground

This commit is contained in:
Robin Bygrave
2016-06-08 14:38:08 +12:00
parent 353175626d
commit cd56b3ca3c
9 changed files with 72 additions and 41 deletions
@@ -5,6 +5,15 @@ package com.avaje.ebean.cache;
*/
public interface ServerCacheManager {
/**
* Return true if the L2 caching is local.
* <p>
* Local L2 caching means that the cache updates should occur in foreground
* rather than background processing.
* </p>
*/
boolean isLocalL2Caching();
/**
* Return true if there is an active bean cache for this type of bean.
*/
@@ -20,10 +20,13 @@ public class DefaultServerCacheManager implements ServerCacheManager {
private final DefaultCacheHolder collectionIdsCache;
private final boolean localL2Caching;
/**
* Create with a cache factory and default cache options.
*/
public DefaultServerCacheManager(ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
public DefaultServerCacheManager(boolean localL2Caching, ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
this.localL2Caching = localL2Caching;
this.beanCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
this.queryCache = new DefaultCacheHolder(cacheFactory, defaultQueryOptions);
this.naturalKeyCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
@@ -34,7 +37,11 @@ public class DefaultServerCacheManager implements ServerCacheManager {
* Construct when l2 cache is disabled.
*/
public DefaultServerCacheManager() {
this(new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
this(true, new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
}
public boolean isLocalL2Caching() {
return localL2Caching;
}
/**
@@ -49,7 +56,9 @@ public class DefaultServerCacheManager implements ServerCacheManager {
queryCache.clearCache(beanName);
}
/**
* Clear all caches.
*/
public void clearAll() {
beanCache.clearAll();
queryCache.clearAll();
@@ -57,7 +66,6 @@ public class DefaultServerCacheManager implements ServerCacheManager {
collectionIdsCache.clearAll();
}
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName) {
return collectionIdsCache.getCache(beanType.getName() + "." + propertyName, ServerCacheType.COLLECTION_IDS);
}
@@ -87,5 +95,4 @@ public class DefaultServerCacheManager implements ServerCacheManager {
return beanCache.isCaching(beanType.getName());
}
}
@@ -170,6 +170,7 @@ public class DefaultContainer implements SpiContainer {
queryOptions.setMaxIdleSecs(serverConfig.getQueryCacheMaxIdleTime());
queryOptions.setMaxSecsToLive(serverConfig.getQueryCacheMaxTimeToLive());
boolean localL2Caching = false;
ServerCachePlugin plugin = serverConfig.getServerCachePlugin();
if (plugin == null) {
ServiceLoader<ServerCachePlugin> cacheFactories = ServiceLoader.load(ServerCachePlugin.class);
@@ -179,13 +180,14 @@ public class DefaultContainer implements SpiContainer {
plugin = iterator.next();
logger.debug("using ServerCacheFactory {}", plugin.getClass());
} else {
// use the built in default
// use the built in default l2 caching which is local cache based
localL2Caching = true;
plugin = new DefaultServerCachePlugin();
}
}
ServerCacheFactory factory = plugin.create(serverConfig, executor);
return new DefaultServerCacheManager(factory, beanOptions, queryOptions);
return new DefaultServerCacheManager(localL2Caching, factory, beanOptions, queryOptions);
}
/**
@@ -194,20 +196,20 @@ public class DefaultContainer implements SpiContainer {
*/
private BootupClasses getBootupClasses(ServerConfig serverConfig) {
BootupClasses bootupClasses = getBootupClasses1(serverConfig);
bootupClasses.addIdGenerators(serverConfig.getIdGenerators());
bootupClasses.addPersistControllers(serverConfig.getPersistControllers());
bootupClasses.addPostLoaders(serverConfig.getPostLoaders());
bootupClasses.addFindControllers(serverConfig.getFindControllers());
bootupClasses.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
bootupClasses.addPersistListeners(serverConfig.getPersistListeners());
bootupClasses.addQueryAdapters(serverConfig.getQueryAdapters());
bootupClasses.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
bootupClasses.addChangeLogInstances(serverConfig);
BootupClasses bootup = getBootupClasses1(serverConfig);
bootup.addIdGenerators(serverConfig.getIdGenerators());
bootup.addPersistControllers(serverConfig.getPersistControllers());
bootup.addPostLoaders(serverConfig.getPostLoaders());
bootup.addFindControllers(serverConfig.getFindControllers());
bootup.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
bootup.addPersistListeners(serverConfig.getPersistListeners());
bootup.addQueryAdapters(serverConfig.getQueryAdapters());
bootup.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
bootup.addChangeLogInstances(serverConfig);
// run any ServerConfigStartup instances
bootupClasses.runServerConfigStartup(serverConfig);
return bootupClasses;
bootup.runServerConfigStartup(serverConfig);
return bootup;
}
/**
@@ -338,15 +338,16 @@ public class InternalConfiguration {
*/
public TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) {
boolean localL2 = cacheManager.isLocalL2Caching();
if (serverConfig.isExplicitTransactionBeginMode()) {
return new ExplicitTransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
}
if (isAutoCommitMode()) {
return new AutoCommitTransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
}
return new TransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
}
/**
@@ -17,10 +17,10 @@ import java.sql.Connection;
*/
public class AutoCommitTransactionManager extends TransactionManager {
public AutoCommitTransactionManager(ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
public AutoCommitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
super(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
}
/**
@@ -17,10 +17,10 @@ import java.sql.Connection;
*/
public class ExplicitTransactionManager extends TransactionManager {
public ExplicitTransactionManager(ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
public ExplicitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
super(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
}
/**
@@ -84,9 +84,15 @@ public final class PostCommitProcessing {
/**
* Notify the local part of L2 cache.
*/
void notifyLocalCache(boolean viewInvalidation) {
void notifyLocalCache() {
processTableEvents(event.getEventTables());
cacheChanges = event.buildCacheChanges(viewInvalidation);
if (manager.localL2Caching) {
// process l2 cache changes in foreground
processCacheChanges(event.buildCacheChanges(manager.viewInvalidation));
} else {
// collect l2 cache changes for delayed background processing
cacheChanges = event.buildCacheChanges(manager.viewInvalidation);
}
}
/**
@@ -148,9 +154,7 @@ public final class PostCommitProcessing {
Runnable backgroundNotify() {
return new Runnable() {
public void run() {
if (cacheChanges != null) {
manager.processViewInvalidation(cacheChanges.apply());
}
processCacheChanges(cacheChanges);
localPersistListenersNotify();
notifyCluster();
processDocStoreUpdates();
@@ -158,6 +162,15 @@ public final class PostCommitProcessing {
};
}
/**
* Apply the changes to the L2 caches.
*/
private void processCacheChanges(CacheChangeSet cacheChanges) {
if (cacheChanges != null) {
manager.processViewInvalidation(cacheChanges.apply());
}
}
private void localPersistListenersNotify() {
if (persistBeanRequests != null) {
for (int i = 0; i < persistBeanRequests.size(); i++) {
@@ -105,14 +105,17 @@ public class TransactionManager {
*/
private final ChangeLogListener changeLogListener;
private final boolean viewInvalidation;
protected final boolean localL2Caching;
protected final boolean viewInvalidation;
/**
* Create the TransactionManager
*/
public TransactionManager(ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor,
BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
public TransactionManager(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
this.localL2Caching = localL2Caching;
this.persistBatch = config.getPersistBatch();
this.persistBatchOnCascade = config.appliedPersistBatchOnCascade();
this.beanDescriptorManager = descMgr;
@@ -402,7 +405,7 @@ public class TransactionManager {
}
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, transaction);
postCommit.notifyLocalCache(viewInvalidation);
postCommit.notifyLocalCache();
backgroundExecutor.execute(postCommit.backgroundNotify());
for (TransactionEventListener listener : transactionEventListeners) {
@@ -427,7 +430,7 @@ public class TransactionManager {
event.add(tableEvents);
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, event);
postCommit.notifyLocalCache(viewInvalidation);
postCommit.notifyLocalCache();
backgroundExecutor.execute(postCommit.backgroundNotify());
}