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