Skip to content

Commit 4485bde

Browse files
kezhuwmeszinorbi
authored andcommitted
ZOOKEEPER-4921: Retry endlessly to establish a brand-new session
Reviewers: tisonkun Author: kezhuw Closes #2252 from kezhuw/ZOOKEEPER-4921-retry-brand-new-session-endlessly This is cherry picked from commit 0971e5e which is already merged to branch-3.9, this way we make ZOOKEEPER-4923 a pure feature request. Signed-off-by: Kezhu Wang <[email protected]>
1 parent d0fcfb9 commit 4485bde

File tree

2 files changed

+47
-20
lines changed

2 files changed

+47
-20
lines changed

zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ public void run() {
11921192
to = connectTimeout - clientCnxnSocket.getIdleSend();
11931193
}
11941194

1195-
int expiration = expirationTimeout - clientCnxnSocket.getIdleRecv();
1195+
int expiration = sessionId == 0 ? Integer.MAX_VALUE : expirationTimeout - clientCnxnSocket.getIdleRecv();
11961196
if (expiration <= 0) {
11971197
String warnInfo = String.format(
11981198
"Client session timed out, have not heard from server in %dms for session id 0x%s",

zookeeper-server/src/test/java/org/apache/zookeeper/test/SessionTimeoutTest.java

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
package org.apache.zookeeper.test;
2020

21+
import static org.hamcrest.MatcherAssert.assertThat;
22+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
23+
import static org.hamcrest.Matchers.lessThan;
2124
import static org.junit.jupiter.api.Assertions.assertNotNull;
2225
import static org.junit.jupiter.api.Assertions.assertNull;
2326
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -31,12 +34,15 @@
3134
import java.util.concurrent.CompletableFuture;
3235
import java.util.concurrent.CountDownLatch;
3336
import java.util.concurrent.TimeUnit;
37+
import java.util.concurrent.TimeoutException;
3438
import org.apache.zookeeper.CreateMode;
3539
import org.apache.zookeeper.KeeperException;
3640
import org.apache.zookeeper.TestableZooKeeper;
3741
import org.apache.zookeeper.WatchedEvent;
3842
import org.apache.zookeeper.Watcher;
3943
import org.apache.zookeeper.ZooDefs;
44+
import org.apache.zookeeper.ZooKeeper;
45+
import org.apache.zookeeper.common.Time;
4046
import org.junit.jupiter.api.BeforeEach;
4147
import org.junit.jupiter.api.Test;
4248
import org.slf4j.Logger;
@@ -54,6 +60,21 @@ public void setUp() throws Exception {
5460
zk = createClient();
5561
}
5662

63+
private static class ExpiredWatcher implements Watcher {
64+
public volatile CompletableFuture<Void> expired = new CompletableFuture<>();
65+
66+
synchronized void reset() {
67+
expired = new CompletableFuture<>();
68+
}
69+
70+
@Override
71+
public synchronized void process(WatchedEvent event) {
72+
if (event.getState() == Event.KeeperState.Expired) {
73+
expired.complete(null);
74+
}
75+
}
76+
}
77+
5778
private static class BusyServer implements AutoCloseable {
5879
private final ServerSocket server;
5980
private final Socket client;
@@ -143,17 +164,24 @@ public void testSessionExpirationAfterAllServerDown() throws Exception {
143164
// stop client also to gain less distraction
144165
zk.close();
145166

146-
// small connection timeout to gain quick ci feedback
147-
int sessionTimeout = 3000;
148-
CompletableFuture<Void> expired = new CompletableFuture<>();
167+
// given: established session
168+
int sessionTimeout = 3000; // small connection timeout to gain quick ci feedback
169+
ExpiredWatcher watcher = new ExpiredWatcher();
149170
zk = createClient(new CountdownWatcher(), hostPort, sessionTimeout);
150-
zk.register(event -> {
151-
if (event.getState() == Watcher.Event.KeeperState.Expired) {
152-
expired.complete(null);
153-
}
154-
});
171+
zk.register(watcher);
172+
173+
// when: all server down
174+
long start = Time.currentElapsedTime();
175+
zk.sync("/"); // touch timeout counts
155176
stopServer();
156-
expired.join();
177+
178+
// then: get Expired after session timeout
179+
watcher.expired.join();
180+
long elapsed = Time.currentElapsedTime() - start;
181+
assertThat(elapsed, greaterThanOrEqualTo((long) zk.getSessionTimeout()));
182+
assertThat(elapsed, lessThan(zk.getSessionTimeout() * 10L));
183+
184+
// then: future request will get SessionExpiredException
157185
assertThrows(KeeperException.SessionExpiredException.class, () -> zk.exists("/", null));
158186
}
159187

@@ -162,18 +190,17 @@ public void testSessionExpirationWhenNoServerUp() throws Exception {
162190
// stop client also to gain less distraction
163191
zk.close();
164192

193+
// given: unavailable cluster
165194
stopServer();
166195

167-
// small connection timeout to gain quick ci feedback
168-
int sessionTimeout = 3000;
169-
CompletableFuture<Void> expired = new CompletableFuture<>();
170-
new TestableZooKeeper(hostPort, sessionTimeout, event -> {
171-
if (event.getState() == Watcher.Event.KeeperState.Expired) {
172-
expired.complete(null);
173-
}
174-
});
175-
expired.join();
176-
assertThrows(KeeperException.SessionExpiredException.class, () -> zk.exists("/", null));
196+
// when: try to establish a brand-new session
197+
int sessionTimeout = 300; // small connection timeout to gain quick ci feedback
198+
ExpiredWatcher watcher = new ExpiredWatcher();
199+
try (ZooKeeper zk = new ZooKeeper(hostPort, sessionTimeout, watcher)) {
200+
// then: never Expired
201+
assertThrows(TimeoutException.class, () -> watcher.expired.get(3 * sessionTimeout, TimeUnit.MILLISECONDS));
202+
assertThrows(KeeperException.ConnectionLossException.class, () -> zk.exists("/", null));
203+
}
177204
}
178205

179206
@Test

0 commit comments

Comments
 (0)