<R> R performOperation( Function<? super S2, ? extends R> function, ResultsAccumulator<R> remoteResults, Predicate<? super R> earlyTerminatePredicate) { ConsistentHash ch = dm.getConsistentHash(); TerminalOperation<R> op = new SingleRunOperation( intermediateOperations, supplierForSegments(ch, segmentsToFilter, null), function); Object id = csm.remoteStreamOperation( getParallelDistribution(), parallel, ch, segmentsToFilter, keysToFilter, Collections.emptyMap(), includeLoader, op, remoteResults, earlyTerminatePredicate); try { R localValue = op.performOperation(); remoteResults.onCompletion(null, Collections.emptySet(), localValue); if (id != null) { try { if ((earlyTerminatePredicate == null || !earlyTerminatePredicate.test(localValue)) && !csm.awaitCompletion(id, timeout, timeoutUnit)) { throw new TimeoutException(); } } catch (InterruptedException e) { throw new CacheException(e); } } log.tracef("Finished operation for id %s", id); return remoteResults.currentValue; } finally { csm.forgetOperation(id); } }
<R> R performOperationRehashAware( Function<? super S2, ? extends R> function, boolean retryOnRehash, ResultsAccumulator<R> remoteResults, Predicate<? super R> earlyTerminatePredicate) { Set<Integer> segmentsToProcess = segmentsToFilter; TerminalOperation<R> op; do { ConsistentHash ch = dm.getReadConsistentHash(); if (retryOnRehash) { op = new SegmentRetryingOperation( intermediateOperations, supplierForSegments(ch, segmentsToProcess, null), function); } else { op = new SingleRunOperation( intermediateOperations, supplierForSegments(ch, segmentsToProcess, null), function); } Object id = csm.remoteStreamOperationRehashAware( getParallelDistribution(), parallel, ch, segmentsToProcess, keysToFilter, Collections.emptyMap(), includeLoader, op, remoteResults, earlyTerminatePredicate); try { R localValue; boolean localRun = ch.getMembers().contains(localAddress); if (localRun) { localValue = op.performOperation(); // TODO: we can do this more efficiently - since we drop all results locally if (dm.getReadConsistentHash().equals(ch)) { Set<Integer> ourSegments = ch.getPrimarySegmentsForOwner(localAddress); if (segmentsToProcess != null) { ourSegments.retainAll(segmentsToProcess); } remoteResults.onCompletion(null, ourSegments, localValue); } else { if (segmentsToProcess != null) { Set<Integer> ourSegments = ch.getPrimarySegmentsForOwner(localAddress); ourSegments.retainAll(segmentsToProcess); remoteResults.onSegmentsLost(ourSegments); } else { remoteResults.onSegmentsLost(ch.getPrimarySegmentsForOwner(localAddress)); } } } else { // This isn't actually used because localRun short circuits first localValue = null; } if (id != null) { try { if ((!localRun || earlyTerminatePredicate == null || !earlyTerminatePredicate.test(localValue)) && !csm.awaitCompletion(id, timeout, timeoutUnit)) { throw new TimeoutException(); } } catch (InterruptedException e) { throw new CacheException(e); } } if (!remoteResults.lostSegments.isEmpty()) { segmentsToProcess = new HashSet<>(remoteResults.lostSegments); remoteResults.lostSegments.clear(); log.tracef("Found %s lost segments for identifier %s", segmentsToProcess, id); } else { // If we didn't lose any segments we don't need to process anymore if (segmentsToProcess != null) { segmentsToProcess = null; } log.tracef("Finished rehash aware operation for id %s", id); } } finally { csm.forgetOperation(id); } } while (segmentsToProcess != null && !segmentsToProcess.isEmpty()); return remoteResults.currentValue; }