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