
reactor.rx.action.aggregation.BufferShiftAction Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2015 Pivotal Software Inc., Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package reactor.rx.action.aggregation;
import org.reactivestreams.Subscription;
import reactor.core.Dispatcher;
import reactor.core.dispatch.InsufficientCapacityException;
import reactor.fn.Consumer;
import reactor.fn.Pausable;
import reactor.fn.timer.Timer;
import reactor.rx.action.Action;
import reactor.rx.subscription.BatchSubscription;
import reactor.rx.subscription.PushSubscription;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author Stephane Maldini
* @since 2.0
*/
public final class BufferShiftAction extends Action> {
private final List> buckets = new LinkedList<>();
private final Consumer timeshiftTask;
private final long timeshift;
private final TimeUnit unit;
private final Timer timer;
private final int skip;
private final int batchSize;
private Pausable timeshiftRegistration;
private int index;
public BufferShiftAction(Dispatcher dispatcher, int size, int skip) {
this(dispatcher, size, skip, -1l, -1l, null, null);
}
public BufferShiftAction(final Dispatcher dispatcher, int size, int skip,
final long timeshift, final long timespan, TimeUnit unit, final Timer timer) {
super(size);
this.skip = skip;
this.batchSize = size;
if (timespan > 0 && timeshift > 0) {
final TimeUnit targetUnit = unit != null ? unit : TimeUnit.SECONDS;
final Consumer> flushTimerTask = new Consumer>() {
@Override
public void accept(List bucket) {
Iterator> it = buckets.iterator();
while (it.hasNext()) {
List itBucket = it.next();
if (bucket == itBucket) {
it.remove();
broadcastNext(bucket);
break;
}
}
}
};
this.timeshiftTask = new Consumer() {
@Override
public void accept(Long aLong) {
try {
if (!isPublishing()) {
return;
}
dispatcher.tryDispatch(null, new Consumer() {
@Override
public void accept(Void aVoid) {
final List bucket = new ArrayList();
buckets.add(bucket);
timer.submit(new Consumer() {
@Override
public void accept(Long aLong) {
dispatcher.dispatch(bucket, flushTimerTask, null);
}
}, timespan, targetUnit);
}
}, null);
} catch (InsufficientCapacityException e) {
//IGNORE
}
}
};
this.timeshift = timeshift;
this.unit = targetUnit;
this.timer = timer;
} else {
this.timeshift = -1l;
this.unit = null;
this.timer = null;
this.timeshiftTask = null;
}
}
@Override
protected void doOnSubscribe(Subscription subscription) {
if(timer != null) {
timeshiftRegistration = timer.schedule(timeshiftTask,
timeshift,
unit);
}
}
@Override
protected PushSubscription createTrackingSubscription(Subscription subscription) {
return new BatchSubscription<>(subscription, this, skip + batchSize);
}
@Override
protected void doNext(T value) {
if (timer == null && index++ % skip == 0) {
buckets.add(batchSize < 2048 ? new ArrayList(batchSize) : new ArrayList());
}
flushCallback(value);
}
@Override
protected void doError(Throwable ev) {
buckets.clear();
super.doError(ev);
}
@Override
protected void doComplete() {
for (List bucket : buckets) {
broadcastNext(bucket);
}
buckets.clear();
super.doComplete();
}
private void flushCallback(T event) {
Iterator> it = buckets.iterator();
while (it.hasNext()) {
List bucket = it.next();
bucket.add(event);
if (bucket.size() == batchSize) {
it.remove();
broadcastNext(bucket);
}
}
}
@Override
public String toString() {
return super.toString() + "{skip=" + skip + "}";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy