Skip to content

Commit

Permalink
make netty-resolver-dns optional
Browse files Browse the repository at this point in the history
  • Loading branch information
yueki1993 committed Nov 22, 2020
1 parent bb645d2 commit ec85577
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 18 deletions.
11 changes: 6 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,6 @@
<artifactId>netty-handler</artifactId>
</dependency>

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns</artifactId>
</dependency>

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
Expand Down Expand Up @@ -210,6 +205,12 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver-dns</artifactId>
<optional>true</optional>
</dependency>

<!-- OS-native transports -->

<dependency>
Expand Down
7 changes: 1 addition & 6 deletions src/main/java/io/lettuce/core/AbstractRedisClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.resolver.dns.DnsAddressResolverGroup;
import io.netty.resolver.dns.DnsNameResolverBuilder;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.internal.logging.InternalLogger;
Expand Down Expand Up @@ -306,9 +303,7 @@ protected void resolver(ConnectionBuilder connectionBuilder, ConnectionPoint con
LettuceAssert.notNull(connectionPoint, "ConnectionPoint must not be null");

if (connectionPoint.getSocket() == null) {
connectionBuilder.bootstrap().resolver(
new DnsAddressResolverGroup(new DnsNameResolverBuilder().channelType(Transports.datagramChannelClass())
.socketChannelType(Transports.socketChannelClass().asSubclass(SocketChannel.class))));
connectionBuilder.bootstrap().resolver(clientResources.addressResolverGroup());
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/io/lettuce/core/Transports.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* @author Yohei Ueki
* @since 4.4
*/
class Transports {
public class Transports {

/**
* @return the default {@link EventLoopGroup} for socket transport that is compatible with {@link #socketChannelClass()}.
Expand All @@ -51,7 +51,7 @@ static Class<? extends EventLoopGroup> eventLoopGroupClass() {
/**
* @return the default {@link Channel} for socket (network/TCP) transport.
*/
static Class<? extends Channel> socketChannelClass() {
public static Class<? extends Channel> socketChannelClass() {

if (NativeTransports.isSocketSupported()) {
return NativeTransports.socketChannelClass();
Expand All @@ -63,7 +63,7 @@ static Class<? extends Channel> socketChannelClass() {
/**
* @return the default {@link DatagramChannel} for socket (network/UDP) transport.
*/
static Class<? extends DatagramChannel> datagramChannelClass() {
public static Class<? extends DatagramChannel> datagramChannelClass() {

if (NativeTransports.isSocketSupported()) {
return NativeTransports.datagramChannelClass();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.lettuce.core.resource;

import java.util.function.Supplier;

import io.lettuce.core.Transports;
import io.netty.channel.socket.SocketChannel;
import io.netty.resolver.AddressResolverGroup;
import io.netty.resolver.DefaultAddressResolverGroup;
import io.netty.resolver.dns.DnsAddressResolverGroup;
import io.netty.resolver.dns.DnsNameResolverBuilder;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
* Wraps and provides {@link AddressResolverGroup} classes. This is to protect the user from {@link ClassNotFoundException}'s
* caused by the absence of the {@literal netty-dns-resolver} library during runtime. This class will be deleted when
* {@literal netty-dns-resolver} becomes mandatory. Internal API.
*
* @author Yohei Ueki
* @since xxx
*/
class AddressResolverGroupProvider {

private static final InternalLogger logger = InternalLoggerFactory.getInstance(AddressResolverGroupProvider.class);

private static final AddressResolverGroup<?> ADDRESS_RESOLVER_GROUP;

static {
boolean dnsResolverAvailable;
try {
Class.forName("io.netty.resolver.dns.DnsAddressResolverGroup");
dnsResolverAvailable = true;
} catch (ClassNotFoundException e) {
dnsResolverAvailable = false;
}

// create addressResolverGroup instance via Supplier to avoid NoClassDefFoundError.
Supplier<AddressResolverGroup<?>> supplier;
if (dnsResolverAvailable) {
logger.debug("Starting with netty's non-blocking DNS resolver library");
supplier = AddressResolverGroupProvider::defaultDnsAddressResolverGroup;
} else {
logger.debug("Starting without optional netty's non-blocking DNS resolver library");
supplier = () -> DefaultAddressResolverGroup.INSTANCE;
}
ADDRESS_RESOLVER_GROUP = supplier.get();
}

/**
* Returns the {@link AddressResolverGroup} for dns resolution.
*
* @return the {@link DnsAddressResolverGroup} if {@literal netty-dns-resolver} is available, otherwise return
* {@link DefaultAddressResolverGroup#INSTANCE}.
* @since xxx
*/
static AddressResolverGroup<?> addressResolverGroup() {
return ADDRESS_RESOLVER_GROUP;
}

private static DnsAddressResolverGroup defaultDnsAddressResolverGroup() {
return new DnsAddressResolverGroup(new DnsNameResolverBuilder().channelType(Transports.datagramChannelClass())
.socketChannelType(Transports.socketChannelClass().asSubclass(SocketChannel.class)));
}

}
23 changes: 23 additions & 0 deletions src/main/java/io/lettuce/core/resource/ClientResources.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.lettuce.core.metrics.CommandLatencyCollectorOptions;
import io.lettuce.core.metrics.CommandLatencyRecorder;
import io.lettuce.core.tracing.Tracing;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.Timer;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.Future;
Expand All @@ -45,10 +46,12 @@
* <li>{@link DnsResolver} to collect latency details. Requires the {@literal LatencyUtils} library.</li>
* <li>{@link Timer} for scheduling</li>
* <li>{@link Tracing} to trace Redis commands.</li>
* <li>{@link AddressResolverGroup} for dns resolution.</li>
* </ul>
*
* @author Mark Paluch
* @author Mikhael Sokolov
* @author Yohei Ueki
* @since 3.4
* @see DefaultClientResources
*/
Expand Down Expand Up @@ -241,6 +244,18 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo
*/
Builder tracing(Tracing tracing);

/**
* Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if
* {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to
* {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available,
* otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}.
*
* @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}.
* @return {@code this} {@link Builder}
* @since xxx
*/
Builder addressResolverGroup(AddressResolverGroup<?> addressResolverGroup);

/**
* @return a new instance of {@link DefaultClientResources}.
*/
Expand Down Expand Up @@ -385,4 +400,12 @@ default Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCo
*/
Tracing tracing();

/**
* Return the {@link AddressResolverGroup} instance for dns resolution.
*
* @return the address resolver group.
* @since xxx
*/
AddressResolverGroup<?> addressResolverGroup();

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import io.lettuce.core.metrics.MetricCollector;
import io.lettuce.core.resource.Delay.StatefulDelay;
import io.lettuce.core.tracing.Tracing;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
Expand Down Expand Up @@ -70,9 +71,11 @@
* <li>a {@code socketAddressResolver} which is a provided instance of {@link SocketAddressResolver}.</li>
* <li>a {@code timer} that is a provided instance of {@link io.netty.util.HashedWheelTimer}.</li>
* <li>a {@code tracing} that is a provided instance of {@link Tracing}.</li>
* <li>a {@code addressResolverGroup} that is a provided instance of {@link AddressResolverGroup}.</li>
* </ul>
*
* @author Mark Paluch
* @author Yohei Ueki
* @since 3.4
*/
public class DefaultClientResources implements ClientResources {
Expand Down Expand Up @@ -103,6 +106,12 @@ public class DefaultClientResources implements ClientResources {
*/
public static final NettyCustomizer DEFAULT_NETTY_CUSTOMIZER = DefaultNettyCustomizer.INSTANCE;

/**
* Default {@link AddressResolverGroup}.
*/
public static final AddressResolverGroup<?> DEFAULT_ADDRESS_RESOLVER_GROUP = AddressResolverGroupProvider
.addressResolverGroup();

static {

int threads = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads",
Expand Down Expand Up @@ -147,6 +156,8 @@ public class DefaultClientResources implements ClientResources {

private final Tracing tracing;

private final AddressResolverGroup<?> addressResolverGroup;

private volatile boolean shutdownCalled = false;

protected DefaultClientResources(Builder builder) {
Expand Down Expand Up @@ -243,6 +254,7 @@ protected DefaultClientResources(Builder builder) {
reconnectDelay = builder.reconnectDelay;
nettyCustomizer = builder.nettyCustomizer;
tracing = builder.tracing;
addressResolverGroup = builder.addressResolverGroup;

if (!sharedTimer && timer instanceof HashedWheelTimer) {
((HashedWheelTimer) timer).start();
Expand Down Expand Up @@ -308,6 +320,8 @@ public static class Builder implements ClientResources.Builder {

private Tracing tracing = Tracing.disabled();

private AddressResolverGroup<?> addressResolverGroup = DEFAULT_ADDRESS_RESOLVER_GROUP;

private Builder() {
}

Expand Down Expand Up @@ -569,6 +583,25 @@ public Builder tracing(Tracing tracing) {
return this;
}

/**
* Sets the {@link AddressResolverGroup} for dns resolution. This option is only effective if
* {@link DnsResolvers#UNRESOLVED} is used as {@link DnsResolver}. Defaults to
* {@link io.netty.resolver.DefaultAddressResolverGroup#INSTANCE} if {@literal netty-dns-resolver} is not available,
* otherwise defaults to {@link io.netty.resolver.dns.DnsAddressResolverGroup}.
*
* @param addressResolverGroup the {@link AddressResolverGroup} instance, must not be {@code null}.
* @return {@code this} {@link ClientResources.Builder}
* @since xxx
*/
@Override
public Builder addressResolverGroup(AddressResolverGroup<?> addressResolverGroup) {

LettuceAssert.notNull(addressResolverGroup, "AddressResolverGroup must not be null");

this.addressResolverGroup = addressResolverGroup;
return this;
}

/**
* @return a new instance of {@link DefaultClientResources}.
*/
Expand Down Expand Up @@ -603,7 +636,7 @@ public DefaultClientResources.Builder mutate() {
.commandLatencyPublisherOptions(commandLatencyPublisherOptions()).dnsResolver(dnsResolver())
.eventBus(eventBus()).eventExecutorGroup(eventExecutorGroup()).reconnectDelay(reconnectDelay)
.socketAddressResolver(socketAddressResolver()).nettyCustomizer(nettyCustomizer()).timer(timer())
.tracing(tracing());
.tracing(tracing()).addressResolverGroup(addressResolverGroup());

builder.sharedCommandLatencyCollector = sharedEventLoopGroupProvider;
builder.sharedEventExecutor = sharedEventExecutor;
Expand Down Expand Up @@ -742,4 +775,9 @@ public Tracing tracing() {
return tracing;
}

@Override
public AddressResolverGroup<?> addressResolverGroup() {
return addressResolverGroup;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.lettuce.test.TestFutures;
import io.lettuce.test.resource.FastShutdown;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import io.netty.util.concurrent.EventExecutorGroup;
Expand All @@ -39,6 +40,7 @@
* Unit tests for {@link DefaultClientResources}.
*
* @author Mark Paluch
* @author Yohei Ueki
*/
class DefaultClientResourcesUnitTests {

Expand Down Expand Up @@ -108,16 +110,19 @@ void testProvidedResources() {
EventBus eventBusMock = mock(EventBus.class);
CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class);
NettyCustomizer nettyCustomizer = mock(NettyCustomizer.class);
AddressResolverGroup<?> addressResolverGroup = mock(AddressResolverGroup.class);

DefaultClientResources sut = DefaultClientResources.builder().eventExecutorGroup(executorMock)
.eventLoopGroupProvider(groupProviderMock).timer(timerMock).eventBus(eventBusMock)
.commandLatencyRecorder(latencyCollectorMock).nettyCustomizer(nettyCustomizer).build();
.commandLatencyRecorder(latencyCollectorMock).nettyCustomizer(nettyCustomizer)
.addressResolverGroup(addressResolverGroup).build();

assertThat(sut.eventExecutorGroup()).isSameAs(executorMock);
assertThat(sut.eventLoopGroupProvider()).isSameAs(groupProviderMock);
assertThat(sut.timer()).isSameAs(timerMock);
assertThat(sut.eventBus()).isSameAs(eventBusMock);
assertThat(sut.nettyCustomizer()).isSameAs(nettyCustomizer);
assertThat(sut.addressResolverGroup()).isSameAs(addressResolverGroup);

assertThat(TestFutures.getOrTimeout(sut.shutdown())).isTrue();

Expand All @@ -137,11 +142,11 @@ void mutateResources() {
Timer timerMock2 = mock(Timer.class);
EventBus eventBusMock = mock(EventBus.class);
CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class);

AddressResolverGroup<?> addressResolverGroupMock = mock(AddressResolverGroup.class);

ClientResources sut = ClientResources.builder().eventExecutorGroup(executorMock)
.eventLoopGroupProvider(groupProviderMock).timer(timerMock).eventBus(eventBusMock)
.commandLatencyRecorder(latencyCollectorMock).build();
.commandLatencyRecorder(latencyCollectorMock).addressResolverGroup(addressResolverGroupMock).build();

ClientResources copy = sut.mutate().timer(timerMock2).build();

Expand All @@ -151,6 +156,7 @@ void mutateResources() {
assertThat(sut.timer()).isSameAs(timerMock);
assertThat(copy.timer()).isSameAs(timerMock2).isNotSameAs(timerMock);
assertThat(sut.eventBus()).isSameAs(eventBusMock);
assertThat(sut.addressResolverGroup()).isSameAs(addressResolverGroupMock);

assertThat(TestFutures.getOrTimeout(sut.shutdown())).isTrue();

Expand Down

0 comments on commit ec85577

Please sign in to comment.