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.replication; 019 020import java.io.IOException; 021import org.apache.hadoop.hbase.HBaseClassTestRule; 022import org.apache.hadoop.hbase.HBaseTestingUtility; 023import org.apache.hadoop.hbase.ProcedureTestUtil; 024import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 025import org.apache.hadoop.hbase.procedure2.Procedure; 026import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 027import org.apache.hadoop.hbase.replication.ReplicationException; 028import org.apache.hadoop.hbase.testclassification.LargeTests; 029import org.apache.hadoop.hbase.testclassification.MasterTests; 030import org.junit.AfterClass; 031import org.junit.BeforeClass; 032import org.junit.ClassRule; 033import org.junit.Test; 034import org.junit.experimental.categories.Category; 035 036import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.PeerModificationState; 037 038@Category({ MasterTests.class, LargeTests.class }) 039public class TestModifyPeerProcedureRetryBackoff { 040 041 @ClassRule 042 public static final HBaseClassTestRule CLASS_RULE = 043 HBaseClassTestRule.forClass(TestModifyPeerProcedureRetryBackoff.class); 044 045 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 046 047 private static boolean FAIL = true; 048 049 public static class TestModifyPeerProcedure extends ModifyPeerProcedure { 050 051 public TestModifyPeerProcedure() { 052 } 053 054 public TestModifyPeerProcedure(String peerId) { 055 super(peerId); 056 } 057 058 @Override 059 public PeerOperationType getPeerOperationType() { 060 return PeerOperationType.ADD; 061 } 062 063 private void tryFail() throws ReplicationException { 064 synchronized (TestModifyPeerProcedureRetryBackoff.class) { 065 if (FAIL) { 066 throw new ReplicationException("Inject error"); 067 } 068 FAIL = true; 069 } 070 } 071 072 @Override 073 protected <T extends Procedure<MasterProcedureEnv>> void addChildProcedure( 074 @SuppressWarnings("unchecked") T... subProcedure) { 075 // Make it a no-op 076 } 077 078 @Override 079 protected PeerModificationState nextStateAfterRefresh() { 080 return PeerModificationState.SERIAL_PEER_REOPEN_REGIONS; 081 } 082 083 @Override 084 protected boolean enablePeerBeforeFinish() { 085 return true; 086 } 087 088 @Override 089 protected void updateLastPushedSequenceIdForSerialPeer(MasterProcedureEnv env) 090 throws IOException, ReplicationException { 091 tryFail(); 092 } 093 094 @Override 095 protected void reopenRegions(MasterProcedureEnv env) throws IOException { 096 try { 097 tryFail(); 098 } catch (ReplicationException e) { 099 throw new IOException(e); 100 } 101 } 102 103 @Override 104 protected void enablePeer(MasterProcedureEnv env) throws ReplicationException { 105 tryFail(); 106 } 107 108 @Override 109 protected void prePeerModification(MasterProcedureEnv env) 110 throws IOException, ReplicationException { 111 tryFail(); 112 } 113 114 @Override 115 protected void updatePeerStorage(MasterProcedureEnv env) throws ReplicationException { 116 tryFail(); 117 } 118 119 @Override 120 protected void postPeerModification(MasterProcedureEnv env) 121 throws IOException, ReplicationException { 122 tryFail(); 123 } 124 } 125 126 @BeforeClass 127 public static void setUp() throws Exception { 128 UTIL.startMiniCluster(1); 129 } 130 131 @AfterClass 132 public static void tearDown() throws Exception { 133 UTIL.shutdownMiniCluster(); 134 } 135 136 private void assertBackoffIncrease() throws IOException, InterruptedException { 137 ProcedureTestUtil.waitUntilProcedureWaitingTimeout(UTIL, TestModifyPeerProcedure.class, 30000); 138 ProcedureTestUtil.waitUntilProcedureTimeoutIncrease(UTIL, TestModifyPeerProcedure.class, 2); 139 synchronized (TestModifyPeerProcedureRetryBackoff.class) { 140 FAIL = false; 141 } 142 UTIL.waitFor(30000, () -> FAIL); 143 } 144 145 @Test 146 public void test() throws IOException, InterruptedException { 147 ProcedureExecutor<MasterProcedureEnv> procExec = 148 UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(); 149 long procId = procExec.submitProcedure(new TestModifyPeerProcedure("1")); 150 // PRE_PEER_MODIFICATION 151 assertBackoffIncrease(); 152 // UPDATE_PEER_STORAGE 153 assertBackoffIncrease(); 154 // No retry for REFRESH_PEER_ON_RS 155 // SERIAL_PEER_REOPEN_REGIONS 156 assertBackoffIncrease(); 157 // SERIAL_PEER_UPDATE_LAST_PUSHED_SEQ_ID 158 assertBackoffIncrease(); 159 // SERIAL_PEER_SET_PEER_ENABLED 160 assertBackoffIncrease(); 161 // No retry for SERIAL_PEER_ENABLE_PEER_REFRESH_PEER_ON_RS 162 // POST_PEER_MODIFICATION 163 assertBackoffIncrease(); 164 UTIL.waitFor(30000, () -> procExec.isFinished(procId)); 165 } 166}