use of org.infinispan.container.entries.InternalCacheEntry 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.container.entries.InternalCacheEntry in project infinispan by infinispan.
the class ScatteredStateConsumerImpl method backupEntries.
private void backupEntries(List<InternalCacheEntry<?, ?>> entries) {
long incrementedCounter = chunkCounter.incrementAndGet();
if (log.isTraceEnabled())
log.tracef("Backing up entries, chunk counter is %d", incrementedCounter);
Map<Object, InternalCacheValue<?>> map = new HashMap<>();
for (InternalCacheEntry<?, ?> entry : entries) {
map.put(entry.getKey(), entry.toInternalCacheValue());
}
PutMapCommand putMapCommand = commandsFactory.buildPutMapCommand(map, null, STATE_TRANSFER_FLAGS);
putMapCommand.setTopologyId(rpcManager.getTopologyId());
rpcManager.invokeCommand(backupAddress, putMapCommand, SingleResponseCollector.validOnly(), rpcManager.getSyncRpcOptions()).whenComplete(((response, throwable) -> {
try {
if (throwable != null) {
log.failedOutBoundTransferExecution(throwable);
}
} finally {
long decrementedCounter = chunkCounter.decrementAndGet();
if (log.isTraceEnabled())
log.tracef("Backed up entries, chunk counter is %d", decrementedCounter);
if (decrementedCounter == 0) {
notifyEndOfStateTransferIfNeeded();
}
}
}));
}
use of org.infinispan.container.entries.InternalCacheEntry in project infinispan by infinispan.
the class ScatteredStateProviderImpl method invalidateChunks.
private void invalidateChunks(Collection<StateChunk> stateChunks, Set<Address> otherMembers, AtomicInteger outboundInvalidations, CompletableFuture<Void> invalidationFuture, 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.getTopologyId();
versions[i] = version.getVersion();
++i;
}
}
}
if (log.isTraceEnabled()) {
log.tracef("Invalidating %d entries from segments %s", numEntries, stateChunks.stream().map(StateChunk::getSegmentId).collect(Collectors.toList()));
}
outboundInvalidations.incrementAndGet();
rpcManager.invokeCommand(otherMembers, commandsFactory.buildInvalidateVersionsCommand(cacheTopology.getTopologyId(), keys, topologyIds, versions, true), MapResponseCollector.ignoreLeavers(otherMembers.size()), rpcManager.getSyncRpcOptions()).whenComplete((r, t) -> {
try {
if (t != null) {
log.failedInvalidatingRemoteCache(t);
}
} finally {
if (outboundInvalidations.decrementAndGet() == 0) {
invalidationFuture.complete(null);
}
}
});
}
use of org.infinispan.container.entries.InternalCacheEntry in project infinispan by infinispan.
the class L1WriteSynchronizerTest method testSpawnedThreadBlockingValueTimeWait.
@Test
public void testSpawnedThreadBlockingValueTimeWait() throws InterruptedException, ExecutionException, TimeoutException {
Object value = new Object();
Future future = fork(() -> sync.get(5, TimeUnit.SECONDS));
// This should not return since we haven't signaled the sync yet
try {
future.get(50, TimeUnit.MILLISECONDS);
fail("Should have thrown a timeout exception");
} catch (TimeoutException e) {
// This should time out exception
}
InternalCacheEntry ice = new ImmortalCacheEntry(value, value);
sync.runL1UpdateIfPossible(ice);
assertEquals(ice, future.get(1, TimeUnit.SECONDS));
}
use of org.infinispan.container.entries.InternalCacheEntry in project infinispan by infinispan.
the class L1WriteSynchronizerTest method verifyDCUpdate.
private void verifyDCUpdate(long iceLifespan, boolean shouldBeIceLifespan) {
Object value = new Object();
Object key = new Object();
InternalCacheEntry ice = when(mock(InternalCacheEntry.class, RETURNS_DEEP_STUBS).getValue()).thenReturn(value).getMock();
when(ice.getKey()).thenReturn(key);
when(ice.getLifespan()).thenReturn(iceLifespan);
sync.runL1UpdateIfPossible(ice);
verify(dc).put(eq(key), eq(value), any(Metadata.class));
Metadata.Builder verifier = verify(ice.getMetadata().builder());
verifier.lifespan(shouldBeIceLifespan ? iceLifespan : l1Timeout);
verifier.maxIdle(-1);
}
Aggregations