From 1c4df641853ca3e8b5840105eb88197c9cf89888 Mon Sep 17 00:00:00 2001 From: Nikita Date: Tue, 23 Jan 2018 11:42:34 +0300 Subject: [PATCH] Fixed - Wrong parsing of RScript.ReturnType.MULTI result. #1251 --- .../client/handler/CommandDecoder.java | 46 ++++++++++++++----- .../org/redisson/client/handler/State.java | 18 ++++---- .../redisson/client/handler/StateLevel.java | 16 +++++++ .../java/org/redisson/RedissonScriptTest.java | 35 ++++++++++++++ 4 files changed, 94 insertions(+), 21 deletions(-) diff --git a/redisson/src/main/java/org/redisson/client/handler/CommandDecoder.java b/redisson/src/main/java/org/redisson/client/handler/CommandDecoder.java index 71207b635..d529ea939 100644 --- a/redisson/src/main/java/org/redisson/client/handler/CommandDecoder.java +++ b/redisson/src/main/java/org/redisson/client/handler/CommandDecoder.java @@ -137,12 +137,11 @@ public class CommandDecoder extends ReplayingDecoder { decodeList(in, cmd, firstLevel.getParts(), ctx.channel(), secondLevel.getSize(), secondLevel.getParts()); - Channel channel = ctx.channel(); MultiDecoder decoder = messageDecoder(cmd, firstLevel.getParts()); if (decoder != null) { Object result = decoder.decode(firstLevel.getParts(), state()); if (data != null) { - handleResult(cmd, null, result, true, channel); + handleResult(cmd, null, result, true, ctx.channel()); } } } @@ -152,7 +151,18 @@ public class CommandDecoder extends ReplayingDecoder { state().resetLevel(); decode(in, cmd, null, ctx.channel()); } else { - decodeList(in, cmd, null, ctx.channel(), firstLevel.getSize(), firstLevel.getParts()); + if (firstLevel.getLastList() != null) { + decodeList(in, cmd, firstLevel.getParts(), ctx.channel(), firstLevel.getLastListSize(), firstLevel.getLastList()); + firstLevel.setLastList(null); + firstLevel.setLastListSize(0); + + if (in.isReadable()) { + decode(in, cmd, firstLevel.getParts(), ctx.channel()); + } + decodeList(in, cmd, null, ctx.channel(), 0, firstLevel.getParts()); + } else { + decodeList(in, cmd, null, ctx.channel(), firstLevel.getSize(), firstLevel.getParts()); + } } } } @@ -287,22 +297,34 @@ public class CommandDecoder extends ReplayingDecoder { } handleResult(data, parts, result, false, channel); } else if (code == '*') { - int level = state().incLevel(); - long size = readLong(in); List respParts; - if (state().getLevels().size()-1 >= level) { - StateLevel stateLevel = state().getLevels().get(level); - respParts = stateLevel.getParts(); - size = stateLevel.getSize(); - } else { + + StateLevel lastLevel = state().getLastLevel(); + if (lastLevel != null && lastLevel.getSize() != lastLevel.getParts().size()) { respParts = new ArrayList(); - if (state().isMakeCheckpoint()) { - state().addLevel(new StateLevel(size, respParts)); + lastLevel.setLastListSize(size); + lastLevel.setLastList(respParts); + } else { + int level = state().incLevel(); + if (state().getLevels().size()-1 >= level) { + StateLevel stateLevel = state().getLevels().get(level); + respParts = stateLevel.getParts(); + size = stateLevel.getSize(); + } else { + respParts = new ArrayList(); + if (state().isMakeCheckpoint()) { + state().addLevel(new StateLevel(size, respParts)); + } } } decodeList(in, data, parts, channel, size, respParts); + + if (lastLevel != null && lastLevel.getLastList() != null) { + lastLevel.setLastList(null); + lastLevel.setLastListSize(0); + } } else { String dataStr = in.toString(0, in.writerIndex(), CharsetUtil.UTF_8); throw new IllegalStateException("Can't decode replay: " + dataStr); diff --git a/redisson/src/main/java/org/redisson/client/handler/State.java b/redisson/src/main/java/org/redisson/client/handler/State.java index 6fab0d7f3..8d7b40175 100644 --- a/redisson/src/main/java/org/redisson/client/handler/State.java +++ b/redisson/src/main/java/org/redisson/client/handler/State.java @@ -28,7 +28,6 @@ public class State { private int level = -1; private List levels; - private DecoderState decoderStateCopy; private final boolean makeCheckpoint; public State(boolean makeCheckpoint) { @@ -41,6 +40,7 @@ public class State { public void resetLevel() { level = -1; + levels.clear(); } public int decLevel() { return --level; @@ -49,6 +49,13 @@ public class State { return ++level; } + public StateLevel getLastLevel() { + if (levels == null || levels.isEmpty()) { + return null; + } + return levels.get(level); + } + public void addLevel(StateLevel stateLevel) { if (levels == null) { levels = new ArrayList(2); @@ -76,17 +83,10 @@ public class State { this.decoderState = decoderState; } - public DecoderState getDecoderStateCopy() { - return decoderStateCopy; - } - public void setDecoderStateCopy(DecoderState decoderStateCopy) { - this.decoderStateCopy = decoderStateCopy; - } - @Override public String toString() { return "State [batchIndex=" + batchIndex + ", decoderState=" + decoderState + ", level=" + level + ", levels=" - + levels + ", decoderStateCopy=" + decoderStateCopy + "]"; + + levels + "]"; } diff --git a/redisson/src/main/java/org/redisson/client/handler/StateLevel.java b/redisson/src/main/java/org/redisson/client/handler/StateLevel.java index 710728dd8..bfbd4980d 100644 --- a/redisson/src/main/java/org/redisson/client/handler/StateLevel.java +++ b/redisson/src/main/java/org/redisson/client/handler/StateLevel.java @@ -21,6 +21,8 @@ public class StateLevel { private long size; private List parts; + private long lastListSize; + private List lastList; public StateLevel(long size, List parts) { super(); @@ -28,6 +30,20 @@ public class StateLevel { this.parts = parts; } + public long getLastListSize() { + return lastListSize; + } + public void setLastListSize(long lastListSize) { + this.lastListSize = lastListSize; + } + + public List getLastList() { + return lastList; + } + public void setLastList(List lastList) { + this.lastList = lastList; + } + public long getSize() { return size; } diff --git a/redisson/src/test/java/org/redisson/RedissonScriptTest.java b/redisson/src/test/java/org/redisson/RedissonScriptTest.java index 5c0f9ecf9..7ee416ceb 100644 --- a/redisson/src/test/java/org/redisson/RedissonScriptTest.java +++ b/redisson/src/test/java/org/redisson/RedissonScriptTest.java @@ -5,16 +5,51 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import org.junit.Assert; import org.junit.Test; import org.redisson.api.RFuture; +import org.redisson.api.RLexSortedSet; import org.redisson.api.RScript; import org.redisson.api.RScript.Mode; import org.redisson.client.RedisException; +import org.redisson.client.codec.StringCodec; public class RedissonScriptTest extends BaseTest { + @Test + public void testMulti() throws InterruptedException, ExecutionException { + RLexSortedSet idx2 = redisson.getLexSortedSet("ABCD17436"); + + Long l = new Long("1506524856000"); + for (int i = 0; i < 100; i++) { + String s = "DENY" + "\t" + "TESTREDISSON" + "\t" + + Long.valueOf(l) + "\t" + "helloworld_hongqin"; + idx2.add(s); + l = l + 1; + } + + StringCodec codec = new StringCodec(); + String max = "'[DENY" + "\t" + "TESTREDISSON" + "\t" + "1506524856099'"; + String min = "'[DENY" + "\t" + "TESTREDISSON" + "\t" + "1506524856000'"; + String luaScript1= "local d = {}; d[1] = redis.call('zrevrangebylex','ABCD17436'," +max+","+min+",'LIMIT',0,5); "; + luaScript1= luaScript1 + " d[2] = redis.call('zrevrangebylex','ABCD17436'," +max+","+min+",'LIMIT',0,15); "; + luaScript1= luaScript1 + " d[3] = redis.call('zrevrangebylex','ABCD17436'," +max+","+min+",'LIMIT',0,25); "; + luaScript1 = luaScript1 + " return d;"; + + Future r1 = redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, codec, + luaScript1, + RScript.ReturnType.MULTI, Collections.emptyList()); + List> obj1 = (List>) r1.get(); + + assertThat(obj1).hasSize(3); + assertThat(obj1.get(0)).hasSize(5); + assertThat(obj1.get(1)).hasSize(15); + assertThat(obj1.get(2)).hasSize(25); + } + @Test public void testEval() { RScript script = redisson.getScript();