You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gc...@apache.org on 2012/10/22 21:12:44 UTC

svn commit: r1401015 - in /hbase/trunk/hbase-server/src: main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java

Author: gchanan
Date: Mon Oct 22 19:12:43 2012
New Revision: 1401015

URL: http://svn.apache.org/viewvc?rev=1401015&view=rev
Log:
HBASE-6987 Port HBASE-6920 to trunk (?)

Added:
    hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java
    hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java
Modified:
    hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java

Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java?rev=1401015&r1=1401014&r2=1401015&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java Mon Oct 22 19:12:43 2012
@@ -209,7 +209,7 @@ public class HBaseAdmin implements Abort
    * @throws ZooKeeperConnectionException
    * @throws MasterNotRunningException
    */
-   public boolean isMasterRunning()
+  public boolean isMasterRunning()
   throws MasterNotRunningException, ZooKeeperConnectionException {
     return connection.isMasterRunning();
   }
@@ -1845,16 +1845,8 @@ public class HBaseAdmin implements Abort
         }
       }
 
-      // Check Master, same logic.
-      MasterAdminKeepAliveConnection master = null;
-      try {
-        master = connection.getKeepAliveMasterAdmin();
-        master.isMasterRunning(null,RequestConverter.buildIsMasterRunningRequest());
-      } finally {
-        if (master != null) {
-          master.close();
-        }
-      }
+      // Check Master
+      connection.isMasterRunning();
 
     } finally {
       connection.close();

Added: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java?rev=1401015&view=auto
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java (added)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java Mon Oct 22 19:12:43 2012
@@ -0,0 +1,98 @@
+/**
+ * Copyright The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.client;
+
+import static org.junit.Assert.*;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.MasterAdminProtocol;
+import org.apache.hadoop.hbase.MasterMonitorProtocol;
+import org.apache.hadoop.hbase.MasterNotRunningException;
+import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.ipc.RandomTimeoutRpcEngine;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(MediumTests.class)
+public class TestClientTimeouts {
+  final Log LOG = LogFactory.getLog(getClass());
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+  protected static int SLAVES = 1;
+
+ /**
+   * @throws java.lang.Exception
+   */
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    Configuration conf = TEST_UTIL.getConfiguration();
+    RandomTimeoutRpcEngine.setProtocolEngine(conf, MasterAdminProtocol.class);
+    RandomTimeoutRpcEngine.setProtocolEngine(conf, MasterMonitorProtocol.class);
+    TEST_UTIL.startMiniCluster(SLAVES);
+  }
+
+  /**
+   * @throws java.lang.Exception
+   */
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniCluster();
+  }
+
+  /**
+   * Test that a client that fails an RPC to the master retries properly and
+   * doesn't throw any unexpected exceptions.
+   * @throws Exception
+   */
+  @Test
+  public void testAdminTimeout() throws Exception {
+    long lastLimit = HConstants.DEFAULT_HBASE_CLIENT_PREFETCH_LIMIT;
+    HConnection lastConnection = null;
+    boolean lastFailed = false;
+    int initialInvocations = RandomTimeoutRpcEngine.getNumberOfInvocations();
+    for (int i = 0; i < 5 || (lastFailed && i < 100); ++i) {
+      lastFailed = false;
+      // Ensure the HBaseAdmin uses a new connection by changing Configuration.
+      Configuration conf = HBaseConfiguration.create(TEST_UTIL.getConfiguration());
+      conf.setLong(HConstants.HBASE_CLIENT_PREFETCH_LIMIT, ++lastLimit);
+      try {
+        HBaseAdmin admin = new HBaseAdmin(conf);
+        HConnection connection = admin.getConnection();
+        assertFalse(connection == lastConnection);
+        // run some admin commands
+        HBaseAdmin.checkHBaseAvailable(conf);
+        admin.setBalancerRunning(false, false);
+      } catch (MasterNotRunningException ex) {
+        // Since we are randomly throwing SocketTimeoutExceptions, it is possible to get
+        // a MasterNotRunningException.  It's a bug if we get other exceptions.
+        lastFailed = true;
+      }
+    }
+    // Ensure the RandomTimeoutRpcEngine is actually being used.
+    assertFalse(lastFailed);
+    assertTrue(RandomTimeoutRpcEngine.getNumberOfInvocations() > initialInvocations);
+  }
+}

Added: hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java?rev=1401015&view=auto
==============================================================================
--- hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java (added)
+++ hbase/trunk/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/RandomTimeoutRpcEngine.java Mon Oct 22 19:12:43 2012
@@ -0,0 +1,99 @@
+/**
+ * Copyright The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.ipc;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.hadoop.hbase.ipc.VersionedProtocol;
+import javax.net.SocketFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.security.User;
+
+import com.google.protobuf.ServiceException;
+
+/**
+ * RpcEngine that random throws a SocketTimeoutEngine for testing.
+ * Make sure to call setProtocolEngine to have the client actually use the RpcEngine
+ * for a specific protocol
+ */
+public class RandomTimeoutRpcEngine extends ProtobufRpcEngine {
+
+  private static final Random RANDOM = new Random(System.currentTimeMillis());
+  public static double chanceOfTimeout = 0.3;
+  private static AtomicInteger invokations = new AtomicInteger();
+  
+  public VersionedProtocol getProxy(
+      Class<? extends VersionedProtocol> protocol, long clientVersion,
+      InetSocketAddress addr, User ticket,
+      Configuration conf, SocketFactory factory, int rpcTimeout) throws IOException {
+    // Start up the requested-for proxy so we can pass-through calls to the underlying
+    // RpcEngine.  Also instantiate and return our own proxy (RandomTimeoutInvocationHandler)
+    // that will either throw exceptions or pass through to the underlying proxy.
+    VersionedProtocol actualProxy = super.getProxy(protocol, clientVersion, addr,
+      ticket, conf, factory, rpcTimeout);
+    RandomTimeoutInvocationHandler invoker =
+      new RandomTimeoutInvocationHandler(actualProxy);
+    VersionedProtocol object = (VersionedProtocol)Proxy.newProxyInstance(
+      protocol.getClassLoader(), new Class[]{protocol}, invoker);
+    return object;
+  }
+
+  /**
+   * Call this in order to set this class to run as the RpcEngine for the given protocol
+   */
+  public static void setProtocolEngine(Configuration conf, Class protocol) {
+    HBaseRPC.setProtocolEngine(conf, protocol, RandomTimeoutRpcEngine.class);
+  }
+
+  /**
+   * @return the number of times the invoker has been invoked
+   */
+  public static int getNumberOfInvocations() {
+    return invokations.get();
+  }
+
+  static class RandomTimeoutInvocationHandler implements InvocationHandler {
+    private VersionedProtocol actual = null;
+
+    public RandomTimeoutInvocationHandler(VersionedProtocol actual) {
+      this.actual = actual;
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+    throws Throwable {
+      RandomTimeoutRpcEngine.invokations.getAndIncrement();
+      if (RANDOM.nextFloat() < chanceOfTimeout) {
+        // throw a ServiceException, becuase that is the only exception type that
+      	// {@link ProtobufRpcEngine} throws.  If this RpcEngine is used with a different
+      	// "actual" type, this may not properly mimic the underlying RpcEngine.
+        throw new ServiceException(new SocketTimeoutException("fake timeout"));
+      }
+      return Proxy.getInvocationHandler(actual).invoke(proxy, method, args);
+    }
+  }
+}