diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/ClearRegionBlockCacheTestBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/ClearRegionBlockCacheTestBase.java new file mode 100644 index 000000000000..c98157072088 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/ClearRegionBlockCacheTestBase.java @@ -0,0 +1,180 @@ +/* + * 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.regionserver; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.apache.hadoop.hbase.CacheEvictionStats; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.HBaseTestingUtil; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.AsyncAdmin; +import org.apache.hadoop.hbase.client.AsyncConnection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.io.hfile.BlockCache; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public abstract class ClearRegionBlockCacheTestBase { + + private static final byte[] FAMILY = Bytes.toBytes("family"); + private static final byte[][] SPLIT_KEY = new byte[][] { Bytes.toBytes("5") }; + private static final int NUM_RS = 2; + + private static TableName tableName; + private static HBaseTestingUtil htu; + private static HRegionServer rs1; + private static HRegionServer rs2; + + protected static void setUpCluster(TableName testTableName) throws Exception { + setUpCluster(testTableName, false); + } + + protected static void setUpBucketCacheCluster(TableName testTableName) throws Exception { + setUpCluster(testTableName, true); + } + + private static void setUpCluster(TableName testTableName, boolean bucketCache) throws Exception { + tableName = testTableName; + htu = new HBaseTestingUtil(); + if (bucketCache) { + htu.getConfiguration().set(HConstants.BUCKET_CACHE_IOENGINE_KEY, "offheap"); + htu.getConfiguration().setInt(HConstants.BUCKET_CACHE_SIZE_KEY, 30); + } + htu.startMiniCluster(NUM_RS); + rs1 = htu.getMiniHBaseCluster().getRegionServer(0); + rs2 = htu.getMiniHBaseCluster().getRegionServer(1); + + try (Table table = htu.createTable(testTableName, FAMILY, SPLIT_KEY)) { + htu.loadNumericRows(table, FAMILY, 1, 10); + htu.flush(testTableName); + } + } + + protected static void tearDownCluster() throws Exception { + if (htu != null) { + htu.shutdownMiniCluster(); + } + } + + @BeforeEach + void clearBlockCacheBeforeTest() { + clearRegionBlockCache(rs1); + clearRegionBlockCache(rs2); + } + + @Test + void testClearBlockCache() throws Exception { + BlockCache blockCache1 = rs1.getBlockCache().get(); + BlockCache blockCache2 = rs2.getBlockCache().get(); + + long initialBlockCount1 = blockCache1.getBlockCount(); + long initialBlockCount2 = blockCache2.getBlockCount(); + + // scan will cause blocks to be added in BlockCache + scanAllRegionsForRS(rs1); + assertEquals(blockCache1.getBlockCount() - initialBlockCount1, + htu.getNumHFilesForRS(rs1, tableName, FAMILY)); + clearRegionBlockCache(rs1); + + scanAllRegionsForRS(rs2); + assertEquals(blockCache2.getBlockCount() - initialBlockCount2, + htu.getNumHFilesForRS(rs2, tableName, FAMILY)); + clearRegionBlockCache(rs2); + + assertEquals(initialBlockCount1, blockCache1.getBlockCount(), "" + blockCache1.getBlockCount()); + assertEquals(initialBlockCount2, blockCache2.getBlockCount(), "" + blockCache2.getBlockCount()); + } + + @Test + void testClearBlockCacheFromAdmin() throws Exception { + Admin admin = htu.getAdmin(); + + BlockCache blockCache1 = rs1.getBlockCache().get(); + BlockCache blockCache2 = rs2.getBlockCache().get(); + long initialBlockCount1 = blockCache1.getBlockCount(); + long initialBlockCount2 = blockCache2.getBlockCount(); + + // scan will cause blocks to be added in BlockCache + scanAllRegionsForRS(rs1); + assertEquals(blockCache1.getBlockCount() - initialBlockCount1, + htu.getNumHFilesForRS(rs1, tableName, FAMILY)); + scanAllRegionsForRS(rs2); + assertEquals(blockCache2.getBlockCount() - initialBlockCount2, + htu.getNumHFilesForRS(rs2, tableName, FAMILY)); + + CacheEvictionStats stats = admin.clearBlockCache(tableName); + assertEquals( + htu.getNumHFilesForRS(rs1, tableName, FAMILY) + htu.getNumHFilesForRS(rs2, tableName, FAMILY), + stats.getEvictedBlocks()); + assertEquals(initialBlockCount1, blockCache1.getBlockCount()); + assertEquals(initialBlockCount2, blockCache2.getBlockCount()); + } + + @Test + void testClearBlockCacheFromAsyncAdmin() throws Exception { + try (AsyncConnection conn = + ConnectionFactory.createAsyncConnection(htu.getConfiguration()).get()) { + AsyncAdmin admin = conn.getAdmin(); + + BlockCache blockCache1 = rs1.getBlockCache().get(); + BlockCache blockCache2 = rs2.getBlockCache().get(); + long initialBlockCount1 = blockCache1.getBlockCount(); + long initialBlockCount2 = blockCache2.getBlockCount(); + + // scan will cause blocks to be added in BlockCache + scanAllRegionsForRS(rs1); + assertEquals(blockCache1.getBlockCount() - initialBlockCount1, + htu.getNumHFilesForRS(rs1, tableName, FAMILY)); + scanAllRegionsForRS(rs2); + assertEquals(blockCache2.getBlockCount() - initialBlockCount2, + htu.getNumHFilesForRS(rs2, tableName, FAMILY)); + + CacheEvictionStats stats = admin.clearBlockCache(tableName).get(); + assertEquals(htu.getNumHFilesForRS(rs1, tableName, FAMILY) + + htu.getNumHFilesForRS(rs2, tableName, FAMILY), stats.getEvictedBlocks()); + assertEquals(initialBlockCount1, blockCache1.getBlockCount()); + assertEquals(initialBlockCount2, blockCache2.getBlockCount()); + } + } + + private void scanAllRegionsForRS(HRegionServer rs) throws IOException { + for (Region region : rs.getRegions(tableName)) { + try (RegionScanner scanner = region.getScanner(new Scan())) { + List cells = new ArrayList<>(); + while (scanner.next(cells)) { + cells.clear(); + } + } + } + } + + private void clearRegionBlockCache(HRegionServer rs) { + for (Region region : rs.getRegions(tableName)) { + rs.clearRegionBlockCache(region); + } + } +} diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCache.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCache.java index fade7bdbabad..791b4bddf41b 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCache.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCache.java @@ -17,171 +17,25 @@ */ package org.apache.hadoop.hbase.regionserver; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.stream.Stream; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.CacheEvictionStats; -import org.apache.hadoop.hbase.Cell; -import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate; -import org.apache.hadoop.hbase.HBaseTestingUtil; -import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.SingleProcessHBaseCluster; import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.client.Admin; -import org.apache.hadoop.hbase.client.AsyncAdmin; -import org.apache.hadoop.hbase.client.AsyncConnection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.Scan; -import org.apache.hadoop.hbase.client.Table; -import org.apache.hadoop.hbase.io.hfile.BlockCache; import org.apache.hadoop.hbase.testclassification.LargeTests; -import org.apache.hadoop.hbase.util.Bytes; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.TestTemplate; -import org.junit.jupiter.params.provider.Arguments; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Tag(LargeTests.TAG) -@HBaseParameterizedTestTemplate(name = "{index}: {0}") -public class TestClearRegionBlockCache { - - private static final Logger LOG = LoggerFactory.getLogger(TestClearRegionBlockCache.class); - private static final TableName TABLE_NAME = TableName.valueOf("testClearRegionBlockCache"); - private static final byte[] FAMILY = Bytes.toBytes("family"); - private static final byte[][] SPLIT_KEY = new byte[][] { Bytes.toBytes("5") }; - private static final int NUM_RS = 2; - - private final HBaseTestingUtil HTU = new HBaseTestingUtil(); - - private Configuration CONF = HTU.getConfiguration(); - private Table table; - private HRegionServer rs1, rs2; - private SingleProcessHBaseCluster cluster; - - private final String cacheType; - - public TestClearRegionBlockCache(String cacheType) { - this.cacheType = cacheType; - } - - public static Stream parameters() { - return Stream.of(Arguments.of("lru"), Arguments.of("bucket")); - } - - @BeforeEach - public void setup() throws Exception { - if (cacheType.equals("bucket")) { - CONF.set(HConstants.BUCKET_CACHE_IOENGINE_KEY, "offheap"); - CONF.setInt(HConstants.BUCKET_CACHE_SIZE_KEY, 30); - } - - cluster = HTU.startMiniCluster(NUM_RS); - rs1 = cluster.getRegionServer(0); - rs2 = cluster.getRegionServer(1); - - // Create table - table = HTU.createTable(TABLE_NAME, FAMILY, SPLIT_KEY); - - HTU.loadNumericRows(table, FAMILY, 1, 10); - HTU.flush(TABLE_NAME); - } - - @AfterEach - public void teardown() throws Exception { - HTU.shutdownMiniCluster(); - } +public class TestClearRegionBlockCache extends ClearRegionBlockCacheTestBase { - @TestTemplate - public void testClearBlockCache() throws Exception { - BlockCache blockCache1 = rs1.getBlockCache().get(); - BlockCache blockCache2 = rs2.getBlockCache().get(); - - long initialBlockCount1 = blockCache1.getBlockCount(); - long initialBlockCount2 = blockCache2.getBlockCount(); - - // scan will cause blocks to be added in BlockCache - scanAllRegionsForRS(rs1); - assertEquals(blockCache1.getBlockCount() - initialBlockCount1, - HTU.getNumHFilesForRS(rs1, TABLE_NAME, FAMILY)); - clearRegionBlockCache(rs1); - - scanAllRegionsForRS(rs2); - assertEquals(blockCache2.getBlockCount() - initialBlockCount2, - HTU.getNumHFilesForRS(rs2, TABLE_NAME, FAMILY)); - clearRegionBlockCache(rs2); - - assertEquals(initialBlockCount1, blockCache1.getBlockCount(), "" + blockCache1.getBlockCount()); - assertEquals(initialBlockCount2, blockCache2.getBlockCount(), "" + blockCache2.getBlockCount()); - } - - @TestTemplate - public void testClearBlockCacheFromAdmin() throws Exception { - Admin admin = HTU.getAdmin(); - - BlockCache blockCache1 = rs1.getBlockCache().get(); - BlockCache blockCache2 = rs2.getBlockCache().get(); - long initialBlockCount1 = blockCache1.getBlockCount(); - long initialBlockCount2 = blockCache2.getBlockCount(); - - // scan will cause blocks to be added in BlockCache - scanAllRegionsForRS(rs1); - assertEquals(blockCache1.getBlockCount() - initialBlockCount1, - HTU.getNumHFilesForRS(rs1, TABLE_NAME, FAMILY)); - scanAllRegionsForRS(rs2); - assertEquals(blockCache2.getBlockCount() - initialBlockCount2, - HTU.getNumHFilesForRS(rs2, TABLE_NAME, FAMILY)); - - CacheEvictionStats stats = admin.clearBlockCache(TABLE_NAME); - assertEquals(stats.getEvictedBlocks(), HTU.getNumHFilesForRS(rs1, TABLE_NAME, FAMILY) - + HTU.getNumHFilesForRS(rs2, TABLE_NAME, FAMILY)); - assertEquals(initialBlockCount1, blockCache1.getBlockCount()); - assertEquals(initialBlockCount2, blockCache2.getBlockCount()); - } - - @TestTemplate - public void testClearBlockCacheFromAsyncAdmin() throws Exception { - try (AsyncConnection conn = - ConnectionFactory.createAsyncConnection(HTU.getConfiguration()).get()) { - AsyncAdmin admin = conn.getAdmin(); - - BlockCache blockCache1 = rs1.getBlockCache().get(); - BlockCache blockCache2 = rs2.getBlockCache().get(); - long initialBlockCount1 = blockCache1.getBlockCount(); - long initialBlockCount2 = blockCache2.getBlockCount(); - - // scan will cause blocks to be added in BlockCache - scanAllRegionsForRS(rs1); - assertEquals(blockCache1.getBlockCount() - initialBlockCount1, - HTU.getNumHFilesForRS(rs1, TABLE_NAME, FAMILY)); - scanAllRegionsForRS(rs2); - assertEquals(blockCache2.getBlockCount() - initialBlockCount2, - HTU.getNumHFilesForRS(rs2, TABLE_NAME, FAMILY)); - - CacheEvictionStats stats = admin.clearBlockCache(TABLE_NAME).get(); - assertEquals(stats.getEvictedBlocks(), HTU.getNumHFilesForRS(rs1, TABLE_NAME, FAMILY) - + HTU.getNumHFilesForRS(rs2, TABLE_NAME, FAMILY)); - assertEquals(initialBlockCount1, blockCache1.getBlockCount()); - assertEquals(initialBlockCount2, blockCache2.getBlockCount()); - } - } + private static final TableName TABLE_NAME = + TableName.valueOf("testClearRegionBlockCacheWithLruBlockCache"); - private void scanAllRegionsForRS(HRegionServer rs) throws IOException { - for (Region region : rs.getRegions(TABLE_NAME)) { - RegionScanner scanner = region.getScanner(new Scan()); - while (scanner.next(new ArrayList())) - ; - } + @BeforeAll + public static void setUp() throws Exception { + setUpCluster(TABLE_NAME); } - private void clearRegionBlockCache(HRegionServer rs) { - for (Region region : rs.getRegions(TABLE_NAME)) { - rs.clearRegionBlockCache(region); - } + @AfterAll + public static void tearDown() throws Exception { + tearDownCluster(); } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCacheWithBucketCache.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCacheWithBucketCache.java new file mode 100644 index 000000000000..45537b994f25 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestClearRegionBlockCacheWithBucketCache.java @@ -0,0 +1,41 @@ +/* + * 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.regionserver; + +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; + +@Tag(LargeTests.TAG) +public class TestClearRegionBlockCacheWithBucketCache extends ClearRegionBlockCacheTestBase { + + private static final TableName TABLE_NAME = + TableName.valueOf("testClearRegionBlockCacheWithBucketCache"); + + @BeforeAll + public static void setUp() throws Exception { + setUpBucketCacheCluster(TABLE_NAME); + } + + @AfterAll + public static void tearDown() throws Exception { + tearDownCluster(); + } +}