package org.infinispan.stream.impl.tx;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.infinispan.CacheStream;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.context.impl.LocalTxInvocationContext;
import org.infinispan.distribution.DistributionManager;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.remoting.transport.Address;
import org.infinispan.stream.impl.AbstractCacheStream;
import org.infinispan.stream.impl.DistributedCacheStream;
import org.infinispan.stream.impl.DistributedDoubleCacheStream;
import org.infinispan.stream.impl.DistributedIntCacheStream;
import org.infinispan.stream.impl.DistributedLongCacheStream;
/**
* A distributed cache stream that also utilizes transactional awareness. Basically this adds functionality to
* take items from the local tx context and add them to the local stream that is produced to enable our stream to
* operate upon entries in the context that don't map to our segments that are normally ignored in a distributed
* stream.
* @param <R> the type of stream
*/
public class TxDistributedCacheStream<R> extends DistributedCacheStream<R> {
private final Address localAddress;
private final LocalTxInvocationContext ctx;
private final ConsistentHash hash;
public <K, V> TxDistributedCacheStream(Address localAddress, boolean parallel, DistributionManager dm,
Supplier<CacheStream<CacheEntry<K, V>>> supplier, TxClusterStreamManager<?> csm, boolean includeLoader,
int distributedBatchSize, Executor executor, ComponentRegistry registry, LocalTxInvocationContext ctx) {
super(localAddress, parallel, dm, supplier, csm, includeLoader, distributedBatchSize, executor, registry);
this.localAddress = localAddress;
this.hash = dm.getWriteConsistentHash();
this.ctx = ctx;
}
public <K, V> TxDistributedCacheStream(Address localAddress, boolean parallel, DistributionManager dm,
Supplier<CacheStream<CacheEntry<K, V>>> supplier, TxClusterStreamManager<?> csm, boolean includeLoader,
int distributedBatchSize, Executor executor, ComponentRegistry registry,
Function<? super CacheEntry<K, V>, R> function, LocalTxInvocationContext ctx) {
super(localAddress, parallel, dm, supplier, csm, includeLoader, distributedBatchSize, executor, registry, function);
this.localAddress = localAddress;
this.hash = dm.getWriteConsistentHash();
this.ctx = ctx;
}
TxDistributedCacheStream(AbstractCacheStream other, Address localAddress, ConsistentHash hash,
LocalTxInvocationContext ctx) {
super(other);
this.localAddress = localAddress;
this.hash = hash;
this.ctx = ctx;
}
@Override
protected Supplier<Stream<CacheEntry>> supplierForSegments(ConsistentHash ch, Set<Integer> targetSegments,
Set<Object> excludedKeys, boolean primaryOnly) {
return () -> {
Supplier<Stream<CacheEntry>> supplier = super.supplierForSegments(ch, targetSegments, excludedKeys, primaryOnly);
// Now we have to add entries that aren't mapped to our local segments since we are excluding those
// remotely via {@link TxClusterStreamManager} using the same hash
Set<CacheEntry> set = ctx.getLookedUpEntries().values().stream()
.filter(e -> !isPrimaryOwner(ch, e))
.collect(Collectors.toSet());
Stream<CacheEntry> suppliedStream = supplier.get();
if (!set.isEmpty()) {
return Stream.concat(set.stream(), suppliedStream);
}
return suppliedStream;
};
}
@Override
protected DistributedDoubleCacheStream doubleCacheStream() {
return new TxDistributedDoubleCacheStream(this, localAddress, hash, ctx);
}
@Override
protected DistributedLongCacheStream longCacheStream() {
return new TxDistributedLongCacheStream(this, localAddress, hash, ctx);
}
@Override
protected DistributedIntCacheStream intCacheStream() {
return new TxDistributedIntCacheStream(this, localAddress, hash, ctx);
}
}