org.redisson.command.RedisQueuedBatchExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redisson-all Show documentation
Show all versions of redisson-all Show documentation
Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC
/**
* Copyright (c) 2013-2020 Nikita Koksharov
*
* 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 org.redisson.command;
import org.redisson.api.BatchOptions;
import org.redisson.api.BatchOptions.ExecutionMode;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.*;
import org.redisson.command.CommandBatchService.ConnectionEntry;
import org.redisson.command.CommandBatchService.Entry;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.NodeSource;
import org.redisson.connection.NodeSource.Redirect;
import org.redisson.liveobject.core.RedissonObjectBuilder;
import org.redisson.misc.AsyncCountDownLatch;
import org.redisson.misc.LogHelper;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* @author Nikita Koksharov
*
* @param type of value
* @param type of returned value
*/
public class RedisQueuedBatchExecutor extends BaseRedisBatchExecutor {
private final ConcurrentMap connections;
private final AsyncCountDownLatch latch;
@SuppressWarnings("ParameterNumber")
public RedisQueuedBatchExecutor(boolean readOnlyMode, NodeSource source, Codec codec, RedisCommand command,
Object[] params, RPromise mainPromise, boolean ignoreRedirect, ConnectionManager connectionManager,
RedissonObjectBuilder objectBuilder, ConcurrentMap commands,
ConcurrentMap connections, BatchOptions options, AtomicInteger index,
AtomicBoolean executed, AsyncCountDownLatch latch) {
super(readOnlyMode, source, codec, command, params, mainPromise, ignoreRedirect, connectionManager, objectBuilder,
commands, options, index, executed);
this.connections = connections;
this.latch = latch;
}
@Override
public void execute() {
addBatchCommandData(null);
if (!readOnlyMode && this.options.getExecutionMode() == ExecutionMode.REDIS_READ_ATOMIC) {
throw new IllegalStateException("Data modification commands can't be used with queueStore=REDIS_READ_ATOMIC");
}
super.execute();
}
@Override
protected void releaseConnection(RPromise attemptPromise, RFuture connectionFuture) {
if (RedisCommands.EXEC.getName().equals(command.getName())) {
super.releaseConnection(attemptPromise, connectionFuture);
}
if (RedisCommands.DISCARD.getName().equals(command.getName())) {
super.releaseConnection(attemptPromise, connectionFuture);
}
}
@Override
protected void handleSuccess(RPromise promise, RFuture connectionFuture, R res)
throws ReflectiveOperationException {
if (RedisCommands.EXEC.getName().equals(command.getName())) {
super.handleSuccess(promise, connectionFuture, res);
return;
}
if (RedisCommands.DISCARD.getName().equals(command.getName())) {
super.handleSuccess(promise, connectionFuture, null);
if (executed.compareAndSet(false, true)) {
connectionFuture.getNow().forceFastReconnectAsync().onComplete((r, e) -> {
releaseConnection(promise, connectionFuture);
});
}
return;
}
try {
BatchPromise batchPromise = (BatchPromise) promise;
RPromise sentPromise = (RPromise) batchPromise.getSentPromise();
super.handleSuccess(sentPromise, connectionFuture, null);
} finally {
latch.countDown();
}
}
@Override
protected void handleError(RFuture connectionFuture, Throwable cause) {
try {
if (mainPromise instanceof BatchPromise) {
BatchPromise batchPromise = (BatchPromise) mainPromise;
RPromise sentPromise = (RPromise) batchPromise.getSentPromise();
sentPromise.tryFailure(cause);
mainPromise.tryFailure(cause);
if (executed.compareAndSet(false, true)) {
connectionFuture.getNow().forceFastReconnectAsync().onComplete((res, e) -> {
RedisQueuedBatchExecutor.super.releaseConnection(mainPromise, connectionFuture);
});
}
return;
}
super.handleError(connectionFuture, cause);
} finally {
latch.countDown();
}
}
@Override
protected void sendCommand(RPromise attemptPromise, RedisConnection connection) {
MasterSlaveEntry msEntry = getEntry(source);
ConnectionEntry connectionEntry = connections.get(msEntry);
boolean syncSlaves = options.getSyncSlaves() > 0;
if (source.getRedirect() == Redirect.ASK) {
List> list = new ArrayList>(2);
RPromise promise = new RedissonPromise();
list.add(new CommandData(promise, codec, RedisCommands.ASKING, new Object[]{}));
if (connectionEntry.isFirstCommand()) {
list.add(new CommandData(promise, codec, RedisCommands.MULTI, new Object[]{}));
connectionEntry.setFirstCommand(false);
}
list.add(new CommandData(attemptPromise, codec, command, params));
RPromise main = new RedissonPromise();
writeFuture = connection.send(new CommandsData(main, list, true, syncSlaves));
} else {
if (log.isDebugEnabled()) {
log.debug("acquired connection for command {} and params {} from slot {} using node {}... {}",
command, LogHelper.toString(params), source, connection.getRedisClient().getAddr(), connection);
}
if (connectionEntry.isFirstCommand()) {
List> list = new ArrayList>(2);
list.add(new CommandData(new RedissonPromise(), codec, RedisCommands.MULTI, new Object[]{}));
list.add(new CommandData(attemptPromise, codec, command, params));
RPromise main = new RedissonPromise();
writeFuture = connection.send(new CommandsData(main, list, true, syncSlaves));
connectionEntry.setFirstCommand(false);
} else {
if (RedisCommands.EXEC.getName().equals(command.getName())) {
Entry entry = commands.get(msEntry);
List> list = new ArrayList<>();
if (options.isSkipResult()) {
list.add(new CommandData(new RedissonPromise(), codec, RedisCommands.CLIENT_REPLY, new Object[]{ "OFF" }));
}
list.add(new CommandData(attemptPromise, codec, command, params));
if (options.isSkipResult()) {
list.add(new CommandData(new RedissonPromise(), codec, RedisCommands.CLIENT_REPLY, new Object[]{ "ON" }));
}
if (options.getSyncSlaves() > 0) {
BatchCommandData, ?> waitCommand = new BatchCommandData(RedisCommands.WAIT,
new Object[] { this.options.getSyncSlaves(), this.options.getSyncTimeout() }, index.incrementAndGet());
list.add(waitCommand);
entry.getCommands().add(waitCommand);
}
RPromise main = new RedissonPromise();
writeFuture = connection.send(new CommandsData(main, list, new ArrayList(entry.getCommands()),
options.isSkipResult(), false, true, syncSlaves));
} else {
RPromise main = new RedissonPromise();
List> list = new ArrayList<>();
list.add(new CommandData(attemptPromise, codec, command, params));
writeFuture = connection.send(new CommandsData(main, list, true, syncSlaves));
}
}
}
}
@Override
protected RFuture getConnection() {
MasterSlaveEntry msEntry = getEntry(source);
ConnectionEntry entry = connections.get(msEntry);
if (entry == null) {
entry = new ConnectionEntry();
ConnectionEntry oldEntry = connections.putIfAbsent(msEntry, entry);
if (oldEntry != null) {
entry = oldEntry;
}
}
if (entry.getConnectionFuture() != null) {
return entry.getConnectionFuture();
}
synchronized (this) {
if (entry.getConnectionFuture() != null) {
return entry.getConnectionFuture();
}
RFuture connectionFuture;
if (this.options.getExecutionMode() == ExecutionMode.REDIS_WRITE_ATOMIC) {
connectionFuture = connectionManager.connectionWriteOp(source, null);
} else {
connectionFuture = connectionManager.connectionReadOp(source, null);
}
connectionFuture.syncUninterruptibly();
entry.setConnectionFuture(connectionFuture);
return connectionFuture;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy