|
|
|
@ -19,7 +19,6 @@ import static org.redisson.client.protocol.RedisCommands.EVAL_OBJECT;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.LINDEX;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.LLEN;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.LPOP;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.LPUSH;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.LREM_SINGLE;
|
|
|
|
|
import static org.redisson.client.protocol.RedisCommands.RPUSH;
|
|
|
|
|
|
|
|
|
@ -28,6 +27,10 @@ import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import org.reactivestreams.Processor;
|
|
|
|
|
import org.reactivestreams.Publisher;
|
|
|
|
|
import org.reactivestreams.Subscriber;
|
|
|
|
|
import org.reactivestreams.Subscription;
|
|
|
|
|
import org.redisson.client.codec.Codec;
|
|
|
|
|
import org.redisson.client.protocol.RedisCommand;
|
|
|
|
|
import org.redisson.client.protocol.RedisCommands;
|
|
|
|
@ -38,13 +41,9 @@ import org.redisson.client.protocol.convertor.IntegerReplayConvertor;
|
|
|
|
|
import org.redisson.client.protocol.convertor.LongReplayConvertor;
|
|
|
|
|
import org.redisson.core.RListReactive;
|
|
|
|
|
|
|
|
|
|
import rx.Observable;
|
|
|
|
|
import rx.Observable.OnSubscribe;
|
|
|
|
|
import rx.Single;
|
|
|
|
|
import rx.SingleSubscriber;
|
|
|
|
|
import rx.Subscriber;
|
|
|
|
|
import rx.observables.ConnectableObservable;
|
|
|
|
|
import rx.subjects.PublishSubject;
|
|
|
|
|
import reactor.core.reactivestreams.SubscriberBarrier;
|
|
|
|
|
import reactor.rx.Stream;
|
|
|
|
|
import reactor.rx.subscription.ReactiveSubscription;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Distributed and concurrent implementation of {@link java.util.List}
|
|
|
|
@ -64,80 +63,101 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Long> size() {
|
|
|
|
|
public Publisher<Long> size() {
|
|
|
|
|
return commandExecutor.readObservable(getName(), codec, LLEN, getName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Observable<V> descendingIterator() {
|
|
|
|
|
public Publisher<V> descendingIterator() {
|
|
|
|
|
return iterator(-1, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Observable<V> iterator() {
|
|
|
|
|
public Publisher<V> iterator() {
|
|
|
|
|
return iterator(0, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Observable<V> descendingIterator(int startIndex) {
|
|
|
|
|
public Publisher<V> descendingIterator(int startIndex) {
|
|
|
|
|
return iterator(startIndex, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Observable<V> iterator(int startIndex) {
|
|
|
|
|
public Publisher<V> iterator(int startIndex) {
|
|
|
|
|
return iterator(startIndex, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Observable<V> iterator(final int startIndex, final boolean forward) {
|
|
|
|
|
return Observable.create(new OnSubscribe<V>() {
|
|
|
|
|
private Publisher<V> iterator(final int startIndex, final boolean forward) {
|
|
|
|
|
return new Stream<V>() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void subscribe(final Subscriber<? super V> t) {
|
|
|
|
|
t.onSubscribe(new ReactiveSubscription<V>(this, t) {
|
|
|
|
|
|
|
|
|
|
private int currentIndex = startIndex;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void call(final Subscriber<? super V> t) {
|
|
|
|
|
get(currentIndex).subscribe(new SingleSubscriber<V>() {
|
|
|
|
|
protected void onRequest(final long n) {
|
|
|
|
|
final ReactiveSubscription<V> m = this;
|
|
|
|
|
get(currentIndex).subscribe(new Subscriber<V>() {
|
|
|
|
|
V currValue;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(Throwable e) {
|
|
|
|
|
t.onError(e);
|
|
|
|
|
public void onSubscribe(Subscription s) {
|
|
|
|
|
s.request(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onSuccess(V val) {
|
|
|
|
|
if (val == null) {
|
|
|
|
|
t.onCompleted();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
t.onNext(val);
|
|
|
|
|
public void onNext(V value) {
|
|
|
|
|
currValue = value;
|
|
|
|
|
m.onNext(value);
|
|
|
|
|
if (forward) {
|
|
|
|
|
currentIndex++;
|
|
|
|
|
} else {
|
|
|
|
|
currentIndex--;
|
|
|
|
|
}
|
|
|
|
|
call(t);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(Throwable error) {
|
|
|
|
|
m.onError(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onComplete() {
|
|
|
|
|
if (currValue == null) {
|
|
|
|
|
m.onComplete();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (n-1 == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
onRequest(n-1);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Long> add(V e) {
|
|
|
|
|
public Publisher<Long> add(V e) {
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, RPUSH, getName(), e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Boolean> remove(Object o) {
|
|
|
|
|
public Publisher<Boolean> remove(Object o) {
|
|
|
|
|
return remove(o, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Single<Boolean> remove(Object o, int count) {
|
|
|
|
|
protected Publisher<Boolean> remove(Object o, int count) {
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, LREM_SINGLE, getName(), count, o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Boolean> containsAll(Collection<?> c) {
|
|
|
|
|
public Publisher<Boolean> containsAll(Collection<?> c) {
|
|
|
|
|
return commandExecutor.evalReadObservable(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 4),
|
|
|
|
|
"local items = redis.call('lrange', KEYS[1], 0, -1) " +
|
|
|
|
|
"for i=1, #items do " +
|
|
|
|
@ -152,48 +172,19 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Long> addAll(final Collection<? extends V> c) {
|
|
|
|
|
public Publisher<Long> addAll(final Collection<? extends V> c) {
|
|
|
|
|
if (c.isEmpty()) {
|
|
|
|
|
return size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final PublishSubject<Long> promise = newObservable();
|
|
|
|
|
ConnectableObservable<Long> r = promise.replay();
|
|
|
|
|
r.connect();
|
|
|
|
|
Single<Long> sizeObservable = size();
|
|
|
|
|
sizeObservable.subscribe(new SingleSubscriber<Long>() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onSuccess(final Long listSize) {
|
|
|
|
|
List<Object> args = new ArrayList<Object>(c.size() + 1);
|
|
|
|
|
args.add(getName());
|
|
|
|
|
args.addAll(c);
|
|
|
|
|
Single<Long> res = commandExecutor.writeObservable(getName(), codec, RPUSH, args.toArray());
|
|
|
|
|
res.subscribe(new SingleSubscriber<Long>() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onSuccess(Long value) {
|
|
|
|
|
promise.onNext(value);
|
|
|
|
|
promise.onCompleted();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(Throwable error) {
|
|
|
|
|
promise.onError(error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(Throwable error) {
|
|
|
|
|
promise.onError(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
return r.toSingle();
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, RPUSH, args.toArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Long> addAll(final long index, final Collection<? extends V> coll) {
|
|
|
|
|
public Publisher<Long> addAll(final long index, final Collection<? extends V> coll) {
|
|
|
|
|
if (coll.isEmpty()) {
|
|
|
|
|
return size();
|
|
|
|
|
}
|
|
|
|
@ -203,15 +194,15 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
Collections.reverse(elements);
|
|
|
|
|
elements.add(0, getName());
|
|
|
|
|
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, LPUSH, elements.toArray());
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, RedisCommands.LPUSH, elements.toArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final PublishSubject<Long> promise = newObservable();
|
|
|
|
|
final Processor<Long, Long> promise = newObservable();
|
|
|
|
|
|
|
|
|
|
Single<Long> s = size();
|
|
|
|
|
s.subscribe(new SingleSubscriber<Long>() {
|
|
|
|
|
Publisher<Long> s = size();
|
|
|
|
|
s.subscribe(new SubscriberBarrier<Long, Long>(promise) {
|
|
|
|
|
@Override
|
|
|
|
|
public void onSuccess(Long size) {
|
|
|
|
|
public void doNext(Long size) {
|
|
|
|
|
if (!isPositionInRange(index, size)) {
|
|
|
|
|
IndexOutOfBoundsException e = new IndexOutOfBoundsException("index: " + index + " but current size: "+ size);
|
|
|
|
|
promise.onError(e);
|
|
|
|
@ -228,7 +219,7 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
List<Object> args = new ArrayList<Object>(coll.size() + 1);
|
|
|
|
|
args.add(index);
|
|
|
|
|
args.addAll(coll);
|
|
|
|
|
Single<Long> f = commandExecutor.evalWriteObservable(getName(), codec, new RedisCommand<Long>("EVAL", new LongReplayConvertor(), 5),
|
|
|
|
|
Publisher<Long> f = commandExecutor.evalWriteObservable(getName(), codec, new RedisCommand<Long>("EVAL", new LongReplayConvertor(), 5),
|
|
|
|
|
"local ind = table.remove(ARGV, 1); " + // index is the first parameter
|
|
|
|
|
"local tail = redis.call('lrange', KEYS[1], ind, -1); " +
|
|
|
|
|
"redis.call('ltrim', KEYS[1], 0, ind - 1); " +
|
|
|
|
@ -239,16 +230,12 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
f.subscribe(toSubscriber(promise));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(Throwable error) {
|
|
|
|
|
promise.onError(error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return promise.toSingle();
|
|
|
|
|
return promise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Boolean> removeAll(Collection<?> c) {
|
|
|
|
|
public Publisher<Boolean> removeAll(Collection<?> c) {
|
|
|
|
|
return commandExecutor.evalWriteObservable(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 4),
|
|
|
|
|
"local v = false " +
|
|
|
|
|
"for i = 0, table.getn(ARGV), 1 do "
|
|
|
|
@ -260,7 +247,7 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Boolean> retainAll(Collection<?> c) {
|
|
|
|
|
public Publisher<Boolean> retainAll(Collection<?> c) {
|
|
|
|
|
return commandExecutor.evalWriteObservable(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 4),
|
|
|
|
|
"local changed = false " +
|
|
|
|
|
"local items = redis.call('lrange', KEYS[1], 0, -1) "
|
|
|
|
@ -286,7 +273,7 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<V> get(long index) {
|
|
|
|
|
public Publisher<V> get(long index) {
|
|
|
|
|
return commandExecutor.readObservable(getName(), codec, LINDEX, getName(), index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -295,7 +282,7 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<V> set(long index, V element) {
|
|
|
|
|
public Publisher<V> set(long index, V element) {
|
|
|
|
|
return commandExecutor.evalWriteObservable(getName(), codec, new RedisCommand<Object>("EVAL", 5),
|
|
|
|
|
"local v = redis.call('lindex', KEYS[1], ARGV[1]); " +
|
|
|
|
|
"redis.call('lset', KEYS[1], ARGV[1], ARGV[2]); " +
|
|
|
|
@ -304,17 +291,17 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Void> fastSet(long index, V element) {
|
|
|
|
|
public Publisher<Void> fastSet(long index, V element) {
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, RedisCommands.LSET, getName(), index, element);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Long> add(long index, V element) {
|
|
|
|
|
public Publisher<Long> add(long index, V element) {
|
|
|
|
|
return addAll(index, Collections.singleton(element));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<V> remove(int index) {
|
|
|
|
|
public Publisher<V> remove(int index) {
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
return commandExecutor.writeObservable(getName(), codec, LPOP, getName());
|
|
|
|
|
}
|
|
|
|
@ -329,11 +316,11 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Boolean> contains(Object o) {
|
|
|
|
|
public Publisher<Boolean> contains(Object o) {
|
|
|
|
|
return indexOf(o, new BooleanNumberReplayConvertor());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private <R> Single<R> indexOf(Object o, Convertor<R> convertor) {
|
|
|
|
|
private <R> Publisher<R> indexOf(Object o, Convertor<R> convertor) {
|
|
|
|
|
return commandExecutor.evalReadObservable(getName(), codec, new RedisCommand<R>("EVAL", convertor, 4),
|
|
|
|
|
"local key = KEYS[1] " +
|
|
|
|
|
"local obj = ARGV[1] " +
|
|
|
|
@ -348,12 +335,12 @@ public class RedissonListReactive<V> extends RedissonExpirableReactive implement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Integer> indexOf(Object o) {
|
|
|
|
|
public Publisher<Integer> indexOf(Object o) {
|
|
|
|
|
return indexOf(o, new IntegerReplayConvertor());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Single<Integer> lastIndexOf(Object o) {
|
|
|
|
|
public Publisher<Integer> lastIndexOf(Object o) {
|
|
|
|
|
return commandExecutor.evalReadObservable(getName(), codec, new RedisCommand<Integer>("EVAL", new IntegerReplayConvertor(), 4),
|
|
|
|
|
"local key = KEYS[1] " +
|
|
|
|
|
"local obj = ARGV[1] " +
|
|
|
|
|