001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.List; 025import org.apache.hadoop.hbase.CacheEvictionStats; 026import org.apache.hadoop.hbase.Cell; 027import org.apache.hadoop.hbase.HBaseTestingUtil; 028import org.apache.hadoop.hbase.HConstants; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.client.Admin; 031import org.apache.hadoop.hbase.client.AsyncAdmin; 032import org.apache.hadoop.hbase.client.AsyncConnection; 033import org.apache.hadoop.hbase.client.ConnectionFactory; 034import org.apache.hadoop.hbase.client.Scan; 035import org.apache.hadoop.hbase.client.Table; 036import org.apache.hadoop.hbase.io.hfile.BlockCache; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.junit.jupiter.api.BeforeEach; 039import org.junit.jupiter.api.Test; 040 041public abstract class ClearRegionBlockCacheTestBase { 042 043 private static final byte[] FAMILY = Bytes.toBytes("family"); 044 private static final byte[][] SPLIT_KEY = new byte[][] { Bytes.toBytes("5") }; 045 private static final int NUM_RS = 2; 046 047 private static TableName tableName; 048 private static HBaseTestingUtil htu; 049 private static HRegionServer rs1; 050 private static HRegionServer rs2; 051 052 protected static void setUpCluster(TableName testTableName) throws Exception { 053 setUpCluster(testTableName, false); 054 } 055 056 protected static void setUpBucketCacheCluster(TableName testTableName) throws Exception { 057 setUpCluster(testTableName, true); 058 } 059 060 private static void setUpCluster(TableName testTableName, boolean bucketCache) throws Exception { 061 tableName = testTableName; 062 htu = new HBaseTestingUtil(); 063 if (bucketCache) { 064 htu.getConfiguration().set(HConstants.BUCKET_CACHE_IOENGINE_KEY, "offheap"); 065 htu.getConfiguration().setInt(HConstants.BUCKET_CACHE_SIZE_KEY, 30); 066 } 067 htu.startMiniCluster(NUM_RS); 068 rs1 = htu.getMiniHBaseCluster().getRegionServer(0); 069 rs2 = htu.getMiniHBaseCluster().getRegionServer(1); 070 071 try (Table table = htu.createTable(testTableName, FAMILY, SPLIT_KEY)) { 072 htu.loadNumericRows(table, FAMILY, 1, 10); 073 htu.flush(testTableName); 074 } 075 } 076 077 protected static void tearDownCluster() throws Exception { 078 if (htu != null) { 079 htu.shutdownMiniCluster(); 080 } 081 } 082 083 @BeforeEach 084 void clearBlockCacheBeforeTest() { 085 clearRegionBlockCache(rs1); 086 clearRegionBlockCache(rs2); 087 } 088 089 @Test 090 void testClearBlockCache() throws Exception { 091 BlockCache blockCache1 = rs1.getBlockCache().get(); 092 BlockCache blockCache2 = rs2.getBlockCache().get(); 093 094 long initialBlockCount1 = blockCache1.getBlockCount(); 095 long initialBlockCount2 = blockCache2.getBlockCount(); 096 097 // scan will cause blocks to be added in BlockCache 098 scanAllRegionsForRS(rs1); 099 assertEquals(blockCache1.getBlockCount() - initialBlockCount1, 100 htu.getNumHFilesForRS(rs1, tableName, FAMILY)); 101 clearRegionBlockCache(rs1); 102 103 scanAllRegionsForRS(rs2); 104 assertEquals(blockCache2.getBlockCount() - initialBlockCount2, 105 htu.getNumHFilesForRS(rs2, tableName, FAMILY)); 106 clearRegionBlockCache(rs2); 107 108 assertEquals(initialBlockCount1, blockCache1.getBlockCount(), "" + blockCache1.getBlockCount()); 109 assertEquals(initialBlockCount2, blockCache2.getBlockCount(), "" + blockCache2.getBlockCount()); 110 } 111 112 @Test 113 void testClearBlockCacheFromAdmin() throws Exception { 114 Admin admin = htu.getAdmin(); 115 116 BlockCache blockCache1 = rs1.getBlockCache().get(); 117 BlockCache blockCache2 = rs2.getBlockCache().get(); 118 long initialBlockCount1 = blockCache1.getBlockCount(); 119 long initialBlockCount2 = blockCache2.getBlockCount(); 120 121 // scan will cause blocks to be added in BlockCache 122 scanAllRegionsForRS(rs1); 123 assertEquals(blockCache1.getBlockCount() - initialBlockCount1, 124 htu.getNumHFilesForRS(rs1, tableName, FAMILY)); 125 scanAllRegionsForRS(rs2); 126 assertEquals(blockCache2.getBlockCount() - initialBlockCount2, 127 htu.getNumHFilesForRS(rs2, tableName, FAMILY)); 128 129 CacheEvictionStats stats = admin.clearBlockCache(tableName); 130 assertEquals( 131 htu.getNumHFilesForRS(rs1, tableName, FAMILY) + htu.getNumHFilesForRS(rs2, tableName, FAMILY), 132 stats.getEvictedBlocks()); 133 assertEquals(initialBlockCount1, blockCache1.getBlockCount()); 134 assertEquals(initialBlockCount2, blockCache2.getBlockCount()); 135 } 136 137 @Test 138 void testClearBlockCacheFromAsyncAdmin() throws Exception { 139 try (AsyncConnection conn = 140 ConnectionFactory.createAsyncConnection(htu.getConfiguration()).get()) { 141 AsyncAdmin admin = conn.getAdmin(); 142 143 BlockCache blockCache1 = rs1.getBlockCache().get(); 144 BlockCache blockCache2 = rs2.getBlockCache().get(); 145 long initialBlockCount1 = blockCache1.getBlockCount(); 146 long initialBlockCount2 = blockCache2.getBlockCount(); 147 148 // scan will cause blocks to be added in BlockCache 149 scanAllRegionsForRS(rs1); 150 assertEquals(blockCache1.getBlockCount() - initialBlockCount1, 151 htu.getNumHFilesForRS(rs1, tableName, FAMILY)); 152 scanAllRegionsForRS(rs2); 153 assertEquals(blockCache2.getBlockCount() - initialBlockCount2, 154 htu.getNumHFilesForRS(rs2, tableName, FAMILY)); 155 156 CacheEvictionStats stats = admin.clearBlockCache(tableName).get(); 157 assertEquals(htu.getNumHFilesForRS(rs1, tableName, FAMILY) 158 + htu.getNumHFilesForRS(rs2, tableName, FAMILY), stats.getEvictedBlocks()); 159 assertEquals(initialBlockCount1, blockCache1.getBlockCount()); 160 assertEquals(initialBlockCount2, blockCache2.getBlockCount()); 161 } 162 } 163 164 private void scanAllRegionsForRS(HRegionServer rs) throws IOException { 165 for (Region region : rs.getRegions(tableName)) { 166 try (RegionScanner scanner = region.getScanner(new Scan())) { 167 List<Cell> cells = new ArrayList<>(); 168 while (scanner.next(cells)) { 169 cells.clear(); 170 } 171 } 172 } 173 } 174 175 private void clearRegionBlockCache(HRegionServer rs) { 176 for (Region region : rs.getRegions(tableName)) { 177 rs.clearRegionBlockCache(region); 178 } 179 } 180}