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.master.procedure; 019 020import static org.junit.Assert.assertTrue; 021 022import java.io.IOException; 023import org.apache.hadoop.hbase.HBaseClassTestRule; 024import org.apache.hadoop.hbase.HBaseTestingUtility; 025import org.apache.hadoop.hbase.TableName; 026import org.apache.hadoop.hbase.client.RegionInfo; 027import org.apache.hadoop.hbase.master.RegionState.State; 028import org.apache.hadoop.hbase.master.ServerManager; 029import org.apache.hadoop.hbase.master.assignment.AssignmentManager; 030import org.apache.hadoop.hbase.master.assignment.RegionStates.RegionStateNode; 031import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 032import org.apache.hadoop.hbase.testclassification.MasterTests; 033import org.apache.hadoop.hbase.testclassification.MediumTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.junit.AfterClass; 036import org.junit.BeforeClass; 037import org.junit.ClassRule; 038import org.junit.Test; 039import org.junit.experimental.categories.Category; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos.ProcedureState; 044 045/** 046 * Confirm that we will do backoff when retrying on reopening table regions, to avoid consuming all 047 * the CPUs. 048 */ 049@Category({ MasterTests.class, MediumTests.class }) 050public class TestReopenTableRegionsProcedureBackoff { 051 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestReopenTableRegionsProcedureBackoff.class); 055 056 private static final Logger LOG = 057 LoggerFactory.getLogger(TestReopenTableRegionsProcedureBackoff.class); 058 059 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 060 061 private static TableName TABLE_NAME = TableName.valueOf("Backoff"); 062 063 private static byte[] CF = Bytes.toBytes("cf"); 064 065 @BeforeClass 066 public static void setUp() throws Exception { 067 UTIL.getConfiguration().setInt(ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 1); 068 UTIL.startMiniCluster(1); 069 UTIL.createTable(TABLE_NAME, CF); 070 } 071 072 @AfterClass 073 public static void tearDown() throws Exception { 074 UTIL.shutdownMiniCluster(); 075 } 076 077 @Test 078 public void testRetryBackoff() throws IOException, InterruptedException { 079 AssignmentManager am = UTIL.getMiniHBaseCluster().getMaster().getAssignmentManager(); 080 ProcedureExecutor<MasterProcedureEnv> procExec = 081 UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(); 082 RegionInfo regionInfo = UTIL.getAdmin().getRegions(TABLE_NAME).get(0); 083 RegionStateNode regionNode = am.getRegionStates().getRegionStateNode(regionInfo); 084 long openSeqNum; 085 synchronized (regionNode) { 086 openSeqNum = regionNode.getOpenSeqNum(); 087 // make a fake state to let the procedure wait. 088 regionNode.setState(State.OPENING); 089 regionNode.setOpenSeqNum(-1L); 090 } 091 ReopenTableRegionsProcedure proc = new ReopenTableRegionsProcedure(TABLE_NAME); 092 procExec.submitProcedure(proc); 093 UTIL.waitFor(10000, () -> proc.getState() == ProcedureState.WAITING_TIMEOUT); 094 long oldTimeout = 0; 095 int timeoutIncrements = 0; 096 for (;;) { 097 long timeout = proc.getTimeout(); 098 if (timeout > oldTimeout) { 099 LOG.info("Timeout incremented, was {}, now is {}, increments={}", timeout, oldTimeout, 100 timeoutIncrements); 101 oldTimeout = timeout; 102 timeoutIncrements++; 103 if (timeoutIncrements > 3) { 104 // If we incremented at least twice, break; the backoff is working. 105 break; 106 } 107 } 108 Thread.sleep(1000); 109 } 110 synchronized (regionNode) { 111 // reset to the correct state 112 regionNode.setState(State.OPEN); 113 regionNode.setOpenSeqNum(openSeqNum); 114 } 115 ProcedureSyncWait.waitForProcedureToComplete(procExec, proc, 60000); 116 assertTrue(regionNode.getOpenSeqNum() > openSeqNum); 117 } 118}