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