/**
* Copyright 2016 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;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import org.redisson.api.Node;
import org.redisson.api.NodeType;
import org.redisson.api.NodesGroup;
import org.redisson.api.RFuture;
import org.redisson.client.RedisConnection;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.connection.ConnectionListener;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.RedisClientEntry;
import org.redisson.misc.RPromise;
import org.redisson.misc.URLBuilder;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
* @param <N> node type
*/
public class RedisNodes<N extends Node> implements NodesGroup<N> {
final ConnectionManager connectionManager;
public RedisNodes(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
@Override
public N getNode(String address) {
Collection<N> clients = (Collection<N>) connectionManager.getClients();
InetSocketAddress addr = URLBuilder.toAddress(address);
for (N node : clients) {
if (node.getAddr().equals(addr)) {
return node;
}
}
return null;
}
@Override
public Collection<N> getNodes(NodeType type) {
Collection<N> clients = (Collection<N>) connectionManager.getClients();
List<N> result = new ArrayList<N>();
for (N node : clients) {
if (node.getType().equals(type)) {
result.add(node);
}
}
return result;
}
@Override
public Collection<N> getNodes() {
return (Collection<N>) connectionManager.getClients();
}
@Override
public boolean pingAll() {
List<RedisClientEntry> clients = new ArrayList<RedisClientEntry>(connectionManager.getClients());
final Map<RedisConnection, RFuture<String>> result = new ConcurrentHashMap<RedisConnection, RFuture<String>>(clients.size());
final CountDownLatch latch = new CountDownLatch(clients.size());
for (RedisClientEntry entry : clients) {
RFuture<RedisConnection> f = entry.getClient().connectAsync();
f.addListener(new FutureListener<RedisConnection>() {
@Override
public void operationComplete(Future<RedisConnection> future) throws Exception {
if (future.isSuccess()) {
final RedisConnection c = future.getNow();
RPromise<RedisConnection> connectionFuture = connectionManager.newPromise();
connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig());
connectionFuture.addListener(new FutureListener<RedisConnection>() {
@Override
public void operationComplete(Future<RedisConnection> future) throws Exception {
RFuture<String> r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING);
result.put(c, r);
latch.countDown();
}
});
} else {
latch.countDown();
}
}
});
}
long time = System.currentTimeMillis();
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (System.currentTimeMillis() - time >= connectionManager.getConfig().getConnectTimeout()) {
for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
entry.getKey().closeAsync();
}
return false;
}
time = System.currentTimeMillis();
boolean res = true;
for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
RFuture<String> f = entry.getValue();
f.awaitUninterruptibly();
if (!"PONG".equals(f.getNow())) {
res = false;
}
entry.getKey().closeAsync();
}
// true and no futures missed during client connection
return res && result.size() == clients.size();
}
@Override
public int addConnectionListener(ConnectionListener connectionListener) {
return connectionManager.getConnectionEventsHub().addListener(connectionListener);
}
@Override
public void removeConnectionListener(int listenerId) {
connectionManager.getConnectionEventsHub().removeListener(listenerId);
}
}