Skip to content

Commit 7c9144a

Browse files
committed
Temp commit: Add support for failover
1 parent e5bf1ac commit 7c9144a

11 files changed

+464
-146
lines changed

r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/ConnectionStrategy.java

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.asyncer.r2dbc.mysql;
1818

1919
import io.asyncer.r2dbc.mysql.client.Client;
20+
import io.asyncer.r2dbc.mysql.client.ReactorNettyClient;
2021
import io.asyncer.r2dbc.mysql.internal.util.StringUtils;
2122
import io.netty.channel.ChannelOption;
2223
import io.netty.resolver.AddressResolver;
@@ -26,13 +27,17 @@
2627
import io.netty.util.concurrent.EventExecutor;
2728
import io.netty.util.internal.logging.InternalLogger;
2829
import io.netty.util.internal.logging.InternalLoggerFactory;
30+
import io.r2dbc.spi.R2dbcNonTransientResourceException;
31+
import org.jetbrains.annotations.Nullable;
2932
import reactor.core.publisher.Mono;
3033
import reactor.netty.resources.LoopResources;
3134
import reactor.netty.tcp.TcpClient;
3235

3336
import java.net.InetSocketAddress;
3437
import java.time.Duration;
3538
import java.time.ZoneId;
39+
import java.util.function.Function;
40+
import java.util.function.Supplier;
3641

3742
/**
3843
* An interface of a connection strategy that considers how to obtain a MySQL {@link Client} object.
@@ -49,7 +54,7 @@ interface ConnectionStrategy {
4954
*
5055
* @return a logged-in {@link Client} object.
5156
*/
52-
Mono<Client> connect();
57+
Mono<? extends Client> connect();
5358

5459
/**
5560
* Creates a general-purpose {@link TcpClient} with the given {@link SocketClientConfiguration}.
@@ -87,7 +92,7 @@ static TcpClient createTcpClient(SocketClientConfiguration configuration, boolea
8792
* @param configuration a configuration that affects login behavior.
8893
* @return a logged-in {@link Client} object.
8994
*/
90-
static Mono<Client> connectWithInit(
95+
static Mono<ReactorNettyClient> connectWithInit(
9196
TcpClient tcpClient,
9297
Credential credential,
9398
MySqlConnectionConfiguration configuration
@@ -110,7 +115,7 @@ static Mono<Client> connectWithInit(
110115
configuration.isPreserveInstants(),
111116
connectionTimeZone
112117
);
113-
}).flatMap(context -> Client.connect(tcpClient, configuration.getSsl(), context)).flatMap(client -> {
118+
}).flatMap(ctx -> ReactorNettyClient.connect(tcpClient, configuration.getSsl(), ctx)).flatMap(client -> {
114119
// Lazy init database after handshake/login
115120
MySqlSslConfiguration ssl = configuration.getSsl();
116121
String loginDb = configuration.isCreateDatabaseIfNotExist() ? "" : configuration.getDatabase();
@@ -126,30 +131,88 @@ static Mono<Client> connectWithInit(
126131
).then(Mono.just(client)).onErrorResume(e -> client.forceClose().then(Mono.error(e)));
127132
});
128133
}
129-
}
130-
131-
/**
132-
* Resolves the {@link InetSocketAddress} to IP address, randomly pick one if it resolves to multiple IP addresses.
133-
*
134-
* @since 1.2.0
135-
*/
136-
final class BalancedResolverGroup extends AddressResolverGroup<InetSocketAddress> {
137134

138-
BalancedResolverGroup() {
135+
/**
136+
* Creates an exception that indicates a retry failure.
137+
*
138+
* @param message the message of the exception.
139+
* @param cause the last exception that caused the retry.
140+
* @return a retry failure exception.
141+
*/
142+
static R2dbcNonTransientResourceException retryFail(String message, @Nullable Throwable cause) {
143+
return new R2dbcNonTransientResourceException(
144+
message,
145+
"H1000",
146+
9000,
147+
cause
148+
);
139149
}
140150

141-
public static final BalancedResolverGroup INSTANCE;
151+
/**
152+
* Connect and login to a MySQL server with a specific TCP socket address.
153+
*
154+
* @since 1.2.0
155+
*/
156+
final class InetConnectFunction implements Function<Supplier<InetSocketAddress>, Mono<ReactorNettyClient>> {
157+
158+
private final boolean balancedDns;
159+
160+
private final boolean tcpKeepAlive;
161+
162+
private final boolean tcpNoDelay;
163+
164+
private final Credential credential;
142165

143-
static {
144-
INSTANCE = new BalancedResolverGroup();
145-
Runtime.getRuntime().addShutdownHook(new Thread(
146-
INSTANCE::close,
147-
"R2DBC-MySQL-BalancedResolverGroup-ShutdownHook"
148-
));
166+
private final MySqlConnectionConfiguration configuration;
167+
168+
InetConnectFunction(
169+
boolean balancedDns,
170+
boolean tcpKeepAlive,
171+
boolean tcpNoDelay,
172+
Credential credential,
173+
MySqlConnectionConfiguration configuration
174+
) {
175+
this.balancedDns = balancedDns;
176+
this.tcpKeepAlive = tcpKeepAlive;
177+
this.tcpNoDelay = tcpNoDelay;
178+
this.credential = credential;
179+
this.configuration = configuration;
180+
}
181+
182+
@Override
183+
public Mono<ReactorNettyClient> apply(Supplier<InetSocketAddress> address) {
184+
TcpClient client = ConnectionStrategy.createTcpClient(configuration.getClient(), balancedDns)
185+
.option(ChannelOption.SO_KEEPALIVE, tcpKeepAlive)
186+
.option(ChannelOption.TCP_NODELAY, tcpNoDelay)
187+
.remoteAddress(address);
188+
189+
return ConnectionStrategy.connectWithInit(client, credential, configuration);
190+
}
149191
}
150192

151-
@Override
152-
protected AddressResolver<InetSocketAddress> newResolver(EventExecutor executor) {
153-
return new RoundRobinInetAddressResolver(executor, new DefaultNameResolver(executor)).asAddressResolver();
193+
/**
194+
* Resolves the {@link InetSocketAddress} to IP address, randomly pick one if it resolves to multiple IP addresses.
195+
*
196+
* @since 1.2.0
197+
*/
198+
final class BalancedResolverGroup extends AddressResolverGroup<InetSocketAddress> {
199+
200+
BalancedResolverGroup() {
201+
}
202+
203+
public static final BalancedResolverGroup INSTANCE;
204+
205+
static {
206+
INSTANCE = new BalancedResolverGroup();
207+
Runtime.getRuntime().addShutdownHook(new Thread(
208+
INSTANCE::close,
209+
"R2DBC-MySQL-BalancedResolverGroup-ShutdownHook"
210+
));
211+
}
212+
213+
@Override
214+
protected AddressResolver<InetSocketAddress> newResolver(EventExecutor executor) {
215+
return new RoundRobinInetAddressResolver(executor, new DefaultNameResolver(executor)).asAddressResolver();
216+
}
154217
}
155218
}

r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/InitFlow.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.asyncer.r2dbc.mysql.cache.PrepareCache;
2323
import io.asyncer.r2dbc.mysql.client.Client;
2424
import io.asyncer.r2dbc.mysql.client.FluxExchangeable;
25+
import io.asyncer.r2dbc.mysql.client.ReactorNettyClient;
2526
import io.asyncer.r2dbc.mysql.codec.Codecs;
2627
import io.asyncer.r2dbc.mysql.codec.CodecsBuilder;
2728
import io.asyncer.r2dbc.mysql.constant.CompressionAlgorithm;
@@ -75,7 +76,7 @@
7576
import java.util.function.Function;
7677

7778
/**
78-
* A message flow utility that can initializes the session of {@link Client}.
79+
* A message flow utility that can initializes the session of {@link ReactorNettyClient}.
7980
* <p>
8081
* It should not use server-side prepared statements, because {@link PrepareCache} will be initialized after the session
8182
* is initialized.
@@ -117,9 +118,9 @@ final class InitFlow {
117118
};
118119

119120
/**
120-
* Initializes handshake and login a {@link Client}.
121+
* Initializes handshake and login a {@link ReactorNettyClient}.
121122
*
122-
* @param client the {@link Client} to exchange messages with.
123+
* @param client the {@link ReactorNettyClient} to exchange messages with.
123124
* @param sslMode the {@link SslMode} defines SSL capability and behavior.
124125
* @param database the database that will be connected.
125126
* @param user the user that will be login.
@@ -128,7 +129,7 @@ final class InitFlow {
128129
* @param zstdCompressionLevel the zstd compression level.
129130
* @return a {@link Mono} that indicates the initialization is done, or an error if the initialization failed.
130131
*/
131-
static Mono<Void> initHandshake(Client client, SslMode sslMode, String database, String user,
132+
static Mono<Void> initHandshake(ReactorNettyClient client, SslMode sslMode, String database, String user,
132133
@Nullable CharSequence password, Set<CompressionAlgorithm> compressionAlgorithms, int zstdCompressionLevel) {
133134
return client.exchange(new HandshakeExchangeable(
134135
client,
@@ -488,7 +489,7 @@ final class HandshakeExchangeable extends FluxExchangeable<Void> {
488489
private final Sinks.Many<SubsequenceClientMessage> requests = Sinks.many().unicast()
489490
.onBackpressureBuffer(Queues.<SubsequenceClientMessage>one().get());
490491

491-
private final Client client;
492+
private final ReactorNettyClient client;
492493

493494
private final SslMode sslMode;
494495

@@ -511,7 +512,7 @@ final class HandshakeExchangeable extends FluxExchangeable<Void> {
511512

512513
private boolean sslCompleted;
513514

514-
HandshakeExchangeable(Client client, SslMode sslMode, String database, String user,
515+
HandshakeExchangeable(ReactorNettyClient client, SslMode sslMode, String database, String user,
515516
@Nullable CharSequence password, Set<CompressionAlgorithm> compressions,
516517
int zstdCompressionLevel) {
517518
this.client = client;

0 commit comments

Comments
 (0)