/** * * 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 java.io.IOException; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.PoolMap.PoolType; import org.junit.*; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** * Tests HTablePool. */ @RunWith(Suite.class) @Suite.SuiteClasses({TestHTablePool.TestHTableReusablePool.class, TestHTablePool.TestHTableThreadLocalPool.class}) @Category(MediumTests.class) public class TestHTablePool { private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); private final static byte[] TABLENAME = Bytes.toBytes("TestHTablePool"); @BeforeClass public static void setUpBeforeClass() throws Exception { TEST_UTIL.startMiniCluster(1); TEST_UTIL.createTable(TABLENAME, HConstants.CATALOG_FAMILY); } @AfterClass public static void tearDownAfterClass() throws Exception { TEST_UTIL.shutdownMiniCluster(); } public abstract static class TestHTablePoolType extends TestCase { protected abstract PoolType getPoolType(); @Test public void testTableWithStringName() throws Exception { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE, getPoolType()); String tableName = Bytes.toString(TABLENAME); // Request a table from an empty pool HTableInterface table = pool.getTable(tableName); Assert.assertNotNull(table); // Close table (returns table to the pool) table.close(); // Request a table of the same name HTableInterface sameTable = pool.getTable(tableName); Assert.assertSame( ((HTablePool.PooledHTable) table).getWrappedTable(), ((HTablePool.PooledHTable) sameTable).getWrappedTable()); } @Test public void testTableWithByteArrayName() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE, getPoolType()); // Request a table from an empty pool HTableInterface table = pool.getTable(TABLENAME); Assert.assertNotNull(table); // Close table (returns table to the pool) table.close(); // Request a table of the same name HTableInterface sameTable = pool.getTable(TABLENAME); Assert.assertSame( ((HTablePool.PooledHTable) table).getWrappedTable(), ((HTablePool.PooledHTable) sameTable).getWrappedTable()); } @Test public void testTablesWithDifferentNames() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE, getPoolType()); // We add the class to the table name as the HBase cluster is reused // during the tests: this gives naming unicity. byte[] otherTable = Bytes.toBytes( "OtherTable_" + getClass().getSimpleName() ); TEST_UTIL.createTable(otherTable, HConstants.CATALOG_FAMILY); // Request a table from an empty pool HTableInterface table1 = pool.getTable(TABLENAME); HTableInterface table2 = pool.getTable(otherTable); Assert.assertNotNull(table2); // Close tables (returns tables to the pool) table1.close(); table2.close(); // Request tables of the same names HTableInterface sameTable1 = pool.getTable(TABLENAME); HTableInterface sameTable2 = pool.getTable(otherTable); Assert.assertSame( ((HTablePool.PooledHTable) table1).getWrappedTable(), ((HTablePool.PooledHTable) sameTable1).getWrappedTable()); Assert.assertSame( ((HTablePool.PooledHTable) table2).getWrappedTable(), ((HTablePool.PooledHTable) sameTable2).getWrappedTable()); } @Test public void testProxyImplementationReturned() { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE); String tableName = Bytes.toString(TABLENAME);// Request a table from // an // empty pool HTableInterface table = pool.getTable(tableName); // Test if proxy implementation is returned Assert.assertTrue(table instanceof HTablePool.PooledHTable); } @Test public void testDeprecatedUsagePattern() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE); String tableName = Bytes.toString(TABLENAME);// Request a table from // an // empty pool // get table will return proxy implementation HTableInterface table = pool.getTable(tableName); // put back the proxy implementation instead of closing it pool.putTable(table); // Request a table of the same name HTableInterface sameTable = pool.getTable(tableName); // test no proxy over proxy created Assert.assertSame(((HTablePool.PooledHTable) table).getWrappedTable(), ((HTablePool.PooledHTable) sameTable).getWrappedTable()); } @Test public void testReturnDifferentTable() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), Integer.MAX_VALUE); String tableName = Bytes.toString(TABLENAME);// Request a table from // an // empty pool // get table will return proxy implementation final HTableInterface table = pool.getTable(tableName); HTableInterface alienTable = new HTable(TEST_UTIL.getConfiguration(), TABLENAME) { // implementation doesn't matter as long the table is not from // pool }; try { // put the wrong table in pool pool.putTable(alienTable); Assert.fail("alien table accepted in pool"); } catch (IllegalArgumentException e) { Assert.assertTrue("alien table rejected", true); } } } @Category(MediumTests.class) public static class TestHTableReusablePool extends TestHTablePoolType { @Override protected PoolType getPoolType() { return PoolType.Reusable; } @Test public void testTableWithMaxSize() throws Exception { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2, getPoolType()); // Request tables from an empty pool HTableInterface table1 = pool.getTable(TABLENAME); HTableInterface table2 = pool.getTable(TABLENAME); HTableInterface table3 = pool.getTable(TABLENAME); // Close tables (returns tables to the pool) table1.close(); table2.close(); // The pool should reject this one since it is already full table3.close(); // Request tables of the same name HTableInterface sameTable1 = pool.getTable(TABLENAME); HTableInterface sameTable2 = pool.getTable(TABLENAME); HTableInterface sameTable3 = pool.getTable(TABLENAME); Assert.assertSame( ((HTablePool.PooledHTable) table1).getWrappedTable(), ((HTablePool.PooledHTable) sameTable1).getWrappedTable()); Assert.assertSame( ((HTablePool.PooledHTable) table2).getWrappedTable(), ((HTablePool.PooledHTable) sameTable2).getWrappedTable()); Assert.assertNotSame( ((HTablePool.PooledHTable) table3).getWrappedTable(), ((HTablePool.PooledHTable) sameTable3).getWrappedTable()); } @Test public void testCloseTablePool() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4, getPoolType()); HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration()); if (admin.tableExists(TABLENAME)) { admin.disableTable(TABLENAME); admin.deleteTable(TABLENAME); } HTableDescriptor tableDescriptor = new HTableDescriptor(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) { tables[i].close(); } Assert.assertEquals(4, pool.getCurrentPoolSize(Bytes.toString(TABLENAME))); pool.closeTablePool(TABLENAME); Assert.assertEquals(0, pool.getCurrentPoolSize(Bytes.toString(TABLENAME))); } } @Category(MediumTests.class) public static class TestHTableThreadLocalPool extends TestHTablePoolType { @Override protected PoolType getPoolType() { return PoolType.ThreadLocal; } @Test public void testTableWithMaxSize() throws Exception { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2, getPoolType()); // Request tables from an empty pool HTableInterface table1 = pool.getTable(TABLENAME); HTableInterface table2 = pool.getTable(TABLENAME); HTableInterface table3 = pool.getTable(TABLENAME); // Close tables (returns tables to the pool) table1.close(); table2.close(); // The pool should not reject this one since the number of threads // <= 2 table3.close(); // Request tables of the same name HTableInterface sameTable1 = pool.getTable(TABLENAME); HTableInterface sameTable2 = pool.getTable(TABLENAME); HTableInterface sameTable3 = pool.getTable(TABLENAME); Assert.assertSame( ((HTablePool.PooledHTable) table3).getWrappedTable(), ((HTablePool.PooledHTable) sameTable1).getWrappedTable()); Assert.assertSame( ((HTablePool.PooledHTable) table3).getWrappedTable(), ((HTablePool.PooledHTable) sameTable2).getWrappedTable()); Assert.assertSame( ((HTablePool.PooledHTable) table3).getWrappedTable(), ((HTablePool.PooledHTable) sameTable3).getWrappedTable()); } @Test public void testCloseTablePool() throws IOException { HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4, getPoolType()); HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration()); if (admin.tableExists(TABLENAME)) { admin.disableTable(TABLENAME); admin.deleteTable(TABLENAME); } HTableDescriptor tableDescriptor = new HTableDescriptor(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) { tables[i].close(); } Assert.assertEquals(1, pool.getCurrentPoolSize(Bytes.toString(TABLENAME))); pool.closeTablePool(TABLENAME); Assert.assertEquals(0, pool.getCurrentPoolSize(Bytes.toString(TABLENAME))); } } }