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