2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.regionserver
;
20 import java
.io
.IOException
;
21 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
22 import org
.apache
.hadoop
.hbase
.HBaseTestingUtil
;
23 import org
.apache
.hadoop
.hbase
.HConstants
;
24 import org
.apache
.hadoop
.hbase
.NotServingRegionException
;
25 import org
.apache
.hadoop
.hbase
.ServerName
;
26 import org
.apache
.hadoop
.hbase
.TableName
;
27 import org
.apache
.hadoop
.hbase
.client
.Put
;
28 import org
.apache
.hadoop
.hbase
.client
.RegionInfo
;
29 import org
.apache
.hadoop
.hbase
.client
.RegionLocator
;
30 import org
.apache
.hadoop
.hbase
.client
.Table
;
31 import org
.apache
.hadoop
.hbase
.client
.TableDescriptor
;
32 import org
.apache
.hadoop
.hbase
.master
.HMaster
;
33 import org
.apache
.hadoop
.hbase
.regionserver
.handler
.OpenRegionHandler
;
34 import org
.apache
.hadoop
.hbase
.testclassification
.MediumTests
;
35 import org
.apache
.hadoop
.hbase
.testclassification
.RegionServerTests
;
36 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
37 import org
.apache
.hadoop
.hbase
.util
.JVMClusterUtil
;
38 import org
.apache
.hadoop
.hbase
.util
.JVMClusterUtil
.RegionServerThread
;
39 import org
.apache
.hadoop
.hbase
.util
.Threads
;
40 import org
.junit
.AfterClass
;
41 import org
.junit
.Assert
;
42 import org
.junit
.BeforeClass
;
43 import org
.junit
.ClassRule
;
44 import org
.junit
.Test
;
45 import org
.junit
.experimental
.categories
.Category
;
46 import org
.slf4j
.Logger
;
47 import org
.slf4j
.LoggerFactory
;
49 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.ProtobufUtil
;
50 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.RequestConverter
;
51 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.AdminProtos
;
52 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.AdminProtos
.CloseRegionRequest
;
55 * Tests on the region server, without the master.
57 @Category({RegionServerTests
.class, MediumTests
.class})
58 public class TestRegionServerNoMaster
{
61 public static final HBaseClassTestRule CLASS_RULE
=
62 HBaseClassTestRule
.forClass(TestRegionServerNoMaster
.class);
64 private static final Logger LOG
= LoggerFactory
.getLogger(TestRegionServerNoMaster
.class);
65 private static final int NB_SERVERS
= 1;
66 private static Table table
;
67 private static final byte[] row
= Bytes
.toBytes("ee");
69 private static RegionInfo hri
;
71 private static byte[] regionName
;
72 private static final HBaseTestingUtil HTU
= new HBaseTestingUtil();
76 public static void before() throws Exception
{
77 HTU
.startMiniCluster(NB_SERVERS
);
78 final TableName tableName
= TableName
.valueOf(TestRegionServerNoMaster
.class.getSimpleName());
80 // Create table then get the single region for our new table.
81 table
= HTU
.createTable(tableName
,HConstants
.CATALOG_FAMILY
);
83 p
.addColumn(HConstants
.CATALOG_FAMILY
, row
, row
);
86 try (RegionLocator locator
= HTU
.getConnection().getRegionLocator(tableName
)) {
87 hri
= locator
.getRegionLocation(row
, false).getRegion();
89 regionName
= hri
.getRegionName();
91 stopMasterAndCacheMetaLocation(HTU
);
94 public static void stopMasterAndCacheMetaLocation(HBaseTestingUtil HTU
)
95 throws IOException
, InterruptedException
{
96 // cache meta location, so we will not go to master to lookup meta region location
97 for (JVMClusterUtil
.RegionServerThread t
: HTU
.getMiniHBaseCluster().getRegionServerThreads()) {
98 try (RegionLocator locator
=
99 t
.getRegionServer().getConnection().getRegionLocator(TableName
.META_TABLE_NAME
)) {
100 locator
.getAllRegionLocations();
103 try (RegionLocator locator
= HTU
.getConnection().getRegionLocator(TableName
.META_TABLE_NAME
)) {
104 locator
.getAllRegionLocations();
107 HMaster master
= HTU
.getHBaseCluster().getMaster();
108 Thread masterThread
= HTU
.getHBaseCluster().getMasterThread();
111 LOG
.info("Waiting until master thread exits");
112 while (masterThread
!= null && masterThread
.isAlive()) {
116 HRegionServer
.TEST_SKIP_REPORTING_TRANSITION
= true;
119 /** Flush the given region in the mini cluster. Since no master, we cannot use HBaseAdmin.flush() */
120 public static void flushRegion(HBaseTestingUtil HTU
, RegionInfo regionInfo
)
122 for (RegionServerThread rst
: HTU
.getMiniHBaseCluster().getRegionServerThreads()) {
123 HRegion region
= rst
.getRegionServer().getRegionByEncodedName(regionInfo
.getEncodedName());
124 if (region
!= null) {
129 throw new IOException("Region to flush cannot be found");
133 public static void afterClass() throws Exception
{
134 HRegionServer
.TEST_SKIP_REPORTING_TRANSITION
= false;
138 HTU
.shutdownMiniCluster();
141 private static HRegionServer
getRS() {
142 return HTU
.getHBaseCluster().getLiveRegionServerThreads().get(0).getRegionServer();
146 public static void openRegion(HBaseTestingUtil HTU
, HRegionServer rs
, RegionInfo hri
)
148 AdminProtos
.OpenRegionRequest orr
=
149 RequestConverter
.buildOpenRegionRequest(rs
.getServerName(), hri
, null);
150 AdminProtos
.OpenRegionResponse responseOpen
= rs
.getRpcServices().openRegion(null, orr
);
152 Assert
.assertTrue(responseOpen
.getOpeningStateCount() == 1);
153 Assert
.assertTrue(responseOpen
.getOpeningState(0).
154 equals(AdminProtos
.OpenRegionResponse
.RegionOpeningState
.OPENED
));
157 checkRegionIsOpened(HTU
, rs
, hri
);
160 public static void checkRegionIsOpened(HBaseTestingUtil HTU
, HRegionServer rs
,
161 RegionInfo hri
) throws Exception
{
162 while (!rs
.getRegionsInTransitionInRS().isEmpty()) {
166 Assert
.assertTrue(rs
.getRegion(hri
.getRegionName()).isAvailable());
169 public static void closeRegion(HBaseTestingUtil HTU
, HRegionServer rs
, RegionInfo hri
)
171 AdminProtos
.CloseRegionRequest crr
= ProtobufUtil
.buildCloseRegionRequest(
172 rs
.getServerName(), hri
.getRegionName());
173 AdminProtos
.CloseRegionResponse responseClose
= rs
.getRpcServices().closeRegion(null, crr
);
174 Assert
.assertTrue(responseClose
.getClosed());
175 checkRegionIsClosed(HTU
, rs
, hri
);
178 public static void checkRegionIsClosed(HBaseTestingUtil HTU
, HRegionServer rs
,
179 RegionInfo hri
) throws Exception
{
180 while (!rs
.getRegionsInTransitionInRS().isEmpty()) {
185 Assert
.assertFalse(rs
.getRegion(hri
.getRegionName()).isAvailable());
186 } catch (NotServingRegionException expected
) {
187 // That's how it work: if the region is closed we have an exception.
192 * Close the region without using ZK
194 private void closeRegionNoZK() throws Exception
{
195 // no transition in ZK
196 AdminProtos
.CloseRegionRequest crr
=
197 ProtobufUtil
.buildCloseRegionRequest(getRS().getServerName(), regionName
);
198 AdminProtos
.CloseRegionResponse responseClose
= getRS().getRpcServices().closeRegion(null, crr
);
199 Assert
.assertTrue(responseClose
.getClosed());
201 // now waiting & checking. After a while, the transition should be done and the region closed
202 checkRegionIsClosed(HTU
, getRS(), hri
);
207 public void testCloseByRegionServer() throws Exception
{
209 openRegion(HTU
, getRS(), hri
);
213 public void testMultipleCloseFromMaster() throws Exception
{
214 for (int i
= 0; i
< 10; i
++) {
215 AdminProtos
.CloseRegionRequest crr
=
216 ProtobufUtil
.buildCloseRegionRequest(getRS().getServerName(), regionName
, null);
218 AdminProtos
.CloseRegionResponse responseClose
=
219 getRS().getRpcServices().closeRegion(null, crr
);
220 Assert
.assertTrue("request " + i
+ " failed",
221 responseClose
.getClosed() || responseClose
.hasClosed());
222 } catch (org
.apache
.hbase
.thirdparty
.com
.google
.protobuf
.ServiceException se
) {
223 Assert
.assertTrue("The next queries may throw an exception.", i
> 0);
227 checkRegionIsClosed(HTU
, getRS(), hri
);
229 openRegion(HTU
, getRS(), hri
);
233 * Test that if we do a close while opening it stops the opening.
236 public void testCancelOpeningWithoutZK() throws Exception
{
239 checkRegionIsClosed(HTU
, getRS(), hri
);
241 // Let do the initial steps, without having a handler
242 getRS().getRegionsInTransitionInRS().put(hri
.getEncodedNameAsBytes(), Boolean
.TRUE
);
244 // That's a close without ZK.
245 AdminProtos
.CloseRegionRequest crr
=
246 ProtobufUtil
.buildCloseRegionRequest(getRS().getServerName(), regionName
);
248 getRS().getRpcServices().closeRegion(null, crr
);
249 Assert
.assertTrue(false);
250 } catch (org
.apache
.hbase
.thirdparty
.com
.google
.protobuf
.ServiceException expected
) {
253 // The state in RIT should have changed to close
254 Assert
.assertEquals(Boolean
.FALSE
, getRS().getRegionsInTransitionInRS().get(
255 hri
.getEncodedNameAsBytes()));
257 // Let's start the open handler
258 TableDescriptor htd
= getRS().getTableDescriptors().get(hri
.getTable());
260 getRS().getExecutorService().submit(new OpenRegionHandler(getRS(), getRS(), hri
, htd
, -1));
262 // The open handler should have removed the region from RIT but kept the region closed
263 checkRegionIsClosed(HTU
, getRS(), hri
);
265 openRegion(HTU
, getRS(), hri
);
269 * Tests an on-the-fly RPC that was scheduled for the earlier RS on the same port
270 * for openRegion. The region server should reject this RPC. (HBASE-9721)
273 public void testOpenCloseRegionRPCIntendedForPreviousServer() throws Exception
{
274 Assert
.assertTrue(getRS().getRegion(regionName
).isAvailable());
276 ServerName sn
= getRS().getServerName();
277 ServerName earlierServerName
= ServerName
.valueOf(sn
.getHostname(), sn
.getPort(), 1);
280 CloseRegionRequest request
= ProtobufUtil
.buildCloseRegionRequest(earlierServerName
, regionName
);
281 getRS().getRSRpcServices().closeRegion(null, request
);
282 Assert
.fail("The closeRegion should have been rejected");
283 } catch (org
.apache
.hbase
.thirdparty
.com
.google
.protobuf
.ServiceException se
) {
284 Assert
.assertTrue(se
.getCause() instanceof IOException
);
285 Assert
.assertTrue(se
.getCause().getMessage().contains("This RPC was intended for a different server"));
291 AdminProtos
.OpenRegionRequest orr
= RequestConverter
.buildOpenRegionRequest(
292 earlierServerName
, hri
, null);
293 getRS().getRSRpcServices().openRegion(null, orr
);
294 Assert
.fail("The openRegion should have been rejected");
295 } catch (org
.apache
.hbase
.thirdparty
.com
.google
.protobuf
.ServiceException se
) {
296 Assert
.assertTrue(se
.getCause() instanceof IOException
);
297 Assert
.assertTrue(se
.getCause().getMessage().contains("This RPC was intended for a different server"));
299 openRegion(HTU
, getRS(), hri
);