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 byte[] TABLENAME = Bytes.toBytes("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, 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 = Bytes.toString(TABLENAME);
62  
63  			// Request a table from an empty pool
64  			HTableInterface 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  			HTableInterface 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  			HTableInterface 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  			HTableInterface 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 			HTableInterface table1 = pool.getTable(TABLENAME);
109 			HTableInterface 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 			HTableInterface sameTable1 = pool.getTable(TABLENAME);
118 			HTableInterface 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 = Bytes.toString(TABLENAME);// Request a table from
131                               // an
132                               // empty pool
133       HTableInterface 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 = Bytes.toString(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       HTableInterface 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 = Bytes.toString(TABLENAME);// Request a table from
166                               // an
167                               // empty pool
168 
169       // get table will return proxy implementation
170       final HTableInterface table = pool.getTable(tableName);
171       HTableInterface alienTable = new HTable(TEST_UTIL.getConfiguration(),
172           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 = Bytes.toString(TABLENAME);
190 
191       // Request a table from an empty pool
192       HTableInterface 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   }
213 
214   @Category(MediumTests.class)
215 	public static class TestHTableReusablePool extends TestHTablePoolType {
216 		@Override
217 		protected PoolType getPoolType() {
218 			return PoolType.Reusable;
219 		}
220 
221 		@Test
222 		public void testTableWithMaxSize() throws Exception {
223 			HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2,
224 					getPoolType());
225 
226 			// Request tables from an empty pool
227 			HTableInterface table1 = pool.getTable(TABLENAME);
228 			HTableInterface table2 = pool.getTable(TABLENAME);
229 			HTableInterface table3 = pool.getTable(TABLENAME);
230 
231 			// Close tables (returns tables to the pool)
232 			table1.close();
233 			table2.close();
234 			// The pool should reject this one since it is already full
235 			table3.close();
236 
237 			// Request tables of the same name
238 			HTableInterface sameTable1 = pool.getTable(TABLENAME);
239 			HTableInterface sameTable2 = pool.getTable(TABLENAME);
240 			HTableInterface sameTable3 = pool.getTable(TABLENAME);
241 			Assert.assertSame(
242 					((HTablePool.PooledHTable) table1).getWrappedTable(),
243 					((HTablePool.PooledHTable) sameTable1).getWrappedTable());
244 			Assert.assertSame(
245 					((HTablePool.PooledHTable) table2).getWrappedTable(),
246 					((HTablePool.PooledHTable) sameTable2).getWrappedTable());
247 			Assert.assertNotSame(
248 					((HTablePool.PooledHTable) table3).getWrappedTable(),
249 					((HTablePool.PooledHTable) sameTable3).getWrappedTable());
250 		}
251 
252 		@Test
253 		public void testCloseTablePool() throws IOException {
254 			HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4,
255 					getPoolType());
256 			HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
257 
258 			if (admin.tableExists(TABLENAME)) {
259 				admin.disableTable(TABLENAME);
260 				admin.deleteTable(TABLENAME);
261 			}
262 
263 			HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLENAME));
264 			tableDescriptor.addFamily(new HColumnDescriptor("randomFamily"));
265 			admin.createTable(tableDescriptor);
266 
267 			// Request tables from an empty pool
268 			HTableInterface[] tables = new HTableInterface[4];
269 			for (int i = 0; i < 4; ++i) {
270 				tables[i] = pool.getTable(TABLENAME);
271 			}
272 
273 			pool.closeTablePool(TABLENAME);
274 
275 			for (int i = 0; i < 4; ++i) {
276 				tables[i].close();
277 			}
278 
279 			Assert.assertEquals(4,
280 					pool.getCurrentPoolSize(Bytes.toString(TABLENAME)));
281 
282 			pool.closeTablePool(TABLENAME);
283 
284 			Assert.assertEquals(0,
285 					pool.getCurrentPoolSize(Bytes.toString(TABLENAME)));
286 		}
287 	}
288 
289   @Category(MediumTests.class)
290 	public static class TestHTableThreadLocalPool extends TestHTablePoolType {
291 		@Override
292 		protected PoolType getPoolType() {
293 			return PoolType.ThreadLocal;
294 		}
295 
296 		@Test
297 		public void testTableWithMaxSize() throws Exception {
298 			HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 2,
299 					getPoolType());
300 
301 			// Request tables from an empty pool
302 			HTableInterface table1 = pool.getTable(TABLENAME);
303 			HTableInterface table2 = pool.getTable(TABLENAME);
304 			HTableInterface table3 = pool.getTable(TABLENAME);
305 
306 			// Close tables (returns tables to the pool)
307 			table1.close();
308 			table2.close();
309 			// The pool should not reject this one since the number of threads
310 			// <= 2
311 			table3.close();
312 
313 			// Request tables of the same name
314 			HTableInterface sameTable1 = pool.getTable(TABLENAME);
315 			HTableInterface sameTable2 = pool.getTable(TABLENAME);
316 			HTableInterface sameTable3 = pool.getTable(TABLENAME);
317 			Assert.assertSame(
318 					((HTablePool.PooledHTable) table3).getWrappedTable(),
319 					((HTablePool.PooledHTable) sameTable1).getWrappedTable());
320 			Assert.assertSame(
321 					((HTablePool.PooledHTable) table3).getWrappedTable(),
322 					((HTablePool.PooledHTable) sameTable2).getWrappedTable());
323 			Assert.assertSame(
324 					((HTablePool.PooledHTable) table3).getWrappedTable(),
325 					((HTablePool.PooledHTable) sameTable3).getWrappedTable());
326 		}
327 
328 		@Test
329 		public void testCloseTablePool() throws IOException {
330 			HTablePool pool = new HTablePool(TEST_UTIL.getConfiguration(), 4,
331 					getPoolType());
332 			HBaseAdmin admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
333 
334 			if (admin.tableExists(TABLENAME)) {
335 				admin.disableTable(TABLENAME);
336 				admin.deleteTable(TABLENAME);
337 			}
338 
339 			HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLENAME));
340 			tableDescriptor.addFamily(new HColumnDescriptor("randomFamily"));
341 			admin.createTable(tableDescriptor);
342 
343 			// Request tables from an empty pool
344 			HTableInterface[] tables = new HTableInterface[4];
345 			for (int i = 0; i < 4; ++i) {
346 				tables[i] = pool.getTable(TABLENAME);
347 			}
348 
349 			pool.closeTablePool(TABLENAME);
350 
351 			for (int i = 0; i < 4; ++i) {
352 				tables[i].close();
353 			}
354 
355 			Assert.assertEquals(1,
356 					pool.getCurrentPoolSize(Bytes.toString(TABLENAME)));
357 
358 			pool.closeTablePool(TABLENAME);
359 
360 			Assert.assertEquals(0,
361 					pool.getCurrentPoolSize(Bytes.toString(TABLENAME)));
362 		}
363 	}
364 
365 }