Merge with master

This commit is contained in:
Marcos Nils
2014-02-18 22:30:40 -03:00
9 changed files with 233 additions and 331 deletions

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ target/
build/ build/
bin/ bin/
tags tags
.idea
*.aof
*.rdb

View File

@@ -25,6 +25,7 @@ define REDIS3_CONF
daemonize yes daemonize yes
port 6381 port 6381
requirepass foobared requirepass foobared
masterauth foobared
pidfile /tmp/redis3.pid pidfile /tmp/redis3.pid
logfile /tmp/redis3.log logfile /tmp/redis3.log
save "" save ""
@@ -52,7 +53,7 @@ pidfile /tmp/redis5.pid
logfile /tmp/redis5.log logfile /tmp/redis5.log
save "" save ""
appendonly no appendonly no
slaveof localhost 6381 slaveof localhost 6379
endef endef
define REDIS6_CONF define REDIS6_CONF
@@ -64,7 +65,6 @@ pidfile /tmp/redis6.pid
logfile /tmp/redis6.log logfile /tmp/redis6.log
save "" save ""
appendonly no appendonly no
slaveof localhost 6379
endef endef
define REDIS7_CONF define REDIS7_CONF
@@ -76,18 +76,7 @@ pidfile /tmp/redis7.pid
logfile /tmp/redis7.log logfile /tmp/redis7.log
save "" save ""
appendonly no appendonly no
endef slaveof localhost 6384
define REDIS8_CONF
daemonize yes
port 6386
requirepass foobared
masterauth foobared
pidfile /tmp/redis8.pid
logfile /tmp/redis8.log
save ""
appendonly no
slaveof localhost 6385
endef endef
# SENTINELS # SENTINELS
@@ -97,7 +86,7 @@ daemonize yes
sentinel monitor mymaster 127.0.0.1 6379 1 sentinel monitor mymaster 127.0.0.1 6379 1
sentinel auth-pass mymaster foobared sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 2000 sentinel down-after-milliseconds mymaster 2000
sentinel failover-timeout mymaster 180000 sentinel failover-timeout mymaster 120000
sentinel parallel-syncs mymaster 1 sentinel parallel-syncs mymaster 1
pidfile /tmp/sentinel1.pid pidfile /tmp/sentinel1.pid
logfile /tmp/sentinel1.log logfile /tmp/sentinel1.log
@@ -106,11 +95,11 @@ endef
define REDIS_SENTINEL2 define REDIS_SENTINEL2
port 26380 port 26380
daemonize yes daemonize yes
sentinel monitor mymaster 127.0.0.1 6381 2 sentinel monitor mymaster 127.0.0.1 6381 1
sentinel auth-pass mymaster foobared sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 2000 sentinel down-after-milliseconds mymaster 2000
sentinel parallel-syncs mymaster 1 sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000 sentinel failover-timeout mymaster 120000
pidfile /tmp/sentinel2.pid pidfile /tmp/sentinel2.pid
logfile /tmp/sentinel2.log logfile /tmp/sentinel2.log
endef endef
@@ -118,25 +107,13 @@ endef
define REDIS_SENTINEL3 define REDIS_SENTINEL3
port 26381 port 26381
daemonize yes daemonize yes
sentinel monitor mymaster 127.0.0.1 6381 2 sentinel monitor mymasterfailover 127.0.0.1 6384 1
sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 2000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
pidfile /tmp/sentinel3.pid
logfile /tmp/sentinel3.log
endef
define REDIS_SENTINEL4
port 26382
daemonize yes
sentinel monitor mymasterfailover 127.0.0.1 6385 1
sentinel auth-pass mymasterfailover foobared sentinel auth-pass mymasterfailover foobared
sentinel down-after-milliseconds mymasterfailover 2000 sentinel down-after-milliseconds mymasterfailover 2000
sentinel failover-timeout mymasterfailover 180000 sentinel failover-timeout mymasterfailover 120000
sentinel parallel-syncs mymasterfailover 1 sentinel parallel-syncs mymasterfailover 1
pidfile /tmp/sentinel4.pid pidfile /tmp/sentinel3.pid
logfile /tmp/sentinel4.log logfile /tmp/sentinel3.log
endef endef
# CLUSTER REDIS NODES # CLUSTER REDIS NODES
@@ -183,11 +160,9 @@ export REDIS4_CONF
export REDIS5_CONF export REDIS5_CONF
export REDIS6_CONF export REDIS6_CONF
export REDIS7_CONF export REDIS7_CONF
export REDIS8_CONF
export REDIS_SENTINEL1 export REDIS_SENTINEL1
export REDIS_SENTINEL2 export REDIS_SENTINEL2
export REDIS_SENTINEL3 export REDIS_SENTINEL3
export REDIS_SENTINEL4
export REDIS_CLUSTER_NODE1_CONF export REDIS_CLUSTER_NODE1_CONF
export REDIS_CLUSTER_NODE2_CONF export REDIS_CLUSTER_NODE2_CONF
export REDIS_CLUSTER_NODE3_CONF export REDIS_CLUSTER_NODE3_CONF
@@ -200,14 +175,11 @@ start: cleanup
echo "$$REDIS5_CONF" | redis-server - echo "$$REDIS5_CONF" | redis-server -
echo "$$REDIS6_CONF" | redis-server - echo "$$REDIS6_CONF" | redis-server -
echo "$$REDIS7_CONF" | redis-server - echo "$$REDIS7_CONF" | redis-server -
echo "$$REDIS8_CONF" | redis-server -
echo "$$REDIS_SENTINEL1" > /tmp/sentinel1.conf && redis-server /tmp/sentinel1.conf --sentinel echo "$$REDIS_SENTINEL1" > /tmp/sentinel1.conf && redis-server /tmp/sentinel1.conf --sentinel
@sleep 0.5 @sleep 0.5
echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel
@sleep 0.5 @sleep 0.5
echo "$$REDIS_SENTINEL3" > /tmp/sentinel3.conf && redis-server /tmp/sentinel3.conf --sentinel echo "$$REDIS_SENTINEL3" > /tmp/sentinel3.conf && redis-server /tmp/sentinel3.conf --sentinel
@sleep 0.5
echo "$$REDIS_SENTINEL4" > /tmp/sentinel4.conf && redis-server /tmp/sentinel4.conf --sentinel
echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server -
@@ -219,24 +191,20 @@ cleanup:
stop: stop:
kill `cat /tmp/redis1.pid` kill `cat /tmp/redis1.pid`
kill `cat /tmp/redis2.pid` kill `cat /tmp/redis2.pid`
# this get's segfaulted by the tests kill `cat /tmp/redis3.pid`
kill `cat /tmp/redis3.pid` || true kill `cat /tmp/redis4.pid`
kill `cat /tmp/redis4.pid` || true kill `cat /tmp/redis5.pid`
kill `cat /tmp/redis5.pid` || true kill `cat /tmp/redis6.pid`
kill `cat /tmp/redis6.pid` || true
kill `cat /tmp/redis7.pid` kill `cat /tmp/redis7.pid`
kill `cat /tmp/redis8.pid`
kill `cat /tmp/sentinel1.pid` kill `cat /tmp/sentinel1.pid`
kill `cat /tmp/sentinel2.pid` kill `cat /tmp/sentinel2.pid`
kill `cat /tmp/sentinel3.pid` kill `cat /tmp/sentinel3.pid`
kill `cat /tmp/sentinel4.pid`
kill `cat /tmp/redis_cluster_node1.pid` || true kill `cat /tmp/redis_cluster_node1.pid` || true
kill `cat /tmp/redis_cluster_node2.pid` || true kill `cat /tmp/redis_cluster_node2.pid` || true
kill `cat /tmp/redis_cluster_node3.pid` || true kill `cat /tmp/redis_cluster_node3.pid` || true
rm -f /tmp/sentinel1.conf rm -f /tmp/sentinel1.conf
rm -f /tmp/sentinel2.conf rm -f /tmp/sentinel2.conf
rm -f /tmp/sentinel3.conf rm -f /tmp/sentinel3.conf
rm -f /tmp/sentinel4.conf
rm -f /tmp/redis_cluster_node1.conf rm -f /tmp/redis_cluster_node1.conf
rm -f /tmp/redis_cluster_node2.conf rm -f /tmp/redis_cluster_node2.conf
rm -f /tmp/redis_cluster_node3.conf rm -f /tmp/redis_cluster_node3.conf

View File

@@ -9,7 +9,7 @@
<packaging>jar</packaging> <packaging>jar</packaging>
<groupId>redis.clients</groupId> <groupId>redis.clients</groupId>
<artifactId>jedis</artifactId> <artifactId>jedis</artifactId>
<version>2.4.1-SNAPSHOT</version> <version>2.4.2-SNAPSHOT</version>
<name>Jedis</name> <name>Jedis</name>
<description>Jedis is a blazingly small and sane Redis java client.</description> <description>Jedis is a blazingly small and sane Redis java client.</description>
<url>https://github.com/xetorthio/jedis</url> <url>https://github.com/xetorthio/jedis</url>
@@ -45,8 +45,8 @@
</scm> </scm>
<properties> <properties>
<redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385,localhost:6386</redis-hosts> <redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385</redis-hosts>
<sentinel-hosts>localhost:26379,localhost:26380,localhost:26381,localhost:26382</sentinel-hosts> <sentinel-hosts>localhost:26379,localhost:26380,localhost:26381</sentinel-hosts>
<cluster-hosts>localhost:7379,localhost:7380,localhost:7381</cluster-hosts> <cluster-hosts>localhost:7379,localhost:7380,localhost:7381</cluster-hosts>
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
</properties> </properties>

View File

@@ -23,7 +23,6 @@ public class HostAndPortUtil {
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3));
clusterHostAndPortList.add(new HostAndPort("localhost", 7379)); clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
clusterHostAndPortList.add(new HostAndPort("localhost", 7380)); clusterHostAndPortList.add(new HostAndPort("localhost", 7380));

View File

@@ -2,18 +2,17 @@ package redis.clients.jedis.tests;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import redis.clients.jedis.DebugParams;
import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.JedisSentinelPool; import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Transaction; import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.tests.utils.JedisSentinelTestUtil;
public class JedisSentinelPoolTest extends JedisTestBase { public class JedisSentinelPoolTest extends JedisTestBase {
private static final String MASTER_NAME = "mymaster"; private static final String MASTER_NAME = "mymaster";
@@ -22,12 +21,8 @@ public class JedisSentinelPoolTest extends JedisTestBase {
.get(2); .get(2);
protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers() protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers()
.get(3); .get(3);
protected static HostAndPort slave2 = HostAndPortUtil.getRedisServers()
.get(4);
protected static HostAndPort sentinel1 = HostAndPortUtil protected static HostAndPort sentinel1 = HostAndPortUtil
.getSentinelServers().get(1); .getSentinelServers().get(1);
protected static HostAndPort sentinel2 = HostAndPortUtil
.getSentinelServers().get(2);
protected static Jedis sentinelJedis1; protected static Jedis sentinelJedis1;
@@ -36,7 +31,6 @@ public class JedisSentinelPoolTest extends JedisTestBase {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
sentinels.add(sentinel1.toString()); sentinels.add(sentinel1.toString());
sentinels.add(sentinel2.toString());
sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort());
} }
@@ -46,17 +40,47 @@ public class JedisSentinelPoolTest extends JedisTestBase {
JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
new GenericObjectPoolConfig(), 1000, "foobared", 2); new GenericObjectPoolConfig(), 1000, "foobared", 2);
// perform failover forceFailover(pool);
doSegFaultMaster(pool); forceFailover(pool);
// perform failover once again
doSegFaultMaster(pool);
// you can test failover as much as possible // you can test failover as much as possible
// but you need to prepare additional slave per failover
} }
private void doSegFaultMaster(JedisSentinelPool pool) @Test
public void returnResourceShouldResetState() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
config, 1000, "foobared", 2);
Jedis jedis = pool.getResource();
Jedis jedis2 = null;
try {
jedis.set("hello", "jedis");
Transaction t = jedis.multi();
t.set("hello", "world");
pool.returnResource(jedis);
jedis2 = pool.getResource();
assertTrue(jedis == jedis2);
assertEquals("jedis", jedis2.get("hello"));
} catch (JedisConnectionException e) {
if (jedis2 != null) {
pool.returnBrokenResource(jedis2);
jedis2 = null;
}
} finally {
if (jedis2 != null)
pool.returnResource(jedis2);
pool.destroy();
}
}
private void forceFailover(JedisSentinelPool pool)
throws InterruptedException { throws InterruptedException {
HostAndPort oldMaster = pool.getCurrentHostMaster(); HostAndPort oldMaster = pool.getCurrentHostMaster();
@@ -64,12 +88,14 @@ public class JedisSentinelPoolTest extends JedisTestBase {
Jedis jedis = pool.getResource(); Jedis jedis = pool.getResource();
assertEquals("PONG", jedis.ping()); assertEquals("PONG", jedis.ping());
try { // It can throw JedisDataException while there's no slave to promote
jedis.debug(DebugParams.SEGFAULT()); // There's nothing we can do, so we just pass Exception to make test
} catch (Exception e) { // fail fast
} sentinelJedis1.sentinelFailover(MASTER_NAME);
waitForFailover(pool, oldMaster); waitForFailover(pool, oldMaster);
// JedisSentinelPool recognize master but may not changed internal pool
// yet
Thread.sleep(100); Thread.sleep(100);
jedis = pool.getResource(); jedis = pool.getResource();
@@ -80,62 +106,15 @@ public class JedisSentinelPoolTest extends JedisTestBase {
private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster)
throws InterruptedException { throws InterruptedException {
waitForJedisSentinelPoolRecognizeNewMaster(pool); HostAndPort newMaster = JedisSentinelTestUtil
.waitForNewPromotedMaster(sentinelJedis1);
waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster);
} }
private void waitForJedisSentinelPoolRecognizeNewMaster( private void waitForJedisSentinelPoolRecognizeNewMaster(
JedisSentinelPool pool) throws InterruptedException { JedisSentinelPool pool, HostAndPort newMaster)
throws InterruptedException {
final AtomicReference<String> newmaster = new AtomicReference<String>(
"");
sentinelJedis1.psubscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// TODO Auto-generated method stub
}
@Override
public void onPMessage(String pattern, String channel,
String message) {
if (channel.equals("+switch-master")) {
newmaster.set(message);
punsubscribe();
}
// TODO Auto-generated method stub
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
}, "*");
String[] chunks = newmaster.get().split(" ");
HostAndPort newMaster = new HostAndPort(chunks[3],
Integer.parseInt(chunks[4]));
while (true) { while (true) {
String host = pool.getCurrentHostMaster().getHost(); String host = pool.getCurrentHostMaster().getHost();
@@ -151,24 +130,4 @@ public class JedisSentinelPoolTest extends JedisTestBase {
} }
} }
@Test
public void returnResourceShouldResetState() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
config, 1000, "foobared", 2);
Jedis jedis = pool.getResource();
jedis.set("hello", "jedis");
Transaction t = jedis.multi();
t.set("hello", "world");
pool.returnResource(jedis);
Jedis jedis2 = pool.getResource();
assertTrue(jedis == jedis2);
assertEquals("jedis", jedis2.get("hello"));
pool.returnResource(jedis2);
pool.destroy();
}
} }

View File

@@ -22,15 +22,15 @@ public class JedisSentinelTest extends JedisTestBase {
protected static HostAndPort master = HostAndPortUtil.getRedisServers() protected static HostAndPort master = HostAndPortUtil.getRedisServers()
.get(0); .get(0);
protected static HostAndPort slave = HostAndPortUtil.getRedisServers().get( protected static HostAndPort slave = HostAndPortUtil.getRedisServers()
5); .get(4);
protected static HostAndPort sentinel = HostAndPortUtil protected static HostAndPort sentinel = HostAndPortUtil
.getSentinelServers().get(0); .getSentinelServers().get(0);
protected static HostAndPort sentinelForFailover = HostAndPortUtil protected static HostAndPort sentinelForFailover = HostAndPortUtil
.getSentinelServers().get(3); .getSentinelServers().get(2);
protected static HostAndPort masterForFailover = HostAndPortUtil protected static HostAndPort masterForFailover = HostAndPortUtil
.getRedisServers().get(6); .getRedisServers().get(5);
@Before @Before
public void setup() throws InterruptedException { public void setup() throws InterruptedException {
@@ -50,30 +50,35 @@ public class JedisSentinelTest extends JedisTestBase {
@Test @Test
public void sentinel() { public void sentinel() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort()); Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
List<Map<String, String>> masters = j.sentinelMasters();
boolean inMasters = false; try {
for (Map<String, String> master : masters) List<Map<String, String>> masters = j.sentinelMasters();
if (MASTER_NAME.equals(master.get("name")))
inMasters = true;
assertTrue(inMasters); boolean inMasters = false;
for (Map<String, String> master : masters)
if (MASTER_NAME.equals(master.get("name")))
inMasters = true;
List<String> masterHostAndPort = j assertTrue(inMasters);
.sentinelGetMasterAddrByName(MASTER_NAME);
HostAndPort masterFromSentinel = new HostAndPort(
masterHostAndPort.get(0), Integer.parseInt(masterHostAndPort
.get(1)));
assertEquals(master, masterFromSentinel);
List<Map<String, String>> slaves = j.sentinelSlaves(MASTER_NAME); List<String> masterHostAndPort = j
assertTrue(slaves.size() > 0); .sentinelGetMasterAddrByName(MASTER_NAME);
assertEquals(master.getPort(), HostAndPort masterFromSentinel = new HostAndPort(
Integer.parseInt(slaves.get(0).get("master-port"))); masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
assertEquals(master, masterFromSentinel);
// DO NOT RE-RUN TEST TOO FAST, RESET TAKES SOME TIME TO... RESET List<Map<String, String>> slaves = j.sentinelSlaves(MASTER_NAME);
assertEquals(Long.valueOf(1), j.sentinelReset(MASTER_NAME)); assertTrue(slaves.size() > 0);
assertEquals(Long.valueOf(0), j.sentinelReset("woof" + MASTER_NAME)); assertEquals(master.getPort(),
Integer.parseInt(slaves.get(0).get("master-port")));
// DO NOT RE-RUN TEST TOO FAST, RESET TAKES SOME TIME TO... RESET
assertEquals(Long.valueOf(1), j.sentinelReset(MASTER_NAME));
assertEquals(Long.valueOf(0), j.sentinelReset("woof" + MASTER_NAME));
} finally {
j.close();
}
} }
@Test @Test
@@ -81,40 +86,48 @@ public class JedisSentinelTest extends JedisTestBase {
Jedis j = new Jedis(sentinelForFailover.getHost(), Jedis j = new Jedis(sentinelForFailover.getHost(),
sentinelForFailover.getPort()); sentinelForFailover.getPort());
HostAndPort currentMaster = new HostAndPort( try {
masterForFailover.getHost(), masterForFailover.getPort()); List<String> masterHostAndPort = j
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
HostAndPort currentMaster = new HostAndPort(masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
String result = j.sentinelFailover(FAILOVER_MASTER_NAME);
assertEquals("OK", result);
List<String> masterHostAndPort = j JedisSentinelTestUtil.waitForNewPromotedMaster(j);
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
String result = j.sentinelFailover(FAILOVER_MASTER_NAME);
assertEquals("OK", result);
JedisSentinelTestUtil.waitForNewPromotedMaster(sentinelForFailover, masterHostAndPort = j
FAILOVER_MASTER_NAME, currentMaster); .sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
HostAndPort newMaster = new HostAndPort(masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
masterHostAndPort = j.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME); assertNotEquals(newMaster, currentMaster);
HostAndPort newMaster = new HostAndPort(masterHostAndPort.get(0), } finally {
Integer.parseInt(masterHostAndPort.get(1))); j.close();
}
assertNotEquals(newMaster, currentMaster);
} }
@Test @Test
public void sentinelMonitor() { public void sentinelMonitor() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort()); Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
// monitor new master
String result = j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
assertEquals("OK", result);
// already monitored
try { try {
j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP, master.getPort(), // monitor new master
1); String result = j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
fail(); master.getPort(), 1);
} catch (JedisDataException e) { assertEquals("OK", result);
// pass
// already monitored
try {
j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
fail();
} catch (JedisDataException e) {
// pass
}
} finally {
j.close();
} }
} }
@@ -122,19 +135,23 @@ public class JedisSentinelTest extends JedisTestBase {
public void sentinelRemove() { public void sentinelRemove() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort()); Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
ensureMonitored(sentinel, REMOVE_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
String result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertEquals("OK", result);
// not exist
try { try {
result = j.sentinelRemove(REMOVE_MASTER_NAME); ensureMonitored(sentinel, REMOVE_MASTER_NAME, MASTER_IP,
assertNotEquals("OK", result); master.getPort(), 1);
fail();
} catch (JedisDataException e) { String result = j.sentinelRemove(REMOVE_MASTER_NAME);
// pass assertEquals("OK", result);
// not exist
try {
result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertNotEquals("OK", result);
fail();
} catch (JedisDataException e) {
// pass
}
} finally {
j.close();
} }
} }
@@ -142,24 +159,29 @@ public class JedisSentinelTest extends JedisTestBase {
public void sentinelSet() { public void sentinelSet() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort()); Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
Map<String, String> parameterMap = new HashMap<String, String>(); try {
parameterMap.put("down-after-milliseconds", String.valueOf(1234)); Map<String, String> parameterMap = new HashMap<String, String>();
parameterMap.put("parallel-syncs", String.valueOf(3)); parameterMap.put("down-after-milliseconds", String.valueOf(1234));
parameterMap.put("quorum", String.valueOf(2)); parameterMap.put("parallel-syncs", String.valueOf(3));
j.sentinelSet(MASTER_NAME, parameterMap); parameterMap.put("quorum", String.valueOf(2));
j.sentinelSet(MASTER_NAME, parameterMap);
List<Map<String, String>> masters = j.sentinelMasters(); List<Map<String, String>> masters = j.sentinelMasters();
for (Map<String, String> master : masters) { for (Map<String, String> master : masters) {
if (master.get("name").equals(MASTER_NAME)) { if (master.get("name").equals(MASTER_NAME)) {
assertEquals(1234, assertEquals(1234, Integer.parseInt(master
Integer.parseInt(master.get("down-after-milliseconds"))); .get("down-after-milliseconds")));
assertEquals(3, Integer.parseInt(master.get("parallel-syncs"))); assertEquals(3,
assertEquals(2, Integer.parseInt(master.get("quorum"))); Integer.parseInt(master.get("parallel-syncs")));
assertEquals(2, Integer.parseInt(master.get("quorum")));
}
} }
}
parameterMap.put("quorum", String.valueOf(1)); parameterMap.put("quorum", String.valueOf(1));
j.sentinelSet(MASTER_NAME, parameterMap); j.sentinelSet(MASTER_NAME, parameterMap);
} finally {
j.close();
}
} }
private void ensureMonitored(HostAndPort sentinel, String masterName, private void ensureMonitored(HostAndPort sentinel, String masterName,
@@ -168,6 +190,8 @@ public class JedisSentinelTest extends JedisTestBase {
try { try {
j.sentinelMonitor(masterName, ip, port, quorum); j.sentinelMonitor(masterName, ip, port, quorum);
} catch (JedisDataException e) { } catch (JedisDataException e) {
} finally {
j.close();
} }
} }
@@ -176,6 +200,9 @@ public class JedisSentinelTest extends JedisTestBase {
try { try {
j.sentinelRemove(masterName); j.sentinelRemove(masterName);
} catch (JedisDataException e) { } catch (JedisDataException e) {
} finally {
j.close();
} }
} }
} }

View File

@@ -155,7 +155,7 @@ public class ShardedJedisPoolTest extends Assert {
// items on one shard // items on one shard
// alter shard 1 and recreate pool // alter shard 1 and recreate pool
pool.destroy(); pool.destroy();
shards.set(1, new JedisShardInfo("nohost", 1234)); shards.set(1, new JedisShardInfo("localhost", 1234));
pool = new ShardedJedisPool(redisConfig, shards); pool = new ShardedJedisPool(redisConfig, shards);
jedis = pool.getResource(); jedis = pool.getResource();
Long actual = Long.valueOf(0); Long actual = Long.valueOf(0);

View File

@@ -0,0 +1,17 @@
package redis.clients.jedis.tests.utils;
public class FailoverAbortedException extends RuntimeException {
private static final long serialVersionUID = 1925110762858409954L;
public FailoverAbortedException(String message) {
super(message);
}
public FailoverAbortedException(Throwable cause) {
super(cause);
}
public FailoverAbortedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,131 +1,60 @@
package redis.clients.jedis.tests.utils; package redis.clients.jedis.tests.utils;
import java.util.List; import java.util.concurrent.atomic.AtomicReference;
import java.util.Map;
import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.tests.utils.FailoverAbortedException;
public class JedisSentinelTestUtil { public class JedisSentinelTestUtil {
public static HostAndPort waitForNewPromotedMaster(Jedis sentinelJedis)
public static void waitForSentinelRecognizeRedisReplication(
HostAndPort sentinel, String masterName, HostAndPort master,
List<HostAndPort> slaves) throws InterruptedException {
Jedis sentinelJedis = new Jedis(sentinel.getHost(), sentinel.getPort());
while (true) {
Thread.sleep(1000);
if (!isMasterRecognized(sentinelJedis, masterName, master)) {
System.out.println("Master not recognized by Sentinel "
+ sentinel.getHost() + ":" + sentinel.getPort()
+ ", sleep...");
continue;
}
if (!isSlavesRecognized(sentinelJedis, masterName, slaves)) {
System.out.println("Slaves not recognized by Sentinel "
+ sentinel.getHost() + ":" + sentinel.getPort()
+ ", sleep...");
continue;
}
// all recognized
break;
}
}
public static HostAndPort waitForNewPromotedMaster(HostAndPort sentinel,
String masterName, HostAndPort oldMaster)
throws InterruptedException { throws InterruptedException {
Jedis sentinelJedis = new Jedis(sentinel.getHost(), sentinel.getPort());
HostAndPort newMaster = null; final AtomicReference<String> newmaster = new AtomicReference<String>(
while (true) { "");
Thread.sleep(1000);
List<String> sentinelMasterInfos = sentinelJedis sentinelJedis.psubscribe(new JedisPubSub() {
.sentinelGetMasterAddrByName(masterName);
if (sentinelMasterInfos == null) { @Override
System.out public void onMessage(String channel, String message) {
.println("Cannot retrieve Sentinel's master address info, sleep...");
continue;
} }
newMaster = new HostAndPort(sentinelMasterInfos.get(0), @Override
Integer.parseInt(sentinelMasterInfos.get(1))); public void onPMessage(String pattern, String channel,
String message) {
if (channel.equals("+switch-master")) {
newmaster.set(message);
punsubscribe();
} else if (channel.startsWith("-failover-abort")) {
punsubscribe();
throw new FailoverAbortedException("Unfortunately sentinel cannot failover... reason(channel) : " +
channel + " / message : " + message);
}
}
if (!newMaster.equals(oldMaster)) @Override
break; public void onSubscribe(String channel, int subscribedChannels) {
}
System.out @Override
.println("Sentinel's master is not yet changed, sleep..."); public void onUnsubscribe(String channel, int subscribedChannels) {
} }
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
}
}, "*");
String[] chunks = newmaster.get().split(" ");
HostAndPort newMaster = new HostAndPort(chunks[3],
Integer.parseInt(chunks[4]));
return newMaster; return newMaster;
} }
public static void waitForSentinelsRecognizeEachOthers()
throws InterruptedException {
// During failover, master has been changed
// It means that sentinels need to recognize other sentinels from new
// master's hello channel
// Without recognizing, Sentinels cannot run failover
// Sentinels need to take some time to recognize each other...
// http://redis.io/topics/sentinel
// Sentinel Rule #8: Every Sentinel publishes a message to every
// monitored master
// Pub/Sub channel __sentinel__:hello, every five seconds, blabla...
// FIXME There're no command for sentinel to list recognized sentinels
// so sleep wisely (channel's hello message interval + margin)
Thread.sleep(5000 + 500);
}
private static boolean isMasterRecognized(Jedis sentinelJedis,
String masterName, HostAndPort master) {
List<String> sentinelMasterInfos = sentinelJedis
.sentinelGetMasterAddrByName(masterName);
if (sentinelMasterInfos == null)
return false;
HostAndPort sentinelMaster = new HostAndPort(
sentinelMasterInfos.get(0),
Integer.parseInt(sentinelMasterInfos.get(1)));
return sentinelMaster.equals(master);
}
private static boolean isSlavesRecognized(Jedis sentinelJedis,
String masterName, List<HostAndPort> slaves) {
List<Map<String, String>> slavesMap = sentinelJedis
.sentinelSlaves(masterName);
if (slavesMap.size() != slaves.size())
return false;
int slavesRecognized = 0;
for (HostAndPort slave : slaves) {
if (isSlaveFoundInSlavesMap(slavesMap, slave))
slavesRecognized++;
}
return slavesRecognized == slaves.size();
}
private static boolean isSlaveFoundInSlavesMap(
List<Map<String, String>> slavesMap, HostAndPort slave) {
for (Map<String, String> slaveMap : slavesMap) {
HostAndPort sentinelSlave = new HostAndPort(slaveMap.get("ip"),
Integer.parseInt(slaveMap.get("port")));
if (sentinelSlave.equals(slave))
return true;
}
return false;
}
} }