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; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.List; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.client.RegionInfo; 028import org.apache.hadoop.hbase.client.RegionLocator; 029import org.apache.hadoop.hbase.client.Table; 030import org.apache.hadoop.hbase.regionserver.HRegion; 031import org.apache.hadoop.hbase.regionserver.HRegionServer; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 036import org.apache.hadoop.hbase.util.JVMClusterUtil; 037import org.apache.hadoop.hbase.util.Threads; 038import org.junit.ClassRule; 039import org.junit.Rule; 040import org.junit.Test; 041import org.junit.experimental.categories.Category; 042import org.junit.rules.TestName; 043import org.slf4j.Logger; 044import org.slf4j.LoggerFactory; 045 046import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 047 048/** 049 * Test HBASE-3694 whether the GlobalMemStoreSize is the same as the summary of all the online 050 * region's MemStoreSize 051 */ 052@Category({ MiscTests.class, MediumTests.class }) 053public class TestGlobalMemStoreSize { 054 055 @ClassRule 056 public static final HBaseClassTestRule CLASS_RULE = 057 HBaseClassTestRule.forClass(TestGlobalMemStoreSize.class); 058 059 private static final Logger LOG = LoggerFactory.getLogger(TestGlobalMemStoreSize.class); 060 private static int regionServerNum = 4; 061 private static int regionNum = 16; 062 // total region num = region num + root and meta regions 063 private static int totalRegionNum = regionNum + 2; 064 065 private HBaseTestingUtility TEST_UTIL; 066 private MiniHBaseCluster cluster; 067 068 @Rule 069 public TestName name = new TestName(); 070 071 /** 072 * Test the global mem store size in the region server is equal to sum of each region's mem store 073 * size 074 */ 075 @Test 076 public void testGlobalMemStore() throws Exception { 077 // Start the cluster 078 LOG.info("Starting cluster"); 079 Configuration conf = HBaseConfiguration.create(); 080 TEST_UTIL = new HBaseTestingUtility(conf); 081 TEST_UTIL.startMiniCluster(regionServerNum); 082 cluster = TEST_UTIL.getHBaseCluster(); 083 LOG.info("Waiting for active/ready master"); 084 cluster.waitForActiveAndReadyMaster(); 085 086 // Create a table with regions 087 final TableName table = TableName.valueOf(name.getMethodName()); 088 byte[] family = Bytes.toBytes("family"); 089 LOG.info("Creating table with " + regionNum + " regions"); 090 Table ht = TEST_UTIL.createMultiRegionTable(table, family, regionNum); 091 int numRegions = -1; 092 try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(table)) { 093 numRegions = r.getStartKeys().length; 094 } 095 assertEquals(regionNum, numRegions); 096 waitForAllRegionsAssigned(); 097 098 for (HRegionServer server : getOnlineRegionServers()) { 099 long globalMemStoreSize = 0; 100 for (RegionInfo regionInfo : ProtobufUtil.getOnlineRegions(null, server.getRSRpcServices())) { 101 globalMemStoreSize += server.getRegion(regionInfo.getEncodedName()).getMemStoreDataSize(); 102 } 103 assertEquals(server.getRegionServerAccounting().getGlobalMemStoreDataSize(), 104 globalMemStoreSize); 105 } 106 107 // check the global memstore size after flush 108 int i = 0; 109 for (HRegionServer server : getOnlineRegionServers()) { 110 LOG.info("Starting flushes on " + server.getServerName() + ", size=" 111 + server.getRegionServerAccounting().getGlobalMemStoreDataSize()); 112 113 for (RegionInfo regionInfo : ProtobufUtil.getOnlineRegions(null, server.getRSRpcServices())) { 114 HRegion r = server.getRegion(regionInfo.getEncodedName()); 115 flush(r, server); 116 } 117 LOG.info("Post flush on " + server.getServerName()); 118 long now = EnvironmentEdgeManager.currentTime(); 119 long timeout = now + 1000; 120 while ( 121 server.getRegionServerAccounting().getGlobalMemStoreDataSize() != 0 122 && timeout < EnvironmentEdgeManager.currentTime() 123 ) { 124 Threads.sleep(10); 125 } 126 long size = server.getRegionServerAccounting().getGlobalMemStoreDataSize(); 127 if (size > 0) { 128 // If size > 0, see if its because the meta region got edits while 129 // our test was running.... 130 for (RegionInfo regionInfo : ProtobufUtil.getOnlineRegions(null, 131 server.getRSRpcServices())) { 132 HRegion r = server.getRegion(regionInfo.getEncodedName()); 133 long l = r.getMemStoreDataSize(); 134 if (l > 0) { 135 // Only meta could have edits at this stage. Give it another flush 136 // clear them. 137 assertTrue(regionInfo.isMetaRegion()); 138 LOG.info(r.toString() + " " + l + ", reflushing"); 139 r.flush(true); 140 } 141 } 142 } 143 size = server.getRegionServerAccounting().getGlobalMemStoreDataSize(); 144 assertEquals("Server=" + server.getServerName() + ", i=" + i++, 0, size); 145 } 146 147 ht.close(); 148 TEST_UTIL.shutdownMiniCluster(); 149 } 150 151 /** 152 * Flush and log stats on flush 153 */ 154 private void flush(final HRegion r, final HRegionServer server) throws IOException { 155 LOG.info("Flush " + r.toString() + " on " + server.getServerName() + ", " + r.flush(true) 156 + ", size=" + server.getRegionServerAccounting().getGlobalMemStoreDataSize()); 157 } 158 159 private List<HRegionServer> getOnlineRegionServers() { 160 List<HRegionServer> list = new ArrayList<>(); 161 for (JVMClusterUtil.RegionServerThread rst : cluster.getRegionServerThreads()) { 162 if (rst.getRegionServer().isOnline()) { 163 list.add(rst.getRegionServer()); 164 } 165 } 166 return list; 167 } 168 169 /** 170 * Wait until all the regions are assigned. 171 */ 172 private void waitForAllRegionsAssigned() throws IOException { 173 while (true) { 174 int regionCount = HBaseTestingUtility.getAllOnlineRegions(cluster).size(); 175 if (regionCount >= totalRegionNum) break; 176 LOG.debug("Waiting for there to be " + totalRegionNum + " regions, but there are " 177 + regionCount + " right now."); 178 try { 179 Thread.sleep(100); 180 } catch (InterruptedException e) { 181 } 182 } 183 } 184}