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 java.io.IOException; 021import java.util.concurrent.CountDownLatch; 022import org.apache.hadoop.hbase.HBaseClassTestRule; 023import org.apache.hadoop.hbase.HBaseCommonTestingUtility; 024import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility.NoopProcedure; 025import org.apache.hadoop.hbase.procedure2.store.wal.WALProcedureStore; 026import org.apache.hadoop.hbase.testclassification.MasterTests; 027import org.apache.hadoop.hbase.testclassification.MediumTests; 028import org.junit.After; 029import org.junit.AfterClass; 030import org.junit.Before; 031import org.junit.ClassRule; 032import org.junit.Rule; 033import org.junit.Test; 034import org.junit.experimental.categories.Category; 035import org.junit.rules.TestName; 036 037/** 038 * Testcase for HBASE-20973 039 */ 040@Category({ MasterTests.class, MediumTests.class }) 041public class TestProcedureRollbackAIOOB { 042 @ClassRule 043 public static final HBaseClassTestRule CLASS_RULE = 044 HBaseClassTestRule.forClass(TestProcedureRollbackAIOOB.class); 045 046 private static final HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility(); 047 048 public static final class ParentProcedure extends NoopProcedure<Void> { 049 050 private final CountDownLatch latch = new CountDownLatch(1); 051 052 private boolean scheduled; 053 054 @Override 055 protected Procedure<Void>[] execute(Void env) 056 throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException { 057 latch.await(); 058 if (scheduled) { 059 return null; 060 } 061 scheduled = true; 062 return new Procedure[] { new SubProcedure() }; 063 } 064 } 065 066 public static final class SubProcedure extends NoopProcedure<Void> { 067 068 @Override 069 protected Procedure[] execute(Void env) 070 throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException { 071 setFailure("Inject error", new RuntimeException("Inject error")); 072 return null; 073 } 074 } 075 076 private WALProcedureStore procStore; 077 078 private ProcedureExecutor<Void> procExec; 079 080 @Rule 081 public final TestName name = new TestName(); 082 083 @Before 084 public void setUp() throws IOException { 085 procStore = ProcedureTestingUtility.createWalStore(UTIL.getConfiguration(), 086 UTIL.getDataTestDir(name.getMethodName())); 087 procStore.start(2); 088 procExec = new ProcedureExecutor<Void>(UTIL.getConfiguration(), null, procStore); 089 ProcedureTestingUtility.initAndStartWorkers(procExec, 2, true); 090 } 091 092 @After 093 public void tearDown() { 094 procExec.stop(); 095 procStore.stop(false); 096 } 097 098 @AfterClass 099 public static void tearDownAfterClass() throws IOException { 100 UTIL.cleanupTestDir(); 101 } 102 103 @Test 104 public void testArrayIndexOutOfBounds() { 105 ParentProcedure proc = new ParentProcedure(); 106 long procId = procExec.submitProcedure(proc); 107 long noopProcId = -1L; 108 // make sure that the sub procedure will have a new BitSetNode 109 for (int i = 0; i < Long.SIZE - 2; i++) { 110 noopProcId = procExec.submitProcedure(new NoopProcedure<>()); 111 } 112 final long lastNoopProcId = noopProcId; 113 UTIL.waitFor(30000, () -> procExec.isFinished(lastNoopProcId)); 114 proc.latch.countDown(); 115 UTIL.waitFor(10000, () -> procExec.isFinished(procId)); 116 } 117}