package com.lambdaworks.redis.masterslave;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.lambdaworks.redis.*;
import com.lambdaworks.redis.api.StatefulRedisConnection;
import com.lambdaworks.redis.internal.LettuceAssert;
import com.lambdaworks.redis.models.role.RedisInstance;
import com.lambdaworks.redis.models.role.RedisNodeDescription;
import com.lambdaworks.redis.models.role.RoleParser;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
/**
* Topology provider for a static node collection. This provider uses a static collection of nodes to determine the role of each
* {@link RedisURI node}. Node roles may change during runtime but the configuration must remain the same. This
* {@link TopologyProvider} does not auto-discover nodes.
*
* @author Mark Paluch
*/
public class StaticMasterSlaveTopologyProvider implements TopologyProvider {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(StaticMasterSlaveTopologyProvider.class);
private final RedisClient redisClient;
private final Iterable<RedisURI> redisURIs;
public StaticMasterSlaveTopologyProvider(RedisClient redisClient, Iterable<RedisURI> redisURIs) {
LettuceAssert.notNull(redisClient, "RedisClient must not be null");
LettuceAssert.notNull(redisURIs, "RedisURIs must not be null");
LettuceAssert.notNull(redisURIs.iterator().hasNext(), "RedisURIs must not be empty");
this.redisClient = redisClient;
this.redisURIs = redisURIs;
}
@Override
@SuppressWarnings("rawtypes")
public List<RedisNodeDescription> getNodes() {
List<StatefulRedisConnection<String, String>> connections = new ArrayList<>();
Map<RedisURI, RedisFuture<List<Object>>> roles = new HashMap<>();
try {
for (RedisURI redisURI : redisURIs) {
try {
StatefulRedisConnection<String, String> connection = redisClient.connect(redisURI);
connections.add(connection);
roles.put(redisURI, connection.async().role());
} catch (RuntimeException e) {
logger.warn("Cannot connect to {}", redisURI, e);
}
}
RedisURI next = redisURIs.iterator().next();
boolean success = LettuceFutures.awaitAll(next.getTimeout(), next.getUnit(),
roles.values().toArray(new Future[roles.size()]));
if (success) {
List<RedisNodeDescription> result = new ArrayList<>();
for (Map.Entry<RedisURI, RedisFuture<List<Object>>> entry : roles.entrySet()) {
if (!entry.getValue().isDone()) {
continue;
}
RedisURI key = entry.getKey();
RedisInstance redisInstance = RoleParser.parse(entry.getValue().get());
result.add(new RedisMasterSlaveNode(key.getHost(), key.getPort(), key, redisInstance.getRole()));
}
return result;
}
} catch (ExecutionException e) {
throw new IllegalStateException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RedisCommandInterruptedException(e);
} finally {
for (StatefulRedisConnection<String, String> connection : connections) {
connection.close();
}
}
return Collections.emptyList();
}
}