Search in sources :

Example 1 with ValueMatcher

use of org.infinispan.commands.write.ValueMatcher in project infinispan by infinispan.

the class CallInterceptor method visitReadWriteKeyValueCommand.

@Override
public Object visitReadWriteKeyValueCommand(InvocationContext ctx, ReadWriteKeyValueCommand command) throws Throwable {
    ValueMatcher valueMatcher = command.getValueMatcher();
    // It's not worth looking up the entry if we're never going to apply the change.
    if (valueMatcher == ValueMatcher.MATCH_NEVER) {
        command.fail();
        return null;
    }
    MVCCEntry e = (MVCCEntry) ctx.lookupEntry(command.getKey());
    // Could be that the key is not local
    if (e == null)
        return null;
    Object prevValue = command.getPrevValue();
    Metadata prevMetadata = command.getPrevMetadata();
    boolean hasCommandRetry = command.hasAnyFlag(FlagBitSets.COMMAND_RETRY);
    // Command only has one previous value, do not override it
    if (prevValue == null && !hasCommandRetry) {
        prevValue = e.getValue();
        prevMetadata = e.getMetadata();
        command.setPrevValueAndMetadata(prevValue, prevMetadata);
    }
    // Protect against outdated old value using the value matcher.
    // If the value has been update while on the retry, use the newer value.
    // Also take into account that the value might have been removed.
    // TODO: Configure equivalence function
    // TODO: this won't work properly until we store if the command was executed or not...
    Object oldPrevValue = e.getValue();
    // Note: other commands don't clone the entry as they don't carry the previous value for comparison
    // using value matcher - if other commands are retried these can apply the function multiple times.
    // Here we don't want to modify the value in context when trying what would be the outcome of the operation.
    MVCCEntry copy = e.clone();
    DataConversion valueDataConversion = command.getValueDataConversion();
    Object decodedArgument = valueDataConversion.fromStorage(command.getArgument());
    EntryViews.AccessLoggingReadWriteView view = EntryViews.readWrite(copy, prevValue, prevMetadata, command.getKeyDataConversion(), valueDataConversion);
    Object ret = snapshot(command.getBiFunction().apply(decodedArgument, view));
    if (valueMatcher.matches(oldPrevValue, prevValue, copy.getValue())) {
        log.tracef("Execute read-write function on previous value %s and previous metadata %s", prevValue, prevMetadata);
        e.setValue(copy.getValue());
        e.setMetadata(copy.getMetadata());
        // These are the only flags that should be changed with EntryViews.readWrite
        e.setChanged(copy.isChanged());
        e.setRemoved(copy.isRemoved());
    }
    // The effective result of retried command is not safe; we'll go to backup anyway
    if (!e.isChanged() && !hasCommandRetry) {
        command.fail();
    }
    updateStoreFlags(command, e);
    return Param.StatisticsMode.isSkip(command.getParams()) ? ret : StatsEnvelope.create(ret, e, prevValue != null, view.isRead());
}
Also used : DataConversion(org.infinispan.encoding.DataConversion) ValueMatcher(org.infinispan.commands.write.ValueMatcher) EntryViews(org.infinispan.functional.impl.EntryViews) Metadata(org.infinispan.metadata.Metadata) MVCCEntry(org.infinispan.container.entries.MVCCEntry)

Example 2 with ValueMatcher

use of org.infinispan.commands.write.ValueMatcher in project infinispan by infinispan.

the class CallInterceptor method visitPutKeyValueCommand.

@Override
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
    // It's not worth looking up the entry if we're never going to apply the change.
    ValueMatcher valueMatcher = command.getValueMatcher();
    if (valueMatcher == ValueMatcher.MATCH_NEVER) {
        command.fail();
        return null;
    }
    // noinspection unchecked
    Object key = command.getKey();
    MVCCEntry<Object, Object> e = (MVCCEntry) ctx.lookupEntry(key);
    if (e == null) {
        throw new IllegalStateException("Not wrapped");
    }
    Object newValue = command.getValue();
    Metadata metadata = command.getMetadata();
    if (metadata instanceof InternalMetadataImpl) {
        InternalMetadataImpl internalMetadata = (InternalMetadataImpl) metadata;
        metadata = internalMetadata.actual();
        e.setCreated(internalMetadata.created());
        e.setLastUsed(internalMetadata.lastUsed());
    }
    Object prevValue = e.getValue();
    if (!valueMatcher.matches(prevValue, null, newValue)) {
        command.fail();
        return prevValue;
    }
    return performPut(e, ctx, valueMatcher, key, newValue, metadata, command, command.hasAnyFlag(FlagBitSets.PUT_FOR_STATE_TRANSFER | FlagBitSets.PUT_FOR_X_SITE_STATE_TRANSFER));
}
Also used : ValueMatcher(org.infinispan.commands.write.ValueMatcher) Metadata(org.infinispan.metadata.Metadata) InternalMetadataImpl(org.infinispan.metadata.impl.InternalMetadataImpl) MVCCEntry(org.infinispan.container.entries.MVCCEntry)

Example 3 with ValueMatcher

use of org.infinispan.commands.write.ValueMatcher in project infinispan by infinispan.

the class CallInterceptor method visitRemoveExpiredCommand.

@Override
public Object visitRemoveExpiredCommand(InvocationContext ctx, RemoveExpiredCommand command) throws Throwable {
    Object key = command.getKey();
    MVCCEntry e = (MVCCEntry) ctx.lookupEntry(key);
    Metadata metadata = command.getMetadata();
    // When it isn't the primary owner, just accept the removal as is, trusting the primary did the appropriate checks
    if (command.hasAnyFlag(FlagBitSets.BACKUP_WRITE)) {
        if (log.isTraceEnabled()) {
            log.trace("Removing expired entry without checks as we are backup as primary already performed them");
        }
        e.setExpired(true);
        return performRemove(e, ctx, ValueMatcher.MATCH_ALWAYS, key, e.getValue() != null ? e.getValue() : null, command.getValue(), metadata, false, command);
    }
    if (e != null && !e.isRemoved()) {
        Object prevValue = e.getValue();
        Object optionalValue = command.getValue();
        Long lifespan = command.getLifespan();
        ValueMatcher valueMatcher = command.getValueMatcher();
        // We also skip checks if lifespan is null as this is a max idle expiration
        if (lifespan == null || command.hasAnyFlag(FlagBitSets.SKIP_SHARED_CACHE_STORE)) {
            if (valueMatcher.matches(prevValue, optionalValue, null)) {
                e.setExpired(true);
                return performRemove(e, ctx, valueMatcher, key, prevValue, optionalValue, metadata, false, command);
            }
        } else if (versionFromEntry(e) == nonExistentVersion) {
            // If we have a value though we should verify it matches the value as well
            if (optionalValue == null || valueMatcher.matches(prevValue, optionalValue, null)) {
                e.setExpired(true);
                return performRemove(e, ctx, valueMatcher, key, prevValue, optionalValue, metadata, false, command);
            }
        } else if (e.getLifespan() > 0 && e.getLifespan() == lifespan) {
            // Lastly if there is metadata we have to verify it equals our lifespan and the value match.
            if (valueMatcher.matches(prevValue, optionalValue, null)) {
                // expire should give a good enough buffer range to not create a false positive.
                if (ExpiryHelper.isExpiredMortal(lifespan, e.getCreated(), timeService.wallClockTime() + CLOCK_BUFFER)) {
                    if (log.isTraceEnabled()) {
                        log.tracef("Removing entry as its lifespan and value match and it created on %s with a current time of %s", e.getCreated(), timeService.wallClockTime());
                    }
                    e.setExpired(true);
                    return performRemove(e, ctx, valueMatcher, key, prevValue, optionalValue, metadata, false, command);
                } else if (log.isTraceEnabled()) {
                    log.tracef("Cannot remove entry due to it not being expired - this can be caused by different " + "clocks on nodes or a concurrent write");
                }
            } else if (log.isTraceEnabled()) {
                log.tracef("Cannot remove entry due to the value not being equal. Matcher: %s, PrevValue: %s, ExpectedValue: %s. Double check equality is working for the value", valueMatcher, prevValue, optionalValue);
            }
        } else if (log.isTraceEnabled()) {
            log.trace("Cannot remove entry as its lifespan or value do not match");
        }
    } else {
        if (log.isTraceEnabled()) {
            log.trace("Nothing to remove since the entry doesn't exist in the context or it is already removed - assume command was successful");
        }
        return true;
    }
    command.fail();
    return false;
}
Also used : ValueMatcher(org.infinispan.commands.write.ValueMatcher) Metadata(org.infinispan.metadata.Metadata) MVCCEntry(org.infinispan.container.entries.MVCCEntry)

Example 4 with ValueMatcher

use of org.infinispan.commands.write.ValueMatcher in project infinispan by infinispan.

the class CallInterceptor method visitReplaceCommand.

@Override
public Object visitReplaceCommand(InvocationContext ctx, ReplaceCommand command) throws Throwable {
    ValueMatcher valueMatcher = command.getValueMatcher();
    // It's not worth looking up the entry if we're never going to apply the change.
    if (valueMatcher == ValueMatcher.MATCH_NEVER) {
        command.fail();
        // TODO: this seems like a bug.. ?
        return null;
    }
    Object key = command.getKey();
    // noinspection unchecked
    MVCCEntry<Object, Object> e = (MVCCEntry) ctx.lookupEntry(key);
    // We need the null check as in non-tx caches we don't always wrap the entry on the origin
    Object prevValue = e.getValue();
    Object newValue = command.getNewValue();
    Object expectedValue = command.getOldValue();
    if (valueMatcher.matches(prevValue, expectedValue, newValue)) {
        e.setChanged(true);
        e.setValue(newValue);
        Metadata newMetadata = command.getMetadata();
        Metadata prevMetadata = e.getMetadata();
        CompletionStage<Void> stage = cacheNotifier.notifyCacheEntryModified(key, newValue, newMetadata, expectedValue == null ? prevValue : expectedValue, prevMetadata, true, ctx, command);
        Metadatas.updateMetadata(e, newMetadata);
        updateStoreFlags(command, e);
        return delayedValue(stage, expectedValue == null ? prevValue : true);
    }
    command.fail();
    return expectedValue == null ? prevValue : false;
}
Also used : ValueMatcher(org.infinispan.commands.write.ValueMatcher) Metadata(org.infinispan.metadata.Metadata) MVCCEntry(org.infinispan.container.entries.MVCCEntry)

Example 5 with ValueMatcher

use of org.infinispan.commands.write.ValueMatcher in project infinispan by infinispan.

the class BaseDistributionInterceptor method primaryReturnHandler.

protected Object primaryReturnHandler(InvocationContext ctx, AbstractDataWriteCommand command, Object localResult) {
    if (!command.isSuccessful()) {
        if (log.isTraceEnabled())
            log.tracef("Skipping the replication of the conditional command as it did not succeed on primary owner (%s).", command);
        return localResult;
    }
    LocalizedCacheTopology cacheTopology = checkTopologyId(command);
    int segment = SegmentSpecificCommand.extractSegment(command, command.getKey(), keyPartitioner);
    DistributionInfo distributionInfo = cacheTopology.getSegmentDistribution(segment);
    Collection<Address> owners = distributionInfo.writeOwners();
    if (owners.size() == 1) {
        // There are no backups, skip the replication part.
        return localResult;
    }
    // Cache the matcher and reset it if we get OOTE (or any other exception) from backup
    ValueMatcher originalMatcher = command.getValueMatcher();
    // Ignore the previous value on the backup owners
    command.setValueMatcher(ValueMatcher.MATCH_ALWAYS);
    if (!isSynchronous(command)) {
        if (isReplicated) {
            rpcManager.sendToAll(command, DeliverOrder.PER_SENDER);
        } else {
            rpcManager.sendToMany(owners, command, DeliverOrder.PER_SENDER);
        }
        // Switch to the retry policy, in case the primary owner changes before we commit locally
        command.setValueMatcher(originalMatcher.matcherForRetry());
        return localResult;
    }
    VoidResponseCollector collector = VoidResponseCollector.ignoreLeavers();
    RpcOptions rpcOptions = rpcManager.getSyncRpcOptions();
    // Mark the command as a backup write so it can skip some checks
    command.addFlags(FlagBitSets.BACKUP_WRITE);
    CompletionStage<Void> remoteInvocation = isReplicated ? rpcManager.invokeCommandOnAll(command, collector, rpcOptions) : rpcManager.invokeCommand(owners, command, collector, rpcOptions);
    return asyncValue(remoteInvocation.handle((ignored, t) -> {
        // Unset the backup write bit as the command will be retried
        command.setFlagsBitSet(command.getFlagsBitSet() & ~FlagBitSets.BACKUP_WRITE);
        // Switch to the retry policy, in case the primary owner changed and the write already succeeded on the new primary
        command.setValueMatcher(originalMatcher.matcherForRetry());
        CompletableFutures.rethrowExceptionIfPresent(t);
        return localResult;
    }));
}
Also used : WriteCommand(org.infinispan.commands.write.WriteCommand) Arrays(java.util.Arrays) GetCacheEntryCommand(org.infinispan.commands.read.GetCacheEntryCommand) CacheNotFoundResponse(org.infinispan.remoting.responses.CacheNotFoundResponse) LogFactory(org.infinispan.util.logging.LogFactory) UnsureResponse(org.infinispan.remoting.responses.UnsureResponse) GetKeysInGroupCommand(org.infinispan.commands.remote.GetKeysInGroupCommand) InvocationContext(org.infinispan.context.InvocationContext) CompletableFutures(org.infinispan.util.concurrent.CompletableFutures) TxInvocationContext(org.infinispan.context.impl.TxInvocationContext) OutdatedTopologyException(org.infinispan.statetransfer.OutdatedTopologyException) Map(java.util.Map) RpcOptions(org.infinispan.remoting.rpc.RpcOptions) ConsistentHash(org.infinispan.distribution.ch.ConsistentHash) Collection(java.util.Collection) InvocationSuccessFunction(org.infinispan.interceptors.InvocationSuccessFunction) ResponseCollector(org.infinispan.remoting.transport.ResponseCollector) List(java.util.List) SingletonMapResponseCollector(org.infinispan.remoting.transport.impl.SingletonMapResponseCollector) CompletionStage(java.util.concurrent.CompletionStage) Stream(java.util.stream.Stream) SuccessfulResponse(org.infinispan.remoting.responses.SuccessfulResponse) InternalCacheValue(org.infinispan.container.entries.InternalCacheValue) FlagAffectedCommand(org.infinispan.commands.FlagAffectedCommand) TopologyAffectedCommand(org.infinispan.commands.TopologyAffectedCommand) ArrayCollector(org.infinispan.commons.util.ArrayCollector) InternalCacheEntry(org.infinispan.container.entries.InternalCacheEntry) HashMap(java.util.HashMap) GetAllCommand(org.infinispan.commands.read.GetAllCommand) RemoteValueRetrievedListener(org.infinispan.distribution.RemoteValueRetrievedListener) Function(java.util.function.Function) ReadOnlyKeyCommand(org.infinispan.commands.functional.ReadOnlyKeyCommand) InternalExpirationManager(org.infinispan.expiration.impl.InternalExpirationManager) ArrayList(java.util.ArrayList) Start(org.infinispan.factories.annotations.Start) MapResponseCollector(org.infinispan.remoting.transport.impl.MapResponseCollector) FlagBitSets(org.infinispan.context.impl.FlagBitSets) AbstractDataWriteCommand(org.infinispan.commands.write.AbstractDataWriteCommand) KeyPartitioner(org.infinispan.distribution.ch.KeyPartitioner) SingleResponseCollector(org.infinispan.remoting.transport.impl.SingleResponseCollector) ClusteredGetCommand(org.infinispan.commands.remote.ClusteredGetCommand) Log(org.infinispan.util.logging.Log) BiConsumer(java.util.function.BiConsumer) VoidResponseCollector(org.infinispan.remoting.transport.impl.VoidResponseCollector) AbstractDataCommand(org.infinispan.commands.read.AbstractDataCommand) SegmentSpecificCommand(org.infinispan.commands.SegmentSpecificCommand) DataWriteCommand(org.infinispan.commands.write.DataWriteCommand) ValueMatcher(org.infinispan.commands.write.ValueMatcher) ClearCommand(org.infinispan.commands.write.ClearCommand) Address(org.infinispan.remoting.transport.Address) ExceptionResponse(org.infinispan.remoting.responses.ExceptionResponse) Response(org.infinispan.remoting.responses.Response) ClusteringInterceptor(org.infinispan.interceptors.impl.ClusteringInterceptor) ReplicableCommand(org.infinispan.commands.ReplicableCommand) GetKeyValueCommand(org.infinispan.commands.read.GetKeyValueCommand) CacheEntry(org.infinispan.container.entries.CacheEntry) ValidResponse(org.infinispan.remoting.responses.ValidResponse) Inject(org.infinispan.factories.annotations.Inject) ReadOnlyManyCommand(org.infinispan.commands.functional.ReadOnlyManyCommand) LocalizedCacheTopology(org.infinispan.distribution.LocalizedCacheTopology) GlobalTransaction(org.infinispan.transaction.xa.GlobalTransaction) DistributionInfo(org.infinispan.distribution.DistributionInfo) VisitableCommand(org.infinispan.commands.VisitableCommand) DeliverOrder(org.infinispan.remoting.inboundhandler.DeliverOrder) Collections(java.util.Collections) BaseClusteredReadCommand(org.infinispan.commands.remote.BaseClusteredReadCommand) TimeService(org.infinispan.commons.time.TimeService) NullCacheEntry(org.infinispan.container.entries.NullCacheEntry) RpcOptions(org.infinispan.remoting.rpc.RpcOptions) Address(org.infinispan.remoting.transport.Address) ValueMatcher(org.infinispan.commands.write.ValueMatcher) VoidResponseCollector(org.infinispan.remoting.transport.impl.VoidResponseCollector) LocalizedCacheTopology(org.infinispan.distribution.LocalizedCacheTopology) DistributionInfo(org.infinispan.distribution.DistributionInfo)

Aggregations

ValueMatcher (org.infinispan.commands.write.ValueMatcher)8 MVCCEntry (org.infinispan.container.entries.MVCCEntry)6 Metadata (org.infinispan.metadata.Metadata)6 Collection (java.util.Collection)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 CompletionStage (java.util.concurrent.CompletionStage)2 Function (java.util.function.Function)2 ReplicableCommand (org.infinispan.commands.ReplicableCommand)2 VisitableCommand (org.infinispan.commands.VisitableCommand)2 AbstractDataWriteCommand (org.infinispan.commands.write.AbstractDataWriteCommand)2 DataWriteCommand (org.infinispan.commands.write.DataWriteCommand)2 WriteCommand (org.infinispan.commands.write.WriteCommand)2 CacheEntry (org.infinispan.container.entries.CacheEntry)2 InvocationContext (org.infinispan.context.InvocationContext)2 DistributionInfo (org.infinispan.distribution.DistributionInfo)2 LocalizedCacheTopology (org.infinispan.distribution.LocalizedCacheTopology)2 Inject (org.infinispan.factories.annotations.Inject)2 Response (org.infinispan.remoting.responses.Response)2 RpcOptions (org.infinispan.remoting.rpc.RpcOptions)2