-
Notifications
You must be signed in to change notification settings - Fork 7.3k
ZOOKEEPER-4419: The potential exception in Learner$LeaderConnector.connectToLeader may cause unnecessary re-election or service delay #1782
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
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 |
|---|---|---|
|
|
@@ -396,7 +396,7 @@ public void run() { | |
| } | ||
|
|
||
| private Socket connectToLeader() throws IOException, X509Exception, InterruptedException { | ||
| Socket sock = createSocket(); | ||
| Socket sock = null; | ||
|
|
||
| // leader connection timeout defaults to tickTime * initLimit | ||
| int connectTimeout = self.tickTime * self.initLimit; | ||
|
|
@@ -410,8 +410,12 @@ private Socket connectToLeader() throws IOException, X509Exception, InterruptedE | |
| int remainingTimeout; | ||
| long startNanoTime = nanoTime(); | ||
|
|
||
| for (int tries = 0; tries < 5 && socket.get() == null; tries++) { | ||
| for (int tries = 0; tries < 5; tries++) { | ||
| try { | ||
| sock = createSocket(); | ||
| if (socket.get() == null) { | ||
| continue; | ||
|
Member
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. ? What does this mean ? I think all we have to do is moving Besides, shall we close
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. I don't understand this either. Wouldn't be better to use the try block for creating and closing? try (Socket sock = createSocket()) {
...
}
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.
Member
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.
We need the created socket on return, so "try-with-resources" statement is not going to work here.
I think it should be catch-and-swallow. 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 have a small question if I may.
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. The "continue;" you mentioned handles the case that In a broader sense, the loop 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. hello, Key comments are:
Then I propose the following outline. Socket sock = null;
for (...) {
try {
sock = createSocket();
remainingTimeout = ...;
sockConnect(sock, ...);
if (sslEnabled) {
handshake(...);
}
sock.setTcpNoDelay(...);
break; // success
} catch (IOException e) {
// close failed socket before retrying
if (sock != null) {
try {
sock.close();
} catch (IOException closeException) {
LOG.debug("Failed to close socket after connection failure", closeException);
}
sock = null;
}
// keep existing timeout calculation and logging unchanged
remainingTimeout = ...;
if (remainingTimeout <= leaderConnectDelayDuringRetryMs) {
LOG.error(...);
throw e;
} else if (tries >= 4) {
LOG.error(...);
throw e;
} else {
LOG.warn(...);
}
}
Thread.sleep(leaderConnectDelayDuringRetryMs);
}
return sock; |
||
| } | ||
| // recalculate the init limit time because retries sleep for 1000 milliseconds | ||
| remainingTimeout = connectTimeout - (int) ((nanoTime() - startNanoTime) / 1_000_000); | ||
| if (remainingTimeout <= 0) { | ||
|
|
@@ -451,7 +455,6 @@ private Socket connectToLeader() throws IOException, X509Exception, InterruptedE | |
| remainingTimeout, | ||
| address, | ||
| e); | ||
| sock = createSocket(); | ||
| } | ||
| } | ||
| Thread.sleep(leaderConnectDelayDuringRetryMs); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connectToLeadercould be called concurrently for different addresses, so it is good to break eagerly when there is a success connection.