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.JVMClusterUtil; 036import org.apache.hadoop.hbase.util.Threads; 037import org.junit.ClassRule; 038import org.junit.Rule; 039import org.junit.Test; 040import org.junit.experimental.categories.Category; 041import org.junit.rules.TestName; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 046 047/** 048 * Test HBASE-3694 whether the GlobalMemStoreSize is the same as the summary 049 * of all the online region's MemStoreSize 050 */ 051@Category({MiscTests.class, MediumTests.class}) 052public class TestGlobalMemStoreSize { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestGlobalMemStoreSize.class); 057 058 private static final Logger LOG = LoggerFactory.getLogger(TestGlobalMemStoreSize.class); 059 private static int regionServerNum = 4; 060 private static int regionNum = 16; 061 // total region num = region num + root and meta regions 062 private static int totalRegionNum = regionNum+2; 063 064 private HBaseTestingUtility TEST_UTIL; 065 private MiniHBaseCluster cluster; 066 067 @Rule 068 public TestName name = new TestName(); 069 070 /** 071 * Test the global mem store size in the region server is equal to sum of each 072 * region's mem store size 073 * @throws Exception 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 : 101 ProtobufUtil.getOnlineRegions(null, server.getRSRpcServices())) { 102 globalMemStoreSize += server.getRegion(regionInfo.getEncodedName()).getMemStoreDataSize(); 103 } 104 assertEquals(server.getRegionServerAccounting().getGlobalMemStoreDataSize(), 105 globalMemStoreSize); 106 } 107 108 // check the global memstore size after flush 109 int i = 0; 110 for (HRegionServer server : getOnlineRegionServers()) { 111 LOG.info("Starting flushes on " + server.getServerName() + 112 ", size=" + server.getRegionServerAccounting().getGlobalMemStoreDataSize()); 113 114 for (RegionInfo regionInfo : 115 ProtobufUtil.getOnlineRegions(null, server.getRSRpcServices())) { 116 HRegion r = server.getRegion(regionInfo.getEncodedName()); 117 flush(r, server); 118 } 119 LOG.info("Post flush on " + server.getServerName()); 120 long now = System.currentTimeMillis(); 121 long timeout = now + 1000; 122 while(server.getRegionServerAccounting().getGlobalMemStoreDataSize() != 0 && 123 timeout < System.currentTimeMillis()) { 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 : 131 ProtobufUtil.getOnlineRegions(null, 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 * @param r 154 * @param server 155 * @throws IOException 156 */ 157 private void flush(final HRegion r, final HRegionServer server) 158 throws IOException { 159 LOG.info("Flush " + r.toString() + " on " + server.getServerName() + 160 ", " + r.flush(true) + ", size=" + 161 server.getRegionServerAccounting().getGlobalMemStoreDataSize()); 162 } 163 164 private List<HRegionServer> getOnlineRegionServers() { 165 List<HRegionServer> list = new ArrayList<>(); 166 for (JVMClusterUtil.RegionServerThread rst : 167 cluster.getRegionServerThreads()) { 168 if (rst.getRegionServer().isOnline()) { 169 list.add(rst.getRegionServer()); 170 } 171 } 172 return list; 173 } 174 175 /** 176 * Wait until all the regions are assigned. 177 */ 178 private void waitForAllRegionsAssigned() throws IOException { 179 while (true) { 180 int regionCount = HBaseTestingUtility.getAllOnlineRegions(cluster).size(); 181 if (regionCount >= totalRegionNum) break; 182 LOG.debug("Waiting for there to be "+ totalRegionNum 183 +" regions, but there are " + regionCount + " right now."); 184 try { 185 Thread.sleep(100); 186 } catch (InterruptedException e) {} 187 } 188 } 189}