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; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertNotNull; 023import static org.junit.jupiter.api.Assertions.assertNull; 024import static org.junit.jupiter.api.Assertions.assertTrue; 025 026import java.io.IOException; 027import java.util.concurrent.TimeUnit; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.hbase.HBaseTestingUtil; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.JMXListener; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.Waiter; 034import org.apache.hadoop.hbase.client.Admin; 035import org.apache.hadoop.hbase.client.Connection; 036import org.apache.hadoop.hbase.client.ConnectionFactory; 037import org.apache.hadoop.hbase.client.RegionInfo; 038import org.apache.hadoop.hbase.client.RegionLocator; 039import org.apache.hadoop.hbase.client.Table; 040import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 041import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 042import org.apache.hadoop.hbase.master.HMaster; 043import org.apache.hadoop.hbase.regionserver.compactions.CompactionConfiguration; 044import org.apache.hadoop.hbase.testclassification.MediumTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.junit.jupiter.api.AfterAll; 047import org.junit.jupiter.api.BeforeAll; 048import org.junit.jupiter.api.BeforeEach; 049import org.junit.jupiter.api.Tag; 050import org.junit.jupiter.api.Test; 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053 054/** 055 * Verify that the Online config Changes on the HRegionServer side are actually happening. We should 056 * add tests for important configurations which will be changed online. 057 */ 058 059@Tag(MediumTests.TAG) 060public class TestRegionServerOnlineConfigChange { 061 062 private static final Logger LOG = 063 LoggerFactory.getLogger(TestRegionServerOnlineConfigChange.class.getName()); 064 private static final long WAIT_TIMEOUT = TimeUnit.MINUTES.toMillis(2); 065 private static HBaseTestingUtil hbaseTestingUtility = new HBaseTestingUtil(); 066 private static Configuration conf = null; 067 068 private static Table t1 = null; 069 private static HRegionServer rs1 = null; 070 private static HMaster hMaster = null; 071 private static byte[] r1name = null; 072 private static Region r1 = null; 073 074 private final static String table1Str = "table1"; 075 private final static String columnFamily1Str = "columnFamily1"; 076 private final static TableName TABLE1 = TableName.valueOf(table1Str); 077 private final static byte[] COLUMN_FAMILY1 = Bytes.toBytes(columnFamily1Str); 078 private final static long MAX_FILE_SIZE = 20 * 1024 * 1024L; 079 080 @BeforeAll 081 public static void setUpBeforeClass() throws Exception { 082 conf = hbaseTestingUtility.getConfiguration(); 083 hbaseTestingUtility.startMiniCluster(2); 084 t1 = hbaseTestingUtility.createTable( 085 TableDescriptorBuilder.newBuilder(TABLE1).setMaxFileSize(MAX_FILE_SIZE).build(), 086 new byte[][] { COLUMN_FAMILY1 }, conf); 087 } 088 089 @AfterAll 090 public static void tearDown() throws Exception { 091 hbaseTestingUtility.shutdownMiniCluster(); 092 } 093 094 @BeforeEach 095 public void setUp() throws Exception { 096 try (RegionLocator locator = hbaseTestingUtility.getConnection().getRegionLocator(TABLE1)) { 097 RegionInfo firstHRI = locator.getAllRegionLocations().get(0).getRegion(); 098 r1name = firstHRI.getRegionName(); 099 rs1 = hbaseTestingUtility.getHBaseCluster() 100 .getRegionServer(hbaseTestingUtility.getHBaseCluster().getServerWith(r1name)); 101 r1 = rs1.getRegion(r1name); 102 hMaster = hbaseTestingUtility.getHBaseCluster().getMaster(); 103 } 104 } 105 106 /** 107 * Check if the number of compaction threads changes online 108 */ 109 @Test 110 public void testNumCompactionThreadsOnlineChange() { 111 assertNotNull(rs1.getCompactSplitThread()); 112 int newNumSmallThreads = rs1.getCompactSplitThread().getSmallCompactionThreadNum() + 1; 113 int newNumLargeThreads = rs1.getCompactSplitThread().getLargeCompactionThreadNum() + 1; 114 115 conf.setInt("hbase.regionserver.thread.compaction.small", newNumSmallThreads); 116 conf.setInt("hbase.regionserver.thread.compaction.large", newNumLargeThreads); 117 rs1.getConfigurationManager().notifyAllObservers(conf); 118 119 assertEquals(newNumSmallThreads, rs1.getCompactSplitThread().getSmallCompactionThreadNum()); 120 assertEquals(newNumLargeThreads, rs1.getCompactSplitThread().getLargeCompactionThreadNum()); 121 } 122 123 /** 124 * Test that the configurations in the CompactionConfiguration class change properly. 125 */ 126 @Test 127 public void testCompactionConfigurationOnlineChange() throws IOException { 128 String strPrefix = "hbase.hstore.compaction."; 129 Store s = r1.getStore(COLUMN_FAMILY1); 130 if (!(s instanceof HStore)) { 131 LOG.error("Can't test the compaction configuration of HStore class. " 132 + "Got a different implementation other than HStore"); 133 return; 134 } 135 HStore hstore = (HStore) s; 136 137 // Set the new compaction ratio to a different value. 138 double newCompactionRatio = 139 hstore.getStoreEngine().getCompactionPolicy().getConf().getCompactionRatio() + 0.1; 140 conf.setFloat(strPrefix + "ratio", (float) newCompactionRatio); 141 142 // Notify all the observers, which includes the Store object. 143 rs1.getConfigurationManager().notifyAllObservers(conf); 144 145 // Check if the compaction ratio got updated in the Compaction Configuration 146 assertEquals(newCompactionRatio, 147 hstore.getStoreEngine().getCompactionPolicy().getConf().getCompactionRatio(), 0.00001); 148 149 // Check if the off peak compaction ratio gets updated. 150 double newOffPeakCompactionRatio = 151 hstore.getStoreEngine().getCompactionPolicy().getConf().getCompactionRatioOffPeak() + 0.1; 152 conf.setFloat(strPrefix + "ratio.offpeak", (float) newOffPeakCompactionRatio); 153 rs1.getConfigurationManager().notifyAllObservers(conf); 154 assertEquals(newOffPeakCompactionRatio, 155 hstore.getStoreEngine().getCompactionPolicy().getConf().getCompactionRatioOffPeak(), 0.00001); 156 157 // Check if the throttle point gets updated. 158 long newThrottlePoint = 159 hstore.getStoreEngine().getCompactionPolicy().getConf().getThrottlePoint() + 10; 160 conf.setLong("hbase.regionserver.thread.compaction.throttle", newThrottlePoint); 161 rs1.getConfigurationManager().notifyAllObservers(conf); 162 assertEquals(newThrottlePoint, 163 hstore.getStoreEngine().getCompactionPolicy().getConf().getThrottlePoint()); 164 165 // Check if the minFilesToCompact gets updated. 166 int newMinFilesToCompact = 167 hstore.getStoreEngine().getCompactionPolicy().getConf().getMinFilesToCompact() + 1; 168 conf.setLong(strPrefix + "min", newMinFilesToCompact); 169 rs1.getConfigurationManager().notifyAllObservers(conf); 170 assertEquals(newMinFilesToCompact, 171 hstore.getStoreEngine().getCompactionPolicy().getConf().getMinFilesToCompact()); 172 173 // Check if the maxFilesToCompact gets updated. 174 int newMaxFilesToCompact = 175 hstore.getStoreEngine().getCompactionPolicy().getConf().getMaxFilesToCompact() + 1; 176 conf.setLong(strPrefix + "max", newMaxFilesToCompact); 177 rs1.getConfigurationManager().notifyAllObservers(conf); 178 assertEquals(newMaxFilesToCompact, 179 hstore.getStoreEngine().getCompactionPolicy().getConf().getMaxFilesToCompact()); 180 181 // Check OffPeak hours is updated in an online fashion. 182 conf.setLong(CompactionConfiguration.HBASE_HSTORE_OFFPEAK_START_HOUR, 6); 183 conf.setLong(CompactionConfiguration.HBASE_HSTORE_OFFPEAK_END_HOUR, 7); 184 rs1.getConfigurationManager().notifyAllObservers(conf); 185 assertFalse(hstore.getOffPeakHours().isOffPeakHour(4)); 186 187 // Check if the minCompactSize gets updated. 188 long newMinCompactSize = 189 hstore.getStoreEngine().getCompactionPolicy().getConf().getMinCompactSize() + 1; 190 conf.setLong(strPrefix + "min.size", newMinCompactSize); 191 rs1.getConfigurationManager().notifyAllObservers(conf); 192 assertEquals(newMinCompactSize, 193 hstore.getStoreEngine().getCompactionPolicy().getConf().getMinCompactSize()); 194 195 // Check if the maxCompactSize gets updated. 196 long newMaxCompactSize = 197 hstore.getStoreEngine().getCompactionPolicy().getConf().getMaxCompactSize() - 1; 198 conf.setLong(strPrefix + "max.size", newMaxCompactSize); 199 rs1.getConfigurationManager().notifyAllObservers(conf); 200 assertEquals(newMaxCompactSize, 201 hstore.getStoreEngine().getCompactionPolicy().getConf().getMaxCompactSize()); 202 // Check if the offPeakMaxCompactSize gets updated. 203 long newOffpeakMaxCompactSize = 204 hstore.getStoreEngine().getCompactionPolicy().getConf().getOffPeakMaxCompactSize() - 1; 205 conf.setLong(CompactionConfiguration.HBASE_HSTORE_COMPACTION_MAX_SIZE_OFFPEAK_KEY, 206 newOffpeakMaxCompactSize); 207 rs1.getConfigurationManager().notifyAllObservers(conf); 208 assertEquals(newOffpeakMaxCompactSize, 209 hstore.getStoreEngine().getCompactionPolicy().getConf().getOffPeakMaxCompactSize()); 210 211 // Check if majorCompactionPeriod gets updated. 212 long newMajorCompactionPeriod = 213 hstore.getStoreEngine().getCompactionPolicy().getConf().getMajorCompactionPeriod() + 10; 214 conf.setLong(HConstants.MAJOR_COMPACTION_PERIOD, newMajorCompactionPeriod); 215 rs1.getConfigurationManager().notifyAllObservers(conf); 216 assertEquals(newMajorCompactionPeriod, 217 hstore.getStoreEngine().getCompactionPolicy().getConf().getMajorCompactionPeriod()); 218 219 // Check if majorCompactionJitter gets updated. 220 float newMajorCompactionJitter = 221 hstore.getStoreEngine().getCompactionPolicy().getConf().getMajorCompactionJitter() + 0.02F; 222 conf.setFloat("hbase.hregion.majorcompaction.jitter", newMajorCompactionJitter); 223 rs1.getConfigurationManager().notifyAllObservers(conf); 224 assertEquals(newMajorCompactionJitter, 225 hstore.getStoreEngine().getCompactionPolicy().getConf().getMajorCompactionJitter(), 0.00001); 226 } 227 228 @Test 229 public void removeClosedRegionFromConfigurationManager() throws Exception { 230 try (Connection connection = ConnectionFactory.createConnection(conf)) { 231 Admin admin = connection.getAdmin(); 232 assertTrue(rs1.getConfigurationManager().containsObserver(r1), 233 "The open region doesn't register as a ConfigurationObserver"); 234 admin.move(r1name); 235 hbaseTestingUtility.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { 236 @Override 237 public boolean evaluate() throws Exception { 238 return rs1.getOnlineRegion(r1name) == null; 239 } 240 }); 241 assertFalse(rs1.getConfigurationManager().containsObserver(r1), 242 "The closed region is not removed from ConfigurationManager"); 243 admin.move(r1name, rs1.getServerName()); 244 hbaseTestingUtility.waitFor(WAIT_TIMEOUT, new Waiter.Predicate<Exception>() { 245 @Override 246 public boolean evaluate() throws Exception { 247 return rs1.getOnlineRegion(r1name) != null; 248 } 249 }); 250 } 251 } 252 253 @Test 254 public void testStoreConfigurationOnlineChange() { 255 rs1.getConfigurationManager().notifyAllObservers(conf); 256 long actualMaxFileSize = r1.getStore(COLUMN_FAMILY1).getReadOnlyConfiguration() 257 .getLong(TableDescriptorBuilder.MAX_FILESIZE, -1); 258 assertEquals(MAX_FILE_SIZE, actualMaxFileSize); 259 } 260 261 @Test 262 public void testCoprocessorConfigurationOnlineChange() { 263 assertNull(rs1.getRegionServerCoprocessorHost().findCoprocessor(JMXListener.class.getName())); 264 // Update configuration directly to simulate dynamic configuration reload 265 Configuration rsConf = rs1.getConfiguration(); 266 rsConf.set(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, JMXListener.class.getName()); 267 rs1.getConfigurationManager().notifyAllObservers(rsConf); 268 assertNotNull( 269 rs1.getRegionServerCoprocessorHost().findCoprocessor(JMXListener.class.getName())); 270 } 271 272 @Test 273 public void testCoprocessorConfigurationOnlineChangeOnMaster() { 274 assertNull(hMaster.getMasterCoprocessorHost().findCoprocessor(JMXListener.class.getName())); 275 // Update configuration directly to simulate dynamic configuration reload 276 Configuration masterConf = hMaster.getConfiguration(); 277 masterConf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, JMXListener.class.getName()); 278 assertFalse(hMaster.isInMaintenanceMode()); 279 hMaster.getConfigurationManager().notifyAllObservers(masterConf); 280 assertNotNull(hMaster.getMasterCoprocessorHost().findCoprocessor(JMXListener.class.getName())); 281 } 282 283}