/** * Forcefully shuts down the connection to this tablet server and fails all the outstanding RPCs. * Only use when shutting down a client. * * @return deferred object to use to track the shutting down of this connection */ public Deferred<Void> shutdown() { // First, check whether we have RPCs in flight and cancel them. for (Iterator<KuduRpc<?>> ite = rpcs_inflight.values().iterator(); ite.hasNext(); ) { KuduRpc<?> rpc = ite.next(); rpc.errback(new ConnectionResetException(null)); ite.remove(); } // Same for the pending RPCs. synchronized (this) { if (pending_rpcs != null) { for (Iterator<KuduRpc<?>> ite = pending_rpcs.iterator(); ite.hasNext(); ) { ite.next().errback(new ConnectionResetException(null)); ite.remove(); } } } final Channel chancopy = chan; if (chancopy == null) { return Deferred.fromResult(null); } if (chancopy.isConnected()) { Channels.disconnect(chancopy); // ... this is going to set it to null. // At this point, all in-flight RPCs are going to be failed. } if (chancopy.isBound()) { Channels.unbind(chancopy); } // It's OK to call close() on a Channel if it's already closed. final ChannelFuture future = Channels.close(chancopy); // Now wrap the ChannelFuture in a Deferred. final Deferred<Void> d = new Deferred<Void>(); // Opportunistically check if it's already completed successfully. if (future.isSuccess()) { d.callback(null); } else { // If we get here, either the future failed (yeah, that sounds weird) // or the future hasn't completed yet (heh). future.addListener( new ChannelFutureListener() { public void operationComplete(final ChannelFuture future) { if (future.isSuccess()) { d.callback(null); return; } final Throwable t = future.getCause(); if (t instanceof Exception) { d.callback(t); } else { // Wrap the Throwable because Deferred doesn't handle Throwables, // it only uses Exception. d.callback( new NonRecoverableException("Failed to shutdown: " + TabletClient.this, t)); } } }); } return d; }
/** Quick and dirty way to close a connection to a tablet server, if it wasn't already closed. */ @VisibleForTesting void disconnect() { Channel chancopy = chan; if (chancopy != null && chancopy.isConnected()) { Channels.disconnect(chancopy); } }