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.master.assignment; 019 020import static org.junit.jupiter.api.Assertions.assertFalse; 021import static org.junit.jupiter.api.Assertions.fail; 022 023import java.io.IOException; 024import java.util.List; 025import java.util.stream.Collectors; 026import java.util.stream.IntStream; 027import java.util.stream.Stream; 028import org.apache.hadoop.hbase.HBaseIOException; 029import org.apache.hadoop.hbase.HBaseTestingUtil; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 032import org.apache.hadoop.hbase.client.RegionInfo; 033import org.apache.hadoop.hbase.client.RegionReplicaUtil; 034import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 035import org.apache.hadoop.hbase.master.HMaster; 036import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 037import org.apache.hadoop.hbase.testclassification.MasterTests; 038import org.apache.hadoop.hbase.testclassification.MediumTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.jupiter.api.AfterAll; 041import org.junit.jupiter.api.AfterEach; 042import org.junit.jupiter.api.BeforeAll; 043import org.junit.jupiter.api.Tag; 044import org.junit.jupiter.api.Test; 045 046@Tag(MasterTests.TAG) 047@Tag(MediumTests.TAG) 048public class TestAssignmentManagerUtil { 049 050 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 051 052 private static TableName TABLE_NAME = TableName.valueOf("AM"); 053 054 private static MasterProcedureEnv ENV; 055 056 private static AssignmentManager AM; 057 058 private static int REGION_REPLICATION = 3; 059 060 @BeforeAll 061 public static void setUp() throws Exception { 062 UTIL.startMiniCluster(1); 063 UTIL.getAdmin().balancerSwitch(false, true); 064 UTIL.createTable(TableDescriptorBuilder.newBuilder(TABLE_NAME) 065 .setColumnFamily(ColumnFamilyDescriptorBuilder.of("cf")) 066 .setRegionReplication(REGION_REPLICATION).build(), new byte[][] { Bytes.toBytes(0) }); 067 UTIL.waitTableAvailable(TABLE_NAME); 068 HMaster master = UTIL.getMiniHBaseCluster().getMaster(); 069 ENV = master.getMasterProcedureExecutor().getEnvironment(); 070 AM = master.getAssignmentManager(); 071 } 072 073 @AfterEach 074 public void tearDownAfterTest() throws IOException { 075 for (RegionInfo region : UTIL.getAdmin().getRegions(TABLE_NAME)) { 076 RegionStateNode regionNode = AM.getRegionStates().getRegionStateNode(region); 077 // confirm that we have released the lock 078 assertFalse(regionNode.isLocked()); 079 TransitRegionStateProcedure proc = regionNode.getProcedure(); 080 if (proc != null) { 081 regionNode.unsetProcedure(proc); 082 } 083 } 084 } 085 086 @AfterAll 087 public static void tearDown() throws Exception { 088 UTIL.shutdownMiniCluster(); 089 } 090 091 private List<RegionInfo> getPrimaryRegions() throws IOException { 092 return UTIL.getAdmin().getRegions(TABLE_NAME).stream() 093 .filter(r -> RegionReplicaUtil.isDefaultReplica(r)).collect(Collectors.toList()); 094 } 095 096 @Test 097 public void testCreateUnassignProcedureForSplitFail() throws IOException { 098 RegionInfo region = getPrimaryRegions().get(0); 099 AM.getRegionStates().getRegionStateNode(region) 100 .setProcedure(TransitRegionStateProcedure.unassign(ENV, region)); 101 try { 102 AssignmentManagerUtil.createUnassignProceduresForSplitOrMerge(ENV, Stream.of(region), 103 REGION_REPLICATION); 104 fail("Should fail as the region is in transition"); 105 } catch (HBaseIOException e) { 106 // expected 107 } 108 } 109 110 @Test 111 public void testCreateUnassignProceduresForMergeFail() throws IOException { 112 List<RegionInfo> regions = getPrimaryRegions(); 113 RegionInfo regionA = regions.get(0); 114 RegionInfo regionB = regions.get(1); 115 AM.getRegionStates().getRegionStateNode(regionB) 116 .setProcedure(TransitRegionStateProcedure.unassign(ENV, regionB)); 117 try { 118 AssignmentManagerUtil.createUnassignProceduresForSplitOrMerge(ENV, 119 Stream.of(regionA, regionB), REGION_REPLICATION); 120 fail("Should fail as the region is in transition"); 121 } catch (HBaseIOException e) { 122 // expected 123 } 124 IntStream.range(0, REGION_REPLICATION) 125 .mapToObj(i -> RegionReplicaUtil.getRegionInfoForReplica(regionA, i)) 126 .map(AM.getRegionStates()::getRegionStateNode).forEachOrdered( 127 rn -> assertFalse(rn.isTransitionScheduled(), "Should have unset the proc for " + rn)); 128 } 129}