org.redisson.connection.pool.ConnectionPool 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.pool;
import org.redisson.api.NodeType;
import org.redisson.client.FailedNodeDetector;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.connection.ClientConnectionsEntry;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.ConnectionsHolder;
import org.redisson.connection.MasterSlaveEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Base connection pool class
*
* @author Nikita Koksharov
*
* @param - connection type
*/
abstract class ConnectionPool {
private final Logger log = LoggerFactory.getLogger(getClass());
protected final Queue entries = new ConcurrentLinkedQueue<>();
final ConnectionManager connectionManager;
final MasterSlaveServersConfig config;
final MasterSlaveEntry masterSlaveEntry;
ConnectionPool(MasterSlaveServersConfig config, ConnectionManager connectionManager, MasterSlaveEntry masterSlaveEntry) {
this.config = config;
this.masterSlaveEntry = masterSlaveEntry;
this.connectionManager = connectionManager;
}
public final void addEntry(ClientConnectionsEntry entry) {
entries.add(entry);
}
public final void removeEntry(ClientConnectionsEntry entry) {
entries.remove(entry);
}
protected abstract ConnectionsHolder getConnectionHolder(ClientConnectionsEntry entry, boolean trackChanges);
public CompletableFuture get(RedisCommand> command, boolean trackChanges) {
List entriesCopy = new LinkedList<>(entries);
entriesCopy.removeIf(n -> n.isFreezed() || !isHealthy(n));
if (!entriesCopy.isEmpty()) {
ClientConnectionsEntry entry = config.getLoadBalancer().getEntry(entriesCopy, command);
log.debug("Entry {} selected as connection source", entry);
return acquireConnection(command, entry, trackChanges);
}
List failed = new LinkedList<>();
List freezed = new LinkedList<>();
for (ClientConnectionsEntry entry : entries) {
if (entry.getClient().getConfig().getFailedNodeDetector().isNodeFailed()) {
failed.add(entry.getClient().getAddr());
} else if (entry.isFreezed()) {
freezed.add(entry.getClient().getAddr());
}
}
StringBuilder errorMsg = new StringBuilder(getClass().getSimpleName() + " no available Redis entries. " +
"Master entry host: " + masterSlaveEntry.getClient().getAddr() + " entries " + entries);
if (!freezed.isEmpty()) {
errorMsg.append(" Disconnected hosts: ").append(freezed);
}
if (!failed.isEmpty()) {
errorMsg.append(" Hosts disconnected by 'failedNodeDetector:' ").append(failed);
}
RedisConnectionException exception = new RedisConnectionException(errorMsg.toString());
CompletableFuture result = new CompletableFuture<>();
result.completeExceptionally(exception);
return result;
}
public CompletableFuture get(RedisCommand> command, ClientConnectionsEntry entry, boolean trackChanges) {
return acquireConnection(command, entry, trackChanges);
}
protected final CompletableFuture acquireConnection(RedisCommand> command, ClientConnectionsEntry entry, boolean trackChanges) {
ConnectionsHolder handler = getConnectionHolder(entry, trackChanges);
CompletableFuture result = handler.acquireConnection(command);
CompletableFuture cancelableFuture = new CompletableFuture<>();
result.whenComplete((r, e) -> {
if (e != null) {
if (entry.getNodeType() == NodeType.SLAVE) {
FailedNodeDetector detector = entry.getClient().getConfig().getFailedNodeDetector();
detector.onConnectFailed();
if (detector.isNodeFailed()) {
log.error("Redis node {} has been marked as failed according to the detection logic defined in {}",
entry.getClient().getAddr(), detector);
masterSlaveEntry.shutdownAndReconnectAsync(entry.getClient(), e);
}
}
cancelableFuture.completeExceptionally(e);
return;
}
entry.addHandler(r, handler);
if (entry.getNodeType() == NodeType.SLAVE) {
entry.getClient().getConfig().getFailedNodeDetector().onConnectSuccessful();
}
if (!cancelableFuture.complete(r)) {
entry.returnConnection(r);
}
});
return cancelableFuture;
}
private boolean isHealthy(ClientConnectionsEntry entry) {
if (entry.getNodeType() == NodeType.SLAVE
&& entry.getClient().getConfig().getFailedNodeDetector().isNodeFailed()) {
return false;
}
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy