Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ISPN-8708 Remote iteration with limited batch sends finished segments
* Use KeyWatchingListener for each publisher
- Loading branch information
Showing
9 changed files
with
257 additions
and
130 deletions.
There are no files selected for viewing
65 changes: 65 additions & 0 deletions
65
core/src/main/java/org/infinispan/stream/impl/AbstractRehashPublisherDecorator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,65 @@ | |||
package org.infinispan.stream.impl; | |||
|
|||
import java.util.PrimitiveIterator; | |||
import java.util.function.Consumer; | |||
import java.util.function.Supplier; | |||
|
|||
import org.infinispan.commons.util.IntSet; | |||
import org.infinispan.commons.util.SmallIntSet; | |||
import org.infinispan.distribution.DistributionManager; | |||
import org.infinispan.distribution.ch.ConsistentHash; | |||
import org.infinispan.remoting.transport.Address; | |||
import org.infinispan.util.logging.Log; | |||
import org.reactivestreams.Publisher; | |||
|
|||
import io.reactivex.Flowable; | |||
|
|||
/** | |||
* Abstract publisher decorator that is used to notify segment listener of loss of segments while entries are | |||
* being retrieved. | |||
* @author wburns | |||
* @since 9.0 | |||
*/ | |||
public abstract class AbstractRehashPublisherDecorator<S> implements PublisherDecorator<S> { | |||
final AbstractCacheStream.IteratorOperation iteratorOperation; | |||
final DistributionManager dm; | |||
final Address localAddress; | |||
final Consumer<? super Supplier<PrimitiveIterator.OfInt>> lostSegments; | |||
final Consumer<Object> keyConsumer; | |||
|
|||
AbstractRehashPublisherDecorator(AbstractCacheStream.IteratorOperation iteratorOperation, DistributionManager dm, | |||
Address localAddress, Consumer<? super Supplier<PrimitiveIterator.OfInt>> lostSegments, | |||
Consumer<Object> keyConsumer) { | |||
this.iteratorOperation = iteratorOperation; | |||
this.dm = dm; | |||
this.localAddress = localAddress; | |||
this.lostSegments = lostSegments; | |||
this.keyConsumer = keyConsumer; | |||
} | |||
|
|||
abstract Log getLog(); | |||
|
|||
Publisher<S> decorateLocal(Consumer<? super Supplier<PrimitiveIterator.OfInt>> completedSegments, | |||
ConsistentHash beginningCh, boolean onlyLocal, IntSet segmentsToFilter, | |||
Publisher<S> localPublisher) { | |||
Publisher<S> convertedPublisher = Flowable.fromPublisher(localPublisher).doOnComplete(() -> { | |||
IntSet ourSegments; | |||
if (onlyLocal) { | |||
ourSegments = SmallIntSet.from(beginningCh.getSegmentsForOwner(localAddress)); | |||
} else { | |||
ourSegments = SmallIntSet.from(beginningCh.getPrimarySegmentsForOwner(localAddress)); | |||
} | |||
ourSegments.retainAll(segmentsToFilter); | |||
// This will notify both completed and suspect of segments that may not even exist or were completed before | |||
// on a rehash | |||
if (dm.getReadConsistentHash().equals(beginningCh)) { | |||
getLog().tracef("Local iterator has completed segments %s", ourSegments); | |||
completedSegments.accept((Supplier<PrimitiveIterator.OfInt>) ourSegments::iterator); | |||
} else { | |||
getLog().tracef("Local iterator segments %s are all suspect as consistent hash has changed", ourSegments); | |||
lostSegments.accept((Supplier<PrimitiveIterator.OfInt>) ourSegments::iterator); | |||
} | |||
}); | |||
return iteratorOperation.handlePublisher(convertedPublisher, keyConsumer); | |||
} | |||
} |
74 changes: 68 additions & 6 deletions
74
core/src/main/java/org/infinispan/stream/impl/CompletionRehashPublisherDecorator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,33 +1,95 @@ | |||
package org.infinispan.stream.impl; | package org.infinispan.stream.impl; | ||
|
|
||
import java.lang.invoke.MethodHandles; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.PrimitiveIterator; | import java.util.PrimitiveIterator; | ||
import java.util.function.Consumer; | import java.util.function.Consumer; | ||
import java.util.function.Supplier; | import java.util.function.Supplier; | ||
|
|
||
import org.infinispan.commons.util.IntSet; | |||
import org.infinispan.distribution.DistributionManager; | import org.infinispan.distribution.DistributionManager; | ||
import org.infinispan.distribution.ch.ConsistentHash; | |||
import org.infinispan.remoting.transport.Address; | import org.infinispan.remoting.transport.Address; | ||
import org.infinispan.util.logging.Log; | |||
import org.infinispan.util.logging.LogFactory; | |||
import org.reactivestreams.Publisher; | import org.reactivestreams.Publisher; | ||
|
|
||
import io.reactivex.Flowable; | import io.reactivex.Flowable; | ||
|
|
||
/** | /** | ||
* PublisherDecorator that only notifies a user listener of segment completion after the last entry for a given | |||
* segment has been retrieved from iteration. | |||
* @author wburns | * @author wburns | ||
* @since 9.0 | * @since 9.0 | ||
*/ | */ | ||
public class CompletionRehashPublisherDecorator<S> extends RehashPublisherDecorator<S> { | public class CompletionRehashPublisherDecorator<S> extends RehashPublisherDecorator<S> { | ||
private final KeyWatchingCompletionListener completionListener; | private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); | ||
|
|||
private final Consumer<? super Supplier<PrimitiveIterator.OfInt>> userListener; | |||
private final List<KeyWatchingCompletionListener> completionListeners; | |||
|
|
||
CompletionRehashPublisherDecorator(AbstractCacheStream.IteratorOperation iteratorOperation, DistributionManager dm, | CompletionRehashPublisherDecorator(AbstractCacheStream.IteratorOperation iteratorOperation, DistributionManager dm, | ||
Address localAddress, KeyWatchingCompletionListener completionListener, | Address localAddress, Consumer<? super Supplier<PrimitiveIterator.OfInt>> userListener, | ||
Consumer<? super Supplier<PrimitiveIterator.OfInt>> completedSegments, | Consumer<? super Supplier<PrimitiveIterator.OfInt>> completedSegments, | ||
Consumer<? super Supplier<PrimitiveIterator.OfInt>> lostSegments, Consumer<Object> keyConsumer) { | Consumer<? super Supplier<PrimitiveIterator.OfInt>> lostSegments, Consumer<Object> keyConsumer) { | ||
super(iteratorOperation, dm, localAddress, completedSegments, lostSegments, keyConsumer); | super(iteratorOperation, dm, localAddress, completedSegments, lostSegments, keyConsumer); | ||
this.completionListener = completionListener; | this.userListener = userListener; | ||
this.completionListeners = Collections.synchronizedList(new ArrayList<>(4)); | |||
} | |||
|
|||
public void valueIterated(Object obj) { | |||
for (KeyWatchingCompletionListener kwcl : completionListeners) { | |||
kwcl.valueIterated(obj); | |||
} | |||
} | |||
|
|||
public void complete() { | |||
completionListeners.forEach(KeyWatchingCompletionListener::completed); | |||
} | } | ||
|
|
||
@Override | @Override | ||
protected Publisher<S> decorateBeforeReturn(Publisher<S> publisher) { | Log getLog() { | ||
return Flowable.fromPublisher(super.decorateBeforeReturn(publisher)).doOnNext( | return log; | ||
completionListener::valueAdded); | } | ||
|
|||
@Override | |||
public Publisher<S> decorateRemote(ClusterStreamManager.RemoteIteratorPublisher<S> remotePublisher) { | |||
// We have to have a listener per remote publisher, since we receive results concurrently and we | |||
// can't properly track the completion of keys per segment without them being separated | |||
KeyWatchingCompletionListener kwcl = new KeyWatchingCompletionListener(userListener); | |||
completionListeners.add(kwcl); | |||
|
|||
Publisher<S> convertedPublisher = s -> remotePublisher.subscribe(s, i -> { | |||
// Remote we always notify the provided completed segments as it tracks segment completion | |||
// for retries | |||
completedSegments.accept(i); | |||
// however we have to wait before notifying the user segment completion until | |||
// we iterate upon the last key of the block of segments | |||
kwcl.accept(i); | |||
}, lostSegments); | |||
// We have to track each key received from this publisher as it would map to all segments when completed | |||
return Flowable.fromPublisher(iteratorOperation.handlePublisher(convertedPublisher, keyConsumer)).doOnNext( | |||
kwcl::valueAdded); | |||
} | |||
|
|||
@Override | |||
public Publisher<S> decorateLocal(ConsistentHash beginningCh, boolean onlyLocal, IntSet segmentsToFilter, | |||
Publisher<S> localPublisher) { | |||
KeyWatchingCompletionListener kwcl = new KeyWatchingCompletionListener(userListener); | |||
completionListeners.add(kwcl); | |||
|
|||
Publisher<S> convertedLocalPublisher = decorateLocal(i -> { | |||
// Remote we always notify the provided completed segments as it tracks segment completion | |||
// for retries | |||
completedSegments.accept(i); | |||
// however we have to wait before notifying the user segment completion until | |||
// we iterate upon the last key of the block of segments | |||
kwcl.accept(i); | |||
}, beginningCh, onlyLocal, segmentsToFilter, localPublisher); | |||
// We have to track each key received from this publisher as it would map to all segments when completed | |||
return Flowable.fromPublisher(iteratorOperation.handlePublisher(convertedLocalPublisher, keyConsumer)) | |||
.doOnNext(kwcl::valueAdded); | |||
} | } | ||
} | } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.