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.procedure2; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import java.io.IOException; 024import org.apache.hadoop.fs.FileSystem; 025import org.apache.hadoop.fs.Path; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.HBaseCommonTestingUtility; 028import org.apache.hadoop.hbase.procedure2.store.ProcedureStore; 029import org.apache.hadoop.hbase.testclassification.MasterTests; 030import org.apache.hadoop.hbase.testclassification.SmallTests; 031import org.junit.After; 032import org.junit.Before; 033import org.junit.ClassRule; 034import org.junit.Test; 035import org.junit.experimental.categories.Category; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039@Category({MasterTests.class, SmallTests.class}) 040public class TestChildProcedures { 041 042 @ClassRule 043 public static final HBaseClassTestRule CLASS_RULE = 044 HBaseClassTestRule.forClass(TestChildProcedures.class); 045 046 private static final Logger LOG = LoggerFactory.getLogger(TestChildProcedures.class); 047 048 private static final int PROCEDURE_EXECUTOR_SLOTS = 1; 049 050 private static TestProcEnv procEnv; 051 private static ProcedureExecutor<TestProcEnv> procExecutor; 052 private static ProcedureStore procStore; 053 054 private HBaseCommonTestingUtility htu; 055 private FileSystem fs; 056 private Path testDir; 057 private Path logDir; 058 059 @Before 060 public void setUp() throws IOException { 061 htu = new HBaseCommonTestingUtility(); 062 testDir = htu.getDataTestDir(); 063 fs = testDir.getFileSystem(htu.getConfiguration()); 064 assertTrue(testDir.depth() > 1); 065 066 logDir = new Path(testDir, "proc-logs"); 067 procEnv = new TestProcEnv(); 068 procStore = ProcedureTestingUtility.createStore(htu.getConfiguration(), logDir); 069 procExecutor = new ProcedureExecutor<>(htu.getConfiguration(), procEnv, procStore); 070 procExecutor.testing = new ProcedureExecutor.Testing(); 071 procStore.start(PROCEDURE_EXECUTOR_SLOTS); 072 ProcedureTestingUtility.initAndStartWorkers(procExecutor, PROCEDURE_EXECUTOR_SLOTS, 0, false, 073 true); 074 } 075 076 @After 077 public void tearDown() throws IOException { 078 procExecutor.stop(); 079 procStore.stop(false); 080 fs.delete(logDir, true); 081 } 082 083 @Test 084 public void testChildLoad() throws Exception { 085 procEnv.toggleKillBeforeStoreUpdate = false; 086 087 TestRootProcedure proc = new TestRootProcedure(); 088 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 089 ProcedureTestingUtility.restart(procExecutor); 090 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 091 092 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 093 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 094 } 095 096 @Test 097 public void testChildLoadWithSteppedRestart() throws Exception { 098 procEnv.toggleKillBeforeStoreUpdate = true; 099 100 TestRootProcedure proc = new TestRootProcedure(); 101 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 102 int restartCount = 0; 103 while (!procExecutor.isFinished(procId)) { 104 ProcedureTestingUtility.restart(procExecutor); 105 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 106 restartCount++; 107 } 108 assertEquals(3, restartCount); 109 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 110 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 111 } 112 113 114 /** 115 * Test the state setting that happens after store to WAL; in particular the bit where we 116 * set the parent runnable again after its children have all completed successfully. 117 * See HBASE-20978. 118 */ 119 @Test 120 public void testChildLoadWithRestartAfterChildSuccess() throws Exception { 121 procEnv.toggleKillAfterStoreUpdate = true; 122 123 TestRootProcedure proc = new TestRootProcedure(); 124 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 125 int restartCount = 0; 126 while (!procExecutor.isFinished(procId)) { 127 ProcedureTestingUtility.restart(procExecutor); 128 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 129 restartCount++; 130 } 131 assertEquals(4, restartCount); 132 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 133 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 134 } 135 136 @Test 137 public void testChildRollbackLoad() throws Exception { 138 procEnv.toggleKillBeforeStoreUpdate = false; 139 procEnv.triggerRollbackOnChild = true; 140 141 TestRootProcedure proc = new TestRootProcedure(); 142 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 143 ProcedureTestingUtility.restart(procExecutor); 144 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 145 146 assertProcFailed(procId); 147 } 148 149 @Test 150 public void testChildRollbackLoadWithSteppedRestart() throws Exception { 151 procEnv.toggleKillBeforeStoreUpdate = true; 152 procEnv.triggerRollbackOnChild = true; 153 154 TestRootProcedure proc = new TestRootProcedure(); 155 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 156 int restartCount = 0; 157 while (!procExecutor.isFinished(procId)) { 158 ProcedureTestingUtility.restart(procExecutor); 159 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 160 restartCount++; 161 } 162 assertEquals(2, restartCount); 163 assertProcFailed(procId); 164 } 165 166 private void assertProcFailed(long procId) { 167 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 168 Procedure<?> result = procExecutor.getResult(procId); 169 assertEquals(true, result.isFailed()); 170 LOG.info(result.getException().getMessage()); 171 } 172 173 public static class TestRootProcedure extends SequentialProcedure<TestProcEnv> { 174 public TestRootProcedure() {} 175 176 @Override 177 public Procedure[] execute(TestProcEnv env) { 178 if (env.toggleKillBeforeStoreUpdate) { 179 ProcedureTestingUtility.toggleKillBeforeStoreUpdate(procExecutor); 180 } 181 if (env.toggleKillAfterStoreUpdate) { 182 ProcedureTestingUtility.toggleKillAfterStoreUpdate(procExecutor); 183 } 184 return new Procedure[] { new TestChildProcedure(), new TestChildProcedure() }; 185 } 186 187 @Override 188 public void rollback(TestProcEnv env) { 189 } 190 191 @Override 192 public boolean abort(TestProcEnv env) { 193 return false; 194 } 195 } 196 197 public static class TestChildProcedure extends SequentialProcedure<TestProcEnv> { 198 public TestChildProcedure() {} 199 200 @Override 201 public Procedure[] execute(TestProcEnv env) { 202 if (env.toggleKillBeforeStoreUpdate) { 203 ProcedureTestingUtility.toggleKillBeforeStoreUpdate(procExecutor); 204 } 205 if (env.triggerRollbackOnChild) { 206 setFailure("test", new Exception("test")); 207 } 208 return null; 209 } 210 211 @Override 212 public void rollback(TestProcEnv env) { 213 } 214 215 @Override 216 public boolean abort(TestProcEnv env) { 217 return false; 218 } 219 } 220 221 private static class TestProcEnv { 222 public boolean toggleKillBeforeStoreUpdate = false; 223 public boolean toggleKillAfterStoreUpdate = false; 224 public boolean triggerRollbackOnChild = false; 225 } 226}