org.infinispan.interceptors.distribution.VersionedDistributionInterceptor Maven / Gradle / Ivy
package org.infinispan.interceptors.distribution;
import static org.infinispan.transaction.impl.WriteSkewHelper.readVersionsFromResponse;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.infinispan.commands.tx.PrepareCommand;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.versioning.EntryVersion;
import org.infinispan.container.versioning.InequalVersionComparisonResult;
import org.infinispan.container.versioning.VersionGenerator;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.TxInvocationContext;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.interceptors.InvocationStage;
import org.infinispan.metadata.Metadata;
import org.infinispan.remoting.responses.Response;
import org.infinispan.remoting.transport.Address;
import org.infinispan.transaction.impl.AbstractCacheTransaction;
import org.infinispan.transaction.impl.LocalTransaction;
import org.infinispan.transaction.xa.CacheTransaction;
import org.infinispan.util.concurrent.CompletableFutures;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
/**
* A version of the {@link TxDistributionInterceptor} that adds logic to handling prepares when entries are
* versioned.
*
* @author Manik Surtani
* @author Dan Berindei
*/
public class VersionedDistributionInterceptor extends TxDistributionInterceptor {
private static final Log log = LogFactory.getLog(VersionedDistributionInterceptor.class);
private VersionGenerator versionGenerator;
@Inject
public void init(VersionGenerator versionGenerator) {
this.versionGenerator = versionGenerator;
}
@Override
protected Log getLog() {
return log;
}
@Override
protected void wrapRemoteEntry(InvocationContext ctx, Object key, CacheEntry ice, boolean isWrite) {
if (ctx.isInTxScope()) {
EntryVersion seenVersion = ((TxInvocationContext) ctx).getCacheTransaction().getVersionsRead().get(key);
if (seenVersion != null) {
EntryVersion newVersion = null;
if (ice != null && ice.getMetadata() != null) {
newVersion = ice.getMetadata().version();
}
if (newVersion == null) {
throw new IllegalStateException("Wrapping entry without version");
}
if (seenVersion.compareTo(newVersion) != InequalVersionComparisonResult.EQUAL) {
throw log.writeSkewOnRead(key, key, seenVersion, newVersion);
}
}
}
super.wrapRemoteEntry(ctx, key, ice, isWrite);
}
@Override
protected InvocationStage wrapFunctionalResultOnNonOriginOnReturn(InvocationStage stage, CacheEntry entry) {
return stage.thenApply((rCtx, rCommand, rv) -> {
Metadata metadata = entry.getMetadata();
EntryVersion version = metadata == null || metadata.version() == null ?
versionGenerator.nonExistingVersion() : metadata.version();
return new VersionedResult(rv, version);
});
}
@Override
protected Object wrapFunctionalManyResultOnNonOrigin(InvocationContext ctx, Collection> keys, Object[] values) {
// note: this relies on the fact that keys are already ordered on remote node
EntryVersion[] versions = new EntryVersion[keys.size()];
int i = 0;
for (Object key : keys) {
CacheEntry entry = ctx.lookupEntry(key);
Metadata metadata = entry.getMetadata();
versions[i++] = metadata == null || metadata.version() == null ?
versionGenerator.nonExistingVersion() : metadata.version();
}
return new VersionedResults(values, versions);
}
@Override
protected Object[] unwrapFunctionalManyResultOnOrigin(InvocationContext ctx, List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy