diff --git a/CHANGES.txt b/CHANGES.txt index b1874cb9495..391305c4257 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -497,6 +497,8 @@ Release 0.21.0 - Unreleased (Todd Lipcon via Stack) HBASE-2423 Update 'Getting Started' for 0.20.4 including making "important configurations more visiable" + HBASE-2435 HTablePool - method to release resources after use + (Kay Kay via Stack) NEW FEATURES HBASE-1961 HBase EC2 scripts diff --git a/core/src/main/java/org/apache/hadoop/hbase/client/HTableFactory.java b/core/src/main/java/org/apache/hadoop/hbase/client/HTableFactory.java index 372ed19daab..6dfdff61331 100644 --- a/core/src/main/java/org/apache/hadoop/hbase/client/HTableFactory.java +++ b/core/src/main/java/org/apache/hadoop/hbase/client/HTableFactory.java @@ -39,4 +39,17 @@ public class HTableFactory implements HTableInterfaceFactory { throw new RuntimeException(ioe); } } + + @Override + public void releaseHTableInterface(HTableInterface table) { + try { + table.close(); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + + } + + + } diff --git a/core/src/main/java/org/apache/hadoop/hbase/client/HTableInterfaceFactory.java b/core/src/main/java/org/apache/hadoop/hbase/client/HTableInterfaceFactory.java index a82fb89bf12..a80d94ec92a 100644 --- a/core/src/main/java/org/apache/hadoop/hbase/client/HTableInterfaceFactory.java +++ b/core/src/main/java/org/apache/hadoop/hbase/client/HTableInterfaceFactory.java @@ -37,4 +37,11 @@ public interface HTableInterfaceFactory { * @return HTableInterface instance. */ HTableInterface createHTableInterface(Configuration config, byte[] tableName); + + + /** + * Release the HTable resource represented by the table. + * @param table + */ + void releaseHTableInterface(final HTableInterface table); } diff --git a/core/src/main/java/org/apache/hadoop/hbase/client/HTablePool.java b/core/src/main/java/org/apache/hadoop/hbase/client/HTablePool.java index 2b92cbe5cd8..c7f61fa8048 100755 --- a/core/src/main/java/org/apache/hadoop/hbase/client/HTablePool.java +++ b/core/src/main/java/org/apache/hadoop/hbase/client/HTablePool.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; +import java.util.Queue; /** * A simple pool of HTable instances.

@@ -124,4 +125,41 @@ public class HTablePool { protected HTableInterface createHTable(String tableName) { return this.tableFactory.createHTableInterface(config, Bytes.toBytes(tableName)); } + + /** + * Closes all the HTable instances , belonging to the given table, in the table pool. + *

+ * Note: this is a 'shutdown' of the given table pool and different from + * {@link #putTable(HTableInterface)}, that is used to return the table + * instance to the pool for future re-use. + * + * @param tableName + */ + public void closeTablePool(final String tableName) { + Queue queue = tables.get(tableName); + synchronized (queue) { + HTableInterface table = queue.poll(); + while (table != null) { + this.tableFactory.releaseHTableInterface(table); + table = queue.poll(); + } + } + + } + + /** + * See {@link #closeTablePool(String)}. + * + * @param tableName + */ + public void closeTablePool(final byte[] tableName) { + closeTablePool(Bytes.toString(tableName)); + } + + int getCurrentPoolSize(String tableName) { + Queue queue = tables.get(tableName); + synchronized(queue) { + return queue.size(); + } + } } diff --git a/core/src/test/java/org/apache/hadoop/hbase/client/TestHTablePool.java b/core/src/test/java/org/apache/hadoop/hbase/client/TestHTablePool.java index a58af1faf92..394fd674292 100644 --- a/core/src/test/java/org/apache/hadoop/hbase/client/TestHTablePool.java +++ b/core/src/test/java/org/apache/hadoop/hbase/client/TestHTablePool.java @@ -19,47 +19,73 @@ */ package org.apache.hadoop.hbase.client; +import java.io.IOException; + +import junit.framework.Assert; + import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.HBaseTestCase; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.util.Bytes; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; /** * Tests HTablePool. */ -public class TestHTablePool extends HBaseTestCase { +public class TestHTablePool { + private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + + @BeforeClass + public static void beforeClass() throws Exception { + TEST_UTIL.startMiniCluster(1); + + } + + @AfterClass + public static void afterClass() throws IOException { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test public void testTableWithStringName() { HTablePool pool = new HTablePool((HBaseConfiguration)null, Integer.MAX_VALUE); String tableName = "testTable"; // Request a table from an empty pool HTableInterface table = pool.getTable(tableName); - assertNotNull(table); + Assert.assertNotNull(table); // Return the table to the pool pool.putTable(table); // Request a table of the same name HTableInterface sameTable = pool.getTable(tableName); - assertSame(table, sameTable); + Assert.assertSame(table, sameTable); } + @Test public void testTableWithByteArrayName() { HTablePool pool = new HTablePool((HBaseConfiguration)null, Integer.MAX_VALUE); byte[] tableName = Bytes.toBytes("testTable"); // Request a table from an empty pool HTableInterface table = pool.getTable(tableName); - assertNotNull(table); + Assert.assertNotNull(table); // Return the table to the pool pool.putTable(table); // Request a table of the same name HTableInterface sameTable = pool.getTable(tableName); - assertSame(table, sameTable); + Assert.assertSame(table, sameTable); } + @Test public void testTableWithMaxSize() { HTablePool pool = new HTablePool((HBaseConfiguration)null, 2); String tableName = "testTable"; @@ -79,11 +105,12 @@ public class TestHTablePool extends HBaseTestCase { HTableInterface sameTable1 = pool.getTable(tableName); HTableInterface sameTable2 = pool.getTable(tableName); HTableInterface sameTable3 = pool.getTable(tableName); - assertSame(table1, sameTable1); - assertSame(table2, sameTable2); - assertNotSame(table3, sameTable3); + Assert.assertSame(table1, sameTable1); + Assert.assertSame(table2, sameTable2); + Assert.assertNotSame(table3, sameTable3); } + @Test public void testTablesWithDifferentNames() { HTablePool pool = new HTablePool((HBaseConfiguration)null, Integer.MAX_VALUE); String tableName1 = "testTable1"; @@ -92,7 +119,7 @@ public class TestHTablePool extends HBaseTestCase { // Request a table from an empty pool HTableInterface table1 = pool.getTable(tableName1); HTableInterface table2 = pool.getTable(tableName2); - assertNotNull(table2); + Assert.assertNotNull(table2); // Return the tables to the pool pool.putTable(table1); @@ -101,7 +128,45 @@ public class TestHTablePool extends HBaseTestCase { // Request tables of the same names HTableInterface sameTable1 = pool.getTable(tableName1); HTableInterface sameTable2 = pool.getTable(tableName2); - assertSame(table1, sameTable1); - assertSame(table2, sameTable2); + Assert.assertSame(table1, sameTable1); + Assert.assertSame(table2, sameTable2); } -} \ No newline at end of file + + + @Test + public void testCloseTablePool() throws IOException { + + HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4); + String tableName = "testTable"; + HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration()); + + if (admin.tableExists(tableName)) { + admin.deleteTable(tableName); + } + + HTableDescriptor tableDescriptor = new HTableDescriptor(Bytes + .toBytes(tableName)); + tableDescriptor.addFamily(new HColumnDescriptor("randomFamily")); + admin.createTable(tableDescriptor); + + + // Request tables from an empty pool + HTableInterface[] tables = new HTableInterface[4]; + for (int i = 0; i < 4; ++i ) { + tables[i] = pool.getTable(tableName); + } + + pool.closeTablePool(tableName); + + for (int i = 0; i < 4; ++i ) { + pool.putTable(tables[i]); + } + + Assert.assertEquals(4, pool.getCurrentPoolSize(tableName)); + + pool.closeTablePool(tableName); + + Assert.assertEquals(0, pool.getCurrentPoolSize(tableName)); + + } +}