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.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertNotEquals; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.io.IOException; 025import org.apache.hadoop.fs.FileSystem; 026import org.apache.hadoop.fs.Path; 027import org.apache.hadoop.hbase.HBaseCommonTestingUtil; 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.jupiter.api.AfterEach; 032import org.junit.jupiter.api.BeforeEach; 033import org.junit.jupiter.api.Tag; 034import org.junit.jupiter.api.Test; 035 036@Tag(MasterTests.TAG) 037@Tag(SmallTests.TAG) 038public class TestProcedureMetrics { 039 040 private static final int PROCEDURE_EXECUTOR_SLOTS = 1; 041 042 private TestProcEnv procEnv; 043 private static ProcedureExecutor<TestProcEnv> procExecutor; 044 private ProcedureStore procStore; 045 046 private HBaseCommonTestingUtil htu; 047 private FileSystem fs; 048 private Path testDir; 049 private Path logDir; 050 051 private static int beginCount = 0; 052 private static int successCount = 0; 053 private static int failedCount = 0; 054 055 @BeforeEach 056 public void setUp() throws IOException { 057 htu = new HBaseCommonTestingUtil(); 058 testDir = htu.getDataTestDir(); 059 fs = testDir.getFileSystem(htu.getConfiguration()); 060 assertTrue(testDir.depth() > 1); 061 062 logDir = new Path(testDir, "proc-logs"); 063 procEnv = new TestProcEnv(); 064 procStore = ProcedureTestingUtility.createStore(htu.getConfiguration(), logDir); 065 procExecutor = new ProcedureExecutor<TestProcEnv>(htu.getConfiguration(), procEnv, procStore); 066 procExecutor.testing = new ProcedureExecutor.Testing(); 067 procStore.start(PROCEDURE_EXECUTOR_SLOTS); 068 ProcedureTestingUtility.initAndStartWorkers(procExecutor, PROCEDURE_EXECUTOR_SLOTS, true); 069 } 070 071 @AfterEach 072 public void tearDown() throws IOException { 073 procExecutor.stop(); 074 procStore.stop(false); 075 fs.delete(logDir, true); 076 } 077 078 @Test 079 public void testMetricForSimpleProcedure() throws Exception { 080 // procedure that executes successfully 081 ProcedureMetrics proc = new ProcedureMetrics(true); 082 long id = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 083 assertNotEquals(0, id, "ProcId zero!"); 084 beginCount++; 085 successCount++; 086 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 087 assertEquals(beginCount, proc.beginCount, "beginCount doesn't match!"); 088 assertEquals(successCount, proc.successCount, "successCount doesn't match!"); 089 assertEquals(failedCount, proc.failedCount, "failedCont doesn't match!"); 090 } 091 092 @Test 093 public void testMetricsForFailedProcedure() throws Exception { 094 // procedure that fails 095 ProcedureMetrics proc = new ProcedureMetrics(false); 096 long id = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 097 assertNotEquals(0, id, "ProcId zero!"); 098 beginCount++; 099 failedCount++; 100 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 101 assertEquals(beginCount, proc.beginCount, "beginCount doesn't match!"); 102 assertEquals(successCount, proc.successCount, "successCount doesn't match!"); 103 assertEquals(failedCount, proc.failedCount, "failedCont doesn't match!"); 104 } 105 106 @Test 107 public void testMetricForYieldProcedure() throws Exception { 108 // procedure that yields 109 ProcedureMetrics proc = new ProcedureMetrics(true, true); 110 long id = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 111 assertNotEquals(0, id, "ProcId zero!"); 112 beginCount++; 113 successCount++; 114 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 115 assertEquals(beginCount, proc.beginCount, "beginCount doesn't match!"); 116 assertEquals(successCount, proc.successCount, "successCount doesn't match!"); 117 assertEquals(failedCount, proc.failedCount, "failedCont doesn't match!"); 118 } 119 120 @Test 121 public void testMetricForFailedYiledProcedure() { 122 // procedure that yields and fails 123 ProcedureMetrics proc = new ProcedureMetrics(false, true); 124 long id = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 125 assertNotEquals(0, id, "ProcId zero!"); 126 beginCount++; 127 failedCount++; 128 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 129 assertEquals(beginCount, proc.beginCount, "beginCount doesn't match!"); 130 assertEquals(successCount, proc.successCount, "successCount doesn't match!"); 131 assertEquals(failedCount, proc.failedCount, "failedCont doesn't match!"); 132 } 133 134 @Test 135 public void testMetricForProcedureWithChildren() throws Exception { 136 // Procedure that yileds with one of the sub-procedures that fail 137 int subProcCount = 10; 138 int failChildIndex = 2; 139 int yiledChildIndex = -1; 140 ProcedureMetrics[] subprocs = new ProcedureMetrics[subProcCount]; 141 for (int i = 0; i < subProcCount; ++i) { 142 subprocs[i] = new ProcedureMetrics(failChildIndex != i, yiledChildIndex == i, 3); 143 } 144 145 ProcedureMetrics proc = new ProcedureMetrics(true, true, 3, subprocs); 146 long id = ProcedureTestingUtility.submitAndWait(procExecutor, proc); 147 assertNotEquals(0, id, "ProcId zero!"); 148 beginCount += subProcCount + 1; 149 successCount += subProcCount - (failChildIndex + 1); 150 if (failChildIndex >= 0) { 151 failedCount += subProcCount + 1; 152 } else { 153 successCount++; 154 } 155 ProcedureTestingUtility.waitProcedure(procExecutor, proc); 156 assertEquals(beginCount, proc.beginCount, "beginCount doesn't match!"); 157 assertEquals(successCount, proc.successCount, "successCount doesn't match!"); 158 assertEquals(failedCount, proc.failedCount, "failedCont doesn't match!"); 159 } 160 161 private static class TestProcEnv { 162 public boolean toggleKillBeforeStoreUpdate = false; 163 public boolean triggerRollbackOnChild = false; 164 } 165 166 public static class ProcedureMetrics extends SequentialProcedure<TestProcEnv> { 167 public static long beginCount = 0; 168 public static long successCount = 0; 169 public static long failedCount = 0; 170 171 private boolean success; 172 private boolean yield; 173 private int yieldCount; 174 private int yieldNum; 175 176 private ProcedureMetrics[] subprocs = null; 177 178 public ProcedureMetrics() { 179 this(true); 180 } 181 182 public ProcedureMetrics(boolean success) { 183 this(success, true); 184 } 185 186 public ProcedureMetrics(boolean success, boolean yield) { 187 this(success, yield, 1); 188 } 189 190 public ProcedureMetrics(boolean success, boolean yield, int yieldCount) { 191 this(success, yield, yieldCount, null); 192 } 193 194 public ProcedureMetrics(boolean success, ProcedureMetrics[] subprocs) { 195 this(success, false, 1, subprocs); 196 } 197 198 public ProcedureMetrics(boolean success, boolean yield, int yieldCount, 199 ProcedureMetrics[] subprocs) { 200 this.success = success; 201 this.yield = yield; 202 this.yieldCount = yieldCount; 203 this.subprocs = subprocs; 204 yieldNum = 0; 205 } 206 207 @Override 208 protected void updateMetricsOnSubmit(TestProcEnv env) { 209 beginCount++; 210 } 211 212 @Override 213 protected Procedure[] execute(TestProcEnv env) 214 throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException { 215 if (this.yield) { 216 if (yieldNum < yieldCount) { 217 yieldNum++; 218 throw new ProcedureYieldException(); 219 } 220 } 221 if (!this.success) { 222 setFailure("Failed", new InterruptedException("Failed")); 223 return null; 224 } 225 return subprocs; 226 } 227 228 @Override 229 protected void rollback(TestProcEnv env) throws IOException, InterruptedException { 230 } 231 232 @Override 233 protected boolean abort(TestProcEnv env) { 234 return false; 235 } 236 237 @Override 238 protected void updateMetricsOnFinish(final TestProcEnv env, final long time, boolean success) { 239 if (success) { 240 successCount++; 241 } else { 242 failedCount++; 243 } 244 } 245 } 246}