-
Notifications
You must be signed in to change notification settings - Fork 7.3k
ZOOKEEPER-3774: Close quorum socket asynchronously on the leader to a… #1301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ | |
| import java.util.Objects; | ||
| import java.util.Queue; | ||
| import java.util.concurrent.LinkedBlockingQueue; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.concurrent.atomic.AtomicLong; | ||
| import java.util.concurrent.locks.ReentrantReadWriteLock; | ||
|
|
@@ -40,6 +41,7 @@ | |
| import org.apache.jute.BinaryInputArchive; | ||
| import org.apache.jute.BinaryOutputArchive; | ||
| import org.apache.zookeeper.ZooDefs.OpCode; | ||
| import org.apache.zookeeper.common.Time; | ||
| import org.apache.zookeeper.server.Request; | ||
| import org.apache.zookeeper.server.ServerMetrics; | ||
| import org.apache.zookeeper.server.TxnLogProposalIterator; | ||
|
|
@@ -63,12 +65,21 @@ public class LearnerHandler extends ZooKeeperThread { | |
|
|
||
| private static final Logger LOG = LoggerFactory.getLogger(LearnerHandler.class); | ||
|
|
||
| public static final String LEADER_CLOSE_SOCKET_ASYNC = "leader.closeSocketAsync"; | ||
| public static final boolean closeSocketAsync = Boolean.parseBoolean(System.getProperty(LEADER_CLOSE_SOCKET_ASYNC, "false")); | ||
|
|
||
| static { | ||
| LOG.info("{} = {}", LEADER_CLOSE_SOCKET_ASYNC, closeSocketAsync); | ||
| } | ||
|
|
||
| protected final Socket sock; | ||
|
|
||
| public Socket getSocket() { | ||
| return sock; | ||
| } | ||
|
|
||
| AtomicBoolean sockBeingClosed = new AtomicBoolean(false); | ||
|
|
||
| final LearnerMaster learnerMaster; | ||
|
|
||
| /** Deadline for receiving the next ack. If we are bootstrapping then | ||
|
|
@@ -277,11 +288,8 @@ protected void setBufferedOutput(BufferedOutputStream bufferedOutput) { | |
| } | ||
| } catch (IOException e) { | ||
| LOG.error("Server failed to authenticate quorum learner, addr: {}, closing connection", sock.getRemoteSocketAddress(), e); | ||
| try { | ||
| sock.close(); | ||
| } catch (IOException ie) { | ||
| LOG.error("Exception while closing socket", ie); | ||
| } | ||
| closeSocket(); | ||
|
|
||
| throw new SaslException("Authentication failure: " + e.getMessage()); | ||
| } | ||
|
|
||
|
|
@@ -357,17 +365,11 @@ private void sendPackets() throws InterruptedException { | |
| packetsSent.incrementAndGet(); | ||
| messageTracker.trackSent(p.getType()); | ||
| } catch (IOException e) { | ||
| if (!sock.isClosed()) { | ||
| LOG.warn("Unexpected exception at {}", this, e); | ||
| try { | ||
| // this will cause everything to shutdown on | ||
| // this learner handler and will help notify | ||
| // the learner/observer instantaneously | ||
| sock.close(); | ||
| } catch (IOException ie) { | ||
| LOG.warn("Error closing socket for handler {}", this, ie); | ||
| } | ||
| } | ||
| LOG.error("Exception while sending packets in LearnerHandler", e); | ||
| // this will cause everything to shutdown on | ||
| // this learner handler and will help notify | ||
| // the learner/observer instantaneously | ||
| closeSocket(); | ||
| break; | ||
| } | ||
| } | ||
|
|
@@ -703,16 +705,8 @@ public void run() { | |
| } | ||
| } | ||
| } catch (IOException e) { | ||
| if (sock != null && !sock.isClosed()) { | ||
| LOG.error("Unexpected exception causing shutdown while sock still open", e); | ||
| //close the socket to make sure the | ||
| //other side can see it being close | ||
| try { | ||
| sock.close(); | ||
| } catch (IOException ie) { | ||
| // do nothing | ||
| } | ||
| } | ||
| LOG.error("Unexpected exception in LearnerHandler: ", e); | ||
| closeSocket(); | ||
| } catch (InterruptedException e) { | ||
| LOG.error("Unexpected exception in LearnerHandler.", e); | ||
| } catch (SyncThrottleException e) { | ||
|
|
@@ -1043,13 +1037,9 @@ public void shutdown() { | |
| } catch (InterruptedException e) { | ||
| LOG.warn("Ignoring unexpected exception", e); | ||
| } | ||
| try { | ||
| if (sock != null && !sock.isClosed()) { | ||
| sock.close(); | ||
| } | ||
| } catch (IOException e) { | ||
| LOG.warn("Ignoring unexpected exception during socket close", e); | ||
| } | ||
|
|
||
| closeSocket(); | ||
|
|
||
| this.interrupt(); | ||
| learnerMaster.removeLearnerHandler(this); | ||
| learnerMaster.unregisterLearnerHandlerBean(this); | ||
|
|
@@ -1150,4 +1140,33 @@ public void setFirstPacket(boolean value) { | |
| needOpPacket = value; | ||
| } | ||
|
|
||
| void closeSocket() { | ||
| if (sock != null && !sock.isClosed() && sockBeingClosed.compareAndSet(false, true)) { | ||
| if (closeSocketAsync) { | ||
| LOG.info("Asynchronously closing socket to learner {}.", getSid()); | ||
| closeSockAsync(); | ||
| } else { | ||
| LOG.info("Synchronously closing socket to learner {}.", getSid()); | ||
| closeSockSync(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void closeSockAsync() { | ||
| final Thread closingThread = new Thread(() -> closeSockSync(), "CloseSocketThread(sid:" + this.sid); | ||
| closingThread.setDaemon(true); | ||
| closingThread.start(); | ||
| } | ||
|
|
||
| void closeSockSync() { | ||
| try { | ||
| if (sock != null) { | ||
| long startTime = Time.currentElapsedTime(); | ||
| sock.close(); | ||
| ServerMetrics.getMetrics().SOCKET_CLOSING_TIME.add(Time.currentElapsedTime() - startTime); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would it be useful to record this value even in case of failure ?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm hesitating... This metric is to measure the real time for closing a socket. If it fails, say, the socket is closed already, then the elapsed time is not really the time for closing the socket. |
||
| } | ||
| } catch (IOException e) { | ||
| LOG.warn("Ignoring error closing connection to learner {}", getSid(), e); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.