瀏覽代碼

HADOOP-8294. IPC Connection becomes unusable even if server address was temporarilly unresolvable. Backport of HADOOP-7428. Contributed by Kihwal Lee.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.0@1330040 13f79535-47bb-0310-9956-ffa450edef68
Matthew Foley 13 年之前
父節點
當前提交
91dc38e8a6
共有 3 個文件被更改,包括 63 次插入2 次删除
  1. 3 0
      CHANGES.txt
  2. 6 2
      src/core/org/apache/hadoop/ipc/Client.java
  3. 54 0
      src/test/org/apache/hadoop/ipc/TestIPC.java

+ 3 - 0
CHANGES.txt

@@ -41,6 +41,9 @@ Release 1.0.3 - unreleased
 
     HDFS-119. Fix a bug in logSync(), which causes NameNode block forever. (shv)
 
+    HADOOP-8294. IPC Connection becomes unusable even if server address was temporarilly
+    unresolvable. Backport of HADOOP-7428. (Kihwal Lee via mattf)
+
 Release 1.0.2 - 2012.03.24
 
   NEW FEATURES

+ 6 - 2
src/core/org/apache/hadoop/ipc/Client.java

@@ -612,8 +612,12 @@ public class Client {
           start();
           return;
         }
-      } catch (IOException e) {
-        markClosed(e);
+      } catch (Throwable t) {
+        if (t instanceof IOException) {
+          markClosed((IOException)t);
+        } else {
+          markClosed(new IOException("Couldn't set up IO streams", t));
+        }
         close();
       }
     }

+ 54 - 0
src/test/org/apache/hadoop/ipc/TestIPC.java

@@ -29,12 +29,20 @@ import java.util.Random;
 import java.io.DataInput;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.net.SocketTimeoutException;
 
+import javax.net.SocketFactory;
+
 import junit.framework.TestCase;
 
 import org.apache.hadoop.conf.Configuration;
 
+import static org.mockito.Mockito.*;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
 /** Unit tests for IPC. */
 public class TestIPC extends TestCase {
   public static final Log LOG =
@@ -235,6 +243,52 @@ public class TestIPC extends TestCase {
     }
   }
 
+  /**
+  * Test that, if a RuntimeException is thrown after creating a socket
+  * but before successfully connecting to the IPC server, that the
+  * failure is handled properly. This is a regression test for
+  * HADOOP-7428 (HADOOP-8294).
+  */
+  public void testRTEDuringConnectionSetup() throws Exception {
+    // Set up a socket factory which returns sockets which
+    // throw an RTE when setSoTimeout is called.
+    SocketFactory spyFactory = spy(NetUtils.getDefaultSocketFactory(conf));
+    Mockito.doAnswer(new Answer<Socket>() {
+      @Override
+      public Socket answer(InvocationOnMock invocation) throws Throwable {
+        Socket s = spy((Socket)invocation.callRealMethod());
+        doThrow(new RuntimeException("Injected fault")).when(s)
+          .setSoTimeout(anyInt());
+        return s;
+      }
+    }).when(spyFactory).createSocket();
+ 
+    Server server = new TestServer(1, true);
+    server.start();
+    try {
+      // Call should fail due to injected exception.
+      InetSocketAddress address = NetUtils.getConnectAddress(server);
+      Client client = new Client(LongWritable.class, conf, spyFactory);
+      try {
+        client.call(new LongWritable(RANDOM.nextLong()),
+                address, null, null, 0, conf);
+        fail("Expected an exception to have been thrown");
+      } catch (Exception e) {
+        LOG.info("caught expected exception", e);
+        assertTrue(StringUtils.stringifyException(e).contains(
+            "Injected fault"));
+      }
+      // Resetting to the normal socket behavior should succeed
+      // (i.e. it should not have cached a half-constructed connection)
+  
+      Mockito.reset(spyFactory);
+      client.call(new LongWritable(RANDOM.nextLong()),
+          address, null, null, 0, conf);
+    } finally {
+      server.stop();
+    }
+  }
+
   public void testIpcTimeout() throws Exception {
     // start server
     Server server = new TestServer(1, true);