use of org.infinispan.statetransfer.InboundTransferTask in project infinispan by infinispan.
the class ScatteredStateConsumerImpl method requestKeyTransfer.
private void requestKeyTransfer(IntSet segments) {
boolean isTransferringKeys = false;
synchronized (transferMapsLock) {
List<Address> members = new ArrayList<>(cacheTopology.getActualMembers());
// Reorder the member set to distibute load more evenly
Collections.shuffle(members);
for (Address source : members) {
if (source.equals(rpcManager.getAddress())) {
continue;
}
isTransferringKeys = true;
InboundTransferTask inboundTransfer = new InboundTransferTask(segments, source, cacheTopology.getTopologyId(), rpcManager, commandsFactory, configuration.clustering().stateTransfer().timeout(), cacheName, true);
addTransfer(inboundTransfer, segments);
stateRequestExecutor.executeAsync(() -> {
log.tracef("Requesting keys for segments %s from %s", inboundTransfer.getSegments(), inboundTransfer.getSource());
return inboundTransfer.requestKeys().whenComplete((nil, e) -> onTaskCompletion(inboundTransfer));
});
}
}
if (!isTransferringKeys) {
log.trace("No keys in transfer, finishing segments " + segments);
for (int segment : segments) {
svm.notifyKeyTransferFinished(segment, false, false);
}
notifyEndOfStateTransferIfNeeded();
}
}
use of org.infinispan.statetransfer.InboundTransferTask in project infinispan by infinispan.
the class ScatteredStateConsumerImpl method onTaskCompletion.
@Override
protected void onTaskCompletion(InboundTransferTask inboundTransfer) {
// a bit of overkill since we start these tasks for single segment
IntSet completedSegments = IntSets.immutableEmptySet();
if (log.isTraceEnabled())
log.tracef("Inbound transfer finished %s: %s", inboundTransfer, inboundTransfer.isCompletedSuccessfully() ? "successfully" : "unsuccessfuly");
synchronized (transferMapsLock) {
// transferMapsLock is held when all the tasks are added so we see that all of them are done
for (PrimitiveIterator.OfInt iter = inboundTransfer.getSegments().iterator(); iter.hasNext(); ) {
int segment = iter.nextInt();
List<InboundTransferTask> transfers = transfersBySegment.get(segment);
if (transfers == null) {
// It is possible that two task complete concurrently, one of them checks is all tasks
// for given segments have been completed successfully and (finding out that it's true)
// removes the transfer for given segment. The second task arrives and finds out that
// its record int transfersBySegment is gone, but that's OK, as the segment has been handled.
log.tracef("Transfers for segment %d have not been found.", segment);
} else {
// We are removing here rather than in removeTransfer, because we need to know if we're the last
// finishing task.
transfers.remove(inboundTransfer);
if (transfers.isEmpty()) {
transfersBySegment.remove(segment);
if (log.isTraceEnabled()) {
log.tracef("All transfer tasks for segment %d have completed.", segment);
}
svm.notifyKeyTransferFinished(segment, inboundTransfer.isCompletedSuccessfully(), inboundTransfer.isCancelled());
switch(completedSegments.size()) {
case 0:
completedSegments = IntSets.immutableSet(segment);
break;
case 1:
completedSegments = IntSets.mutableCopyFrom(completedSegments);
// Intentional falls through
default:
completedSegments.set(segment);
}
}
}
}
}
if (completedSegments.isEmpty()) {
log.tracef("Not requesting any values yet because no segments have been completed.");
} else if (inboundTransfer.isCompletedSuccessfully()) {
log.tracef("Requesting values from segments %s, for in-memory keys", completedSegments);
dataContainer.forEach(completedSegments, ice -> {
// TODO: could the version be null in here?
if (ice.getMetadata() instanceof RemoteMetadata) {
Address backup = ((RemoteMetadata) ice.getMetadata()).getAddress();
retrieveEntry(ice.getKey(), backup);
for (Address member : cacheTopology.getActualMembers()) {
if (!member.equals(backup)) {
invalidate(ice.getKey(), ice.getMetadata().version(), member);
}
}
} else {
backupEntry(ice);
for (Address member : nonBackupAddresses) {
invalidate(ice.getKey(), ice.getMetadata().version(), member);
}
}
});
// With passivation, some key could be activated here and we could miss it,
// but then it should be broadcast-loaded in PrefetchInvalidationInterceptor
Publisher<MarshallableEntry<Object, Object>> persistencePublisher = persistenceManager.publishEntries(completedSegments, k -> dataContainer.peek(k) == null, true, true, Configurations::isStateTransferStore);
try {
blockingSubscribe(Flowable.fromPublisher(persistencePublisher).doOnNext(me -> {
try {
Metadata metadata = me.getMetadata();
if (metadata instanceof RemoteMetadata) {
Address backup = ((RemoteMetadata) metadata).getAddress();
retrieveEntry(me.getKey(), backup);
for (Address member : cacheTopology.getActualMembers()) {
if (!member.equals(backup)) {
invalidate(me.getKey(), metadata.version(), member);
}
}
} else {
backupEntry(entryFactory.create(me.getKey(), me.getValue(), me.getMetadata()));
for (Address member : nonBackupAddresses) {
invalidate(me.getKey(), metadata.version(), member);
}
}
} catch (CacheException e) {
log.failedLoadingValueFromCacheStore(me.getKey(), e);
}
}));
} catch (CacheException e) {
PERSISTENCE.failedLoadingKeysFromCacheStore(e);
}
}
boolean lastTransfer = false;
synchronized (transferMapsLock) {
inboundSegments.removeAll(completedSegments);
log.tracef("Unfinished inbound segments: " + inboundSegments);
if (inboundSegments.isEmpty()) {
lastTransfer = true;
}
}
if (lastTransfer) {
for (Map.Entry<Address, BlockingQueue<Object>> pair : retrievedEntries.entrySet()) {
BlockingQueue<Object> queue = pair.getValue();
List<Object> keys = new ArrayList<>(queue.size());
queue.drainTo(keys);
if (!keys.isEmpty()) {
getValuesAndApply(pair.getKey(), keys);
}
}
List<InternalCacheEntry<?, ?>> entries = new ArrayList<>(backupQueue.size());
backupQueue.drainTo(entries);
if (!entries.isEmpty()) {
backupEntries(entries);
}
for (Map.Entry<Address, BlockingQueue<KeyAndVersion>> pair : invalidations.entrySet()) {
BlockingQueue<KeyAndVersion> queue = pair.getValue();
List<KeyAndVersion> list = new ArrayList<>(queue.size());
queue.drainTo(list);
if (!list.isEmpty()) {
invalidate(list, pair.getKey());
}
}
}
// we must not remove the transfer before the requests for values are sent
// as we could notify the end of rebalance too soon
removeTransfer(inboundTransfer);
if (lastTransfer) {
if (log.isTraceEnabled())
log.tracef("Inbound transfer removed, chunk counter is %s", chunkCounter.get());
if (chunkCounter.get() == 0) {
// No values to transfer after all the keys were received, we can end state transfer immediately
notifyEndOfStateTransferIfNeeded();
}
}
}
use of org.infinispan.statetransfer.InboundTransferTask in project infinispan by infinispan.
the class StateReceiverTest method initTransferTaskMock.
private void initTransferTaskMock(CompletableFuture<Void> completableFuture) {
InboundTransferTask task = mock(InboundTransferTask.class);
when(task.requestSegments()).thenReturn(completableFuture);
doReturn(task).when(stateReceiver).createTransferTask(any(Integer.class), any(Address.class), any(CacheTopology.class), any(Long.class));
}
use of org.infinispan.statetransfer.InboundTransferTask in project infinispan by infinispan.
the class StateReceiverTest method testRequestCanBeCancelledDuringTransfer.
@Test(expectedExceptions = CancellationException.class)
public void testRequestCanBeCancelledDuringTransfer() throws Exception {
// Init transfer that blocks and call stop() so the future should complete with CancellationException
InboundTransferTask task = mock(InboundTransferTask.class);
when(task.requestSegments()).thenAnswer(invocationOnMock -> {
TestingUtil.sleepThread(1000);
return CompletableFuture.completedFuture(new HashMap<>());
});
doReturn(task).when(stateReceiver).createTransferTask(any(Integer.class), any(Address.class), any(CacheTopology.class), any(Long.class));
CompletableFuture<List<Map<Address, CacheEntry<Object, Object>>>> future = stateReceiver.getAllReplicasForSegment(0, localizedCacheTopology, 10000);
future.whenComplete((result, throwable) -> {
assertNull(result);
assertNotNull(throwable);
assertTrue(throwable instanceof CancellationException);
});
stateReceiver.stop();
future.get();
}
Aggregations