org.redisson.connection.MasterSlaveEntry Maven / Gradle / Ivy
/**
* Copyright 2018 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 java.net.InetSocketAddress;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.CommandData;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.cluster.ClusterConnectionManager;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReadMode;
import org.redisson.config.SubscriptionMode;
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import org.redisson.connection.balancer.LoadBalancerManager;
import org.redisson.connection.pool.MasterConnectionPool;
import org.redisson.connection.pool.MasterPubSubConnectionPool;
import org.redisson.misc.CountableListener;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.redisson.misc.TransferListener;
import org.redisson.misc.URIBuilder;
import org.redisson.pubsub.PubSubConnectionEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
*/
public class MasterSlaveEntry {
final Logger log = LoggerFactory.getLogger(getClass());
LoadBalancerManager slaveBalancer;
ClientConnectionsEntry masterEntry;
int references;
final MasterSlaveServersConfig config;
final ConnectionManager connectionManager;
final MasterConnectionPool writeConnectionPool;
final MasterPubSubConnectionPool pubSubConnectionPool;
final AtomicBoolean active = new AtomicBoolean(true);
String sslHostname;
public MasterSlaveEntry(ConnectionManager connectionManager, MasterSlaveServersConfig config) {
this.connectionManager = connectionManager;
this.config = config;
slaveBalancer = new LoadBalancerManager(config, connectionManager, this);
writeConnectionPool = new MasterConnectionPool(config, connectionManager, this);
pubSubConnectionPool = new MasterPubSubConnectionPool(config, connectionManager, this);
if (connectionManager instanceof ClusterConnectionManager) {
sslHostname = ((ClusterConnectionManager) connectionManager).getConfigEndpointHostName();
}
}
public MasterSlaveServersConfig getConfig() {
return config;
}
public List> initSlaveBalancer(Collection disconnectedNodes) {
boolean freezeMasterAsSlave = !config.getSlaveAddresses().isEmpty()
&& !config.checkSkipSlavesInit()
&& disconnectedNodes.size() < config.getSlaveAddresses().size();
List> result = new LinkedList>();
RFuture f = addSlave(config.getMasterAddress(), freezeMasterAsSlave, NodeType.MASTER);
result.add(f);
for (URI address : config.getSlaveAddresses()) {
f = addSlave(address, disconnectedNodes.contains(address), NodeType.SLAVE);
result.add(f);
}
return result;
}
public RFuture setupMasterEntry(InetSocketAddress address, URI uri) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, address, uri, sslHostname);
return setupMasterEntry(client);
}
public RFuture setupMasterEntry(URI address) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, address, sslHostname);
return setupMasterEntry(client);
}
private RFuture setupMasterEntry(final RedisClient client) {
final RPromise result = new RedissonPromise();
RFuture addrFuture = client.resolveAddr();
addrFuture.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (!future.isSuccess()) {
client.shutdownAsync();
result.tryFailure(future.cause());
return;
}
masterEntry = new ClientConnectionsEntry(
client,
config.getMasterConnectionMinimumIdleSize(),
config.getMasterConnectionPoolSize(),
config.getSubscriptionConnectionMinimumIdleSize(),
config.getSubscriptionConnectionPoolSize(),
connectionManager,
NodeType.MASTER);
int counter = 1;
if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
counter++;
}
CountableListener listener = new CountableListener(result, client, counter);
RFuture writeFuture = writeConnectionPool.add(masterEntry);
writeFuture.addListener(listener);
if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
RFuture pubSubFuture = pubSubConnectionPool.add(masterEntry);
pubSubFuture.addListener(listener);
}
}
});
return result;
}
public boolean slaveDown(ClientConnectionsEntry entry, FreezeReason freezeReason) {
ClientConnectionsEntry e = slaveBalancer.freeze(entry, freezeReason);
if (e == null) {
return false;
}
return slaveDown(entry);
}
public boolean slaveDown(InetSocketAddress address, FreezeReason freezeReason) {
ClientConnectionsEntry entry = slaveBalancer.freeze(address, freezeReason);
if (entry == null) {
return false;
}
return slaveDown(entry);
}
public boolean slaveDown(URI address, FreezeReason freezeReason) {
ClientConnectionsEntry entry = slaveBalancer.freeze(address, freezeReason);
if (entry == null) {
return false;
}
return slaveDown(entry);
}
private boolean slaveDown(ClientConnectionsEntry entry) {
if (entry.isMasterForRead()) {
return false;
}
// add master as slave if no more slaves available
if (!config.checkSkipSlavesInit() && slaveBalancer.getAvailableClients() == 0) {
if (slaveBalancer.unfreeze(masterEntry.getClient().getAddr(), FreezeReason.SYSTEM)) {
log.info("master {} used as slave", masterEntry.getClient().getAddr());
}
}
entry.reset();
for (RedisConnection connection : entry.getAllConnections()) {
connection.closeAsync();
reattachBlockingQueue(connection);
}
while (true) {
RedisConnection connection = entry.pollConnection();
if (connection == null) {
break;
}
}
entry.getAllConnections().clear();
for (RedisPubSubConnection connection : entry.getAllSubscribeConnections()) {
connection.closeAsync();
connectionManager.getSubscribeService().reattachPubSub(connection);
}
while (true) {
RedisConnection connection = entry.pollSubscribeConnection();
if (connection == null) {
break;
}
}
entry.getAllSubscribeConnections().clear();
return true;
}
private void reattachBlockingQueue(RedisConnection connection) {
final CommandData, ?> commandData = connection.getCurrentCommand();
if (commandData == null
|| !commandData.isBlockingCommand()
|| commandData.getPromise().isDone()) {
return;
}
RFuture newConnection = connectionWriteOp(commandData.getCommand());
newConnection.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (!future.isSuccess()) {
log.error("Can't resubscribe blocking queue {}", commandData);
return;
}
final RedisConnection newConnection = future.getNow();
final FutureListener
© 2015 - 2025 Weber Informatics LLC | Privacy Policy