diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java index 491c547..cd494ad 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java @@ -1159,7 +1159,7 @@ class ConnectionManager { public RegionLocations locateRegion(final TableName tableName, final byte [] row, boolean useCache, boolean retry, int replicaId) throws IOException { - if (this.closed) throw new IOException(toString() + " closed"); + if (this.closed) throw new IOException(toString() + " to " + tableName + " is closed"); if (tableName== null || tableName.getName().length == 0) { throw new IllegalArgumentException( "table name cannot be null or zero length"); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ConnectionCache.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ConnectionCache.java index 89e44bd..72c7491 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ConnectionCache.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ConnectionCache.java @@ -105,6 +105,13 @@ public class ConnectionCache { } /** + * @return Total count of currently cached connections. + */ + public int getConnectionCount() { + return this.connections.size(); + } + + /** * Set the current thread local effective user */ public void setEffectiveUser(String user) { @@ -225,4 +232,4 @@ public class ConnectionCache { return false; } } -} +} \ No newline at end of file diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java index 7155f63..2bfb75b 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServerRunner.java @@ -129,6 +129,7 @@ import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.ServletHolder; import org.mortbay.thread.QueuedThreadPool; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -643,7 +644,8 @@ public class ThriftServerRunner implements Runnable { protected HashMap scannerMap = null; private ThriftMetrics metrics = null; - private final ConnectionCache connectionCache; + @VisibleForTesting + final ConnectionCache connectionCache; private static ThreadLocal> threadLocalTables = new ThreadLocal>() { @@ -739,8 +741,7 @@ public class ThriftServerRunner implements Runnable { int cleanInterval = conf.getInt(CLEANUP_INTERVAL, 10 * 1000); int maxIdleTime = conf.getInt(MAX_IDLETIME, 10 * 60 * 1000); - connectionCache = new ConnectionCache( - conf, userProvider, cleanInterval, maxIdleTime); + connectionCache = new ConnectionCache(conf, userProvider, cleanInterval, maxIdleTime); } /** diff --git a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java index 71e88d5..df42403 100644 --- a/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java +++ b/hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServer.java @@ -42,10 +42,12 @@ import org.apache.hadoop.hbase.filter.ParseFilter; import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.test.MetricsAssertHelper; import org.apache.hadoop.hbase.thrift.ThriftServerRunner.HBaseHandler; +import org.apache.hadoop.hbase.thrift.generated.AlreadyExists; import org.apache.hadoop.hbase.thrift.generated.BatchMutation; import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor; import org.apache.hadoop.hbase.thrift.generated.Hbase; import org.apache.hadoop.hbase.thrift.generated.IOError; +import org.apache.hadoop.hbase.thrift.generated.IllegalArgument; import org.apache.hadoop.hbase.thrift.generated.Mutation; import org.apache.hadoop.hbase.thrift.generated.TAppend; import org.apache.hadoop.hbase.thrift.generated.TCell; @@ -93,8 +95,15 @@ public class TestThriftServer { private static ByteBuffer valueDname = asByteBuffer("valueD"); private static ByteBuffer valueEname = asByteBuffer(100l); + private static int CONNECTION_IDLE_TIME = 1000; + private static int RUN_CLEANER_INTERVAL = 1000; + @BeforeClass public static void beforeClass() throws Exception { + UTIL.getConfiguration().setInt(ThriftServerRunner.HBaseHandler.MAX_IDLETIME, + CONNECTION_IDLE_TIME); + UTIL.getConfiguration().setInt(ThriftServerRunner.HBaseHandler.CLEANUP_INTERVAL, + RUN_CLEANER_INTERVAL); UTIL.getConfiguration().setBoolean(ThriftServerRunner.COALESCE_INC_KEY, true); UTIL.getConfiguration().setBoolean("hbase.table.sanity.checks", false); UTIL.startMiniCluster(); @@ -105,6 +114,35 @@ public class TestThriftServer { UTIL.shutdownMiniCluster(); } + @Test (timeout=30000) + public void testConnectionCache() + throws IOException, IOError, IllegalArgument, AlreadyExists, InterruptedException { + ThriftServerRunner.HBaseHandler handler = + new ThriftServerRunner.HBaseHandler(UTIL.getConfiguration(), + UserProvider.instantiate(UTIL.getConfiguration())); + final ByteBuffer tn = asByteBuffer("tn"); + handler.createTable(tn, getColumnDescriptors()); + List mutations = new ArrayList(1); + mutations.add(new Mutation(false, columnAAname, valueEname, true)); + final int count = 10; + for (int i = 0; i < count; i++) { + try { + if (i > 1) { + // Sleep until count of connections is zero... because idle one got cleaned up. + while (handler.connectionCache.getConnectionCount() > 0) { + Threads.sleep(CONNECTION_IDLE_TIME); + } + } + handler.mutateRow(tn, rowAname, mutations, null); + LOG.info("Mutate " + i); + } catch (IOError e) { + throw new RuntimeException(e); + } catch (IllegalArgument e) { + throw new RuntimeException(e); + } + } + } + /** * Runs all of the tests under a single JUnit test method. We * consolidate all testing to one method because HBaseClusterTestCase