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.assertSame; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.io.IOException; 025import java.util.concurrent.CountDownLatch; 026import java.util.concurrent.ForkJoinPool; 027import java.util.concurrent.Future; 028import java.util.concurrent.atomic.AtomicBoolean; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HBaseTestingUtil; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.regionserver.HRegionServer; 034import org.apache.hadoop.hbase.regionserver.RSRpcServices; 035import org.apache.hadoop.hbase.testclassification.MasterTests; 036import org.apache.hadoop.hbase.testclassification.MediumTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.junit.jupiter.api.AfterAll; 039import org.junit.jupiter.api.BeforeAll; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042 043import org.apache.hbase.thirdparty.com.google.protobuf.RpcController; 044import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; 045 046import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ExecuteProceduresRequest; 047import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ExecuteProceduresResponse; 048 049/** 050 * UT for HBASE-25032. 051 */ 052@Tag(MasterTests.TAG) 053@Tag(MediumTests.TAG) 054public class TestAssignRegionToUninitializedRegionServer { 055 056 private static CountDownLatch ARRIVE; 057 058 private static CountDownLatch RESUME; 059 060 private static AtomicBoolean ASSIGN_CALLED = new AtomicBoolean(false); 061 062 public static final class RSRpcServicesForTest extends RSRpcServices { 063 064 public RSRpcServicesForTest(HRegionServer rs) throws IOException { 065 super(rs); 066 } 067 068 @Override 069 public ExecuteProceduresResponse executeProcedures(RpcController controller, 070 ExecuteProceduresRequest request) throws ServiceException { 071 if (request.getOpenRegionCount() > 0) { 072 ASSIGN_CALLED.set(true); 073 } 074 return super.executeProcedures(controller, request); 075 } 076 } 077 078 public static final class RegionServerForTest extends HRegionServer { 079 080 public RegionServerForTest(Configuration conf) throws IOException { 081 super(conf); 082 } 083 084 @Override 085 protected void tryRegionServerReport(long reportStartTime, long reportEndTime) 086 throws IOException { 087 if (ARRIVE != null) { 088 ARRIVE.countDown(); 089 ARRIVE = null; 090 try { 091 RESUME.await(); 092 } catch (InterruptedException e) { 093 } 094 } 095 super.tryRegionServerReport(reportStartTime, reportEndTime); 096 } 097 098 @Override 099 protected RSRpcServices createRpcServices() throws IOException { 100 return new RSRpcServicesForTest(this); 101 } 102 } 103 104 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 105 106 private static TableName NAME = TableName.valueOf("test"); 107 108 private static byte[] FAMILY = Bytes.toBytes("family"); 109 110 @BeforeAll 111 public static void setUp() throws Exception { 112 UTIL.startMiniCluster(1); 113 UTIL.createTable(NAME, FAMILY); 114 UTIL.waitTableAvailable(NAME); 115 } 116 117 @AfterAll 118 public static void tearDown() throws IOException { 119 UTIL.shutdownMiniCluster(); 120 } 121 122 @Test 123 public void testMove() throws Exception { 124 UTIL.getMiniHBaseCluster().getConfiguration().setClass(HConstants.REGION_SERVER_IMPL, 125 RegionServerForTest.class, HRegionServer.class); 126 CountDownLatch arrive = new CountDownLatch(1); 127 ARRIVE = arrive; 128 RESUME = new CountDownLatch(1); 129 // restart a new region server, and wait until it finish initialization and want to call 130 // regionServerReport, so it will load the peer state to peer cache. 131 Future<HRegionServer> regionServerFuture = ForkJoinPool.commonPool() 132 .submit(() -> UTIL.getMiniHBaseCluster().startRegionServer().getRegionServer()); 133 ARRIVE.await(); 134 // try move region to the new region server, it will fail, but we need to make sure that we do 135 // not try to assign it to the new server. 136 HRegionServer src = UTIL.getRSForFirstRegionInTable(NAME); 137 HRegionServer dst = UTIL.getOtherRegionServer(src); 138 try { 139 UTIL.getAdmin().move(UTIL.getAdmin().getRegions(NAME).get(0).getEncodedNameAsBytes(), 140 dst.getServerName()); 141 // assert the region should still on the original region server, and we didn't call assign to 142 // the new server 143 assertSame(src, UTIL.getRSForFirstRegionInTable(NAME)); 144 assertFalse(ASSIGN_CALLED.get()); 145 } finally { 146 // let the region server go 147 RESUME.countDown(); 148 } 149 // wait the new region server online 150 assertSame(dst, regionServerFuture.get()); 151 // try move again 152 UTIL.getAdmin().move(UTIL.getAdmin().getRegions(NAME).get(0).getEncodedNameAsBytes(), 153 dst.getServerName()); 154 // this time the region should be on the new region server 155 assertSame(dst, UTIL.getRSForFirstRegionInTable(NAME)); 156 assertTrue(ASSIGN_CALLED.get()); 157 } 158}