diff --git a/redisson/src/main/java/org/redisson/BaseIterator.java b/redisson/src/main/java/org/redisson/BaseIterator.java new file mode 100644 index 000000000..1413cbceb --- /dev/null +++ b/redisson/src/main/java/org/redisson/BaseIterator.java @@ -0,0 +1,114 @@ +/** + * Copyright 2018 Nikita Koksharov + * + * 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; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.redisson.client.RedisClient; + +/** + * + * @author Nikita Koksharov + * + * @param entry type + * @param value type + */ +public abstract class BaseIterator implements Iterator { + + private Iterator lastIter; + protected long nextIterPos; + protected RedisClient client; + + private boolean finished; + private boolean currentElementRemoved; + protected E value; + + @Override + public boolean hasNext() { + if (lastIter == null || !lastIter.hasNext()) { + if (finished) { + currentElementRemoved = false; + client = null; + nextIterPos = 0; + + if (!tryAgain()) { + return false; + } + finished = false; + } + do { + ScanResult res = iterator(client, nextIterPos); + + client = res.getRedisClient(); + + if (res.getPos() == 0) { + finished = true; + if (res.getValues().isEmpty()) { + currentElementRemoved = false; + + client = null; + nextIterPos = 0; + if (tryAgain()) { + continue; + } + + return false; + } + } + lastIter = res.getValues().iterator(); + nextIterPos = res.getPos(); + } while (!lastIter.hasNext()); + } + return lastIter.hasNext(); + } + + protected boolean tryAgain() { + return false; + } + + protected abstract ScanResult iterator(RedisClient client, long nextIterPos); + + @Override + public V next() { + if (!hasNext()) { + throw new NoSuchElementException("No such element"); + } + + value = lastIter.next(); + currentElementRemoved = false; + return getValue(value); + } + + protected abstract V getValue(E entry); + + @Override + public void remove() { + if (currentElementRemoved) { + throw new IllegalStateException("Element been already deleted"); + } + if (lastIter == null || value == null) { + throw new IllegalStateException(); + } + + lastIter.remove(); + remove(value); + currentElementRemoved = true; + } + + protected abstract void remove(E value); + +} diff --git a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java index e5e1806c2..64457d537 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseIterator.java @@ -15,15 +15,7 @@ */ package org.redisson; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import org.redisson.client.RedisClient; -import org.redisson.client.protocol.decoder.ListScanResult; import org.redisson.client.protocol.decoder.ScanObjectEntry; -import org.redisson.misc.HashValue; /** * @@ -31,134 +23,11 @@ import org.redisson.misc.HashValue; * * @param value type */ -abstract class RedissonBaseIterator implements Iterator { - - private List firstValues; - private List lastValues; - private Iterator lastIter; - protected long nextIterPos; - protected RedisClient client; - - private boolean finished; - private boolean currentElementRemoved; - private V value; +abstract class RedissonBaseIterator extends BaseIterator { @Override - public boolean hasNext() { - if (lastIter == null || !lastIter.hasNext()) { - if (finished) { - currentElementRemoved = false; - client = null; - firstValues = null; - lastValues = null; - nextIterPos = 0; - - if (!tryAgain()) { - return false; - } - finished = false; - } - do { - ListScanResult res = iterator(client, nextIterPos); - - lastValues = convert(res.getValues()); - client = res.getRedisClient(); - - if (nextIterPos == 0 && firstValues == null) { - firstValues = lastValues; - lastValues = null; - if (isEmpty(firstValues) && tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - } - } else { - if (isEmpty(firstValues)) { - firstValues = lastValues; - lastValues = null; - if (isEmpty(firstValues)) { - if (tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - continue; - } - if (res.getPos() == 0) { - finished = true; - return false; - } - } - } else if (removeAll(lastValues, firstValues) - || (isEmpty(lastValues) && nextIterPos == 0)) { - currentElementRemoved = false; - - client = null; - firstValues = null; - lastValues = null; - nextIterPos = 0; - if (tryAgain()) { - continue; - } - - finished = true; - return false; - } - } - lastIter = res.getValues().iterator(); - nextIterPos = res.getPos(); - } while (!lastIter.hasNext()); - } - return lastIter.hasNext(); - } - - protected boolean isEmpty(List values) { - return values.isEmpty(); - } - - protected boolean removeAll(List lastValues, List firstValues) { - return lastValues.removeAll(firstValues); + protected V getValue(ScanObjectEntry entry) { + return (V) entry.getObj(); } - protected List convert(List list) { - List result = new ArrayList(list.size()); - for (ScanObjectEntry entry : list) { - result.add(entry.getHash()); - } - return result; - } - - protected boolean tryAgain() { - return false; - } - - abstract ListScanResult iterator(RedisClient client, long nextIterPos); - - @Override - public V next() { - if (!hasNext()) { - throw new NoSuchElementException("No such element"); - } - - value = (V) lastIter.next().getObj(); - currentElementRemoved = false; - return value; - } - - @Override - public void remove() { - if (currentElementRemoved) { - throw new IllegalStateException("Element been already deleted"); - } - if (lastIter == null) { - throw new IllegalStateException(); - } - - firstValues.remove(value); - lastIter.remove(); - remove(value); - currentElementRemoved = true; - } - - abstract void remove(V value); - } diff --git a/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java b/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java index a15f3b0df..5b0d33003 100644 --- a/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonBaseMapIterator.java @@ -16,161 +16,31 @@ package org.redisson; import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; -import java.util.NoSuchElementException; -import org.redisson.client.RedisClient; -import org.redisson.client.protocol.decoder.MapScanResult; import org.redisson.client.protocol.decoder.ScanObjectEntry; -import org.redisson.misc.HashValue; /** * * @author Nikita Koksharov * - * @param key type * @param value type - * @param loaded value type */ -public abstract class RedissonBaseMapIterator implements Iterator { - - private Map firstValues; - private Map lastValues; - private Iterator> lastIter; - protected long nextIterPos; - protected RedisClient client; - - private boolean finished; - private boolean currentElementRemoved; - protected Map.Entry entry; - - @Override - public boolean hasNext() { - if (lastIter == null || !lastIter.hasNext()) { - if (finished) { - currentElementRemoved = false; - client = null; - firstValues = null; - lastValues = null; - nextIterPos = 0; - - if (!tryAgain()) { - return false; - } - finished = false; - } - do { - MapScanResult res = iterator(); - - lastValues = convert(res.getMap()); - client = res.getRedisClient(); - - if (nextIterPos == 0 && firstValues == null) { - firstValues = lastValues; - lastValues = null; - if (firstValues.isEmpty() && tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - } - } else { - if (firstValues.isEmpty()) { - firstValues = lastValues; - lastValues = null; - if (firstValues.isEmpty()) { - if (tryAgain()) { - client = null; - firstValues = null; - nextIterPos = 0; - continue; - } - if (res.getPos() == 0) { - finished = true; - return false; - } - } - } else if (lastValues.keySet().removeAll(firstValues.keySet()) - || (lastValues.isEmpty() && nextIterPos == 0)) { - currentElementRemoved = false; - - client = null; - firstValues = null; - lastValues = null; - nextIterPos = 0; - if (tryAgain()) { - continue; - } - - finished = true; - return false; - } - } - lastIter = res.getMap().entrySet().iterator(); - nextIterPos = res.getPos(); - } while (!lastIter.hasNext()); - } - return lastIter.hasNext(); - - } - - protected boolean tryAgain() { - return false; - } - - protected abstract MapScanResult iterator(); - - private Map convert(Map map) { - Map result = new HashMap(map.size()); - for (Entry entry : map.entrySet()) { - result.put(entry.getKey().getHash(), entry.getValue().getHash()); - } - return result; - } - - @Override - public M next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - - entry = lastIter.next(); - currentElementRemoved = false; - return getValue(entry); - } +public abstract class RedissonBaseMapIterator extends BaseIterator> { @SuppressWarnings("unchecked") - protected M getValue(final Entry entry) { - return (M)new AbstractMap.SimpleEntry((K)entry.getKey().getObj(), (V)entry.getValue().getObj()) { + protected V getValue(final Map.Entry entry) { + return (V)new AbstractMap.SimpleEntry(entry.getKey().getObj(), entry.getValue().getObj()) { @Override - public V setValue(V value) { + public Object setValue(Object value) { return put(entry, value); } }; } - @Override - public void remove() { - if (currentElementRemoved) { - throw new IllegalStateException("Element been already deleted"); - } - if (lastIter == null || entry == null) { - throw new IllegalStateException(); - } - - firstValues.remove(entry.getKey().getHash()); - lastIter.remove(); - removeKey(); - currentElementRemoved = true; - entry = null; - } - - protected abstract void removeKey(); - - protected abstract V put(Entry entry, V value); + protected abstract Object put(Entry entry, Object value); } diff --git a/redisson/src/main/java/org/redisson/RedissonExecutorService.java b/redisson/src/main/java/org/redisson/RedissonExecutorService.java index 8b610049c..aed77a9cf 100644 --- a/redisson/src/main/java/org/redisson/RedissonExecutorService.java +++ b/redisson/src/main/java/org/redisson/RedissonExecutorService.java @@ -199,6 +199,10 @@ public class RedissonExecutorService implements RScheduledExecutorService { public int countActiveWorkers() { String id = generateRequestId(); int subscribers = (int) workersTopic.publish(id); + if (subscribers == 0) { + return 0; + } + RSemaphore semaphore = redisson.getSemaphore(workersSemaphoreName + ":" + id); try { semaphore.tryAcquire(subscribers, 10, TimeUnit.MINUTES); diff --git a/redisson/src/main/java/org/redisson/RedissonKeys.java b/redisson/src/main/java/org/redisson/RedissonKeys.java index 36f588d4b..4afe70fc3 100644 --- a/redisson/src/main/java/org/redisson/RedissonKeys.java +++ b/redisson/src/main/java/org/redisson/RedissonKeys.java @@ -121,13 +121,13 @@ public class RedissonKeys implements RKeys { return new RedissonBaseIterator() { @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { return RedissonKeys.this.scanIterator(client, entry, nextIterPos, pattern, count); } @Override - void remove(String value) { - RedissonKeys.this.delete(value); + protected void remove(ScanObjectEntry value) { + RedissonKeys.this.delete((String)value.getObj()); } }; diff --git a/redisson/src/main/java/org/redisson/RedissonMap.java b/redisson/src/main/java/org/redisson/RedissonMap.java index c12a2434f..685e4d2d7 100644 --- a/redisson/src/main/java/org/redisson/RedissonMap.java +++ b/redisson/src/main/java/org/redisson/RedissonMap.java @@ -1102,7 +1102,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { } protected Iterator keyIterator(String pattern) { - return new RedissonMapIterator(RedissonMap.this, pattern) { + return new RedissonMapIterator(RedissonMap.this, pattern) { @Override protected K getValue(java.util.Map.Entry entry) { return (K) entry.getKey().getObj(); @@ -1153,7 +1153,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { } protected Iterator valueIterator(String pattern) { - return new RedissonMapIterator(RedissonMap.this, pattern) { + return new RedissonMapIterator(RedissonMap.this, pattern) { @Override protected V getValue(java.util.Map.Entry entry) { return (V) entry.getValue().getObj(); @@ -1200,7 +1200,7 @@ public class RedissonMap extends RedissonExpirable implements RMap { } protected Iterator> entryIterator(String pattern) { - return new RedissonMapIterator>(RedissonMap.this, pattern); + return new RedissonMapIterator>(RedissonMap.this, pattern); } private void loadValue(final K key, final RPromise result, final boolean replaceValue) { diff --git a/redisson/src/main/java/org/redisson/RedissonMapIterator.java b/redisson/src/main/java/org/redisson/RedissonMapIterator.java index 0b2df3f8d..6846260cc 100644 --- a/redisson/src/main/java/org/redisson/RedissonMapIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonMapIterator.java @@ -17,37 +17,38 @@ package org.redisson; import java.util.Map.Entry; -import org.redisson.client.protocol.decoder.MapScanResult; +import org.redisson.client.RedisClient; import org.redisson.client.protocol.decoder.ScanObjectEntry; /** * * @author Nikita Koksharov * - * @param key type - * @param value type * @param loaded value type */ -public class RedissonMapIterator extends RedissonBaseMapIterator { +public class RedissonMapIterator extends RedissonBaseMapIterator { - private final RedissonMap map; + private final RedissonMap map; private final String pattern; - public RedissonMapIterator(RedissonMap map, String pattern) { + public RedissonMapIterator(RedissonMap map, String pattern) { this.map = map; this.pattern = pattern; } - protected MapScanResult iterator() { - return map.scanIterator(map.getName(), client, nextIterPos, pattern); + @Override + protected Object put(Entry entry, Object value) { + return map.put(entry.getKey().getObj(), value); } - protected void removeKey() { - map.fastRemove((K)entry.getKey().getObj()); + @Override + protected ScanResult> iterator(RedisClient client, long nextIterPos) { + return map.scanIterator(map.getName(), client, nextIterPos, pattern); } - protected V put(Entry entry, V value) { - return map.put((K) entry.getKey().getObj(), value); + @Override + protected void remove(Entry value) { + map.fastRemove(value.getKey().getObj()); } } diff --git a/redisson/src/main/java/org/redisson/RedissonMultiMapKeysIterator.java b/redisson/src/main/java/org/redisson/RedissonMultiMapKeysIterator.java index 851c468ee..0c8ce6d2c 100644 --- a/redisson/src/main/java/org/redisson/RedissonMultiMapKeysIterator.java +++ b/redisson/src/main/java/org/redisson/RedissonMultiMapKeysIterator.java @@ -17,28 +17,35 @@ package org.redisson; import java.util.Map.Entry; -import org.redisson.client.protocol.decoder.MapScanResult; +import org.redisson.client.RedisClient; import org.redisson.client.protocol.decoder.ScanObjectEntry; -public class RedissonMultiMapKeysIterator extends RedissonBaseMapIterator { +/** + * + * @author Nikita Koksharov + * + * @param value type + */ +public class RedissonMultiMapKeysIterator extends RedissonBaseMapIterator { - private final RedissonMultimap map; + private final RedissonMultimap map; - public RedissonMultiMapKeysIterator(RedissonMultimap map) { + public RedissonMultiMapKeysIterator(RedissonMultimap map) { this.map = map; } - - protected MapScanResult iterator() { - return map.scanIterator(client, nextIterPos); + @Override + protected Object put(Entry entry, Object value) { + return map.put(entry.getKey().getObj(), value); } - protected void removeKey() { - map.fastRemove((K)entry.getKey().getObj()); + @Override + protected ScanResult> iterator(RedisClient client, long nextIterPos) { + return map.scanIterator(client, nextIterPos); } - protected V put(Entry entry, V value) { - map.put((K) entry.getKey().getObj(), value); - return null; + @Override + protected void remove(Entry value) { + map.fastRemove(value.getKey().getObj()); } } diff --git a/redisson/src/main/java/org/redisson/RedissonMultimap.java b/redisson/src/main/java/org/redisson/RedissonMultimap.java index cf77b5037..a01ee66a3 100644 --- a/redisson/src/main/java/org/redisson/RedissonMultimap.java +++ b/redisson/src/main/java/org/redisson/RedissonMultimap.java @@ -318,7 +318,7 @@ public abstract class RedissonMultimap extends RedissonExpirable implement @Override public Iterator iterator() { - return new RedissonMultiMapKeysIterator(RedissonMultimap.this) { + return new RedissonMultiMapKeysIterator(RedissonMultimap.this) { @Override protected K getValue(java.util.Map.Entry entry) { return (K) entry.getKey().getObj(); diff --git a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java index 78717a0f1..36a03e64d 100644 --- a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java +++ b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java @@ -322,13 +322,13 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc return new RedissonBaseIterator() { @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { return scanIterator(client, nextIterPos); } @Override - void remove(V value) { - RedissonScoredSortedSet.this.remove(value); + protected void remove(ScanObjectEntry value) { + RedissonScoredSortedSet.this.remove((V)value.getObj()); } }; diff --git a/redisson/src/main/java/org/redisson/RedissonSemaphore.java b/redisson/src/main/java/org/redisson/RedissonSemaphore.java index c78bb59f4..4f5d9d086 100644 --- a/redisson/src/main/java/org/redisson/RedissonSemaphore.java +++ b/redisson/src/main/java/org/redisson/RedissonSemaphore.java @@ -288,6 +288,9 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore { if (permits < 0) { throw new IllegalArgumentException("Permits amount can't be negative"); } + if (permits == 0) { + return RedissonPromise.newSucceededFuture(true); + } return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "local value = redis.call('get', KEYS[1]); " + @@ -469,6 +472,9 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore { if (permits < 0) { throw new IllegalArgumentException("Permits amount can't be negative"); } + if (permits == 0) { + return RedissonPromise.newSucceededFuture(null); + } return commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_VOID, "local value = redis.call('incrby', KEYS[1], ARGV[1]); " + diff --git a/redisson/src/main/java/org/redisson/RedissonSet.java b/redisson/src/main/java/org/redisson/RedissonSet.java index 07fe4882b..8f692d4b0 100644 --- a/redisson/src/main/java/org/redisson/RedissonSet.java +++ b/redisson/src/main/java/org/redisson/RedissonSet.java @@ -109,13 +109,13 @@ public class RedissonSet extends RedissonExpirable implements RSet, ScanIt return new RedissonBaseIterator() { @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { return scanIterator(getName(), client, nextIterPos, pattern); } @Override - void remove(V value) { - RedissonSet.this.remove(value); + protected void remove(ScanObjectEntry value) { + RedissonSet.this.remove((V)value.getObj()); } }; diff --git a/redisson/src/main/java/org/redisson/RedissonSetCache.java b/redisson/src/main/java/org/redisson/RedissonSetCache.java index 45c107455..6e04903fa 100644 --- a/redisson/src/main/java/org/redisson/RedissonSetCache.java +++ b/redisson/src/main/java/org/redisson/RedissonSetCache.java @@ -161,13 +161,13 @@ public class RedissonSetCache extends RedissonExpirable implements RSetCache< return new RedissonBaseIterator() { @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { return scanIterator(getName(), client, nextIterPos, pattern); } @Override - void remove(V value) { - RedissonSetCache.this.remove(value); + protected void remove(ScanObjectEntry value) { + RedissonSetCache.this.remove((V)value.getObj()); } }; diff --git a/redisson/src/main/java/org/redisson/RedissonSetMultimapValues.java b/redisson/src/main/java/org/redisson/RedissonSetMultimapValues.java index 5e509ba98..9cea3350c 100644 --- a/redisson/src/main/java/org/redisson/RedissonSetMultimapValues.java +++ b/redisson/src/main/java/org/redisson/RedissonSetMultimapValues.java @@ -203,13 +203,13 @@ public class RedissonSetMultimapValues extends RedissonExpirable implements R return new RedissonBaseIterator() { @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { return scanIterator(client, nextIterPos, pattern); } @Override - void remove(V value) { - RedissonSetMultimapValues.this.remove(value); + protected void remove(ScanObjectEntry value) { + RedissonSetMultimapValues.this.remove((V)value.getObj()); } }; diff --git a/redisson/src/main/java/org/redisson/RedisClientResult.java b/redisson/src/main/java/org/redisson/ScanResult.java similarity index 86% rename from redisson/src/main/java/org/redisson/RedisClientResult.java rename to redisson/src/main/java/org/redisson/ScanResult.java index 39fb87df8..4f8315d18 100644 --- a/redisson/src/main/java/org/redisson/RedisClientResult.java +++ b/redisson/src/main/java/org/redisson/ScanResult.java @@ -15,6 +15,8 @@ */ package org.redisson; +import java.util.Collection; + import org.redisson.client.RedisClient; /** @@ -22,10 +24,14 @@ import org.redisson.client.RedisClient; * @author Nikita Koksharov * */ -public interface RedisClientResult { +public interface ScanResult { void setRedisClient(RedisClient addr); RedisClient getRedisClient(); + + long getPos(); + + Collection getValues(); } diff --git a/redisson/src/main/java/org/redisson/client/RedisClient.java b/redisson/src/main/java/org/redisson/client/RedisClient.java index aeaae72ce..fb7c56132 100644 --- a/redisson/src/main/java/org/redisson/client/RedisClient.java +++ b/redisson/src/main/java/org/redisson/client/RedisClient.java @@ -15,8 +15,10 @@ */ package org.redisson.client; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; +import java.net.UnknownHostException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -45,6 +47,7 @@ import io.netty.resolver.AddressResolver; import io.netty.resolver.dns.DnsAddressResolverGroup; import io.netty.resolver.dns.DnsServerAddressStreamProviders; import io.netty.util.HashedWheelTimer; +import io.netty.util.NetUtil; import io.netty.util.Timer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.FutureListener; @@ -166,6 +169,17 @@ public class RedisClient { return resolvedAddrFuture.get(); } + byte[] addr = NetUtil.createByteArrayFromIpAddressString(uri.getHost()); + if (addr != null) { + try { + resolvedAddr = new InetSocketAddress(InetAddress.getByAddress(uri.getHost(), addr), uri.getPort()); + } catch (UnknownHostException e) { + // skip + } + promise.trySuccess(resolvedAddr); + return promise; + } + AddressResolver resolver = (AddressResolver) bootstrap.config().resolver().getResolver(bootstrap.config().group().next()); Future resolveFuture = resolver.resolve(InetSocketAddress.createUnresolved(uri.getHost(), uri.getPort())); resolveFuture.addListener(new FutureListener() { @@ -176,12 +190,23 @@ public class RedisClient { return; } - resolvedAddr = future.getNow(); - promise.trySuccess(future.getNow()); + InetSocketAddress resolved = future.getNow(); + resolvedAddr = createInetSocketAddress(resolved, uri.getHost()); + promise.trySuccess(resolvedAddr); } + }); return promise; } + + private InetSocketAddress createInetSocketAddress(InetSocketAddress resolved, String host) { + byte[] addr = NetUtil.createByteArrayFromIpAddressString(resolved.getAddress().getHostAddress()); + try { + return new InetSocketAddress(InetAddress.getByAddress(host, addr), resolved.getPort()); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } public RFuture connectAsync() { final RPromise f = new RedissonPromise(); diff --git a/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java index 9645f6249..daf028f91 100644 --- a/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java +++ b/redisson/src/main/java/org/redisson/client/handler/RedisChannelInitializer.java @@ -33,7 +33,6 @@ import org.redisson.client.RedisClient; import org.redisson.client.RedisClientConfig; import org.redisson.client.RedisConnection; import org.redisson.config.SslProvider; -import org.redisson.misc.URIBuilder; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; @@ -46,6 +45,7 @@ import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.SslHandshakeCompletionEvent; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.util.NetUtil; /** * @@ -164,7 +164,7 @@ public class RedisChannelInitializer extends ChannelInitializer { SslContext sslContext = sslContextBuilder.build(); String hostname = config.getSslHostname(); - if (hostname == null || URIBuilder.isValidIP(hostname)) { + if (hostname == null || NetUtil.createByteArrayFromIpAddressString(hostname) != null) { hostname = config.getAddress().getHost(); } diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java index 503914311..318dee111 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/ListScanResult.java @@ -15,10 +15,9 @@ */ package org.redisson.client.protocol.decoder; -import java.net.InetSocketAddress; import java.util.List; -import org.redisson.RedisClientResult; +import org.redisson.ScanResult; import org.redisson.client.RedisClient; /** @@ -27,21 +26,23 @@ import org.redisson.client.RedisClient; * * @param value type */ -public class ListScanResult implements RedisClientResult { +public class ListScanResult implements ScanResult { - private final Long pos; + private final long pos; private final List values; private RedisClient client; - public ListScanResult(Long pos, List values) { + public ListScanResult(long pos, List values) { this.pos = pos; this.values = values; } - public Long getPos() { + @Override + public long getPos() { return pos; } + @Override public List getValues() { return values; } @@ -51,6 +52,7 @@ public class ListScanResult implements RedisClientResult { this.client = client; } + @Override public RedisClient getRedisClient() { return client; } diff --git a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java index 92a1cc8d4..07d16bbd8 100644 --- a/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java +++ b/redisson/src/main/java/org/redisson/client/protocol/decoder/MapScanResult.java @@ -15,10 +15,10 @@ */ package org.redisson.client.protocol.decoder; -import java.net.InetSocketAddress; +import java.util.Collection; import java.util.Map; -import org.redisson.RedisClientResult; +import org.redisson.ScanResult; import org.redisson.client.RedisClient; /** @@ -28,31 +28,38 @@ import org.redisson.client.RedisClient; * @param key type * @param value type */ -public class MapScanResult implements RedisClientResult { +public class MapScanResult implements ScanResult> { - private final Long pos; + private final long pos; private final Map values; private RedisClient client; - public MapScanResult(Long pos, Map values) { + public MapScanResult(long pos, Map values) { super(); this.pos = pos; this.values = values; } - public Long getPos() { - return pos; + @Override + public Collection> getValues() { + return values.entrySet(); } - + public Map getMap() { return values; } + + @Override + public long getPos() { + return pos; + } @Override public void setRedisClient(RedisClient client) { this.client = client; } + @Override public RedisClient getRedisClient() { return client; } diff --git a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java index 9bf0759d3..9fc9eb69d 100644 --- a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java +++ b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java @@ -29,7 +29,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import org.redisson.RedisClientResult; +import org.redisson.ScanResult; import org.redisson.RedissonReference; import org.redisson.RedissonShutdownException; import org.redisson.SlotCallback; @@ -856,8 +856,8 @@ public class CommandAsyncService implements CommandAsyncExecutor { if (future.isSuccess()) { R res = future.getNow(); - if (res instanceof RedisClientResult) { - ((RedisClientResult) res).setRedisClient(details.getConnectionFuture().getNow().getRedisClient()); + if (res instanceof ScanResult) { + ((ScanResult) res).setRedisClient(details.getConnectionFuture().getNow().getRedisClient()); } if (isRedissonReferenceSupportEnabled()) { diff --git a/redisson/src/main/java/org/redisson/jcache/JCache.java b/redisson/src/main/java/org/redisson/jcache/JCache.java index a258ce40b..7a10046f0 100644 --- a/redisson/src/main/java/org/redisson/jcache/JCache.java +++ b/redisson/src/main/java/org/redisson/jcache/JCache.java @@ -52,6 +52,7 @@ import javax.cache.processor.EntryProcessorResult; import org.redisson.Redisson; import org.redisson.RedissonBaseMapIterator; import org.redisson.RedissonObject; +import org.redisson.ScanResult; import org.redisson.api.RFuture; import org.redisson.api.RLock; import org.redisson.api.RSemaphore; @@ -2094,25 +2095,26 @@ public class JCache extends RedissonObject implements Cache { } protected Iterator keyIterator() { - return new RedissonBaseMapIterator() { + return new RedissonBaseMapIterator() { @Override protected K getValue(Map.Entry entry) { return (K) entry.getKey().getObj(); } @Override - protected MapScanResult iterator() { - return JCache.this.scanIterator(JCache.this.getName(), client, nextIterPos); + protected void remove(java.util.Map.Entry value) { + throw new UnsupportedOperationException(); } @Override - protected void removeKey() { + protected Object put(java.util.Map.Entry entry, Object value) { throw new UnsupportedOperationException(); } @Override - protected V put(Map.Entry entry, V value) { - throw new UnsupportedOperationException(); + protected ScanResult> iterator(RedisClient client, + long nextIterPos) { + return JCache.this.scanIterator(JCache.this.getName(), client, nextIterPos); } }; } @@ -2412,7 +2414,7 @@ public class JCache extends RedissonObject implements Cache { @Override public Iterator> iterator() { checkNotClosed(); - return new RedissonBaseMapIterator>() { + return new RedissonBaseMapIterator>() { @Override protected Cache.Entry getValue(Map.Entry entry) { cacheManager.getStatBean(JCache.this).addHits(1); @@ -2427,19 +2429,23 @@ public class JCache extends RedissonObject implements Cache { } @Override - protected MapScanResult iterator() { - return JCache.this.scanIterator(JCache.this.getName(), client, nextIterPos); + protected void remove(Map.Entry entry) { + JCache.this.remove((K) entry.getKey().getObj()); } @Override - protected void removeKey() { - JCache.this.remove((K) entry.getKey().getObj()); + protected Object put(java.util.Map.Entry entry, Object value) { + throw new UnsupportedOperationException(); } + + @Override - protected V put(Map.Entry entry, V value) { - throw new UnsupportedOperationException(); + protected ScanResult> iterator(RedisClient client, + long nextIterPos) { + return JCache.this.scanIterator(JCache.this.getName(), client, nextIterPos); } + }; } diff --git a/redisson/src/main/java/org/redisson/misc/URIBuilder.java b/redisson/src/main/java/org/redisson/misc/URIBuilder.java index 65ee49438..1cbc56def 100644 --- a/redisson/src/main/java/org/redisson/misc/URIBuilder.java +++ b/redisson/src/main/java/org/redisson/misc/URIBuilder.java @@ -18,9 +18,12 @@ package org.redisson.misc; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; -import java.util.regex.Pattern; +import java.net.UnknownHostException; + +import io.netty.util.NetUtil; /** * @@ -28,9 +31,6 @@ import java.util.regex.Pattern; */ public class URIBuilder { - private static final Pattern ipv4Pattern = Pattern.compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])", Pattern.CASE_INSENSITIVE); - private static final Pattern ipv6Pattern = Pattern.compile("([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}", Pattern.CASE_INSENSITIVE); - public static URI create(String uri) { URI u = URI.create(uri); // Let's assuming most of the time it is OK. @@ -68,15 +68,11 @@ public class URIBuilder { } } - public static boolean isValidIP(String host) { - if (ipv4Pattern.matcher(host).matches()) { - return true; + public static boolean compare(InetSocketAddress entryAddr, URI addr) { + if (addr.getHost().equals("localhost")) { + System.out.println("host to compare: " + addr.getHost()); } - return ipv6Pattern.matcher(host).matches(); - } - - public static boolean compare(InetSocketAddress entryAddr, URI addr) { if (((entryAddr.getHostName() != null && entryAddr.getHostName().equals(addr.getHost())) || entryAddr.getAddress().getHostAddress().equals(addr.getHost())) && entryAddr.getPort() == addr.getPort()) { diff --git a/redisson/src/test/java/org/redisson/RedissonKeysTest.java b/redisson/src/test/java/org/redisson/RedissonKeysTest.java index 6c13be4d2..f53b1cf4f 100644 --- a/redisson/src/test/java/org/redisson/RedissonKeysTest.java +++ b/redisson/src/test/java/org/redisson/RedissonKeysTest.java @@ -1,7 +1,8 @@ package org.redisson; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -9,9 +10,14 @@ import java.util.Set; import org.junit.Assert; import org.junit.Test; +import org.redisson.ClusterRunner.ClusterProcesses; +import org.redisson.RedisRunner.FailedToStartRedisException; import org.redisson.api.RBucket; import org.redisson.api.RMap; import org.redisson.api.RType; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.redisson.connection.balancer.RandomLoadBalancer; public class RedissonKeysTest extends BaseTest { @@ -46,6 +52,67 @@ public class RedissonKeysTest extends BaseTest { assertThat(redisson.getKeys().getType("test1")).isNull(); } + @Test + public void testEmptyKeys() { + Iterable keysIterator = redisson.getKeys().getKeysByPattern("test*", 10); + assertThat(keysIterator.iterator().hasNext()).isFalse(); + } + + @Test + public void testKeysByPattern() throws FailedToStartRedisException, IOException, InterruptedException { + RedisRunner master1 = new RedisRunner().randomPort().randomDir().nosave(); + RedisRunner master2 = new RedisRunner().randomPort().randomDir().nosave(); + RedisRunner master3 = new RedisRunner().randomPort().randomDir().nosave(); + RedisRunner slave1 = new RedisRunner().randomPort().randomDir().nosave(); + RedisRunner slave2 = new RedisRunner().randomPort().randomDir().nosave(); + RedisRunner slave3 = new RedisRunner().randomPort().randomDir().nosave(); + + + ClusterRunner clusterRunner = new ClusterRunner() + .addNode(master1, slave1) + .addNode(master2, slave2) + .addNode(master3, slave3); + ClusterProcesses process = clusterRunner.run(); + + Config config = new Config(); + config.useClusterServers() + .setLoadBalancer(new RandomLoadBalancer()) + .addNodeAddress(process.getNodes().stream().findAny().get().getRedisServerAddressAndPort()); + RedissonClient redisson = Redisson.create(config); + + int size = 10000; + for (int i = 0; i < size; i++) { + redisson.getBucket("test" + i).set(i); + } + + assertThat(redisson.getKeys().count()).isEqualTo(size); + + Long noOfKeysDeleted = 0L; + int chunkSize = 20; + Iterable keysIterator = redisson.getKeys().getKeysByPattern("test*", chunkSize); + Set keys = new HashSet<>(); + for (String key : keysIterator) { + keys.add(key); + + if (keys.size() % chunkSize == 0) { + long res = redisson.getKeys().delete(keys.toArray(new String[keys.size()])); + assertThat(res).isEqualTo(chunkSize); + noOfKeysDeleted += res; + keys.clear(); + } + } + //Delete remaining keys + if (!keys.isEmpty()) { + noOfKeysDeleted += redisson.getKeys().delete(keys.toArray(new String[keys.size()])); + } + + assertThat(noOfKeysDeleted).isEqualTo(size); + + redisson.shutdown(); + process.shutdown(); + } + + @Test public void testKeysIterablePattern() { redisson.getBucket("test1").set("someValue"); diff --git a/redisson/src/test/java/org/redisson/RedissonSemaphoreTest.java b/redisson/src/test/java/org/redisson/RedissonSemaphoreTest.java index d0551d510..1c1ade8f5 100644 --- a/redisson/src/test/java/org/redisson/RedissonSemaphoreTest.java +++ b/redisson/src/test/java/org/redisson/RedissonSemaphoreTest.java @@ -2,17 +2,22 @@ package org.redisson; import static org.assertj.core.api.Assertions.assertThat; -import java.util.concurrent.BrokenBarrierException; -import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Assume; import org.junit.Test; import org.redisson.api.RSemaphore; public class RedissonSemaphoreTest extends BaseConcurrentTest { + @Test + public void testZero() throws InterruptedException { + RSemaphore s = redisson.getSemaphore("test"); + assertThat(s.tryAcquire(0, 10, TimeUnit.MINUTES)).isTrue(); + s.release(0); + assertThat(s.availablePermits()).isZero(); + } + @Test public void testAcquireWithoutSetPermits() throws InterruptedException { RSemaphore s = redisson.getSemaphore("test"); diff --git a/redisson/src/test/java/org/redisson/RedissonTest.java b/redisson/src/test/java/org/redisson/RedissonTest.java index 64c8772b8..d28471b32 100644 --- a/redisson/src/test/java/org/redisson/RedissonTest.java +++ b/redisson/src/test/java/org/redisson/RedissonTest.java @@ -116,7 +116,7 @@ public class RedissonTest { RedissonBaseIterator iter = new RedissonBaseIterator() { int i; @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { i++; if (i == 1) { return new ListScanResult(13L, Collections.emptyList()); @@ -129,7 +129,7 @@ public class RedissonTest { } @Override - void remove(Object value) { + protected void remove(Object value) { } }; @@ -142,7 +142,7 @@ public class RedissonTest { RedissonBaseIterator iter = new RedissonBaseIterator() { int i; @Override - ListScanResult iterator(RedisClient client, long nextIterPos) { + protected ListScanResult iterator(RedisClient client, long nextIterPos) { i++; if (i == 1) { return new ListScanResult(14L, Arrays.asList(new ScanObjectEntry(new HashValue(new long[]{1L}) , 1))); @@ -161,7 +161,7 @@ public class RedissonTest { } @Override - void remove(Integer value) { + protected void remove(ScanObjectEntry value) { } };