org.redisson.connection.ClientConnectionsEntry 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-2024 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.connection;
import io.netty.channel.ChannelFuture;
import org.redisson.api.NodeType;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.CommandData;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.misc.WrappedLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
*
* @author Nikita Koksharov
*
*/
public class ClientConnectionsEntry {
final Logger log = LoggerFactory.getLogger(getClass());
private final ConnectionsHolder connectionsHolder;
private final ConnectionsHolder pubSubConnectionsHolder;
private final TrackedConnectionsHolder trackedConnectionsHolder;
public enum FreezeReason {MANAGER, RECONNECT}
private volatile FreezeReason freezeReason;
final RedisClient client;
private final NodeType nodeType;
private final IdleConnectionWatcher idleConnectionWatcher;
private final ConnectionManager connectionManager;
private volatile boolean initialized = false;
private final WrappedLock lock = new WrappedLock();
private final Map> connection2holder = new ConcurrentHashMap<>();
public ClientConnectionsEntry(RedisClient client, int poolMinSize, int poolMaxSize,
ConnectionManager connectionManager, NodeType nodeType, MasterSlaveServersConfig config) {
this.client = client;
this.connectionsHolder = new ConnectionsHolder<>(client, poolMaxSize, r -> r.connectAsync(),
connectionManager.getServiceManager(), true);
this.idleConnectionWatcher = connectionManager.getServiceManager().getConnectionWatcher();
this.connectionManager = connectionManager;
this.nodeType = nodeType;
this.pubSubConnectionsHolder = new ConnectionsHolder<>(client, config.getSubscriptionConnectionPoolSize(),
r -> r.connectPubSubAsync(), connectionManager.getServiceManager(), false);
if (config.getSubscriptionConnectionPoolSize() > 0) {
idleConnectionWatcher.add(this, config.getSubscriptionConnectionMinimumIdleSize(),
config.getSubscriptionConnectionPoolSize(), pubSubConnectionsHolder);
}
idleConnectionWatcher.add(this, poolMinSize, poolMaxSize, connectionsHolder);
this.trackedConnectionsHolder = new TrackedConnectionsHolder(connectionsHolder);
}
public CompletableFuture initConnections(int minimumIdleSize) {
return connectionsHolder.initConnections(minimumIdleSize);
}
public CompletableFuture initPubSubConnections(int minimumIdleSize) {
return pubSubConnectionsHolder.initConnections(minimumIdleSize);
}
public boolean isInitialized() {
return this.initialized;
}
public void setInitialized(boolean isInited) {
this.initialized = isInited;
}
public NodeType getNodeType() {
return nodeType;
}
public CompletableFuture shutdownAsync() {
idleConnectionWatcher.remove(this);
return client.shutdownAsync().toCompletableFuture();
}
public RedisClient getClient() {
return client;
}
public boolean isFreezed() {
return freezeReason != null;
}
public void setFreezeReason(FreezeReason freezeReason) {
this.freezeReason = freezeReason;
if (freezeReason != null) {
this.initialized = false;
}
}
public FreezeReason getFreezeReason() {
return freezeReason;
}
public WrappedLock getLock() {
return lock;
}
public void reattachPubSub() {
pubSubConnectionsHolder.getFreeConnectionsCounter().removeListeners();
for (RedisPubSubConnection connection : pubSubConnectionsHolder.getAllConnections()) {
connection.closeAsync();
connectionManager.getSubscribeService().reattachPubSub(connection);
}
log.debug("{} PubSub connections to {} have been closed", pubSubConnectionsHolder.getAllConnections().size(), client.getAddr());
pubSubConnectionsHolder.getFreeConnections().clear();
pubSubConnectionsHolder.getAllConnections().clear();
}
public void nodeDown() {
nodeDown(connectionsHolder);
reattachPubSub();
}
protected final void nodeDown(ConnectionsHolder connectionsHolder) {
connectionsHolder.getFreeConnectionsCounter().removeListeners();
for (RedisConnection connection : connectionsHolder.getAllConnections()) {
connection.closeAsync();
reattachBlockingQueue(connection.getCurrentCommand());
}
log.debug("{} connections to {} have been closed", connectionsHolder.getAllConnections().size(), client.getAddr());
connectionsHolder.getFreeConnections().clear();
connectionsHolder.getAllConnections().clear();
}
void reattachBlockingQueue(CommandData, ?> commandData) {
if (commandData == null
|| !commandData.isBlockingCommand()
|| commandData.getPromise().isDone()) {
return;
}
String key = getKey(commandData);
MasterSlaveEntry entry = connectionManager.getEntry(key);
if (entry == null) {
log.debug("Unable to get entry for {} during blocking command reattach {}", key, commandData);
connectionManager.getServiceManager().newTimeout(timeout ->
reattachBlockingQueue(commandData), 1, TimeUnit.SECONDS);
return;
}
CompletableFuture newConnectionFuture = entry.connectionWriteOp(commandData.getCommand());
newConnectionFuture.whenComplete((newConnection, e) -> {
if (e != null) {
log.debug("Unable to acquire connection during blocking command reattach {}", commandData, e);
connectionManager.getServiceManager().newTimeout(timeout ->
reattachBlockingQueue(commandData), 1, TimeUnit.SECONDS);
return;
}
commandData.getPromise().whenComplete((r, ex) -> {
entry.releaseWrite(newConnection);
});
ChannelFuture channelFuture = newConnection.send(commandData);
channelFuture.addListener(future -> {
if (!future.isSuccess()) {
log.debug("Unable to send a command during blocking command reattach {}", commandData, future.cause());
connectionManager.getServiceManager().newTimeout(timeout ->
reattachBlockingQueue(commandData), 1, TimeUnit.SECONDS);
return;
}
log.info("command '{}' has been resent to '{}'", commandData, newConnection.getRedisClient());
});
});
}
private String getKey(CommandData, ?> commandData) {
String key = null;
for (int i = 0; i < commandData.getParams().length; i++) {
Object param = commandData.getParams()[i];
if ("STREAMS".equals(param)) {
Object k = commandData.getParams()[i+1];
if (k instanceof byte[]) {
key = new String((byte[]) k, StandardCharsets.UTF_8);
} else {
key = (String) k;
}
break;
}
}
if (key == null) {
Object k = commandData.getParams()[0];
if (k instanceof byte[]) {
key = new String((byte[]) k, StandardCharsets.UTF_8);
} else {
key = (String) k;
}
}
return key;
}
public ConnectionsHolder getConnectionsHolder() {
return connectionsHolder;
}
public TrackedConnectionsHolder getTrackedConnectionsHolder() {
return trackedConnectionsHolder;
}
public ConnectionsHolder getPubSubConnectionsHolder() {
return pubSubConnectionsHolder;
}
public void addHandler(RedisConnection connection, ConnectionsHolder> handler) {
connection2holder.put(connection, handler);
}
public void returnConnection(T connection) {
ConnectionsHolder handler;
if (connection.getUsage() > 1) {
handler = (ConnectionsHolder) connection2holder.get(connection);
} else {
handler = (ConnectionsHolder) connection2holder.remove(connection);
}
if (handler != null) {
handler.releaseConnection(this, connection);
}
}
@Override
public String toString() {
return "ClientConnectionsEntry{" +
"connectionsHolder=" + connectionsHolder +
", pubSubConnectionsHolder=" + pubSubConnectionsHolder +
", freezeReason=" + freezeReason +
", client=" + client +
", nodeType=" + nodeType +
", initialized=" + initialized +
'}';
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy