1 /**
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18 package org.apache.hadoop.hbase.master;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.mockito.Mockito.when;
24 
25 import java.io.IOException;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29 
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.*;
34 import org.apache.hadoop.hbase.coordination.BaseCoordinatedStateManager;
35 import org.apache.hadoop.hbase.coordination.OpenRegionCoordination;
36 import org.apache.hadoop.hbase.coordination.ZkCoordinatedStateManager;
37 import org.apache.hadoop.hbase.coordination.ZkOpenRegionCoordination;
38 import org.apache.hadoop.hbase.executor.EventType;
39 import org.apache.hadoop.hbase.master.handler.OpenedRegionHandler;
40 import org.apache.hadoop.hbase.regionserver.HRegion;
41 import org.apache.hadoop.hbase.regionserver.HRegionServer;
42 import org.apache.hadoop.hbase.regionserver.Region;
43 import org.apache.hadoop.hbase.testclassification.MediumTests;
44 import org.apache.hadoop.hbase.util.Bytes;
45 import org.apache.hadoop.hbase.util.MockServer;
46 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
47 import org.apache.hadoop.hbase.zookeeper.ZKTableStateManager;
48 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
49 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
50 import org.apache.zookeeper.KeeperException;
51 import org.apache.zookeeper.data.Stat;
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.experimental.categories.Category;
56 import org.mockito.Mockito;
57 
58 @Category(MediumTests.class)
59 public class TestOpenedRegionHandler {
60 
61   private static final Log LOG = LogFactory
62       .getLog(TestOpenedRegionHandler.class);
63 
64   private HBaseTestingUtility TEST_UTIL;
65   private final int NUM_MASTERS = 1;
66   private final int NUM_RS = 1;
67   private Configuration conf;
68   private Configuration resetConf;
69   private ZooKeeperWatcher zkw;
70 
71   @Before
setUp()72   public void setUp() throws Exception {
73     conf = HBaseConfiguration.create();
74     conf.setBoolean("hbase.assignment.usezk", true);
75     TEST_UTIL = HBaseTestingUtility.createLocalHTU(conf);
76   }
77 
78   @After
tearDown()79   public void tearDown() throws Exception {
80     // Stop the cluster
81     TEST_UTIL.shutdownMiniCluster();
82     TEST_UTIL = new HBaseTestingUtility(resetConf);
83   }
84 
85   @Test
testOpenedRegionHandlerOnMasterRestart()86   public void testOpenedRegionHandlerOnMasterRestart() throws Exception {
87     // Start the cluster
88     log("Starting cluster");
89     conf = HBaseConfiguration.create();
90     conf.setBoolean("hbase.assignment.usezk", true);
91     resetConf = conf;
92     TEST_UTIL = new HBaseTestingUtility(conf);
93     TEST_UTIL.startMiniCluster(NUM_MASTERS, NUM_RS);
94     String tableName = "testOpenedRegionHandlerOnMasterRestart";
95     MiniHBaseCluster cluster = createRegions(tableName);
96     abortMaster(cluster);
97 
98     HRegionServer regionServer = cluster.getRegionServer(0);
99     Region region = getRegionBeingServed(cluster, regionServer);
100 
101     // forcefully move a region to OPENED state in zk
102     // Create a ZKW to use in the test
103     zkw = HBaseTestingUtility.createAndForceNodeToOpenedState(TEST_UTIL,
104         region, regionServer.getServerName());
105 
106     // Start up a new master
107     log("Starting up a new master");
108     cluster.startMaster().getMaster();
109     log("Waiting for master to be ready");
110     cluster.waitForActiveAndReadyMaster();
111     log("Master is ready");
112 
113     // Failover should be completed, now wait for no RIT
114     log("Waiting for no more RIT");
115     ZKAssign.blockUntilNoRIT(zkw);
116   }
117   @Test
testShouldNotCompeleteOpenedRegionSuccessfullyIfVersionMismatches()118   public void testShouldNotCompeleteOpenedRegionSuccessfullyIfVersionMismatches()
119       throws Exception {
120     HRegion region = null;
121     try {
122       int testIndex = 0;
123       TEST_UTIL.startMiniZKCluster();
124       final Server server = new MockServer(TEST_UTIL);
125       HTableDescriptor htd = new HTableDescriptor(
126           TableName.valueOf("testShouldNotCompeleteOpenedRegionSuccessfullyIfVersionMismatches"));
127       HRegionInfo hri = new HRegionInfo(htd.getTableName(),
128           Bytes.toBytes(testIndex), Bytes.toBytes(testIndex + 1));
129       region = HRegion.createHRegion(hri, TEST_UTIL.getDataTestDir(), TEST_UTIL.getConfiguration(), htd);
130       assertNotNull(region);
131       AssignmentManager am = Mockito.mock(AssignmentManager.class);
132       RegionStates rsm = Mockito.mock(RegionStates.class);
133       Mockito.doReturn(rsm).when(am).getRegionStates();
134       when(rsm.isRegionInTransition(hri)).thenReturn(false);
135       when(rsm.getRegionState(hri)).thenReturn(
136         new RegionState(region.getRegionInfo(), RegionState.State.OPEN,
137           System.currentTimeMillis(), server.getServerName()));
138       // create a node with OPENED state
139       zkw = HBaseTestingUtility.createAndForceNodeToOpenedState(TEST_UTIL,
140           region, server.getServerName());
141       when(am.getTableStateManager()).thenReturn(new ZKTableStateManager(zkw));
142       Stat stat = new Stat();
143       String nodeName = ZKAssign.getNodeName(zkw, region.getRegionInfo()
144           .getEncodedName());
145       ZKUtil.getDataAndWatch(zkw, nodeName, stat);
146 
147       // use the version for the OpenedRegionHandler
148       BaseCoordinatedStateManager csm = new ZkCoordinatedStateManager();
149       csm.initialize(server);
150       csm.start();
151 
152       OpenRegionCoordination orc = csm.getOpenRegionCoordination();
153       ZkOpenRegionCoordination.ZkOpenRegionDetails zkOrd =
154         new ZkOpenRegionCoordination.ZkOpenRegionDetails();
155       zkOrd.setServerName(server.getServerName());
156       zkOrd.setVersion(stat.getVersion());
157       OpenedRegionHandler handler = new OpenedRegionHandler(server, am, region
158           .getRegionInfo(), orc, zkOrd);
159       // Once again overwrite the same znode so that the version changes.
160       ZKAssign.transitionNode(zkw, region.getRegionInfo(), server
161           .getServerName(), EventType.RS_ZK_REGION_OPENED,
162           EventType.RS_ZK_REGION_OPENED, stat.getVersion());
163 
164       // Should not invoke assignmentmanager.regionOnline. If it is
165       // invoked as per current mocking it will throw null pointer exception.
166       boolean expectedException = false;
167       try {
168         handler.process();
169       } catch (Exception e) {
170         expectedException = true;
171       }
172       assertFalse("The process method should not throw any exception.",
173           expectedException);
174       List<String> znodes = ZKUtil.listChildrenAndWatchForNewChildren(zkw,
175           zkw.assignmentZNode);
176       String regionName = znodes.get(0);
177       assertEquals("The region should not be opened successfully.", regionName,
178           region.getRegionInfo().getEncodedName());
179     } finally {
180       HRegion.closeHRegion(region);
181       TEST_UTIL.shutdownMiniZKCluster();
182     }
183   }
createRegions(String tableName)184   private MiniHBaseCluster createRegions(String tableName)
185       throws InterruptedException, ZooKeeperConnectionException, IOException,
186       KeeperException {
187     MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
188     log("Waiting for active/ready master");
189     cluster.waitForActiveAndReadyMaster();
190     zkw = new ZooKeeperWatcher(conf, "testOpenedRegionHandler", null);
191 
192     // Create a table with regions
193     byte[] table = Bytes.toBytes(tableName);
194     byte[] family = Bytes.toBytes("family");
195     TEST_UTIL.createTable(table, family);
196 
197     //wait till the regions are online
198     log("Waiting for no more RIT");
199     ZKAssign.blockUntilNoRIT(zkw);
200 
201     return cluster;
202   }
abortMaster(MiniHBaseCluster cluster)203   private void abortMaster(MiniHBaseCluster cluster) {
204     // Stop the master
205     log("Aborting master");
206     cluster.abortMaster(0);
207     cluster.waitOnMaster(0);
208     log("Master has aborted");
209   }
getRegionBeingServed(MiniHBaseCluster cluster, HRegionServer regionServer)210   private Region getRegionBeingServed(MiniHBaseCluster cluster,
211       HRegionServer regionServer) {
212     Collection<Region> onlineRegionsLocalContext = regionServer
213         .getOnlineRegionsLocalContext();
214     Iterator<Region> iterator = onlineRegionsLocalContext.iterator();
215     Region region = null;
216     while (iterator.hasNext()) {
217       region = iterator.next();
218       if (!region.getRegionInfo().isMetaTable()) {
219         break;
220       }
221     }
222     return region;
223   }
log(String msg)224   private void log(String msg) {
225     LOG.debug("\n\nTRR: " + msg + "\n");
226   }
227 
228 }
229 
230