try { log.info("Attempting to bootstrap node:{} with layout:{}", server, layout); IClientRouter router = new NettyClientRouter(NodeLocator.parseString(server), corfuRuntimeParameters); router.addClient(new LayoutHandler())
addClient(new BaseHandler()); b.channel(parameters.getSocketType().getChannelClass()); parameters.getNettyChannelOptions().forEach(b::option); b.handler(getChannelInitializer()); b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) parameters.getConnectionTimeout().toMillis()); connectAsync(b);
/** {@inheritDoc} * @deprecated Deprecated, stopping a router without shutting it down is no longer supported. * Please use {@link this#stop()}. */ @Override @Deprecated public void stop(boolean shutdown) { stop(); }
/** Handle when a channel is connected. * * @param future The future that is completed when the channel is connected/ * @param bootstrap The bootstrap to connect a new channel (used on reconnect). */ private void channelConnectionFutureHandler(@Nonnull ChannelFuture future, @Nonnull Bootstrap bootstrap) { if (future.isSuccess()) { // Register a future to reconnect in case we get disconnected addReconnectionOnCloseFuture(future.channel(), bootstrap); log.info("connectAsync[{}]: Channel connected.", node); } else { // Otherwise, the connection failed. If we're not shutdown, try reconnecting after // a sleep period. if (!shutdown) { Sleep.sleepUninterruptibly(parameters.getConnectionRetryRate()); log.info("connectAsync[{}]: Channel connection failed, reconnecting...", node); // Call connect, which will retry the call again. // Note that this is not recursive, because it is called in the // context of the handler future. connectAsync(bootstrap); } } }
void runWithBaseServer(NettyServerDataConstructor nsdc, NettyClientRouterConstructor ncrc, NettyCommFunction actionFn) throws Exception { int port = findRandomOpenPort(); NettyServerData d = nsdc.createNettyServerData(port); NettyClientRouter ncr = null; try { d.bootstrapServer(); ncr = ncrc.createNettyClientRouter(port); ncr.addClient(new BaseHandler()); ncr.start(); actionFn.runTest(ncr, d); } catch (Exception ex) { log.error("Exception ", ex); throw ex; } finally { try { if (ncr != null) {ncr.stop(true);} } catch (Exception ex) { log.warn("Error shutting down client...", ex); } d.shutdownServer(); } }
NettyClientRouter clientRouter = new NettyClientRouter( NodeLocator.builder().host("localhost").port(port).build(), CorfuRuntimeParameters.builder() clientRouter.stop(); Files.copy(serverTrustWithClient.toPath(), serverTrustFile.toPath(), StandardCopyOption.REPLACE_EXISTING); clientRouter = new NettyClientRouter( NodeLocator.builder().host("localhost").port(port).build(), CorfuRuntimeParameters.builder() .tsPasswordFile("src/test/resources/security/reload/password") .build()); clientRouter.getConnectionFuture().join(); assertThat(getBaseClient(clientRouter).pingSync()).isTrue(); clientRouter.stop();
/** * Sends a ping to the server so that the pong response will keep * the channel active in order to avoid a ReadTimeout exception that will * close the channel. */ private void keepAlive() { if (!channel.isOpen()) { log.warn("keepAlive: channel not open, skipping ping. "); return; } sendMessageAndGetCompletable(null, new CorfuMsg(CorfuMsgType.PING)); log.trace("keepAlive: sending ping to {}", this.channel.remoteAddress()); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt.equals(ClientHandshakeEvent.CONNECTED)) { // Handshake successful. Complete the connection future to allow // clients to proceed. channel = ctx.channel(); connectionFuture.complete(null); } else if (evt.equals(ClientHandshakeEvent.FAILED) && connectionFuture.isDone()) { // Handshake failed. If the current completion future is complete, // create a new one to unset it, causing future requests // to wait. connectionFuture = new CompletableFuture<>(); } else if (evt instanceof IdleStateEvent) { IdleStateEvent e = (IdleStateEvent) evt; if (e.state() == IdleState.READER_IDLE) { ctx.close(); } else if (e.state() == IdleState.WRITER_IDLE) { keepAlive(); } } else { log.warn("userEventTriggered: unhandled event {}", evt); } }
/** Add a future which reconnects the server. * * @param channel The channel to use * @param bootstrap The channel bootstrap to use */ private void addReconnectionOnCloseFuture(@Nonnull Channel channel, @Nonnull Bootstrap bootstrap) { channel.closeFuture().addListener((r) -> { log.info("addReconnectionOnCloseFuture[{}]: disconnected", node); // Remove the current completion future, forcing clients to wait for reconnection. connectionFuture = new CompletableFuture<>(); // Exceptionally complete all requests that were waiting for a completion. outstandingRequests.forEach((reqId, reqCompletableFuture) -> { reqCompletableFuture.completeExceptionally( new NetworkException("Disconnected", node)); // And also remove them. outstandingRequests.remove(reqId); }); // If we aren't shutdown, reconnect. if (!shutdown) { Sleep.sleepUninterruptibly(parameters.getConnectionRetryRate()); log.info("addReconnectionOnCloseFuture[{}]: reconnecting...", node); // Asynchronously connect again. connectAsync(bootstrap); } }); }
/** Connect to a remote server asynchronously. * * @param bootstrap The channel boostrap to use * @return A {@link ChannelFuture} which is c */ private ChannelFuture connectAsync(@Nonnull Bootstrap bootstrap) { // If shutdown, return a ChannelFuture that is exceptionally completed. if (shutdown) { return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE) .setFailure(new ShutdownException("Runtime already shutdown!")); } // Use the bootstrap to create a new channel. ChannelFuture f = bootstrap.connect(node.getHost(), node.getPort()); f.addListener((ChannelFuture cf) -> channelConnectionFutureHandler(cf, bootstrap)); return f; }
@Test public void nettyServerClientPingable() throws Exception { runWithBaseServer( (port) -> { return new NettyServerData(ServerContextBuilder.defaultContext(port)); }, (port) -> { return new NettyClientRouter("localhost", port); }, (r, d) -> { assertThat(getBaseClient(r).pingSync()) .isTrue(); }); }
@Test public void nettyServerClientHandshakeMismatchId() throws Exception { runWithBaseServer( (port) -> { return new NettyServerData(ServerContextBuilder.defaultContext(port)); }, (port) -> { NodeLocator nl = NodeLocator.builder() .host("localhost") .port(port) .nodeId(UUID.nameUUIDFromBytes("test".getBytes())) .build(); return new NettyClientRouter(nl, CorfuRuntimeParameters.builder().build()); }, (r, d) -> { assertThat(getBaseClient(r).pingSync()) .isFalse(); }); }
@Test public void nettyServerClientPingableAfterFailure() throws Exception { runWithBaseServer( (port) -> { return new NettyServerData(ServerContextBuilder.defaultContext(port)); }, (port) -> { return new NettyClientRouter("localhost", port); }, (r, d) -> { assertThat(getBaseClient(r).pingSync()) .isTrue(); d.shutdownServer(); d.bootstrapServer(); getBaseClient(r).pingSync(); }); }
@Test public void nettyServerClientHandshakeDefaultId() throws Exception { runWithBaseServer( (port) -> { return new NettyServerData(ServerContextBuilder.defaultContext(port)); }, (port) -> { NodeLocator nl = NodeLocator.builder() .host("localhost") .port(port) .nodeId(UUID.fromString("00000000-0000-0000-0000-000000000000")) .build(); return new NettyClientRouter(nl, CorfuRuntimeParameters.builder().build()); }, (r, d) -> { assertThat(getBaseClient(r).pingSync()) .isTrue(); }); }
@Test public void nettyServerClientHandshakeMatchIds() throws Exception { runWithBaseServer( (port) -> { ServerContext sc = ServerContextBuilder .defaultContext(port); nodeId = sc.getNodeId(); return new NettyServerData(sc); }, (port) -> { NodeLocator nl = NodeLocator.builder() .host("localhost") .port(port) .nodeId(nodeId) .build(); return new NettyClientRouter(nl, CorfuRuntimeParameters.builder().build()); }, (r, d) -> { assertThat(getBaseClient(r).pingSync()) .isTrue(); }); }
/** * Setup a cluster of 1 node. Bootstrap the node with a wrong layout. * Bootstrap the cluster using the BootstrapUtil. It should assert that the node already * bootstrapped is with the wrong layout and then fail with the AlreadyBootstrappedException. */ @Test public void test1NodeBootstrapWithWrongBootstrappedLayoutServer() throws Exception { // Set up cluster of 1 node. final int PORT_0 = 9000; Process corfuServer_1 = runPersistentServer(corfuSingleNodeHost, PORT_0, false); final Layout layout = getLayout(1); final int retries = 3; IClientRouter router = new NettyClientRouter(NodeLocator .parseString(corfuSingleNodeHost + ":" + PORT_0), CorfuRuntime.CorfuRuntimeParameters.builder().build()); router.addClient(new LayoutHandler()).addClient(new BaseHandler()); Layout wrongLayout = new Layout(layout); wrongLayout.getLayoutServers().add("localhost:9005"); retryBootstrapOperation(() -> CFUtils.getUninterruptibly( new LayoutClient(router, layout.getEpoch()).bootstrapLayout(wrongLayout))); assertThatThrownBy(() -> BootstrapUtil.bootstrap(layout, retries, PARAMETERS.TIMEOUT_SHORT)) .hasCauseInstanceOf(AlreadyBootstrappedException.class); shutdownCorfuServer(corfuServer_1); }
/** * Setup a cluster of 1 node. Bootstrap the node with a wrong layout. * Bootstrap the cluster using the BootstrapUtil. It should assert that the node already * bootstrapped is with the wrong layout and then fail with the AlreadyBootstrappedException. */ @Test public void test1NodeBootstrapWithWrongBootstrappedManagementServer() throws Exception { // Set up cluster of 1 node. final int PORT_0 = 9000; Process corfuServer_1 = runPersistentServer(corfuSingleNodeHost, PORT_0, false); final Layout layout = getLayout(1); final int retries = 3; IClientRouter router = new NettyClientRouter(NodeLocator .parseString(corfuSingleNodeHost + ":" + PORT_0), CorfuRuntime.CorfuRuntimeParameters.builder().build()); router.addClient(new LayoutHandler()) .addClient(new ManagementHandler()) .addClient(new BaseHandler()); Layout wrongLayout = new Layout(layout); final ManagementClient managementClient = new ManagementClient(router, layout.getEpoch()); wrongLayout.getLayoutServers().add("localhost:9005"); retryBootstrapOperation(() -> CFUtils.getUninterruptibly( managementClient.bootstrapManagement(wrongLayout))); assertThatThrownBy(() -> BootstrapUtil.bootstrap(layout, retries, PARAMETERS.TIMEOUT_SHORT)) .hasCauseInstanceOf(AlreadyBootstrappedException.class); shutdownCorfuServer(corfuServer_1); }
/** * Setup a cluster of 1 node. Bootstrap the nodes. * Bootstrap the cluster using the BootstrapUtil. It should assert that the node already * bootstrapped is with the same layout and then bootstrap the cluster. */ @Test public void test1NodeBootstrapWithBootstrappedNode() throws Exception { // Set up cluster of 1 nodes. final int PORT_0 = 9000; Process corfuServer_1 = runPersistentServer(corfuSingleNodeHost, PORT_0, false); final Layout layout = getLayout(1); final int retries = 5; IClientRouter router = new NettyClientRouter(NodeLocator .parseString(corfuSingleNodeHost + ":" + PORT_0), CorfuRuntime.CorfuRuntimeParameters.builder().build()); router.addClient(new LayoutHandler()).addClient(new BaseHandler()); retryBootstrapOperation(() -> CFUtils.getUninterruptibly( new LayoutClient(router, layout.getEpoch()).bootstrapLayout(layout))); retryBootstrapOperation(() -> CFUtils.getUninterruptibly( new ManagementClient(router, layout.getEpoch()).bootstrapManagement(layout))); BootstrapUtil.bootstrap(layout, retries, PARAMETERS.TIMEOUT_SHORT); CorfuRuntime corfuRuntime = createDefaultRuntime(); assertThat(corfuRuntime.getLayoutView().getLayout().equals(layout)).isTrue(); shutdownCorfuServer(corfuServer_1); }
}, (port) -> { return new NettyClientRouter( NodeLocator.builder().host("localhost").port(port).build(), CorfuRuntimeParameters.builder()
}, (port) -> { return new NettyClientRouter( NodeLocator.builder().host("localhost").port(port).build(), CorfuRuntimeParameters.builder()