/* * Copyright 2010 The Apache Software Foundation * * 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.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.util.Bytes; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNotNull; /** * This class is for testing HCM features */ public class TestHCM { private static final Log LOG = LogFactory.getLog(TestHCM.class); private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); private static final byte[] TABLE_NAME = Bytes.toBytes("test"); private static final byte[] FAM_NAM = Bytes.toBytes("f"); private static final byte[] ROW = Bytes.toBytes("bbb"); @BeforeClass public static void setUpBeforeClass() throws Exception { TEST_UTIL.startMiniCluster(1); } @AfterClass public static void tearDownAfterClass() throws Exception { TEST_UTIL.shutdownMiniCluster(); } /** * @throws InterruptedException * @throws IllegalAccessException * @throws NoSuchFieldException * @throws ZooKeeperConnectionException * @throws IllegalArgumentException * @throws SecurityException * @see https://issues.apache.org/jira/browse/HBASE-2925 */ @Test public void testManyNewConnectionsDoesnotOOME() throws SecurityException, IllegalArgumentException, ZooKeeperConnectionException, NoSuchFieldException, IllegalAccessException, InterruptedException { createNewConfigurations(); } private static Random _randy = new Random(); public static void createNewConfigurations() throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException, InterruptedException, ZooKeeperConnectionException { HConnection last = null; for (int i = 0; i <= (HConnectionManager.MAX_CACHED_HBASE_INSTANCES * 2); i++) { // set random key to differentiate the connection from previous ones Configuration configuration = HBaseConfiguration.create(); configuration.set("somekey", String.valueOf(_randy.nextInt())); System.out.println("Hash Code: " + configuration.hashCode()); HConnection connection = HConnectionManager.getConnection(configuration); if (last != null) { if (last == connection) { System.out.println("!! Got same connection for once !!"); } } // change the configuration once, and the cached connection is lost forever: // the hashtable holding the cache won't be able to find its own keys // to remove them, so the LRU strategy does not work. configuration.set("someotherkey", String.valueOf(_randy.nextInt())); last = connection; LOG.info("Cache Size: " + getHConnectionManagerCacheSize() + ", Valid Keys: " + getValidKeyCount()); Thread.sleep(100); } Assert.assertEquals(HConnectionManager.MAX_CACHED_HBASE_INSTANCES, getHConnectionManagerCacheSize()); Assert.assertEquals(HConnectionManager.MAX_CACHED_HBASE_INSTANCES, getValidKeyCount()); } private static int getHConnectionManagerCacheSize() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field cacheField = HConnectionManager.class.getDeclaredField("HBASE_INSTANCES"); cacheField.setAccessible(true); Map<?, ?> cache = (Map<?, ?>) cacheField.get(null); return cache.size(); } private static int getValidKeyCount() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field cacheField = HConnectionManager.class.getDeclaredField("HBASE_INSTANCES"); cacheField.setAccessible(true); Map<?, ?> cache = (Map<?, ?>) cacheField.get(null); List<Object> keys = new ArrayList<Object>(cache.keySet()); Set<Object> values = new HashSet<Object>(); for (Object key : keys) { values.add(cache.get(key)); } return values.size(); } /** * Test that when we delete a location using the first row of a region * that we really delete it. * @throws Exception */ @Test public void testRegionCaching() throws Exception{ HTable table = TEST_UTIL.createTable(TABLE_NAME, FAM_NAM); TEST_UTIL.createMultiRegions(table, FAM_NAM); Put put = new Put(ROW); put.add(FAM_NAM, ROW, ROW); table.put(put); HConnectionManager.HConnectionImplementation conn = (HConnectionManager.HConnectionImplementation)table.getConnection(); assertNotNull(conn.getCachedLocation(TABLE_NAME, ROW)); conn.deleteCachedLocation(TABLE_NAME, ROW); HRegionLocation rl = conn.getCachedLocation(TABLE_NAME, ROW); assertNull("What is this location?? " + rl, rl); } }