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, true); 073 } 074 075 @After 076 public void tearDown() throws IOException { 077 procExecutor.stop(); 078 procStore.stop(false); 079 fs.delete(logDir, true); 080 } 081 082 @Test 083 public void testChildLoad() throws Exception { 084 procEnv.toggleKillBeforeStoreUpdate = false; 085 086 TestRootProcedure proc = new TestRootProcedure(); 087 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 088 ProcedureTestingUtility.restart(procExecutor); 089 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 090 091 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 092 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 093 } 094 095 @Test 096 public void testChildLoadWithSteppedRestart() throws Exception { 097 procEnv.toggleKillBeforeStoreUpdate = true; 098 099 TestRootProcedure proc = new TestRootProcedure(); 100 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 101 int restartCount = 0; 102 while (!procExecutor.isFinished(procId)) { 103 ProcedureTestingUtility.restart(procExecutor); 104 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 105 restartCount++; 106 } 107 assertEquals(3, restartCount); 108 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 109 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 110 } 111 112 113 /** 114 * Test the state setting that happens after store to WAL; in particular the bit where we 115 * set the parent runnable again after its children have all completed successfully. 116 * See HBASE-20978. 117 */ 118 @Test 119 public void testChildLoadWithRestartAfterChildSuccess() throws Exception { 120 procEnv.toggleKillAfterStoreUpdate = true; 121 122 TestRootProcedure proc = new TestRootProcedure(); 123 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 124 int restartCount = 0; 125 while (!procExecutor.isFinished(procId)) { 126 ProcedureTestingUtility.restart(procExecutor); 127 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 128 restartCount++; 129 } 130 assertEquals(4, restartCount); 131 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 132 ProcedureTestingUtility.assertProcNotFailed(procExecutor, procId); 133 } 134 135 @Test 136 public void testChildRollbackLoad() throws Exception { 137 procEnv.toggleKillBeforeStoreUpdate = false; 138 procEnv.triggerRollbackOnChild = true; 139 140 TestRootProcedure proc = new TestRootProcedure(); 141 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 142 ProcedureTestingUtility.restart(procExecutor); 143 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 144 145 assertProcFailed(procId); 146 } 147 148 @Test 149 public void testChildRollbackLoadWithSteppedRestart() throws Exception { 150 procEnv.toggleKillBeforeStoreUpdate = true; 151 procEnv.triggerRollbackOnChild = true; 152 153 TestRootProcedure proc = new TestRootProcedure(); 154 long procId = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 155 int restartCount = 0; 156 while (!procExecutor.isFinished(procId)) { 157 ProcedureTestingUtility.restart(procExecutor); 158 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 159 restartCount++; 160 } 161 assertEquals(2, restartCount); 162 assertProcFailed(procId); 163 } 164 165 private void assertProcFailed(long procId) { 166 assertTrue("expected completed proc", procExecutor.isFinished(procId)); 167 Procedure<?> result = procExecutor.getResult(procId); 168 assertEquals(true, result.isFailed()); 169 LOG.info(result.getException().getMessage()); 170 } 171 172 public static class TestRootProcedure extends SequentialProcedure<TestProcEnv> { 173 public TestRootProcedure() {} 174 175 @Override 176 public Procedure[] execute(TestProcEnv env) { 177 if (env.toggleKillBeforeStoreUpdate) { 178 ProcedureTestingUtility.toggleKillBeforeStoreUpdate(procExecutor); 179 } 180 if (env.toggleKillAfterStoreUpdate) { 181 ProcedureTestingUtility.toggleKillAfterStoreUpdate(procExecutor); 182 } 183 return new Procedure[] { new TestChildProcedure(), new TestChildProcedure() }; 184 } 185 186 @Override 187 public void rollback(TestProcEnv env) { 188 } 189 190 @Override 191 public boolean abort(TestProcEnv env) { 192 return false; 193 } 194 } 195 196 public static class TestChildProcedure extends SequentialProcedure<TestProcEnv> { 197 public TestChildProcedure() {} 198 199 @Override 200 public Procedure[] execute(TestProcEnv env) { 201 if (env.toggleKillBeforeStoreUpdate) { 202 ProcedureTestingUtility.toggleKillBeforeStoreUpdate(procExecutor); 203 } 204 if (env.triggerRollbackOnChild) { 205 setFailure("test", new Exception("test")); 206 } 207 return null; 208 } 209 210 @Override 211 public void rollback(TestProcEnv env) { 212 } 213 214 @Override 215 public boolean abort(TestProcEnv env) { 216 return false; 217 } 218 } 219 220 private static class TestProcEnv { 221 public boolean toggleKillBeforeStoreUpdate = false; 222 public boolean toggleKillAfterStoreUpdate = false; 223 public boolean triggerRollbackOnChild = false; 224 } 225}