Skip to content

Commit df6b316

Browse files
xudongcao91jojochuang
authored andcommitted
HADOOP-16677. Recalculate the remaining timeout millis correctly while throwing an InterupptedException in SocketIOWithTimeout. (#1687)
1 parent 97ec34e commit df6b316

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/SocketIOWithTimeout.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -326,34 +326,36 @@ int select(SelectableChannel channel, int ops, long timeout)
326326

327327
SelectionKey key = null;
328328
int ret = 0;
329+
long timeoutLeft = timeout;
329330

330331
try {
331332
while (true) {
332333
long start = (timeout == 0) ? 0 : Time.now();
333334

334335
key = channel.register(info.selector, ops);
335-
ret = info.selector.select(timeout);
336+
ret = info.selector.select(timeoutLeft);
336337

337338
if (ret != 0) {
338339
return ret;
339340
}
340341

341-
if (Thread.currentThread().isInterrupted()) {
342-
throw new InterruptedIOException("Interrupted while waiting for "
343-
+ "IO on channel " + channel + ". " + timeout
344-
+ " millis timeout left.");
345-
}
346-
347342
/* Sometimes select() returns 0 much before timeout for
348343
* unknown reasons. So select again if required.
349344
*/
350345
if (timeout > 0) {
351-
timeout -= Time.now() - start;
352-
if (timeout <= 0) {
353-
return 0;
354-
}
346+
timeoutLeft -= Time.now() - start;
347+
timeoutLeft = Math.max(0, timeoutLeft);
355348
}
356349

350+
if (Thread.currentThread().isInterrupted()) {
351+
throw new InterruptedIOException("Interrupted while waiting for "
352+
+ "IO on channel " + channel + ". Total timeout mills is "
353+
+ timeout + ", " + timeoutLeft + " millis timeout left.");
354+
}
355+
356+
if (timeoutLeft == 0) {
357+
return 0;
358+
}
357359
}
358360
} finally {
359361
if (key != null) {

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/net/TestSocketIOWithTimeout.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,42 @@ public void doWork() throws Exception {
185185
}
186186
}
187187
}
188+
189+
@Test
190+
public void testSocketIOWithTimeoutInterrupted() throws Exception {
191+
Pipe pipe = Pipe.open();
192+
final int timeout = TIMEOUT * 10;
193+
194+
try (Pipe.SourceChannel source = pipe.source();
195+
InputStream in = new SocketInputStream(source, timeout)) {
196+
197+
TestingThread thread = new TestingThread(ctx) {
198+
@Override
199+
public void doWork() throws Exception {
200+
try {
201+
in.read();
202+
fail("Did not fail with interrupt");
203+
} catch (InterruptedIOException ste) {
204+
String detail = ste.getMessage();
205+
String totalString = "Total timeout mills is " + timeout;
206+
String leftString = "millis timeout left";
207+
208+
assertTrue(detail.contains(totalString));
209+
assertTrue(detail.contains(leftString));
210+
}
211+
}
212+
};
213+
214+
ctx.addThread(thread);
215+
ctx.startThreads();
216+
// If the thread is interrupted before it calls read()
217+
// then it throws ClosedByInterruptException due to
218+
// some Java quirk. Waiting for it to call read()
219+
// gets it into select(), so we get the expected
220+
// InterruptedIOException.
221+
Thread.sleep(1000);
222+
thread.interrupt();
223+
ctx.stop();
224+
}
225+
}
188226
}

0 commit comments

Comments
 (0)