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