View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.client;
20  
21  import java.io.IOException;
22  
23  import org.apache.hadoop.hbase.*;
24  import org.apache.hadoop.hbase.testclassification.MediumTests;
25  import org.apache.hadoop.hbase.util.Bytes;
26  import org.apache.hadoop.hbase.util.PoolMap.PoolType;
27  import org.junit.*;
28  import org.junit.experimental.categories.Category;
29  import org.junit.runner.RunWith;
30  import org.junit.runners.Suite;
31  
32  /**
33   * Tests HTablePool.
34   */
35  @RunWith(Suite.class)
36  @Suite.SuiteClasses({TestHTablePool.TestHTableReusablePool.class, TestHTablePool.TestHTableThreadLocalPool.class})
37  @Category(MediumTests.class)
38  public class TestHTablePool {
39    private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
40    private final static String TABLENAME = "TestHTablePool";
41  
42    public abstract static class TestHTablePoolType {
43  
44      @BeforeClass
45      public static void setUpBeforeClass() throws Exception {
46        TEST_UTIL.startMiniCluster(1);
47        TEST_UTIL.createTable(TableName.valueOf(TABLENAME), HConstants.CATALOG_FAMILY);
48      }
49  
50      @AfterClass
51      public static void tearDownAfterClass() throws Exception {
52        TEST_UTIL.shutdownMiniCluster();
53      }
54  
55      protected abstract PoolType getPoolType();
56  
57      @Test
58      public void testTableWithStringName() throws Exception {
59        HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
60            Integer.MAX_VALUE, getPoolType());
61        String tableName = TABLENAME;
62  
63        // Request a table from an empty pool
64        Table table = pool.getTable(tableName);
65        Assert.assertNotNull(table);
66  
67        // Close table (returns table to the pool)
68        table.close();
69  
70        // Request a table of the same name
71        Table sameTable = pool.getTable(tableName);
72        Assert.assertSame(
73            ((HTablePool.PooledHTable) table).getWrappedTable(),
74            ((HTablePool.PooledHTable) sameTable).getWrappedTable());
75      }
76  
77      @Test
78      public void testTableWithByteArrayName() throws IOException {
79        HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
80            Integer.MAX_VALUE, getPoolType());
81  
82        // Request a table from an empty pool
83        Table table = pool.getTable(TABLENAME);
84        Assert.assertNotNull(table);
85  
86        // Close table (returns table to the pool)
87        table.close();
88  
89        // Request a table of the same name
90        Table sameTable = pool.getTable(TABLENAME);
91        Assert.assertSame(
92            ((HTablePool.PooledHTable) table).getWrappedTable(),
93            ((HTablePool.PooledHTable) sameTable).getWrappedTable());
94      }
95  
96      @Test
97      public void testTablesWithDifferentNames() throws IOException {
98        HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
99            Integer.MAX_VALUE, getPoolType());
100       // We add the class to the table name as the HBase cluster is reused
101       //  during the tests: this gives naming unicity.
102       byte[] otherTable = Bytes.toBytes(
103         "OtherTable_" + getClass().getSimpleName()
104       );
105       TEST_UTIL.createTable(otherTable, HConstants.CATALOG_FAMILY);
106 
107       // Request a table from an empty pool
108       Table table1 = pool.getTable(TABLENAME);
109       Table table2 = pool.getTable(otherTable);
110       Assert.assertNotNull(table2);
111 
112       // Close tables (returns tables to the pool)
113       table1.close();
114       table2.close();
115 
116       // Request tables of the same names
117       Table sameTable1 = pool.getTable(TABLENAME);
118       Table sameTable2 = pool.getTable(otherTable);
119       Assert.assertSame(
120           ((HTablePool.PooledHTable) table1).getWrappedTable(),
121           ((HTablePool.PooledHTable) sameTable1).getWrappedTable());
122       Assert.assertSame(
123           ((HTablePool.PooledHTable) table2).getWrappedTable(),
124           ((HTablePool.PooledHTable) sameTable2).getWrappedTable());
125     }
126     @Test
127     public void testProxyImplementationReturned() {
128       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
129           Integer.MAX_VALUE);
130       String tableName = TABLENAME;// Request a table from
131                               // an
132                               // empty pool
133       Table table = pool.getTable(tableName);
134 
135       // Test if proxy implementation is returned
136       Assert.assertTrue(table instanceof HTablePool.PooledHTable);
137     }
138 
139     @Test
140     public void testDeprecatedUsagePattern() throws IOException {
141       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
142           Integer.MAX_VALUE);
143       String tableName = TABLENAME;// Request a table from
144                               // an
145                               // empty pool
146 
147       // get table will return proxy implementation
148       HTableInterface table = pool.getTable(tableName);
149 
150       // put back the proxy implementation instead of closing it
151       pool.putTable(table);
152 
153       // Request a table of the same name
154       Table sameTable = pool.getTable(tableName);
155 
156       // test no proxy over proxy created
157       Assert.assertSame(((HTablePool.PooledHTable) table).getWrappedTable(),
158           ((HTablePool.PooledHTable) sameTable).getWrappedTable());
159     }
160 
161     @Test
162     public void testReturnDifferentTable() throws IOException {
163       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
164           Integer.MAX_VALUE);
165       String tableName = TABLENAME;// Request a table from
166                               // an
167                               // empty pool
168 
169       // get table will return proxy implementation
170       final Table table = pool.getTable(tableName);
171       HTableInterface alienTable = new HTable(TEST_UTIL.getConfiguration(),
172           TableName.valueOf(TABLENAME)) {
173         // implementation doesn't matter as long the table is not from
174         // pool
175       };
176       try {
177         // put the wrong table in pool
178         pool.putTable(alienTable);
179         Assert.fail("alien table accepted in pool");
180       } catch (IllegalArgumentException e) {
181         Assert.assertTrue("alien table rejected", true);
182       }
183     }
184 
185     @Test
186     public void testHTablePoolCloseTwice() throws Exception {
187       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(),
188           Integer.MAX_VALUE, getPoolType());
189       String tableName = TABLENAME;
190 
191       // Request a table from an empty pool
192       Table table = pool.getTable(tableName);
193       Assert.assertNotNull(table);
194       Assert.assertTrue(((HTablePool.PooledHTable) table).isOpen());
195       // Close table (returns table to the pool)
196       table.close();
197       // check if the table is closed
198       Assert.assertFalse(((HTablePool.PooledHTable) table).isOpen());
199       try {
200         table.close();
201         Assert.fail("Should not allow table to be closed twice");
202       } catch (IllegalStateException ex) {
203         Assert.assertTrue("table cannot be closed twice", true);
204       } finally {
205         pool.close();
206       }
207 
208     }   
209 
210   }
211 
212   @Category(MediumTests.class)
213   public static class TestHTableReusablePool extends TestHTablePoolType {
214     @Override
215     protected PoolType getPoolType() {
216       return PoolType.Reusable;
217     }
218 
219     @Test
220     public void testTableWithMaxSize() throws Exception {
221       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2,
222           getPoolType());
223 
224       // Request tables from an empty pool
225       Table table1 = pool.getTable(TABLENAME);
226       Table table2 = pool.getTable(TABLENAME);
227       Table table3 = pool.getTable(TABLENAME);
228 
229       // Close tables (returns tables to the pool)
230       table1.close();
231       table2.close();
232       // The pool should reject this one since it is already full
233       table3.close();
234 
235       // Request tables of the same name
236       Table sameTable1 = pool.getTable(TABLENAME);
237       Table sameTable2 = pool.getTable(TABLENAME);
238       Table sameTable3 = pool.getTable(TABLENAME);
239       Assert.assertSame(
240           ((HTablePool.PooledHTable) table1).getWrappedTable(),
241           ((HTablePool.PooledHTable) sameTable1).getWrappedTable());
242       Assert.assertSame(
243           ((HTablePool.PooledHTable) table2).getWrappedTable(),
244           ((HTablePool.PooledHTable) sameTable2).getWrappedTable());
245       Assert.assertNotSame(
246           ((HTablePool.PooledHTable) table3).getWrappedTable(),
247           ((HTablePool.PooledHTable) sameTable3).getWrappedTable());
248     }
249 
250     @Test
251     public void testCloseTablePool() throws IOException {
252       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4,
253           getPoolType());
254       HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
255 
256       if (admin.tableExists(TABLENAME)) {
257         admin.disableTable(TABLENAME);
258         admin.deleteTable(TABLENAME);
259       }
260 
261       HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLENAME));
262       tableDescriptor.addFamily(new HColumnDescriptor("randomFamily"));
263       admin.createTable(tableDescriptor);
264 
265       // Request tables from an empty pool
266       Table[] tables = new Table[4];
267       for (int i = 0; i < 4; ++i) {
268         tables[i] = pool.getTable(TABLENAME);
269       }
270 
271       pool.closeTablePool(TABLENAME);
272 
273       for (int i = 0; i < 4; ++i) {
274         tables[i].close();
275       }
276 
277       Assert.assertEquals(4,
278           pool.getCurrentPoolSize(TABLENAME));
279 
280       pool.closeTablePool(TABLENAME);
281 
282       Assert.assertEquals(0,
283           pool.getCurrentPoolSize(TABLENAME));
284     }
285   }
286 
287   @Category(MediumTests.class)
288   public static class TestHTableThreadLocalPool extends TestHTablePoolType {
289     @Override
290     protected PoolType getPoolType() {
291       return PoolType.ThreadLocal;
292     }
293 
294     @Test
295     public void testTableWithMaxSize() throws Exception {
296       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2,
297           getPoolType());
298 
299       // Request tables from an empty pool
300       Table table1 = pool.getTable(TABLENAME);
301       Table table2 = pool.getTable(TABLENAME);
302       Table table3 = pool.getTable(TABLENAME);
303 
304       // Close tables (returns tables to the pool)
305       table1.close();
306       table2.close();
307       // The pool should not reject this one since the number of threads
308       // <= 2
309       table3.close();
310 
311       // Request tables of the same name
312       Table sameTable1 = pool.getTable(TABLENAME);
313       Table sameTable2 = pool.getTable(TABLENAME);
314       Table sameTable3 = pool.getTable(TABLENAME);
315       Assert.assertSame(
316           ((HTablePool.PooledHTable) table3).getWrappedTable(),
317           ((HTablePool.PooledHTable) sameTable1).getWrappedTable());
318       Assert.assertSame(
319           ((HTablePool.PooledHTable) table3).getWrappedTable(),
320           ((HTablePool.PooledHTable) sameTable2).getWrappedTable());
321       Assert.assertSame(
322           ((HTablePool.PooledHTable) table3).getWrappedTable(),
323           ((HTablePool.PooledHTable) sameTable3).getWrappedTable());
324     }
325 
326     @Test
327     public void testCloseTablePool() throws IOException {
328       HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4,
329           getPoolType());
330       HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
331 
332       if (admin.tableExists(TABLENAME)) {
333         admin.disableTable(TABLENAME);
334         admin.deleteTable(TABLENAME);
335       }
336 
337       HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLENAME));
338       tableDescriptor.addFamily(new HColumnDescriptor("randomFamily"));
339       admin.createTable(tableDescriptor);
340 
341       // Request tables from an empty pool
342       Table[] tables = new Table[4];
343       for (int i = 0; i < 4; ++i) {
344         tables[i] = pool.getTable(TABLENAME);
345       }
346 
347       pool.closeTablePool(TABLENAME);
348 
349       for (int i = 0; i < 4; ++i) {
350         tables[i].close();
351       }
352 
353       Assert.assertEquals(1,
354           pool.getCurrentPoolSize(TABLENAME));
355 
356       pool.closeTablePool(TABLENAME);
357 
358       Assert.assertEquals(0,
359           pool.getCurrentPoolSize(TABLENAME));
360     }
361   }
362 
363 }