From b6f2fb5fb1fcef6ed9ab22063e824804287d0b9d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 29 Jun 2014 11:55:38 +0200 Subject: [PATCH] Support for SENTINEL MASTERS --- lettuce/pom.xml | 7 +++ .../redis/RedisAsyncConnectionImpl.java | 5 ++ .../redis/RedisCommandBuilder.java | 5 ++ .../redis/RedisSentinelAsyncConnection.java | 8 +++ .../RedisSentinelAsyncConnectionImpl.java | 6 ++ .../redis/RedisServerAsyncConnection.java | 7 ++- .../redis/RedisServerConnection.java | 7 ++- .../redis/SentinelCommandBuilder.java | 15 ++++- .../redis/output/ListOfMapsOutput.java | 60 +++++++++++++++++++ .../redis/protocol/CommandOutput.java | 4 ++ .../redis/protocol/RedisStateMachine.java | 2 + .../redis/SentinelCommandTest.java | 18 ++++++ 12 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 lettuce/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java diff --git a/lettuce/pom.xml b/lettuce/pom.xml index 0a51aa8068..591b1f42a7 100644 --- a/lettuce/pom.xml +++ b/lettuce/pom.xml @@ -93,6 +93,13 @@ 1.2.17 test + + org.hamcrest + hamcrest-library + 1.3 + test + + diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java index c929ae7877..08c4e911a9 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisAsyncConnectionImpl.java @@ -204,6 +204,11 @@ public void debugSegfault() { dispatch(commandBuilder.debugSegfault()); } + @Override + public void debugOom() { + dispatch(commandBuilder.debugOom()); + } + @Override public RedisFuture decr(K key) { return dispatch(commandBuilder.decr(key)); diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 9049b3d901..ad641d1d6a 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -167,6 +167,11 @@ public Command debugSegfault() { return createCommand(DEBUG, null, args); } + public Command debugOom() { + CommandArgs args = new CommandArgs(codec).add("OOM"); + return createCommand(DEBUG, null, args); + } + public Command decr(K key) { return createCommand(DECR, new IntegerOutput(codec), key); } diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java index 42b94f55f5..e942a47c37 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java @@ -2,6 +2,7 @@ import java.io.Closeable; import java.net.SocketAddress; +import java.util.List; import java.util.Map; import java.util.concurrent.Future; @@ -23,6 +24,13 @@ public interface RedisSentinelAsyncConnection extends Closeable { */ Future getMasterAddrByName(K key); + /** + * Enumerates all the monitored masters and their states. + * + * @return RedisFuture<Map<K, V>> + */ + RedisFuture>> masters(); + /** * Show the state and info of the specified master. * diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnectionImpl.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnectionImpl.java index 91c5fac080..58039b1c77 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnectionImpl.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnectionImpl.java @@ -52,6 +52,12 @@ public SocketAddress apply(List input) { return result; } + @Override + public RedisFuture>> masters() { + + return dispatch(commandBuilder.masters()); + } + @Override public RedisFuture> master(K key) { diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java index 42409a45da..d747283889 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java @@ -114,10 +114,15 @@ public interface RedisServerAsyncConnection { RedisFuture debugObject(K key); /** - * Make the server crash. + * Make the server crash: Invalid pointer access. */ void debugSegfault(); + /** + * Make the server crash: Out of memory. + */ + void debugOom(); + /** * Remove all keys from all databases. * diff --git a/lettuce/src/main/java/com/lambdaworks/redis/RedisServerConnection.java b/lettuce/src/main/java/com/lambdaworks/redis/RedisServerConnection.java index 9c98309f51..19b1a367fb 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/RedisServerConnection.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/RedisServerConnection.java @@ -114,10 +114,15 @@ public interface RedisServerConnection { String debugObject(K key); /** - * Make the server crash. + * Make the server crash: Invalid pointer access. */ void debugSegfault(); + /** + * Make the server crash: Out of memory. + */ + void debugOom(); + /** * Remove all keys from all databases. * diff --git a/lettuce/src/main/java/com/lambdaworks/redis/SentinelCommandBuilder.java b/lettuce/src/main/java/com/lambdaworks/redis/SentinelCommandBuilder.java index 3c7e3e8f87..846462077e 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/SentinelCommandBuilder.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/SentinelCommandBuilder.java @@ -1,5 +1,8 @@ package com.lambdaworks.redis; +import static com.lambdaworks.redis.protocol.CommandKeyword.FAILOVER; +import static com.lambdaworks.redis.protocol.CommandKeyword.RESET; +import static com.lambdaworks.redis.protocol.CommandKeyword.SLAVES; import static com.lambdaworks.redis.protocol.CommandType.MONITOR; import static com.lambdaworks.redis.protocol.CommandType.PING; import static com.lambdaworks.redis.protocol.CommandType.SENTINEL; @@ -10,6 +13,7 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.output.IntegerOutput; +import com.lambdaworks.redis.output.ListOfMapsOutput; import com.lambdaworks.redis.output.MapOutput; import com.lambdaworks.redis.output.StatusOutput; import com.lambdaworks.redis.output.ValueListOutput; @@ -31,23 +35,28 @@ public Command> getMasterAddrByKey(K key) { return createCommand(SENTINEL, new ValueListOutput(codec), args); } + public Command>> masters() { + CommandArgs args = new CommandArgs(codec).add("masters"); + return createCommand(SENTINEL, new ListOfMapsOutput(codec), args); + } + public Command> master(K key) { CommandArgs args = new CommandArgs(codec).add("master").addKey(key); return createCommand(SENTINEL, new MapOutput(codec), args); } public Command> slaves(K key) { - CommandArgs args = new CommandArgs(codec).add("slaves").addKey(key); + CommandArgs args = new CommandArgs(codec).add(SLAVES).addKey(key); return createCommand(SENTINEL, new MapOutput(codec), args); } public Command reset(K key) { - CommandArgs args = new CommandArgs(codec).add("reset").addKey(key); + CommandArgs args = new CommandArgs(codec).add(RESET).addKey(key); return createCommand(SENTINEL, new IntegerOutput(codec), args); } public Command failover(K key) { - CommandArgs args = new CommandArgs(codec).add("failover").addKey(key); + CommandArgs args = new CommandArgs(codec).add(FAILOVER).addKey(key); return createCommand(SENTINEL, new StatusOutput(codec), args); } diff --git a/lettuce/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java b/lettuce/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java new file mode 100644 index 0000000000..7f855e034d --- /dev/null +++ b/lettuce/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java @@ -0,0 +1,60 @@ +// Copyright (C) 2011 - Will Glozer. All rights reserved. + +package com.lambdaworks.redis.output; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.protocol.CommandOutput; + +/** + * {@link java.util.List} of maps output. + * + * @param Key type. + * @param Value type. + * + * @author Will Glozer + */ +public class ListOfMapsOutput extends CommandOutput>> { + private MapOutput nested; + private int mapCount = -1; + private List counts = new ArrayList(); + + public ListOfMapsOutput(RedisCodec codec) { + super(codec, new ArrayList>()); + nested = new MapOutput(codec); + } + + @Override + public void set(ByteBuffer bytes) { + nested.set(bytes); + } + + @Override + public void complete(int depth) { + + if (counts.size() > 0) { + int expectedSize = counts.get(0); + + if (nested.get().size() == expectedSize) { + counts.remove(0); + output.add(new HashMap(nested.get())); + nested.get().clear(); + } + } + } + + @Override + public void multi(int count) { + if (mapCount == -1) { + mapCount = count; + } else { + // div 2 because of key value pair counts twice + counts.add(count / 2); + } + } +} diff --git a/lettuce/src/main/java/com/lambdaworks/redis/protocol/CommandOutput.java b/lettuce/src/main/java/com/lambdaworks/redis/protocol/CommandOutput.java index 9744496282..a763d18b00 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/protocol/CommandOutput.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/protocol/CommandOutput.java @@ -122,4 +122,8 @@ public String toString() { sb.append(']'); return sb.toString(); } + + public void multi(int count) { + + } } diff --git a/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java b/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java index 631aec7942..c9df9664ee 100644 --- a/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java +++ b/lettuce/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java @@ -142,6 +142,7 @@ public boolean decode(ByteBuf buffer, RedisCommand command, CommandOutp length = (int) readLong(buffer, buffer.readerIndex(), end); state.count = length; buffer.markReaderIndex(); + output.multi(state.count); } if (state.count <= 0) { @@ -150,6 +151,7 @@ public boolean decode(ByteBuf buffer, RedisCommand command, CommandOutp state.count--; stack.addFirst(new State()); + continue loop; case BYTES: if ((bytes = readBytes(buffer, state.count)) == null) { diff --git a/lettuce/src/test/java/com/lambdaworks/redis/SentinelCommandTest.java b/lettuce/src/test/java/com/lambdaworks/redis/SentinelCommandTest.java index 08bb08e21f..ec1f166a9d 100644 --- a/lettuce/src/test/java/com/lambdaworks/redis/SentinelCommandTest.java +++ b/lettuce/src/test/java/com/lambdaworks/redis/SentinelCommandTest.java @@ -3,11 +3,14 @@ package com.lambdaworks.redis; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.List; import java.util.Map; import java.util.concurrent.Future; @@ -63,6 +66,21 @@ public void getSlaveAddr() throws Exception { } + @Test + public void masters() throws Exception { + + Future>> result = sentinel.masters(); + List> list = result.get(); + + assertThat(list.size(), greaterThan(0)); + + Map map = list.get(0); + assertNotNull(map.get("flags")); + assertNotNull(map.get("config-epoch")); + assertNotNull(map.get("port")); + + } + @Test public void getSlaveDownstate() throws Exception {