org.infinispan.scattered.impl.ScatteredStateProviderImpl Maven / Gradle / Ivy
package org.infinispan.scattered.impl;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.RemoteMetadata;
import org.infinispan.container.versioning.SimpleClusteredVersion;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.metadata.InternalMetadata;
import org.infinispan.metadata.Metadata;
import org.infinispan.remoting.rpc.ResponseMode;
import org.infinispan.remoting.rpc.RpcOptions;
import org.infinispan.remoting.transport.Address;
import org.infinispan.scattered.ScatteredStateProvider;
import org.infinispan.scattered.ScatteredVersionManager;
import org.infinispan.statetransfer.OutboundTransferTask;
import org.infinispan.statetransfer.StateChunk;
import org.infinispan.statetransfer.StateProviderImpl;
import org.infinispan.topology.CacheTopology;
import org.infinispan.util.concurrent.CompletableFutures;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* @author Radim Vansa <[email protected]>
*/
public class ScatteredStateProviderImpl extends StateProviderImpl implements ScatteredStateProvider {
protected ScatteredVersionManager svm;
private RpcOptions syncIgnoreLeavers;
@Inject
public void init(ScatteredVersionManager svm) {
this.svm = svm;
}
@Override
public void start() {
super.start();
syncIgnoreLeavers = rpcManager.getRpcOptionsBuilder(ResponseMode.SYNCHRONOUS_IGNORE_LEAVERS).build();
}
@Override
public CompletableFuture onTopologyUpdate(CacheTopology cacheTopology, boolean isRebalance) {
if (isRebalance) {
// TODO [rvansa]: do this only when member was lost
return replicateAndInvalidate(cacheTopology);
} else {
return CompletableFutures.completedNull();
}
}
// This method handles creating the backup copy and invalidation on other nodes for segments
// that this node keeps from previous topology.
private CompletableFuture replicateAndInvalidate(CacheTopology cacheTopology) {
Address nextMember = getNextMember(cacheTopology);
if (nextMember != null) {
HashSet otherMembers = new HashSet<>(cacheTopology.getActualMembers());
Address localAddress = rpcManager.getAddress();
otherMembers.remove(localAddress);
otherMembers.remove(nextMember);
Set oldSegments = cacheTopology.getCurrentCH().getMembers().contains(localAddress) ?
new HashSet<>(cacheTopology.getCurrentCH().getSegmentsForOwner(localAddress)) : Collections.emptySet();
oldSegments.retainAll(cacheTopology.getPendingCH().getSegmentsForOwner(localAddress));
log.trace("Segments to replicate and invalidate: " + oldSegments);
if (oldSegments.isEmpty()) {
return CompletableFutures.completedNull();
}
// we'll start at 1, so the counter will never drop to 0 until we send all chunks
AtomicInteger outboundInvalidations = new AtomicInteger(1);
CompletableFuture outboundTaskFuture = new CompletableFuture<>();
OutboundTransferTask outboundTransferTask = new OutboundTransferTask(nextMember, oldSegments,
chunkSize,
cacheTopology.getTopologyId(), keyPartitioner,
task -> {
if (outboundInvalidations.decrementAndGet() == 0) {
outboundTaskFuture.complete(null);
}
}, chunks -> invalidateChunks(chunks, otherMembers, outboundInvalidations, outboundTaskFuture, cacheTopology),
OutboundTransferTask::defaultMapEntryFromDataContainer, OutboundTransferTask::defaultMapEntryFromStore,
dataContainer, persistenceManager, rpcManager, commandsFactory, entryFactory, timeout, cacheName, true, true);
outboundTransferTask.execute(executorService);
return outboundTaskFuture;
} else {
return CompletableFutures.completedNull();
}
}
private void invalidateChunks(List stateChunks, Set otherMembers, AtomicInteger outboundInvalidations, CompletableFuture outboundTaskFuture, CacheTopology cacheTopology) {
int numEntries = stateChunks.stream().mapToInt(chunk -> chunk.getCacheEntries().size()).sum();
if (numEntries == 0) {
log.tracef("Nothing to invalidate");
return;
}
Object keys[] = new Object[numEntries];
int topologyIds[] = new int[numEntries];
long versions[] = new long[numEntries];
int i = 0;
for (StateChunk chunk : stateChunks) {
for (InternalCacheEntry entry : chunk.getCacheEntries()) {
// we have replicated the non-versioned entries but we won't invalidate them elsewhere
if (entry.getMetadata() != null && entry.getMetadata().version() != null) {
keys[i] = entry.getKey();
SimpleClusteredVersion version = (SimpleClusteredVersion) entry.getMetadata().version();
topologyIds[i] = version.topologyId;
versions[i] = version.version;
++i;
}
}
}
if (trace) {
log.tracef("Invalidating %d entries from segments %s", numEntries, stateChunks.stream().map(chunk -> chunk.getSegmentId()).collect(Collectors.toList()));
}
outboundInvalidations.incrementAndGet();
rpcManager.invokeRemotelyAsync(otherMembers, commandsFactory.buildInvalidateVersionsCommand(cacheTopology.getTopologyId(), keys, topologyIds, versions, true),
syncIgnoreLeavers).whenComplete((r, t) -> {
try {
if (t != null) {
log.failedInvalidatingRemoteCache(t);
}
} finally {
if (outboundInvalidations.decrementAndGet() == 0) {
outboundTaskFuture.complete(null);
}
}
});
}
private Address getNextMember(CacheTopology cacheTopology) {
Address myAddress = rpcManager.getAddress();
List members = cacheTopology.getActualMembers();
if (members.size() == 1) {
return null;
}
Iterator it = members.iterator();
while (it.hasNext()) {
Address member = it.next();
if (member.equals(myAddress)) {
if (it.hasNext()) {
return it.next();
} else {
return members.get(0);
}
}
}
throw new IllegalStateException();
}
@Override
public void startKeysTransfer(Set segments, Address origin) {
CacheTopology cacheTopology = stateConsumer.getCacheTopology();
Address localAddress = rpcManager.getAddress();
OutboundTransferTask outboundTransferTask = new OutboundTransferTask(origin, segments, chunkSize,
cacheTopology.getTopologyId(), keyPartitioner,
this::onTaskCompletion, list -> {},
(ice, ef) -> {
Metadata metadata = ice.getMetadata();
if (metadata != null && metadata.version() != null) {
return ef.create(ice.getKey(), null, new RemoteMetadata(localAddress, metadata.version()));
} else {
return null;
}
},
(me, ef) -> {
InternalMetadata metadata = me.getMetadata();
if (metadata != null && metadata.version() != null) {
return ef.create(me.getKey(), null, new RemoteMetadata(localAddress, metadata.version()));
} else {
return null;
}
}, dataContainer, persistenceManager, rpcManager, commandsFactory, entryFactory, timeout, cacheName, true, false);
addTransfer(outboundTransferTask);
outboundTransferTask.execute(executorService);
}
@Override
public CompletableFuture confirmRevokedSegments(int topologyId) {
return stateTransferLock.topologyFuture(topologyId);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy