org.infinispan.interceptors.impl.ClusteredCacheLoaderInterceptor Maven / Gradle / Ivy
package org.infinispan.interceptors.impl;
import static org.infinispan.commons.util.Util.toStr;
import org.infinispan.commands.VisitableCommand;
import org.infinispan.commands.write.WriteCommand;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.FlagBitSets;
import org.infinispan.distribution.DistributionInfo;
import org.infinispan.distribution.DistributionManager;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.statetransfer.StateTransferManager;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
/**
* The same as a regular cache loader interceptor, except that it contains additional logic to force loading from the
* cache loader if needed on a remote node, in certain conditions.
*
* @author Manik Surtani
* @since 9.0
*/
public class ClusteredCacheLoaderInterceptor extends CacheLoaderInterceptor {
private static final Log log = LogFactory.getLog(ClusteredCacheLoaderInterceptor.class);
private static final boolean trace = log.isTraceEnabled();
private boolean transactional;
private StateTransferManager stateTransferManager;
private DistributionManager distributionManager;
@Inject
private void injectDependencies(StateTransferManager stateTransferManager, DistributionManager distributionManager) {
this.stateTransferManager = stateTransferManager;
this.distributionManager = distributionManager;
}
@Start(priority = 15)
private void startClusteredCacheLoaderInterceptor() {
transactional = cacheConfiguration.transaction().transactionMode().isTransactional();
}
@Override
protected boolean skipLoadForWriteCommand(WriteCommand cmd, Object key, InvocationContext ctx) {
if (transactional) {
// LoadType.OWNER is used when the previous value is required to produce new value itself (functional commands
// or delta-aware), therefore, we have to load them into context. Other load types have checked the value
// already on the originator and therefore the value is loaded only for WSC (without this interceptor)
if (!ctx.isOriginLocal() && cmd.loadType() != VisitableCommand.LoadType.OWNER) {
return true;
}
} else {
switch (cmd.loadType()) {
case DONT_LOAD:
return true;
case PRIMARY:
if (cmd.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL)) {
return cmd.hasAnyFlag(FlagBitSets.SKIP_CACHE_LOAD);
}
if (!distributionManager.getCacheTopology().getDistribution(key).isPrimary()) {
if (trace) {
log.tracef("Skip load for command %s. This node is not the primary owner of %s", cmd, toStr(key));
}
return true;
}
break;
case OWNER:
if (cmd.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL)) {
return cmd.hasAnyFlag(FlagBitSets.SKIP_CACHE_LOAD);
}
// TODO [Dan] I'm not sure using the write CH is OK here
DistributionInfo info = distributionManager.getCacheTopology().getDistribution(key);
if (!info.isPrimary() && (!info.isWriteOwner() || ctx.isOriginLocal())) {
if (trace) {
log.tracef("Skip load for command %s. This node is neither the primary owner nor non-origin backup of %s", cmd, toStr(key));
}
return true;
}
break;
}
}
return super.skipLoadForWriteCommand(cmd, key, ctx);
}
@Override
protected boolean canLoad(Object key) {
// Don't load the value if we are using distributed mode and aren't in the read CH
return stateTransferManager.isJoinComplete() && isKeyLocal(key);
}
private boolean isKeyLocal(Object key) {
return distributionManager.getCacheTopology().isReadOwner(key);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy