From 5b625d3b2eaa59cb7a6688709918d090e0546c4e Mon Sep 17 00:00:00 2001 From: Nikita Date: Fri, 29 Jan 2016 17:03:31 +0300 Subject: [PATCH] readAllKeySet, readAllValues, readAllEntry methods with async variation added to RMap. #389 --- src/main/java/org/redisson/RedissonMap.java | 30 +++++++++++ .../client/protocol/RedisCommands.java | 3 ++ .../decoder/ObjectMapEntryReplayDecoder.java | 51 +++++++++++++++++++ src/main/java/org/redisson/core/RMap.java | 22 ++++++++ .../java/org/redisson/core/RMapAsync.java | 23 +++++++++ .../java/org/redisson/RedissonMapTest.java | 44 ++++++++++++++-- 6 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/redisson/client/protocol/decoder/ObjectMapEntryReplayDecoder.java diff --git a/src/main/java/org/redisson/RedissonMap.java b/src/main/java/org/redisson/RedissonMap.java index 546637fdd..245e6a7cd 100644 --- a/src/main/java/org/redisson/RedissonMap.java +++ b/src/main/java/org/redisson/RedissonMap.java @@ -189,6 +189,36 @@ public class RedissonMap extends RedissonExpirable implements RMap { return new EntrySet(); } + @Override + public Set readAllKeySet() { + return get(readAllKeySetAsync()); + } + + @Override + public Future> readAllKeySetAsync() { + return commandExecutor.readAsync(getName(), codec, RedisCommands.HKEYS, getName()); + } + + @Override + public Collection readAllValues() { + return get(readAllValuesAsync()); + } + + @Override + public Future> readAllValuesAsync() { + return commandExecutor.readAsync(getName(), codec, RedisCommands.HVALS, getName()); + } + + @Override + public Set> readAllEntrySet() { + return get(readAllEntrySetAsync()); + } + + @Override + public Future>> readAllEntrySetAsync() { + return commandExecutor.readAsync(getName(), codec, RedisCommands.HGETALL_ENTRY, getName()); + } + @Override public V putIfAbsent(K key, V value) { return get(putIfAbsentAsync(key, value)); diff --git a/src/main/java/org/redisson/client/protocol/RedisCommands.java b/src/main/java/org/redisson/client/protocol/RedisCommands.java index d1bfa7182..65635267a 100644 --- a/src/main/java/org/redisson/client/protocol/RedisCommands.java +++ b/src/main/java/org/redisson/client/protocol/RedisCommands.java @@ -18,6 +18,7 @@ package org.redisson.client.protocol; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import org.redisson.client.protocol.RedisCommand.ValueType; import org.redisson.client.protocol.convertor.BitSetReplayConvertor; @@ -42,6 +43,7 @@ import org.redisson.client.protocol.decoder.NestedMultiDecoder; import org.redisson.client.protocol.decoder.NestedMultiDecoder2; import org.redisson.client.protocol.decoder.ObjectFirstResultReplayDecoder; import org.redisson.client.protocol.decoder.ObjectListReplayDecoder; +import org.redisson.client.protocol.decoder.ObjectMapEntryReplayDecoder; import org.redisson.client.protocol.decoder.ObjectMapReplayDecoder; import org.redisson.client.protocol.decoder.ObjectSetReplayDecoder; import org.redisson.client.protocol.decoder.ScoredSortedSetReplayDecoder; @@ -185,6 +187,7 @@ public interface RedisCommands { RedisCommand HSET = new RedisCommand("HSET", new BooleanReplayConvertor(), 2, ValueType.MAP); RedisCommand> HSCAN = new RedisCommand>("HSCAN", new NestedMultiDecoder(new ObjectMapReplayDecoder(), new MapScanResultReplayDecoder()), ValueType.MAP); RedisCommand> HGETALL = new RedisCommand>("HGETALL", new ObjectMapReplayDecoder(), ValueType.MAP); + RedisCommand>> HGETALL_ENTRY = new RedisCommand>>("HGETALL", new ObjectMapEntryReplayDecoder(), ValueType.MAP); RedisCommand> HVALS = new RedisCommand>("HVALS", new ObjectListReplayDecoder(), ValueType.MAP_VALUE); RedisCommand HEXISTS = new RedisCommand("HEXISTS", new BooleanReplayConvertor(), 2, ValueType.MAP_KEY); RedisStrictCommand HLEN = new RedisStrictCommand("HLEN", new IntegerReplayConvertor()); diff --git a/src/main/java/org/redisson/client/protocol/decoder/ObjectMapEntryReplayDecoder.java b/src/main/java/org/redisson/client/protocol/decoder/ObjectMapEntryReplayDecoder.java new file mode 100644 index 000000000..fb95414b2 --- /dev/null +++ b/src/main/java/org/redisson/client/protocol/decoder/ObjectMapEntryReplayDecoder.java @@ -0,0 +1,51 @@ +/** + * Copyright 2014 Nikita Koksharov, Nickolay Borbit + * + * 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.client.protocol.decoder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.redisson.client.handler.State; + +import io.netty.buffer.ByteBuf; + +public class ObjectMapEntryReplayDecoder implements MultiDecoder>> { + + @Override + public Object decode(ByteBuf buf, State state) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> decode(List parts, State state) { + Map result = new HashMap(parts.size()/2); + for (int i = 0; i < parts.size(); i++) { + if (i % 2 != 0) { + result.put(parts.get(i-1), parts.get(i)); + } + } + return result.entrySet(); + } + + @Override + public boolean isApplicable(int paramNum, State state) { + return false; + } + +} diff --git a/src/main/java/org/redisson/core/RMap.java b/src/main/java/org/redisson/core/RMap.java index c318cb647..c9a8fd710 100644 --- a/src/main/java/org/redisson/core/RMap.java +++ b/src/main/java/org/redisson/core/RMap.java @@ -15,6 +15,7 @@ */ package org.redisson.core; +import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -116,6 +117,27 @@ public interface RMap extends ConcurrentMap, RExpirable, RMapAsync readAllKeySet(); + + /** + * Read all values at once + * + * @return + */ + Collection readAllValues(); + + /** + * Read all map entries at once + * + * @return + */ + Set> readAllEntrySet(); + /** * Use {@link #entrySet().iterator()} * diff --git a/src/main/java/org/redisson/core/RMapAsync.java b/src/main/java/org/redisson/core/RMapAsync.java index 7d4461b1b..d6f52be79 100644 --- a/src/main/java/org/redisson/core/RMapAsync.java +++ b/src/main/java/org/redisson/core/RMapAsync.java @@ -15,7 +15,9 @@ */ package org.redisson.core; +import java.util.Collection; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import io.netty.util.concurrent.Future; @@ -69,6 +71,27 @@ public interface RMapAsync extends RExpirableAsync { Future fastPutIfAbsentAsync(K key, V value); + /** + * Read all keys at once + * + * @return + */ + Future> readAllKeySetAsync(); + + /** + * Read all values at once + * + * @return + */ + Future> readAllValuesAsync(); + + /** + * Read all map entries at once + * + * @return + */ + Future>> readAllEntrySetAsync(); + Future getAsync(K key); Future putAsync(K key, V value); diff --git a/src/test/java/org/redisson/RedissonMapTest.java b/src/test/java/org/redisson/RedissonMapTest.java index d0b45bbf1..af9d9ea4f 100644 --- a/src/test/java/org/redisson/RedissonMapTest.java +++ b/src/test/java/org/redisson/RedissonMapTest.java @@ -10,6 +10,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import org.assertj.core.data.MapEntry; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Assert; @@ -255,10 +256,21 @@ public class RedissonMapTest extends BaseTest { map.put(2, "33"); map.put(3, "43"); - Assert.assertEquals(3, map.entrySet().size()); - MatcherAssert.assertThat(map, Matchers.hasEntry(Matchers.equalTo(1), Matchers.equalTo("12"))); - MatcherAssert.assertThat(map, Matchers.hasEntry(Matchers.equalTo(2), Matchers.equalTo("33"))); - MatcherAssert.assertThat(map, Matchers.hasEntry(Matchers.equalTo(3), Matchers.equalTo("43"))); + assertThat(map.entrySet().size()).isEqualTo(3); + Map testMap = new HashMap(map); + assertThat(map.entrySet()).containsOnlyElementsOf(testMap.entrySet()); + } + + @Test + public void testReadAllEntrySet() { + RMap map = redisson.getMap("simple12"); + map.put(1, "12"); + map.put(2, "33"); + map.put(3, "43"); + + assertThat(map.readAllEntrySet().size()).isEqualTo(3); + Map testMap = new HashMap(map); + assertThat(map.readAllEntrySet()).containsOnlyElementsOf(testMap.entrySet()); } @Test @@ -312,6 +324,30 @@ public class RedissonMapTest extends BaseTest { Assert.assertFalse(map.keySet().contains(new SimpleKey("44"))); } + @Test + public void testReadAllKeySet() { + RMap map = redisson.getMap("simple"); + map.put(new SimpleKey("1"), new SimpleValue("2")); + map.put(new SimpleKey("33"), new SimpleValue("44")); + map.put(new SimpleKey("5"), new SimpleValue("6")); + + assertThat(map.readAllKeySet().size()).isEqualTo(3); + Map testMap = new HashMap<>(map); + assertThat(map.readAllKeySet()).containsOnlyElementsOf(testMap.keySet()); + } + + @Test + public void testReadAllValues() { + RMap map = redisson.getMap("simple"); + map.put(new SimpleKey("1"), new SimpleValue("2")); + map.put(new SimpleKey("33"), new SimpleValue("44")); + map.put(new SimpleKey("5"), new SimpleValue("6")); + + assertThat(map.readAllValues().size()).isEqualTo(3); + Map testMap = new HashMap<>(map); + assertThat(map.readAllValues()).containsOnlyElementsOf(testMap.values()); + } + @Test public void testContainsValue() { Map map = redisson.getMap("simple");