diff --git a/CHANGELOG.md b/CHANGELOG.md index 592bd4795..6e4cfb306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ Redisson Releases History ================================ ####Please Note: trunk is current development branch. +####30-Apr-2016 - version 2.2.13 released + +Feature - `RSet.diff` and `RSet.intersection` methods added +Imporovement - `RScoredSortedSet`.`containsAll`, `removeAll` and `retainAll` methods speed optimization +Imporovement - `RSetCache` memory and speed optimization +Imporovement - `RSet`.`retainAll`, `containsAll`, `removeAll` methods speed optimized up to 100x +Fixed - possible infinity `RLock` expiration renewal process +Fixed - error during `RSetCache.readAll` invocation. +Fixed - expiration override wasn't work in `RSetCache.add` + ####22-Apr-2016 - version 2.2.12 released Imporovement - Replaying phase handling in CommandDecoder diff --git a/README.md b/README.md index fdce687bb..9d87ecd05 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,12 @@ Include the following to your dependency list: org.redisson redisson - 2.2.12 + 2.2.13 ### Gradle - compile 'org.redisson:redisson:2.2.12' + compile 'org.redisson:redisson:2.2.13' ### Supported by diff --git a/pom.xml b/pom.xml index c7cf883d8..974c60071 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.redisson redisson - 2.2.13-SNAPSHOT + 2.2.14-SNAPSHOT bundle Redisson diff --git a/src/main/java/org/redisson/RedissonScoredSortedSet.java b/src/main/java/org/redisson/RedissonScoredSortedSet.java index d4f714fb1..43edf86bd 100644 --- a/src/main/java/org/redisson/RedissonScoredSortedSet.java +++ b/src/main/java/org/redisson/RedissonScoredSortedSet.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.net.InetSocketAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -29,8 +30,11 @@ import java.util.Map.Entry; import org.redisson.client.codec.Codec; import org.redisson.client.codec.ScoredCodec; import org.redisson.client.codec.StringCodec; +import org.redisson.client.protocol.RedisCommand; import org.redisson.client.protocol.RedisCommands; import org.redisson.client.protocol.ScoredEntry; +import org.redisson.client.protocol.RedisCommand.ValueType; +import org.redisson.client.protocol.convertor.BooleanReplayConvertor; import org.redisson.client.protocol.decoder.ListScanResult; import org.redisson.command.CommandAsyncExecutor; import org.redisson.core.RScoredSortedSet; @@ -47,6 +51,16 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc super(codec, commandExecutor, name); } + @Override + public Collection readAll() { + return get(readAllAsync()); + } + + @Override + public Future> readAllAsync() { + return valueRangeAsync(0, -1); + } + @Override public V pollFirst() { return get(pollFirstAsync()); @@ -278,27 +292,32 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc @Override public Future containsAllAsync(Collection c) { - return commandExecutor.evalReadAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN_WITH_VALUES, - "local s = redis.call('zrange', KEYS[1], 0, -1);" + - "for i = 1, #s, 1 do " + + if (c.isEmpty()) { + return newSucceededFuture(true); + } + + return commandExecutor.evalReadAsync(getName(), codec, new RedisCommand("EVAL", new BooleanReplayConvertor(), 4, ValueType.OBJECTS), "for j = 1, #ARGV, 1 do " - + "if ARGV[j] == s[i] " - + "then table.remove(ARGV, j) end " + + "local expireDateScore = redis.call('zscore', KEYS[1], ARGV[j]) " + + "if expireDateScore == false then " + + "return 0;" + + "end; " + "end; " - + "end;" - + "return #ARGV == 0 and 1 or 0; ", + + "return 1; ", Collections.singletonList(getName()), c.toArray()); } @Override public Future removeAllAsync(Collection c) { - return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN_WITH_VALUES, - "local v = 0;" - + "for i=1, #ARGV, 5000 do " - + "v = v + redis.call('zrem', KEYS[1], unpack(ARGV, i, math.min(i+4999, #ARGV))); " - + "end " - + "return v > 0;", - Collections.singletonList(getName()), c.toArray()); + if (c.isEmpty()) { + return newSucceededFuture(false); + } + + List params = new ArrayList(c.size()+1); + params.add(getName()); + params.addAll(c); + + return commandExecutor.writeAsync(getName(), codec, RedisCommands.ZREM, params.toArray()); } @Override @@ -310,30 +329,34 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc public boolean retainAll(Collection c) { return get(retainAllAsync(c)); } + + private byte[] encode(V value) { + try { + return codec.getValueEncoder().encode(value); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } @Override public Future retainAllAsync(Collection c) { - return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN_WITH_VALUES, - "local changed = 0 " + - "local s = redis.call('zrange', KEYS[1], 0, -1) " - + "local i = 1 " - + "while i <= #s do " - + "local element = s[i] " - + "local isInAgrs = false " - + "for j = 1, #ARGV, 1 do " - + "if ARGV[j] == element then " - + "isInAgrs = true " - + "break " - + "end " - + "end " - + "if isInAgrs == false then " - + "redis.call('zrem', KEYS[1], element) " - + "changed = 1 " - + "end " - + "i = i + 1 " - + "end " - + "return changed ", - Collections.singletonList(getName()), c.toArray()); + if (c.isEmpty()) { + return deleteAsync(); + } + + List params = new ArrayList(c.size()*2); + for (Object object : c) { + params.add(0); + params.add(encode((V)object)); + } + + return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN, + "redis.call('zadd', KEYS[2], unpack(ARGV)); " + + "local prevSize = redis.call('zcard', KEYS[1]); " + + "local size = redis.call('zinterstore', KEYS[1], 2, KEYS[1], KEYS[2], 'aggregate', 'sum');" + + "redis.call('del', KEYS[2]); " + + "return size ~= prevSize and 1 or 0; ", + Arrays.asList(getName(), "redisson_temp__{" + getName() + "}"), params.toArray()); } @Override @@ -435,6 +458,11 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc return get(entryRangeAsync(startScore, startScoreInclusive, endScore, endScoreInclusive, offset, count)); } + @Override + public Collection> entryRangeReversed(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count) { + return get(entryRangeReversedAsync(startScore, startScoreInclusive, endScore, endScoreInclusive, offset, count)); + } + @Override public Future>> entryRangeAsync(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count) { String startValue = value(startScore, startScoreInclusive); @@ -442,6 +470,13 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc return commandExecutor.readAsync(getName(), codec, RedisCommands.ZRANGEBYSCORE_ENTRY, getName(), startValue, endValue, "WITHSCORES", "LIMIT", offset, count); } + @Override + public Future>> entryRangeReversedAsync(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count) { + String startValue = value(startScore, startScoreInclusive); + String endValue = value(endScore, endScoreInclusive); + return commandExecutor.readAsync(getName(), codec, RedisCommands.ZREVRANGEBYSCORE_ENTRY, getName(), endValue, startValue, "WITHSCORES", "LIMIT", offset, count); + } + @Override public Future revRankAsync(V o) { return commandExecutor.readAsync(getName(), codec, RedisCommands.ZREVRANK_INT, getName(), o); diff --git a/src/main/java/org/redisson/RedissonSet.java b/src/main/java/org/redisson/RedissonSet.java index fc149db07..7303a68cc 100644 --- a/src/main/java/org/redisson/RedissonSet.java +++ b/src/main/java/org/redisson/RedissonSet.java @@ -263,6 +263,58 @@ public class RedissonSet extends RedissonExpirable implements RSet { return commandExecutor.writeAsync(getName(), codec, RedisCommands.SUNION, args.toArray()); } + @Override + public int diff(String... names) { + return get(diffAsync(names)); + } + + @Override + public Future diffAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SDIFFSTORE_INT, args.toArray()); + } + + @Override + public Set readDiff(String... names) { + return get(readDiffAsync(names)); + } + + @Override + public Future> readDiffAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SDIFF, args.toArray()); + } + + @Override + public int intersection(String... names) { + return get(intersectionAsync(names)); + } + + @Override + public Future intersectionAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SINTERSTORE_INT, args.toArray()); + } + + @Override + public Set readIntersection(String... names) { + return get(readIntersectionAsync(names)); + } + + @Override + public Future> readIntersectionAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SINTER, args.toArray()); + } + @Override public void clear() { delete(); diff --git a/src/main/java/org/redisson/RedissonSetMultimapValues.java b/src/main/java/org/redisson/RedissonSetMultimapValues.java index a4cd1513c..629cbd111 100644 --- a/src/main/java/org/redisson/RedissonSetMultimapValues.java +++ b/src/main/java/org/redisson/RedissonSetMultimapValues.java @@ -394,4 +394,56 @@ public class RedissonSetMultimapValues extends RedissonExpirable implements R delete(); } + @Override + public int diff(String... names) { + return get(diffAsync(names)); + } + + @Override + public Future diffAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SDIFFSTORE_INT, args.toArray()); + } + + @Override + public Set readDiff(String... names) { + return get(readDiffAsync(names)); + } + + @Override + public Future> readDiffAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SDIFF, args.toArray()); + } + + @Override + public int intersection(String... names) { + return get(intersectionAsync(names)); + } + + @Override + public Future intersectionAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SINTERSTORE_INT, args.toArray()); + } + + @Override + public Set readIntersection(String... names) { + return get(readIntersectionAsync(names)); + } + + @Override + public Future> readIntersectionAsync(String... names) { + List args = new ArrayList(names.length + 1); + args.add(getName()); + args.addAll(Arrays.asList(names)); + return commandExecutor.writeAsync(getName(), codec, RedisCommands.SINTER, args.toArray()); + } + } diff --git a/src/main/java/org/redisson/client/protocol/RedisCommands.java b/src/main/java/org/redisson/client/protocol/RedisCommands.java index 490914c6c..253e91507 100644 --- a/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -101,6 +101,7 @@ public interface RedisCommands { RedisCommand> ZRANGEBYSCORE = new RedisCommand>("ZRANGEBYSCORE", new ObjectSetReplayDecoder()); RedisCommand> ZRANGEBYSCORE_LIST = new RedisCommand>("ZRANGEBYSCORE", new ObjectListReplayDecoder()); RedisCommand> ZREVRANGEBYSCORE = new RedisCommand>("ZREVRANGEBYSCORE", new ObjectListReplayDecoder()); + RedisCommand>> ZREVRANGEBYSCORE_ENTRY = new RedisCommand>>("ZREVRANGEBYSCORE", new ScoredSortedSetReplayDecoder()); RedisCommand>> ZRANGE_ENTRY = new RedisCommand>>("ZRANGE", new ScoredSortedSetReplayDecoder()); RedisCommand>> ZRANGEBYSCORE_ENTRY = new RedisCommand>>("ZRANGEBYSCORE", new ScoredSortedSetReplayDecoder()); RedisCommand> ZSCAN = new RedisCommand>("ZSCAN", new NestedMultiDecoder(new ScoredSortedSetScanDecoder(), new ScoredSortedSetScanReplayDecoder()), ValueType.OBJECT); @@ -129,8 +130,12 @@ public interface RedisCommands { RedisStrictCommand SCARD_INT = new RedisStrictCommand("SCARD", new IntegerReplayConvertor()); RedisStrictCommand SCARD = new RedisStrictCommand("SCARD"); RedisStrictCommand SUNIONSTORE_INT = new RedisStrictCommand("SUNIONSTORE", new IntegerReplayConvertor()); + RedisStrictCommand SDIFFSTORE_INT = new RedisStrictCommand("SDIFFSTORE", new IntegerReplayConvertor()); + RedisStrictCommand SINTERSTORE_INT = new RedisStrictCommand("SINTERSTORE", new IntegerReplayConvertor()); RedisStrictCommand SUNIONSTORE = new RedisStrictCommand("SUNIONSTORE"); RedisCommand> SUNION = new RedisCommand>("SUNION", new ObjectSetReplayDecoder()); + RedisCommand> SDIFF = new RedisCommand>("SDIFF", new ObjectSetReplayDecoder()); + RedisCommand> SINTER = new RedisCommand>("SINTER", new ObjectSetReplayDecoder()); RedisCommand LSET = new RedisCommand("LSET", new VoidReplayConvertor(), 3); RedisCommand LPOP = new RedisCommand("LPOP"); diff --git a/src/main/java/org/redisson/core/RLexSortedSet.java b/src/main/java/org/redisson/core/RLexSortedSet.java index 2a56ca448..407c01650 100644 --- a/src/main/java/org/redisson/core/RLexSortedSet.java +++ b/src/main/java/org/redisson/core/RLexSortedSet.java @@ -20,6 +20,29 @@ import java.util.Set; public interface RLexSortedSet extends RLexSortedSetAsync, Set, RExpirable { + String pollFirst(); + + String pollLast(); + + String first(); + + String last(); + + /** + * Returns rank of value, with the scores ordered from high to low. + * + * @param o + * @return rank or null if value does not exist + */ + Integer revRank(String o); + + /** + * Read all values at once. + * + * @return + */ + Collection readAll(); + int removeRangeTail(String fromElement, boolean fromInclusive); /** diff --git a/src/main/java/org/redisson/core/RLexSortedSetAsync.java b/src/main/java/org/redisson/core/RLexSortedSetAsync.java index 6616e25e5..42541bfa5 100644 --- a/src/main/java/org/redisson/core/RLexSortedSetAsync.java +++ b/src/main/java/org/redisson/core/RLexSortedSetAsync.java @@ -21,6 +21,21 @@ import io.netty.util.concurrent.Future; public interface RLexSortedSetAsync extends RCollectionAsync { + Future pollLastAsync(); + + Future pollFirstAsync(); + + Future firstAsync(); + + Future lastAsync(); + + /** + * Read all values at once. + * + * @return + */ + Future> readAllAsync(); + Future removeRangeAsync(String fromElement, boolean fromInclusive, String toElement, boolean toInclusive); /** @@ -126,5 +141,13 @@ public interface RLexSortedSetAsync extends RCollectionAsync { */ @Deprecated Future> valueRangeAsync(int startIndex, int endIndex); + + /** + * Returns rank of value, with the scores ordered from high to low. + * + * @param o + * @return rank or null if value does not exist + */ + Future revRankAsync(String o); } diff --git a/src/main/java/org/redisson/core/RScoredSortedSet.java b/src/main/java/org/redisson/core/RScoredSortedSet.java index 27a4c5ea5..19ffcb90c 100644 --- a/src/main/java/org/redisson/core/RScoredSortedSet.java +++ b/src/main/java/org/redisson/core/RScoredSortedSet.java @@ -112,4 +112,13 @@ public interface RScoredSortedSet extends RScoredSortedSetAsync, Iterable< Collection> entryRange(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count); + Collection> entryRangeReversed(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count); + + /** + * Read all values at once. + * + * @return + */ + Collection readAll(); + } diff --git a/src/main/java/org/redisson/core/RScoredSortedSetAsync.java b/src/main/java/org/redisson/core/RScoredSortedSetAsync.java index 83e41798e..e1fe791aa 100644 --- a/src/main/java/org/redisson/core/RScoredSortedSetAsync.java +++ b/src/main/java/org/redisson/core/RScoredSortedSetAsync.java @@ -94,4 +94,13 @@ public interface RScoredSortedSetAsync extends RExpirableAsync { Future>> entryRangeAsync(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count); + Future>> entryRangeReversedAsync(double startScore, boolean startScoreInclusive, double endScore, boolean endScoreInclusive, int offset, int count); + + /** + * Read all values at once. + * + * @return + */ + Future> readAllAsync(); + } diff --git a/src/main/java/org/redisson/core/RSet.java b/src/main/java/org/redisson/core/RSet.java index d98db75f6..316a1c6ff 100644 --- a/src/main/java/org/redisson/core/RSet.java +++ b/src/main/java/org/redisson/core/RSet.java @@ -68,4 +68,40 @@ public interface RSet extends Set, RExpirable, RSetAsync { */ Set readUnion(String... names); + /** + * Diff sets specified by name and write to current set. + * If current set already exists, it is overwritten. + * + * @param names + * @return + */ + int diff(String... names); + + /** + * Diff sets specified by name with current set. + * Without current set state change. + * + * @param names + * @return + */ + + Set readDiff(String... names); + /** + * Intersection sets specified by name and write to current set. + * If current set already exists, it is overwritten. + * + * @param names + * @return + */ + int intersection(String... names); + + /** + * Intersection sets specified by name with current set. + * Without current set state change. + * + * @param names + * @return + */ + Set readIntersection(String... names); + } diff --git a/src/main/java/org/redisson/core/RSetAsync.java b/src/main/java/org/redisson/core/RSetAsync.java index f74512191..214bebc7d 100644 --- a/src/main/java/org/redisson/core/RSetAsync.java +++ b/src/main/java/org/redisson/core/RSetAsync.java @@ -71,4 +71,40 @@ public interface RSetAsync extends RCollectionAsync { */ Future> readUnionAsync(String... keys); + /** + * Diff sets specified by name and write to current set. + * If current set already exists, it is overwritten. + * + * @param names + * @return + */ + Future diffAsync(String... keys); + + /** + * Diff sets specified by name with current set. + * Without current set state change. + * + * @param names + * @return + */ + Future> readDiffAsync(String... keys); + + /** + * Intersection sets specified by name and write to current set. + * If current set already exists, it is overwritten. + * + * @param names + * @return + */ + Future intersectionAsync(String... keys); + + /** + * Intersection sets specified by name with current set. + * Without current set state change. + * + * @param names + * @return + */ + Future> readIntersectionAsync(String... keys); + } diff --git a/src/main/java/org/redisson/core/RSetCache.java b/src/main/java/org/redisson/core/RSetCache.java index a2db04c93..902cb3493 100644 --- a/src/main/java/org/redisson/core/RSetCache.java +++ b/src/main/java/org/redisson/core/RSetCache.java @@ -19,10 +19,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; /** - *

Set-based cache with ability to set TTL for each entry via - * {@link #put(Object, Object, long, TimeUnit)} method. - * And therefore has an complex lua-scripts inside. - * Uses map(value_hash, value) to tie with sorted set which contains expiration record for every value with TTL. + *

Set-based cache with ability to set TTL for each object. *

* *

Current Redis implementation doesn't have set entry eviction functionality. diff --git a/src/test/java/org/redisson/RedissonLexSortedSetTest.java b/src/test/java/org/redisson/RedissonLexSortedSetTest.java index e6ce62d4c..d3d220cb4 100644 --- a/src/test/java/org/redisson/RedissonLexSortedSetTest.java +++ b/src/test/java/org/redisson/RedissonLexSortedSetTest.java @@ -1,12 +1,53 @@ package org.redisson; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import org.redisson.core.RLexSortedSet; public class RedissonLexSortedSetTest extends BaseTest { + @Test + public void testPollLast() { + RLexSortedSet set = redisson.getLexSortedSet("simple"); + Assert.assertNull(set.pollLast()); + + set.add("a"); + set.add("b"); + set.add("c"); + + Assert.assertEquals("c", set.pollLast()); + MatcherAssert.assertThat(set, Matchers.contains("a", "b")); + } + + @Test + public void testPollFirst() { + RLexSortedSet set = redisson.getLexSortedSet("simple"); + Assert.assertNull(set.pollFirst()); + + set.add("a"); + set.add("b"); + set.add("c"); + + Assert.assertEquals("a", set.pollFirst()); + MatcherAssert.assertThat(set, Matchers.contains("b", "c")); + } + + @Test + public void testFirstLast() { + RLexSortedSet set = redisson.getLexSortedSet("simple"); + set.add("a"); + set.add("b"); + set.add("c"); + set.add("d"); + + Assert.assertEquals("a", set.first()); + Assert.assertEquals("d", set.last()); + } + @Test public void testRemoveLexRangeTail() { RLexSortedSet set = redisson.getLexSortedSet("simple"); diff --git a/src/test/java/org/redisson/RedissonScoredSortedSetTest.java b/src/test/java/org/redisson/RedissonScoredSortedSetTest.java index 3b08976af..b51ab43e3 100644 --- a/src/test/java/org/redisson/RedissonScoredSortedSetTest.java +++ b/src/test/java/org/redisson/RedissonScoredSortedSetTest.java @@ -27,6 +27,18 @@ import io.netty.util.concurrent.Future; public class RedissonScoredSortedSetTest extends BaseTest { + @Test + public void testReadAll() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(0, "1"); + set.add(1, "4"); + set.add(2, "2"); + set.add(3, "5"); + set.add(4, "3"); + + assertThat(set.readAll()).containsOnly("1", "2", "4", "5", "3"); + } + @Test public void testAddAll() { RScoredSortedSet set = redisson.getScoredSortedSet("simple"); @@ -288,6 +300,8 @@ public class RedissonScoredSortedSetTest extends BaseTest { Assert.assertTrue(set.retainAll(Arrays.asList(1, 2))); Assert.assertThat(set, Matchers.containsInAnyOrder(1, 2)); Assert.assertEquals(2, set.size()); + assertThat(set.getScore(1)).isEqualTo(10); + assertThat(set.getScore(2)).isEqualTo(20); } @Test @@ -651,12 +665,32 @@ public class RedissonScoredSortedSetTest extends BaseTest { set.add(4, "e"); Collection> r = set.entryRange(1, true, 4, false, 1, 2); + Assert.assertEquals(2, r.size()); ScoredEntry[] a = r.toArray(new ScoredEntry[0]); Assert.assertEquals(2d, a[0].getScore(), 0); Assert.assertEquals(3d, a[1].getScore(), 0); Assert.assertEquals("c", a[0].getValue()); Assert.assertEquals("d", a[1].getValue()); } + + @Test + public void testScoredSortedSetEntryRangeReversed() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + + set.add(0, "a"); + set.add(1, "b"); + set.add(2, "c"); + set.add(3, "d"); + set.add(4, "e"); + + Collection> r = set.entryRangeReversed(1, true, 4, false, 1, 2); + Assert.assertEquals(2, r.size()); + ScoredEntry[] a = r.toArray(new ScoredEntry[0]); + Assert.assertEquals(2d, a[0].getScore(), 0); + Assert.assertEquals(1d, a[1].getScore(), 0); + Assert.assertEquals("c", a[0].getValue()); + Assert.assertEquals("b", a[1].getValue()); + } @Test public void testScoredSortedSetEntryRangeNegativeInf() { diff --git a/src/test/java/org/redisson/RedissonSetTest.java b/src/test/java/org/redisson/RedissonSetTest.java index 0ee987094..4e0fac31f 100644 --- a/src/test/java/org/redisson/RedissonSetTest.java +++ b/src/test/java/org/redisson/RedissonSetTest.java @@ -334,7 +334,81 @@ public class RedissonSetTest extends BaseTest { assertThat(set).containsOnly(5, 6); } + @Test + public void testDiff() { + RSet set = redisson.getSet("set"); + set.add(5); + set.add(6); + RSet set1 = redisson.getSet("set1"); + set1.add(1); + set1.add(2); + set1.add(3); + RSet set2 = redisson.getSet("set2"); + set2.add(3); + set2.add(4); + set2.add(5); + + assertThat(set.diff("set1", "set2")).isEqualTo(2); + assertThat(set).containsOnly(1, 2); + } + + @Test + public void testReadDiff() { + RSet set = redisson.getSet("set"); + set.add(5); + set.add(7); + set.add(6); + RSet set1 = redisson.getSet("set1"); + set1.add(1); + set1.add(2); + set1.add(5); + RSet set2 = redisson.getSet("set2"); + set2.add(3); + set2.add(4); + set2.add(5); + + assertThat(set.readDiff("set1", "set2")).containsOnly(7, 6); + assertThat(set).containsOnly(6, 5, 7); + } + + @Test + public void testIntersection() { + RSet set = redisson.getSet("set"); + set.add(5); + set.add(6); + RSet set1 = redisson.getSet("set1"); + set1.add(1); + set1.add(2); + set1.add(3); + RSet set2 = redisson.getSet("set2"); + set2.add(3); + set2.add(4); + set2.add(5); + + assertThat(set.intersection("set1", "set2")).isEqualTo(1); + assertThat(set).containsOnly(3); + } + + @Test + public void testReadIntersection() { + RSet set = redisson.getSet("set"); + set.add(5); + set.add(7); + set.add(6); + RSet set1 = redisson.getSet("set1"); + set1.add(1); + set1.add(2); + set1.add(5); + RSet set2 = redisson.getSet("set2"); + set2.add(3); + set2.add(4); + set2.add(5); + + assertThat(set.readIntersection("set1", "set2")).containsOnly(5); + assertThat(set).containsOnly(6, 5, 7); + } + @Test public void testMove() throws Exception { RSet set = redisson.getSet("set");