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.store; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021 022import java.io.IOException; 023import java.io.UncheckedIOException; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.List; 027import java.util.stream.Collectors; 028import org.apache.hadoop.hbase.procedure2.Procedure; 029import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; 030import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException; 031import org.apache.hadoop.hbase.procedure2.ProcedureUtil; 032import org.apache.hadoop.hbase.procedure2.ProcedureYieldException; 033import org.apache.hadoop.hbase.procedure2.store.ProcedureStore.ProcedureIterator; 034import org.apache.hadoop.hbase.testclassification.MasterTests; 035import org.apache.hadoop.hbase.testclassification.SmallTests; 036import org.junit.jupiter.api.Tag; 037import org.junit.jupiter.api.Test; 038 039import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos; 040 041@Tag(MasterTests.TAG) 042@Tag(SmallTests.TAG) 043public class TestProcedureTree { 044 045 public static final class TestProcedure extends Procedure<Void> { 046 047 @Override 048 public void setProcId(long procId) { 049 super.setProcId(procId); 050 } 051 052 @Override 053 public void setParentProcId(long parentProcId) { 054 super.setParentProcId(parentProcId); 055 } 056 057 @Override 058 public synchronized void addStackIndex(int index) { 059 super.addStackIndex(index); 060 } 061 062 @Override 063 protected Procedure<Void>[] execute(Void env) 064 throws ProcedureYieldException, ProcedureSuspendedException, InterruptedException { 065 return null; 066 } 067 068 @Override 069 protected void rollback(Void env) throws IOException, InterruptedException { 070 } 071 072 @Override 073 protected boolean abort(Void env) { 074 return false; 075 } 076 077 @Override 078 protected void serializeStateData(ProcedureStateSerializer serializer) throws IOException { 079 } 080 081 @Override 082 protected void deserializeStateData(ProcedureStateSerializer serializer) throws IOException { 083 } 084 } 085 086 private TestProcedure createProc(long procId, long parentProcId) { 087 TestProcedure proc = new TestProcedure(); 088 proc.setProcId(procId); 089 if (parentProcId != Procedure.NO_PROC_ID) { 090 proc.setParentProcId(parentProcId); 091 } 092 return proc; 093 } 094 095 private List<ProcedureProtos.Procedure> toProtos(TestProcedure... procs) { 096 return Arrays.stream(procs).map(p -> { 097 try { 098 return ProcedureUtil.convertToProtoProcedure(p); 099 } catch (IOException e) { 100 throw new UncheckedIOException(e); 101 } 102 }).collect(Collectors.toList()); 103 } 104 105 private List<TestProcedure> getProcs(ProcedureIterator iter) throws IOException { 106 List<TestProcedure> procs = new ArrayList<>(); 107 while (iter.hasNext()) { 108 procs.add((TestProcedure) iter.next()); 109 } 110 return procs; 111 } 112 113 @Test 114 public void testMissingStackId() throws IOException { 115 TestProcedure proc0 = createProc(1, Procedure.NO_PROC_ID); 116 proc0.addStackIndex(0); 117 TestProcedure proc1 = createProc(2, 1); 118 proc1.addStackIndex(1); 119 TestProcedure proc2 = createProc(3, 2); 120 proc2.addStackIndex(3); 121 ProcedureTree tree = ProcedureTree.build(toProtos(proc0, proc1, proc2)); 122 List<TestProcedure> validProcs = getProcs(tree.getValidProcs()); 123 assertEquals(0, validProcs.size()); 124 List<TestProcedure> corruptedProcs = getProcs(tree.getCorruptedProcs()); 125 assertEquals(3, corruptedProcs.size()); 126 assertEquals(1, corruptedProcs.get(0).getProcId()); 127 assertEquals(2, corruptedProcs.get(1).getProcId()); 128 assertEquals(3, corruptedProcs.get(2).getProcId()); 129 } 130 131 @Test 132 public void testDuplicatedStackId() throws IOException { 133 TestProcedure proc0 = createProc(1, Procedure.NO_PROC_ID); 134 proc0.addStackIndex(0); 135 TestProcedure proc1 = createProc(2, 1); 136 proc1.addStackIndex(1); 137 TestProcedure proc2 = createProc(3, 2); 138 proc2.addStackIndex(1); 139 ProcedureTree tree = ProcedureTree.build(toProtos(proc0, proc1, proc2)); 140 List<TestProcedure> validProcs = getProcs(tree.getValidProcs()); 141 assertEquals(0, validProcs.size()); 142 List<TestProcedure> corruptedProcs = getProcs(tree.getCorruptedProcs()); 143 assertEquals(3, corruptedProcs.size()); 144 assertEquals(1, corruptedProcs.get(0).getProcId()); 145 assertEquals(2, corruptedProcs.get(1).getProcId()); 146 assertEquals(3, corruptedProcs.get(2).getProcId()); 147 } 148 149 @Test 150 public void testOrphan() throws IOException { 151 TestProcedure proc0 = createProc(1, Procedure.NO_PROC_ID); 152 proc0.addStackIndex(0); 153 TestProcedure proc1 = createProc(2, 1); 154 proc1.addStackIndex(1); 155 TestProcedure proc2 = createProc(3, Procedure.NO_PROC_ID); 156 proc2.addStackIndex(0); 157 TestProcedure proc3 = createProc(5, 4); 158 proc3.addStackIndex(1); 159 ProcedureTree tree = ProcedureTree.build(toProtos(proc0, proc1, proc2, proc3)); 160 List<TestProcedure> validProcs = getProcs(tree.getValidProcs()); 161 assertEquals(3, validProcs.size()); 162 List<TestProcedure> corruptedProcs = getProcs(tree.getCorruptedProcs()); 163 assertEquals(1, corruptedProcs.size()); 164 assertEquals(5, corruptedProcs.get(0).getProcId()); 165 assertEquals(4, corruptedProcs.get(0).getParentProcId()); 166 } 167}