|
|
|
@ -15,22 +15,23 @@
|
|
|
|
|
*/
|
|
|
|
|
package org.redisson;
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
|
import java.util.function.BiConsumer;
|
|
|
|
|
|
|
|
|
|
import io.netty.buffer.ByteBufUtil;
|
|
|
|
|
import org.redisson.api.RFuture;
|
|
|
|
|
import org.redisson.api.RSemaphore;
|
|
|
|
|
import org.redisson.api.RTopic;
|
|
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
|
|
import org.redisson.api.listener.MessageListener;
|
|
|
|
|
import org.redisson.client.codec.LongCodec;
|
|
|
|
|
import org.redisson.client.codec.StringCodec;
|
|
|
|
|
import org.redisson.command.CommandAsyncExecutor;
|
|
|
|
|
import org.redisson.misc.RPromise;
|
|
|
|
|
import org.redisson.misc.RedissonPromise;
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
|
import java.util.function.BiConsumer;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @author Nikita Koksharov
|
|
|
|
@ -41,9 +42,11 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
private class ResetListener implements BiConsumer<Long, Throwable> {
|
|
|
|
|
|
|
|
|
|
private final RPromise<Void> result;
|
|
|
|
|
private final RSemaphore semaphore;
|
|
|
|
|
|
|
|
|
|
ResetListener(RPromise<Void> result) {
|
|
|
|
|
ResetListener(RSemaphore semaphore, RPromise<Void> result) {
|
|
|
|
|
this.result = result;
|
|
|
|
|
this.semaphore = semaphore;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -59,7 +62,14 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.trySuccess(null);
|
|
|
|
|
semaphore.deleteAsync().onComplete((re, exc) -> {
|
|
|
|
|
if (exc != null) {
|
|
|
|
|
result.tryFailure(exc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.trySuccess(res);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -71,9 +81,13 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
private class SumListener implements BiConsumer<Long, Throwable> {
|
|
|
|
|
|
|
|
|
|
private final RPromise<T> result;
|
|
|
|
|
private final RSemaphore semaphore;
|
|
|
|
|
private final String id;
|
|
|
|
|
|
|
|
|
|
SumListener(RPromise<T> result) {
|
|
|
|
|
SumListener(String id, RSemaphore semaphore, RPromise<T> result) {
|
|
|
|
|
this.result = result;
|
|
|
|
|
this.semaphore = semaphore;
|
|
|
|
|
this.id = id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -89,14 +103,21 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RFuture<T> valueFuture = getAndDeleteAsync();
|
|
|
|
|
RFuture<T> valueFuture = getAndDeleteAsync(id);
|
|
|
|
|
valueFuture.onComplete((res, ex) -> {
|
|
|
|
|
if (ex != null) {
|
|
|
|
|
result.tryFailure(ex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.trySuccess(res);
|
|
|
|
|
|
|
|
|
|
semaphore.deleteAsync().onComplete((re, exc) -> {
|
|
|
|
|
if (exc != null) {
|
|
|
|
|
result.tryFailure(exc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.trySuccess(res);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -108,55 +129,58 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(RedissonBaseAdder.class);
|
|
|
|
|
|
|
|
|
|
private static final long CLEAR_MSG = 0;
|
|
|
|
|
private static final long SUM_MSG = 1;
|
|
|
|
|
private static final String CLEAR_MSG = "0";
|
|
|
|
|
private static final String SUM_MSG = "1";
|
|
|
|
|
|
|
|
|
|
private final RSemaphore semaphore;
|
|
|
|
|
private final RedissonClient redisson;
|
|
|
|
|
private final RTopic topic;
|
|
|
|
|
private final int listenerId;
|
|
|
|
|
|
|
|
|
|
public RedissonBaseAdder(CommandAsyncExecutor connectionManager, String name, RedissonClient redisson) {
|
|
|
|
|
super(connectionManager, name);
|
|
|
|
|
|
|
|
|
|
topic = redisson.getTopic(suffixName(getName(), "topic"), LongCodec.INSTANCE);
|
|
|
|
|
semaphore = redisson.getSemaphore(suffixName(getName(), "semaphore"));
|
|
|
|
|
listenerId = topic.addListener(Long.class, new MessageListener<Long>() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onMessage(CharSequence channel, Long msg) {
|
|
|
|
|
if (msg == SUM_MSG) {
|
|
|
|
|
RFuture<T> addAndGetFuture = addAndGetAsync();
|
|
|
|
|
addAndGetFuture.onComplete((res, e) -> {
|
|
|
|
|
if (e != null) {
|
|
|
|
|
log.error("Can't increase sum", e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
semaphore.releaseAsync().onComplete((r, ex) -> {
|
|
|
|
|
if (ex != null) {
|
|
|
|
|
log.error("Can't release semaphore", ex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msg == CLEAR_MSG) {
|
|
|
|
|
doReset();
|
|
|
|
|
semaphore.releaseAsync().onComplete((res, e) -> {
|
|
|
|
|
if (e != null) {
|
|
|
|
|
log.error("Can't release semaphore", e);
|
|
|
|
|
topic = redisson.getTopic(suffixName(getName(), "topic"), StringCodec.INSTANCE);
|
|
|
|
|
this.redisson = redisson;
|
|
|
|
|
listenerId = topic.addListener(String.class, (channel, msg) -> {
|
|
|
|
|
String[] parts = msg.split(":");
|
|
|
|
|
String id = parts[1];
|
|
|
|
|
|
|
|
|
|
RSemaphore semaphore = getSemaphore(id);
|
|
|
|
|
if (parts[0].equals(SUM_MSG)) {
|
|
|
|
|
RFuture<T> addAndGetFuture = addAndGetAsync(id);
|
|
|
|
|
addAndGetFuture.onComplete((res, e) -> {
|
|
|
|
|
if (e != null) {
|
|
|
|
|
log.error("Can't increase sum", e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
semaphore.releaseAsync().onComplete((r, ex) -> {
|
|
|
|
|
if (ex != null) {
|
|
|
|
|
log.error("Can't release semaphore", ex);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parts[0].equals(CLEAR_MSG)) {
|
|
|
|
|
doReset();
|
|
|
|
|
semaphore.releaseAsync().onComplete((res, e) -> {
|
|
|
|
|
if (e != null) {
|
|
|
|
|
log.error("Can't release semaphore", e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected abstract void doReset();
|
|
|
|
|
|
|
|
|
|
private String generateId() {
|
|
|
|
|
byte[] id = new byte[16];
|
|
|
|
|
ThreadLocalRandom.current().nextBytes(id);
|
|
|
|
|
return ByteBufUtil.hexDump(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void reset() {
|
|
|
|
|
get(resetAsync());
|
|
|
|
|
}
|
|
|
|
@ -167,21 +191,33 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
|
|
|
|
|
public RFuture<T> sumAsync() {
|
|
|
|
|
RPromise<T> result = new RedissonPromise<T>();
|
|
|
|
|
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(SUM_MSG);
|
|
|
|
|
future.onComplete(new SumListener(result));
|
|
|
|
|
|
|
|
|
|
String id = generateId();
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(SUM_MSG + ":" + id);
|
|
|
|
|
RSemaphore semaphore = getSemaphore(id);
|
|
|
|
|
future.onComplete(new SumListener(id, semaphore, result));
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private RSemaphore getSemaphore(String id) {
|
|
|
|
|
return redisson.getSemaphore(suffixName(getName(), id + ":semaphore"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected String getCounterName(String id) {
|
|
|
|
|
return suffixName(getName(), id + ":counter");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RFuture<T> sumAsync(long timeout, TimeUnit timeUnit) {
|
|
|
|
|
RPromise<T> result = new RedissonPromise<T>();
|
|
|
|
|
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(SUM_MSG);
|
|
|
|
|
future.onComplete(new SumListener(result) {
|
|
|
|
|
|
|
|
|
|
String id = generateId();
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(SUM_MSG + ":" + id);
|
|
|
|
|
RSemaphore semaphore = getSemaphore(id);
|
|
|
|
|
future.onComplete(new SumListener(id, semaphore, result) {
|
|
|
|
|
@Override
|
|
|
|
|
protected RFuture<Void> acquireAsync(int value) {
|
|
|
|
|
return tryAcquire(timeout, timeUnit, value);
|
|
|
|
|
return tryAcquire(semaphore, timeout, timeUnit, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
@ -189,8 +225,8 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RFuture<Void> tryAcquire(long timeout, TimeUnit timeUnit, int value) {
|
|
|
|
|
RPromise<Void> acquireResult = new RedissonPromise<Void>();
|
|
|
|
|
protected RFuture<Void> tryAcquire(RSemaphore semaphore, long timeout, TimeUnit timeUnit, int value) {
|
|
|
|
|
RPromise<Void> acquireResult = new RedissonPromise<>();
|
|
|
|
|
semaphore.tryAcquireAsync(value, timeout, timeUnit).onComplete((res, e) -> {
|
|
|
|
|
if (e != null) {
|
|
|
|
|
acquireResult.tryFailure(e);
|
|
|
|
@ -207,22 +243,26 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RFuture<Void> resetAsync() {
|
|
|
|
|
RPromise<Void> result = new RedissonPromise<Void>();
|
|
|
|
|
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(CLEAR_MSG);
|
|
|
|
|
future.onComplete(new ResetListener(result));
|
|
|
|
|
RPromise<Void> result = new RedissonPromise<>();
|
|
|
|
|
|
|
|
|
|
String id = generateId();
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(CLEAR_MSG + ":" + id);
|
|
|
|
|
RSemaphore semaphore = getSemaphore(id);
|
|
|
|
|
future.onComplete(new ResetListener(semaphore, result));
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RFuture<Void> resetAsync(long timeout, TimeUnit timeUnit) {
|
|
|
|
|
RPromise<Void> result = new RedissonPromise<Void>();
|
|
|
|
|
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(CLEAR_MSG);
|
|
|
|
|
future.onComplete(new ResetListener(result) {
|
|
|
|
|
RPromise<Void> result = new RedissonPromise<>();
|
|
|
|
|
|
|
|
|
|
String id = generateId();
|
|
|
|
|
RFuture<Long> future = topic.publishAsync(CLEAR_MSG + ":" + id);
|
|
|
|
|
RSemaphore semaphore = getSemaphore(id);
|
|
|
|
|
future.onComplete(new ResetListener(semaphore, result) {
|
|
|
|
|
@Override
|
|
|
|
|
protected RFuture<Void> acquireAsync(int value) {
|
|
|
|
|
return tryAcquire(timeout, timeUnit, value);
|
|
|
|
|
return tryAcquire(semaphore, timeout, timeUnit, value);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@ -233,8 +273,8 @@ public abstract class RedissonBaseAdder<T extends Number> extends RedissonExpira
|
|
|
|
|
topic.removeListener(listenerId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected abstract RFuture<T> addAndGetAsync();
|
|
|
|
|
protected abstract RFuture<T> addAndGetAsync(String id);
|
|
|
|
|
|
|
|
|
|
protected abstract RFuture<T> getAndDeleteAsync();
|
|
|
|
|
protected abstract RFuture<T> getAndDeleteAsync(String id);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|