Replace infinite Iterable/Iterator with dedicated types
Related: #4065 Motivation: DnsNameResolver was using a special Iterable/Iterator implementation that yields an infinite stream of DNS server addresses. However, this seems to cause confusion. Modifications: - Make DnsServerAddresses an abstract class with an abstract stream() method that returns DnsServerAddressStream - Add DnsServerAddressStream that yields DNS server address infinitely - Remove DnsServerResolver(Group) constructors that accept only a single server address, which wasn't very useful in practice - Extract the DnsServerAddresses implementations to top level - DnsServerAddresses.defaultAddresses() now returns DnsServerAddresses. - Add DnsServerAddresses.defaultAddressList() instead Result: Less confusion and more explicitness
This commit is contained in:
parent
99d6a97b4a
commit
719d1dbad1
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
abstract class DefaultDnsServerAddresses extends DnsServerAddresses {
|
||||||
|
|
||||||
|
protected final InetSocketAddress[] addresses;
|
||||||
|
private final String strVal;
|
||||||
|
|
||||||
|
DefaultDnsServerAddresses(String type, InetSocketAddress[] addresses) {
|
||||||
|
this.addresses = addresses;
|
||||||
|
|
||||||
|
final StringBuilder buf = new StringBuilder(type.length() + 2 + addresses.length * 16);
|
||||||
|
buf.append(type).append('(');
|
||||||
|
|
||||||
|
for (InetSocketAddress a: addresses) {
|
||||||
|
buf.append(a).append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.setLength(buf.length() - 2);
|
||||||
|
buf.append(')');
|
||||||
|
|
||||||
|
strVal = buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return strVal;
|
||||||
|
}
|
||||||
|
}
|
@ -41,7 +41,6 @@ import io.netty.util.collection.IntObjectHashMap;
|
|||||||
import io.netty.util.concurrent.FastThreadLocal;
|
import io.netty.util.concurrent.FastThreadLocal;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.Promise;
|
import io.netty.util.concurrent.Promise;
|
||||||
import io.netty.util.internal.InternalThreadLocalMap;
|
|
||||||
import io.netty.util.internal.OneTimeTask;
|
import io.netty.util.internal.OneTimeTask;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
@ -91,7 +90,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
private static final DatagramDnsResponseDecoder DECODER = new DatagramDnsResponseDecoder();
|
private static final DatagramDnsResponseDecoder DECODER = new DatagramDnsResponseDecoder();
|
||||||
private static final DatagramDnsQueryEncoder ENCODER = new DatagramDnsQueryEncoder();
|
private static final DatagramDnsQueryEncoder ENCODER = new DatagramDnsQueryEncoder();
|
||||||
|
|
||||||
final Iterable<InetSocketAddress> nameServerAddresses;
|
final DnsServerAddresses nameServerAddresses;
|
||||||
final ChannelFuture bindFuture;
|
final ChannelFuture bindFuture;
|
||||||
final DatagramChannel ch;
|
final DatagramChannel ch;
|
||||||
|
|
||||||
@ -107,11 +106,11 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
*/
|
*/
|
||||||
final ConcurrentMap<String, List<DnsCacheEntry>> resolveCache = PlatformDependent.newConcurrentHashMap();
|
final ConcurrentMap<String, List<DnsCacheEntry>> resolveCache = PlatformDependent.newConcurrentHashMap();
|
||||||
|
|
||||||
private final FastThreadLocal<Iterator<InetSocketAddress>> nameServerAddrIterator =
|
private final FastThreadLocal<DnsServerAddressStream> nameServerAddrStream =
|
||||||
new FastThreadLocal<Iterator<InetSocketAddress>>() {
|
new FastThreadLocal<DnsServerAddressStream>() {
|
||||||
@Override
|
@Override
|
||||||
protected Iterator<InetSocketAddress> initialValue() throws Exception {
|
protected DnsServerAddressStream initialValue() throws Exception {
|
||||||
return nameServerAddresses.iterator();
|
return nameServerAddresses.stream();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,72 +130,18 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
|
|
||||||
private volatile int maxPayloadSize;
|
private volatile int maxPayloadSize;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DNS-based name resolver that communicates with a single DNS server.
|
|
||||||
*
|
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
|
||||||
* @param channelType the type of the {@link DatagramChannel} to create
|
|
||||||
* @param nameServerAddress the address of the DNS server
|
|
||||||
*/
|
|
||||||
public DnsNameResolver(
|
|
||||||
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
|
||||||
InetSocketAddress nameServerAddress) {
|
|
||||||
this(eventLoop, channelType, ANY_LOCAL_ADDR, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DNS-based name resolver that communicates with a single DNS server.
|
|
||||||
*
|
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
|
||||||
* @param channelType the type of the {@link DatagramChannel} to create
|
|
||||||
* @param localAddress the local address of the {@link DatagramChannel}
|
|
||||||
* @param nameServerAddress the address of the DNS server
|
|
||||||
*/
|
|
||||||
public DnsNameResolver(
|
|
||||||
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
|
||||||
InetSocketAddress localAddress, InetSocketAddress nameServerAddress) {
|
|
||||||
this(eventLoop, new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DNS-based name resolver that communicates with a single DNS server.
|
|
||||||
*
|
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
|
||||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
|
||||||
* @param nameServerAddress the address of the DNS server
|
|
||||||
*/
|
|
||||||
public DnsNameResolver(
|
|
||||||
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
|
||||||
InetSocketAddress nameServerAddress) {
|
|
||||||
this(eventLoop, channelFactory, ANY_LOCAL_ADDR, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DNS-based name resolver that communicates with a single DNS server.
|
|
||||||
*
|
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
|
||||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
|
||||||
* @param localAddress the local address of the {@link DatagramChannel}
|
|
||||||
* @param nameServerAddress the address of the DNS server
|
|
||||||
*/
|
|
||||||
public DnsNameResolver(
|
|
||||||
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
|
||||||
InetSocketAddress localAddress, InetSocketAddress nameServerAddress) {
|
|
||||||
this(eventLoop, channelFactory, localAddress, DnsServerAddresses.singleton(nameServerAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
||||||
*
|
*
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
||||||
* @param channelType the type of the {@link DatagramChannel} to create
|
* @param channelType the type of the {@link DatagramChannel} to create
|
||||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new {@link Iterator} is
|
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
||||||
* created from this {@link Iterable} to determine which DNS server should be contacted
|
* this to determine which DNS server should be contacted for the next retry in case
|
||||||
* for the next retry in case of failure.
|
* of failure.
|
||||||
*/
|
*/
|
||||||
public DnsNameResolver(
|
public DnsNameResolver(
|
||||||
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
||||||
Iterable<InetSocketAddress> nameServerAddresses) {
|
DnsServerAddresses nameServerAddresses) {
|
||||||
this(eventLoop, channelType, ANY_LOCAL_ADDR, nameServerAddresses);
|
this(eventLoop, channelType, ANY_LOCAL_ADDR, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,13 +151,13 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
||||||
* @param channelType the type of the {@link DatagramChannel} to create
|
* @param channelType the type of the {@link DatagramChannel} to create
|
||||||
* @param localAddress the local address of the {@link DatagramChannel}
|
* @param localAddress the local address of the {@link DatagramChannel}
|
||||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new {@link Iterator} is
|
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
||||||
* created from this {@link Iterable} to determine which DNS server should be contacted
|
* this to determine which DNS server should be contacted for the next retry in case
|
||||||
* for the next retry in case of failure.
|
* of failure.
|
||||||
*/
|
*/
|
||||||
public DnsNameResolver(
|
public DnsNameResolver(
|
||||||
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
EventLoop eventLoop, Class<? extends DatagramChannel> channelType,
|
||||||
InetSocketAddress localAddress, Iterable<InetSocketAddress> nameServerAddresses) {
|
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
|
||||||
this(eventLoop, new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddresses);
|
this(eventLoop, new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,13 +166,13 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
*
|
*
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
||||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
||||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new {@link Iterator} is
|
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
||||||
* created from this {@link Iterable} to determine which DNS server should be contacted
|
* this to determine which DNS server should be contacted for the next retry in case
|
||||||
* for the next retry in case of failure.
|
* of failure.
|
||||||
*/
|
*/
|
||||||
public DnsNameResolver(
|
public DnsNameResolver(
|
||||||
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
||||||
Iterable<InetSocketAddress> nameServerAddresses) {
|
DnsServerAddresses nameServerAddresses) {
|
||||||
this(eventLoop, channelFactory, ANY_LOCAL_ADDR, nameServerAddresses);
|
this(eventLoop, channelFactory, ANY_LOCAL_ADDR, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,13 +182,13 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
||||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
||||||
* @param localAddress the local address of the {@link DatagramChannel}
|
* @param localAddress the local address of the {@link DatagramChannel}
|
||||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new {@link Iterator} is
|
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
||||||
* created from this {@link Iterable} to determine which DNS server should be contacted
|
* this to determine which DNS server should be contacted for the next retry in case
|
||||||
* for the next retry in case of failure.
|
* of failure.
|
||||||
*/
|
*/
|
||||||
public DnsNameResolver(
|
public DnsNameResolver(
|
||||||
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory,
|
||||||
InetSocketAddress localAddress, Iterable<InetSocketAddress> nameServerAddresses) {
|
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
|
||||||
|
|
||||||
super(eventLoop);
|
super(eventLoop);
|
||||||
|
|
||||||
@ -251,10 +196,6 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
checkNotNull(nameServerAddresses, "nameServerAddresses");
|
checkNotNull(nameServerAddresses, "nameServerAddresses");
|
||||||
checkNotNull(localAddress, "localAddress");
|
checkNotNull(localAddress, "localAddress");
|
||||||
|
|
||||||
if (!nameServerAddresses.iterator().hasNext()) {
|
|
||||||
throw new IllegalArgumentException("nameServerAddresses is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nameServerAddresses = nameServerAddresses;
|
this.nameServerAddresses = nameServerAddresses;
|
||||||
bindFuture = newChannel(channelFactory, localAddress);
|
bindFuture = newChannel(channelFactory, localAddress);
|
||||||
ch = (DatagramChannel) bindFuture.channel();
|
ch = (DatagramChannel) bindFuture.channel();
|
||||||
@ -922,17 +863,7 @@ public class DnsNameResolver extends SimpleNameResolver<InetSocketAddress> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InetSocketAddress nextNameServerAddress() {
|
private InetSocketAddress nextNameServerAddress() {
|
||||||
final InternalThreadLocalMap tlm = InternalThreadLocalMap.get();
|
return nameServerAddrStream.get().next();
|
||||||
Iterator<InetSocketAddress> i = nameServerAddrIterator.get(tlm);
|
|
||||||
if (i.hasNext()) {
|
|
||||||
return i.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The iterator has reached at its end, create a new iterator.
|
|
||||||
// We should not reach here if a user created nameServerAddresses via DnsServerAddresses, but just in case ..
|
|
||||||
i = nameServerAddresses.iterator();
|
|
||||||
nameServerAddrIterator.set(tlm, i);
|
|
||||||
return i.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,7 +67,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private final DnsNameResolver parent;
|
private final DnsNameResolver parent;
|
||||||
private final Iterator<InetSocketAddress> nameServerAddrs;
|
private final DnsServerAddressStream nameServerAddrs;
|
||||||
private final Promise<T> promise;
|
private final Promise<T> promise;
|
||||||
private final String hostname;
|
private final String hostname;
|
||||||
private final boolean traceEnabled;
|
private final boolean traceEnabled;
|
||||||
@ -88,7 +88,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
this.hostname = hostname;
|
this.hostname = hostname;
|
||||||
|
|
||||||
nameServerAddrs = parent.nameServerAddresses.iterator();
|
nameServerAddrs = parent.nameServerAddresses.stream();
|
||||||
maxAllowedQueries = parent.maxQueriesPerResolve();
|
maxAllowedQueries = parent.maxQueriesPerResolve();
|
||||||
resolveAddressTypes = parent.resolveAddressTypesUnsafe();
|
resolveAddressTypes = parent.resolveAddressTypesUnsafe();
|
||||||
traceEnabled = parent.isTraceEnabled();
|
traceEnabled = parent.isTraceEnabled();
|
||||||
|
@ -36,53 +36,27 @@ public final class DnsNameResolverGroup extends NameResolverGroup<InetSocketAddr
|
|||||||
|
|
||||||
private final ChannelFactory<? extends DatagramChannel> channelFactory;
|
private final ChannelFactory<? extends DatagramChannel> channelFactory;
|
||||||
private final InetSocketAddress localAddress;
|
private final InetSocketAddress localAddress;
|
||||||
private final Iterable<InetSocketAddress> nameServerAddresses;
|
private final DnsServerAddresses nameServerAddresses;
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
public DnsNameResolverGroup(
|
||||||
Class<? extends DatagramChannel> channelType,
|
Class<? extends DatagramChannel> channelType, DnsServerAddresses nameServerAddresses) {
|
||||||
InetSocketAddress nameServerAddress) {
|
|
||||||
this(channelType, ANY_LOCAL_ADDR, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
|
||||||
Class<? extends DatagramChannel> channelType,
|
|
||||||
InetSocketAddress localAddress, InetSocketAddress nameServerAddress) {
|
|
||||||
this(new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
|
||||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
|
||||||
InetSocketAddress nameServerAddress) {
|
|
||||||
this(channelFactory, ANY_LOCAL_ADDR, nameServerAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
|
||||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
|
||||||
InetSocketAddress localAddress, InetSocketAddress nameServerAddress) {
|
|
||||||
this(channelFactory, localAddress, DnsServerAddresses.singleton(nameServerAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
|
||||||
Class<? extends DatagramChannel> channelType,
|
|
||||||
Iterable<InetSocketAddress> nameServerAddresses) {
|
|
||||||
this(channelType, ANY_LOCAL_ADDR, nameServerAddresses);
|
this(channelType, ANY_LOCAL_ADDR, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
public DnsNameResolverGroup(
|
||||||
Class<? extends DatagramChannel> channelType,
|
Class<? extends DatagramChannel> channelType,
|
||||||
InetSocketAddress localAddress, Iterable<InetSocketAddress> nameServerAddresses) {
|
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
|
||||||
this(new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddresses);
|
this(new ReflectiveChannelFactory<DatagramChannel>(channelType), localAddress, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
public DnsNameResolverGroup(
|
||||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
ChannelFactory<? extends DatagramChannel> channelFactory, DnsServerAddresses nameServerAddresses) {
|
||||||
Iterable<InetSocketAddress> nameServerAddresses) {
|
|
||||||
this(channelFactory, ANY_LOCAL_ADDR, nameServerAddresses);
|
this(channelFactory, ANY_LOCAL_ADDR, nameServerAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DnsNameResolverGroup(
|
public DnsNameResolverGroup(
|
||||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
ChannelFactory<? extends DatagramChannel> channelFactory,
|
||||||
InetSocketAddress localAddress, Iterable<InetSocketAddress> nameServerAddresses) {
|
InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) {
|
||||||
this.channelFactory = channelFactory;
|
this.channelFactory = channelFactory;
|
||||||
this.localAddress = localAddress;
|
this.localAddress = localAddress;
|
||||||
this.nameServerAddresses = nameServerAddresses;
|
this.nameServerAddresses = nameServerAddresses;
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An infinite stream of DNS server addresses.
|
||||||
|
*/
|
||||||
|
public interface DnsServerAddressStream {
|
||||||
|
/**
|
||||||
|
* Retrieves the next DNS server address from the stream.
|
||||||
|
*/
|
||||||
|
InetSocketAddress next();
|
||||||
|
}
|
@ -16,35 +16,29 @@
|
|||||||
|
|
||||||
package io.netty.resolver.dns;
|
package io.netty.resolver.dns;
|
||||||
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
|
||||||
import io.netty.util.internal.ThreadLocalRandom;
|
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a sequence of DNS server addresses to {@link DnsNameResolver}. The {@link Iterator} created by the
|
* Provides an infinite sequence of DNS server addresses to {@link DnsNameResolver}.
|
||||||
* {@link Iterable}s returned by the factory methods of this class is infinite, which means {@link Iterator#hasNext()}
|
|
||||||
* will never return {@code false} and {@link Iterator#next()} will never raise a {@link NoSuchElementException}.
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
|
@SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
|
||||||
public final class DnsServerAddresses {
|
public abstract class DnsServerAddresses {
|
||||||
|
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsServerAddresses.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsServerAddresses.class);
|
||||||
|
|
||||||
private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
|
private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
|
||||||
private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;
|
private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;
|
||||||
|
private static final DnsServerAddresses DEFAULT_NAME_SERVERS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final int DNS_PORT = 53;
|
final int DNS_PORT = 53;
|
||||||
@ -57,11 +51,9 @@ public final class DnsServerAddresses {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final List<String> list = (List<String>) nameservers.invoke(instance);
|
final List<String> list = (List<String>) nameservers.invoke(instance);
|
||||||
final int size = list.size();
|
for (String a: list) {
|
||||||
for (int i = 0; i < size; i ++) {
|
if (a != null) {
|
||||||
String dnsAddr = list.get(i);
|
defaultNameServers.add(new InetSocketAddress(InetAddress.getByName(a), DNS_PORT));
|
||||||
if (dnsAddr != null) {
|
|
||||||
defaultNameServers.add(new InetSocketAddress(InetAddress.getByName(dnsAddr), DNS_PORT));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
@ -88,106 +80,123 @@ public final class DnsServerAddresses {
|
|||||||
|
|
||||||
DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
|
DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
|
||||||
DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
|
DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
|
||||||
|
DEFAULT_NAME_SERVERS = sequential(DEFAULT_NAME_SERVER_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
|
* Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
|
||||||
* addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
|
* addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
|
||||||
* Google public DNS servers. Note that the {@code Iterator} of the returned list is not infinite unlike other
|
* Google public DNS servers.
|
||||||
* factory methods in this class. To make the returned list infinite, pass it to the other factory method. e.g.
|
|
||||||
* <pre>
|
|
||||||
* addresses = {@link #sequential(Iterable) sequential}({@link #defaultAddresses()});
|
|
||||||
* </pre>
|
|
||||||
*/
|
*/
|
||||||
public static List<InetSocketAddress> defaultAddresses() {
|
public static List<InetSocketAddress> defaultAddressList() {
|
||||||
return DEFAULT_NAME_SERVER_LIST;
|
return DEFAULT_NAME_SERVER_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
* Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
|
||||||
* the DNS server addresses in a sequential order.
|
* retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
|
||||||
|
* {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
|
||||||
|
* <p>
|
||||||
|
* This method has the same effect with the following code:
|
||||||
|
* <pre>
|
||||||
|
* DnsServerAddresses.sequential(DnsServerAddresses.defaultAddressList());
|
||||||
|
* </pre>
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public static Iterable<InetSocketAddress> sequential(Iterable<? extends InetSocketAddress> addresses) {
|
public static DnsServerAddresses defaultAddresses() {
|
||||||
|
return DEFAULT_NAME_SERVERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} sequentially. Once the
|
||||||
|
* last address is yielded, it will start again from the first address.
|
||||||
|
*/
|
||||||
|
public static DnsServerAddresses sequential(Iterable<? extends InetSocketAddress> addresses) {
|
||||||
return sequential0(sanitize(addresses));
|
return sequential0(sanitize(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} sequentially. Once the
|
||||||
* the DNS server addresses in a sequential order.
|
* last address is yielded, it will start again from the first address.
|
||||||
*/
|
*/
|
||||||
public static Iterable<InetSocketAddress> sequential(InetSocketAddress... addresses) {
|
public static DnsServerAddresses sequential(InetSocketAddress... addresses) {
|
||||||
return sequential0(sanitize(addresses));
|
return sequential0(sanitize(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Iterable<InetSocketAddress> sequential0(final InetSocketAddress[] addresses) {
|
private static DnsServerAddresses sequential0(final InetSocketAddress... addresses) {
|
||||||
return new Iterable<InetSocketAddress>() {
|
|
||||||
@Override
|
|
||||||
public Iterator<InetSocketAddress> iterator() {
|
|
||||||
return new SequentialAddressIterator(addresses, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
|
||||||
* the DNS server addresses in a shuffled order.
|
|
||||||
*/
|
|
||||||
public static Iterable<InetSocketAddress> shuffled(Iterable<? extends InetSocketAddress> addresses) {
|
|
||||||
return shuffled0(sanitize(addresses));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
|
||||||
* the DNS server addresses in a shuffled order.
|
|
||||||
*/
|
|
||||||
public static Iterable<InetSocketAddress> shuffled(InetSocketAddress... addresses) {
|
|
||||||
return shuffled0(sanitize(addresses));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Iterable<InetSocketAddress> shuffled0(final InetSocketAddress[] addresses) {
|
|
||||||
if (addresses.length == 1) {
|
if (addresses.length == 1) {
|
||||||
return singleton(addresses[0]);
|
return singleton(addresses[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Iterable<InetSocketAddress>() {
|
return new DefaultDnsServerAddresses("sequential", addresses) {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<InetSocketAddress> iterator() {
|
public DnsServerAddressStream stream() {
|
||||||
return new ShuffledAddressIterator(addresses);
|
return new SequentialDnsServerAddressStream(addresses, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code address} in a shuffled order. Once all
|
||||||
* the DNS server addresses in a rotational order. It is similar to {@link #sequential(Iterable)}, but each
|
* addresses are yielded, the addresses are shuffled again.
|
||||||
* {@link Iterator} starts from a different starting point. For example, the first {@link Iterable#iterator()}
|
|
||||||
* will iterate from the first DNS server address, the second one will iterate from the second DNS server address,
|
|
||||||
* and so on.
|
|
||||||
*/
|
*/
|
||||||
public static Iterable<InetSocketAddress> rotational(Iterable<? extends InetSocketAddress> addresses) {
|
public static DnsServerAddresses shuffled(Iterable<? extends InetSocketAddress> addresses) {
|
||||||
|
return shuffled0(sanitize(addresses));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a shuffled order. Once all
|
||||||
|
* addresses are yielded, the addresses are shuffled again.
|
||||||
|
*/
|
||||||
|
public static DnsServerAddresses shuffled(InetSocketAddress... addresses) {
|
||||||
|
return shuffled0(sanitize(addresses));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DnsServerAddresses shuffled0(final InetSocketAddress[] addresses) {
|
||||||
|
if (addresses.length == 1) {
|
||||||
|
return singleton(addresses[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultDnsServerAddresses("shuffled", addresses) {
|
||||||
|
@Override
|
||||||
|
public DnsServerAddressStream stream() {
|
||||||
|
return new ShuffledDnsServerAddressStream(addresses);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a rotational sequential
|
||||||
|
* order. It is similar to {@link #sequential(Iterable)}, but each {@link DnsServerAddressStream} starts from
|
||||||
|
* a different starting point. For example, the first {@link #stream()} will start from the first address, the
|
||||||
|
* second one will start from the second address, and so on.
|
||||||
|
*/
|
||||||
|
public static DnsServerAddresses rotational(Iterable<? extends InetSocketAddress> addresses) {
|
||||||
return rotational0(sanitize(addresses));
|
return rotational0(sanitize(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates
|
* Returns the {@link DnsServerAddresses} that yields the specified {@code addresses} in a rotational sequential
|
||||||
* the DNS server addresses in a rotational order. It is similar to {@link #sequential(Iterable)}, but each
|
* order. It is similar to {@link #sequential(Iterable)}, but each {@link DnsServerAddressStream} starts from
|
||||||
* {@link Iterator} starts from a different starting point. For example, the first {@link Iterable#iterator()}
|
* a different starting point. For example, the first {@link #stream()} will start from the first address, the
|
||||||
* will iterate from the first DNS server address, the second one will iterate from the second DNS server address,
|
* second one will start from the second address, and so on.
|
||||||
* and so on.
|
|
||||||
*/
|
*/
|
||||||
public static Iterable<InetSocketAddress> rotational(InetSocketAddress... addresses) {
|
public static DnsServerAddresses rotational(InetSocketAddress... addresses) {
|
||||||
return rotational0(sanitize(addresses));
|
return rotational0(sanitize(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Iterable<InetSocketAddress> rotational0(final InetSocketAddress[] addresses) {
|
private static DnsServerAddresses rotational0(final InetSocketAddress[] addresses) {
|
||||||
return new RotationalAddresses(addresses);
|
if (addresses.length == 1) {
|
||||||
|
return singleton(addresses[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RotationalDnsServerAddresses(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an infinite {@link Iterable} of the specified DNS server address, whose {@link Iterator} always
|
* Returns the {@link DnsServerAddresses} that yields only a single {@code address}.
|
||||||
* return the same DNS server address.
|
|
||||||
*/
|
*/
|
||||||
public static Iterable<InetSocketAddress> singleton(final InetSocketAddress address) {
|
public static DnsServerAddresses singleton(final InetSocketAddress address) {
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
throw new NullPointerException("address");
|
throw new NullPointerException("address");
|
||||||
}
|
}
|
||||||
@ -195,30 +204,7 @@ public final class DnsServerAddresses {
|
|||||||
throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + address);
|
throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Iterable<InetSocketAddress>() {
|
return new SingletonDnsServerAddresses(address);
|
||||||
|
|
||||||
private final Iterator<InetSocketAddress> iterator = new Iterator<InetSocketAddress>() {
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InetSocketAddress next() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<InetSocketAddress> iterator() {
|
|
||||||
return iterator;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InetSocketAddress[] sanitize(Iterable<? extends InetSocketAddress> addresses) {
|
private static InetSocketAddress[] sanitize(Iterable<? extends InetSocketAddress> addresses) {
|
||||||
@ -244,7 +230,7 @@ public final class DnsServerAddresses {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return DEFAULT_NAME_SERVER_ARRAY;
|
throw new IllegalArgumentException("empty addresses");
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.toArray(new InetSocketAddress[list.size()]);
|
return list.toArray(new InetSocketAddress[list.size()]);
|
||||||
@ -273,123 +259,9 @@ public final class DnsServerAddresses {
|
|||||||
return list.toArray(new InetSocketAddress[list.size()]);
|
return list.toArray(new InetSocketAddress[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DnsServerAddresses() { }
|
/**
|
||||||
|
* Starts a new infinite stream of DNS server addresses. This method is invoked by {@link DnsNameResolver} on every
|
||||||
private static final class SequentialAddressIterator implements Iterator<InetSocketAddress> {
|
* uncached {@link DnsNameResolver#resolve(SocketAddress)} or {@link DnsNameResolver#resolveAll(SocketAddress)}.
|
||||||
|
*/
|
||||||
private final InetSocketAddress[] addresses;
|
public abstract DnsServerAddressStream stream();
|
||||||
private int i;
|
|
||||||
|
|
||||||
SequentialAddressIterator(InetSocketAddress[] addresses, int startIdx) {
|
|
||||||
this.addresses = addresses;
|
|
||||||
i = startIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InetSocketAddress next() {
|
|
||||||
int i = this.i;
|
|
||||||
InetSocketAddress next = addresses[i];
|
|
||||||
if (++ i < addresses.length) {
|
|
||||||
this.i = i;
|
|
||||||
} else {
|
|
||||||
this.i = 0;
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ShuffledAddressIterator implements Iterator<InetSocketAddress> {
|
|
||||||
|
|
||||||
private final InetSocketAddress[] addresses;
|
|
||||||
private int i;
|
|
||||||
|
|
||||||
ShuffledAddressIterator(InetSocketAddress[] addresses) {
|
|
||||||
this.addresses = addresses.clone();
|
|
||||||
|
|
||||||
shuffle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shuffle() {
|
|
||||||
final InetSocketAddress[] addresses = this.addresses;
|
|
||||||
final Random r = ThreadLocalRandom.current();
|
|
||||||
|
|
||||||
for (int i = addresses.length - 1; i >= 0; i --) {
|
|
||||||
InetSocketAddress tmp = addresses[i];
|
|
||||||
int j = r.nextInt(i + 1);
|
|
||||||
addresses[i] = addresses[j];
|
|
||||||
addresses[j] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InetSocketAddress next() {
|
|
||||||
int i = this.i;
|
|
||||||
InetSocketAddress next = addresses[i];
|
|
||||||
if (++ i < addresses.length) {
|
|
||||||
this.i = i;
|
|
||||||
} else {
|
|
||||||
this.i = 0;
|
|
||||||
shuffle();
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class RotationalAddresses implements Iterable<InetSocketAddress> {
|
|
||||||
|
|
||||||
private static final AtomicIntegerFieldUpdater<RotationalAddresses> startIdxUpdater;
|
|
||||||
|
|
||||||
static {
|
|
||||||
AtomicIntegerFieldUpdater<RotationalAddresses> updater =
|
|
||||||
PlatformDependent.newAtomicIntegerFieldUpdater(RotationalAddresses.class, "startIdx");
|
|
||||||
|
|
||||||
if (updater == null) {
|
|
||||||
updater = AtomicIntegerFieldUpdater.newUpdater(RotationalAddresses.class, "startIdx");
|
|
||||||
}
|
|
||||||
|
|
||||||
startIdxUpdater = updater;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final InetSocketAddress[] addresses;
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
private volatile int startIdx;
|
|
||||||
|
|
||||||
RotationalAddresses(InetSocketAddress[] addresses) {
|
|
||||||
this.addresses = addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<InetSocketAddress> iterator() {
|
|
||||||
for (;;) {
|
|
||||||
int curStartIdx = startIdx;
|
|
||||||
int nextStartIdx = curStartIdx + 1;
|
|
||||||
if (nextStartIdx >= addresses.length) {
|
|
||||||
nextStartIdx = 0;
|
|
||||||
}
|
|
||||||
if (startIdxUpdater.compareAndSet(this, curStartIdx, nextStartIdx)) {
|
|
||||||
return new SequentialAddressIterator(addresses, curStartIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||||
|
|
||||||
|
final class RotationalDnsServerAddresses extends DefaultDnsServerAddresses {
|
||||||
|
|
||||||
|
private static final AtomicIntegerFieldUpdater<RotationalDnsServerAddresses> startIdxUpdater;
|
||||||
|
|
||||||
|
static {
|
||||||
|
AtomicIntegerFieldUpdater<RotationalDnsServerAddresses> updater =
|
||||||
|
PlatformDependent.newAtomicIntegerFieldUpdater(RotationalDnsServerAddresses.class, "startIdx");
|
||||||
|
|
||||||
|
if (updater == null) {
|
||||||
|
updater = AtomicIntegerFieldUpdater.newUpdater(RotationalDnsServerAddresses.class, "startIdx");
|
||||||
|
}
|
||||||
|
|
||||||
|
startIdxUpdater = updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
private volatile int startIdx;
|
||||||
|
|
||||||
|
RotationalDnsServerAddresses(InetSocketAddress[] addresses) {
|
||||||
|
super("rotational", addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DnsServerAddressStream stream() {
|
||||||
|
for (;;) {
|
||||||
|
int curStartIdx = startIdx;
|
||||||
|
int nextStartIdx = curStartIdx + 1;
|
||||||
|
if (nextStartIdx >= addresses.length) {
|
||||||
|
nextStartIdx = 0;
|
||||||
|
}
|
||||||
|
if (startIdxUpdater.compareAndSet(this, curStartIdx, nextStartIdx)) {
|
||||||
|
return new SequentialDnsServerAddressStream(addresses, curStartIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
final class SequentialDnsServerAddressStream implements DnsServerAddressStream {
|
||||||
|
|
||||||
|
private final InetSocketAddress[] addresses;
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
SequentialDnsServerAddressStream(InetSocketAddress[] addresses, int startIdx) {
|
||||||
|
this.addresses = addresses;
|
||||||
|
i = startIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress next() {
|
||||||
|
int i = this.i;
|
||||||
|
InetSocketAddress next = addresses[i];
|
||||||
|
if (++ i < addresses.length) {
|
||||||
|
this.i = i;
|
||||||
|
} else {
|
||||||
|
this.i = 0;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toString("sequential", i, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String toString(String type, int index, InetSocketAddress[] addresses) {
|
||||||
|
final StringBuilder buf = new StringBuilder(type.length() + 2 + addresses.length * 16);
|
||||||
|
buf.append(type).append("(index: ").append(index);
|
||||||
|
buf.append(", addrs: (");
|
||||||
|
for (InetSocketAddress a: addresses) {
|
||||||
|
buf.append(a).append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.setLength(buf.length() - 2);
|
||||||
|
buf.append("))");
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import io.netty.util.internal.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
final class ShuffledDnsServerAddressStream implements DnsServerAddressStream {
|
||||||
|
|
||||||
|
private final InetSocketAddress[] addresses;
|
||||||
|
private int i;
|
||||||
|
|
||||||
|
ShuffledDnsServerAddressStream(InetSocketAddress[] addresses) {
|
||||||
|
this.addresses = addresses.clone();
|
||||||
|
|
||||||
|
shuffle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shuffle() {
|
||||||
|
final InetSocketAddress[] addresses = this.addresses;
|
||||||
|
final Random r = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
for (int i = addresses.length - 1; i >= 0; i --) {
|
||||||
|
InetSocketAddress tmp = addresses[i];
|
||||||
|
int j = r.nextInt(i + 1);
|
||||||
|
addresses[i] = addresses[j];
|
||||||
|
addresses[j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress next() {
|
||||||
|
int i = this.i;
|
||||||
|
InetSocketAddress next = addresses[i];
|
||||||
|
if (++ i < addresses.length) {
|
||||||
|
this.i = i;
|
||||||
|
} else {
|
||||||
|
this.i = 0;
|
||||||
|
shuffle();
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return SequentialDnsServerAddressStream.toString("shuffled", i, addresses);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you 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 io.netty.resolver.dns;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
final class SingletonDnsServerAddresses extends DnsServerAddresses {
|
||||||
|
|
||||||
|
private final InetSocketAddress address;
|
||||||
|
private final String strVal;
|
||||||
|
|
||||||
|
private final DnsServerAddressStream stream = new DnsServerAddressStream() {
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress next() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return SingletonDnsServerAddresses.this.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SingletonDnsServerAddresses(InetSocketAddress address) {
|
||||||
|
this.address = address;
|
||||||
|
strVal = new StringBuilder(32).append("singleton(").append(address).append(')').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DnsServerAddressStream stream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return strVal;
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
@ -36,16 +35,16 @@ public class DnsServerAddressesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultAddresses() {
|
public void testDefaultAddresses() {
|
||||||
assertThat(DnsServerAddresses.defaultAddresses().size(), is(greaterThan(0)));
|
assertThat(DnsServerAddresses.defaultAddressList().size(), is(greaterThan(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSequential() {
|
public void testSequential() {
|
||||||
Iterable<InetSocketAddress> seq = DnsServerAddresses.sequential(ADDR1, ADDR2, ADDR3);
|
DnsServerAddresses seq = DnsServerAddresses.sequential(ADDR1, ADDR2, ADDR3);
|
||||||
assertThat(seq.iterator(), is(not(sameInstance(seq.iterator()))));
|
assertThat(seq.stream(), is(not(sameInstance(seq.stream()))));
|
||||||
|
|
||||||
for (int j = 0; j < 2; j ++) {
|
for (int j = 0; j < 2; j ++) {
|
||||||
Iterator<InetSocketAddress> i = seq.iterator();
|
DnsServerAddressStream i = seq.stream();
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
@ -57,9 +56,9 @@ public class DnsServerAddressesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRotational() {
|
public void testRotational() {
|
||||||
Iterable<InetSocketAddress> seq = DnsServerAddresses.rotational(ADDR1, ADDR2, ADDR3);
|
DnsServerAddresses seq = DnsServerAddresses.rotational(ADDR1, ADDR2, ADDR3);
|
||||||
|
|
||||||
Iterator<InetSocketAddress> i = seq.iterator();
|
DnsServerAddressStream i = seq.stream();
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
@ -67,7 +66,7 @@ public class DnsServerAddressesTest {
|
|||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
|
|
||||||
i = seq.iterator();
|
i = seq.stream();
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
@ -75,7 +74,7 @@ public class DnsServerAddressesTest {
|
|||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
|
|
||||||
i = seq.iterator();
|
i = seq.stream();
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
@ -83,7 +82,7 @@ public class DnsServerAddressesTest {
|
|||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
|
|
||||||
i = seq.iterator();
|
i = seq.stream();
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR2);
|
assertNext(i, ADDR2);
|
||||||
assertNext(i, ADDR3);
|
assertNext(i, ADDR3);
|
||||||
@ -94,36 +93,34 @@ public class DnsServerAddressesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShuffled() {
|
public void testShuffled() {
|
||||||
Iterable<InetSocketAddress> seq = DnsServerAddresses.shuffled(ADDR1, ADDR2, ADDR3);
|
DnsServerAddresses seq = DnsServerAddresses.shuffled(ADDR1, ADDR2, ADDR3);
|
||||||
|
|
||||||
// Ensure that all three addresses are returned by the iterator.
|
// Ensure that all three addresses are returned by the iterator.
|
||||||
// In theory, this test can fail at extremely low chance, but we don't really care.
|
// In theory, this test can fail at extremely low chance, but we don't really care.
|
||||||
Set<InetSocketAddress> set = Collections.newSetFromMap(new IdentityHashMap<InetSocketAddress, Boolean>());
|
Set<InetSocketAddress> set = Collections.newSetFromMap(new IdentityHashMap<InetSocketAddress, Boolean>());
|
||||||
Iterator<InetSocketAddress> i = seq.iterator();
|
DnsServerAddressStream i = seq.stream();
|
||||||
for (int j = 0; j < 1048576; j ++) {
|
for (int j = 0; j < 1048576; j ++) {
|
||||||
assertThat(i.hasNext(), is(true));
|
|
||||||
set.add(i.next());
|
set.add(i.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(set.size(), is(3));
|
assertThat(set.size(), is(3));
|
||||||
assertThat(seq.iterator(), is(not(sameInstance(seq.iterator()))));
|
assertThat(seq.stream(), is(not(sameInstance(seq.stream()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingleton() {
|
public void testSingleton() {
|
||||||
Iterable<InetSocketAddress> seq = DnsServerAddresses.singleton(ADDR1);
|
DnsServerAddresses seq = DnsServerAddresses.singleton(ADDR1);
|
||||||
|
|
||||||
// Should return the same iterator instance for least possible footprint.
|
// Should return the same iterator instance for least possible footprint.
|
||||||
assertThat(seq.iterator(), is(sameInstance(seq.iterator())));
|
assertThat(seq.stream(), is(sameInstance(seq.stream())));
|
||||||
|
|
||||||
Iterator<InetSocketAddress> i = seq.iterator();
|
DnsServerAddressStream i = seq.stream();
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
assertNext(i, ADDR1);
|
assertNext(i, ADDR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertNext(Iterator<InetSocketAddress> i, InetSocketAddress addr) {
|
private static void assertNext(DnsServerAddressStream i, InetSocketAddress addr) {
|
||||||
assertThat(i.hasNext(), is(true));
|
|
||||||
assertThat(i.next(), is(sameInstance(addr)));
|
assertThat(i.next(), is(sameInstance(addr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user