1   /**
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.regionserver.handler;
21  
22  import static org.junit.Assert.*;
23  
24  import java.io.IOException;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.Server;
32  import org.apache.hadoop.hbase.executor.RegionTransitionData;
33  import org.apache.hadoop.hbase.executor.EventHandler.EventType;
34  import org.apache.hadoop.hbase.regionserver.HRegion;
35  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.hbase.util.MockRegionServerServices;
38  import org.apache.hadoop.hbase.util.MockServer;
39  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
40  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
41  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
42  import org.apache.zookeeper.KeeperException;
43  import org.apache.zookeeper.KeeperException.NodeExistsException;
44  import org.junit.AfterClass;
45  import org.junit.Before;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  
49  /**
50   * Test of the {@link OpenRegionHandler}.
51   */
52  public class TestOpenRegionHandler {
53    static final Log LOG = LogFactory.getLog(TestOpenRegionHandler.class);
54    private final static HBaseTestingUtility HTU = new HBaseTestingUtility();
55    private static HTableDescriptor TEST_HTD;
56    private HRegionInfo TEST_HRI;
57  
58    private int testIndex = 0;
59  
60    @BeforeClass public static void before() throws Exception {
61      HTU.startMiniZKCluster();
62      TEST_HTD = new HTableDescriptor("TestOpenRegionHandler.java");
63    }
64  
65    @AfterClass public static void after() throws IOException {
66      TEST_HTD = null;
67      HTU.shutdownMiniZKCluster();
68    }
69  
70    /**
71     * Before each test, use a different HRI, so the different tests
72     * don't interfere with each other. This allows us to use just
73     * a single ZK cluster for the whole suite.
74     */
75    @Before
76    public void setupHRI() {
77      TEST_HRI = new HRegionInfo(TEST_HTD.getName(),
78        Bytes.toBytes(testIndex),
79        Bytes.toBytes(testIndex + 1));
80      testIndex++;
81    }
82  
83    /**
84     * Test the openregionhandler can deal with its znode being yanked out from
85     * under it.
86     * @see <a href="https://issues.apache.org/jira/browse/HBASE-3627">HBASE-3627</a>
87     * @throws IOException
88     * @throws NodeExistsException
89     * @throws KeeperException
90     */
91    @Test public void testYankingRegionFromUnderIt()
92    throws IOException, NodeExistsException, KeeperException {
93      final Server server = new MockServer(HTU);
94      final RegionServerServices rss = new MockRegionServerServices();
95  
96      HTableDescriptor htd = TEST_HTD;
97      final HRegionInfo hri = TEST_HRI;
98      HRegion region =
99           HRegion.createHRegion(hri, HTU.getDataTestDir(), HTU
100             .getConfiguration(), htd);
101     assertNotNull(region);
102     OpenRegionHandler handler = new OpenRegionHandler(server, rss, hri, htd) {
103       HRegion openRegion() {
104         // Open region first, then remove znode as though it'd been hijacked.
105         HRegion region = super.openRegion();
106         
107         // Don't actually open region BUT remove the znode as though it'd
108         // been hijacked on us.
109         ZooKeeperWatcher zkw = this.server.getZooKeeper();
110         String node = ZKAssign.getNodeName(zkw, hri.getEncodedName());
111         try {
112           ZKUtil.deleteNodeFailSilent(zkw, node);
113         } catch (KeeperException e) {
114           throw new RuntimeException("Ugh failed delete of " + node, e);
115         }
116         return region;
117       }
118     };
119     // Call process without first creating OFFLINE region in zk, see if
120     // exception or just quiet return (expected).
121     handler.process();
122     ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName());
123     // Call process again but this time yank the zk znode out from under it
124     // post OPENING; again will expect it to come back w/o NPE or exception.
125     handler.process();
126   }
127   
128   @Test
129   public void testFailedOpenRegion() throws Exception {
130     Server server = new MockServer(HTU);
131     RegionServerServices rsServices = new MockRegionServerServices();
132 
133     // Create it OFFLINE, which is what it expects
134     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
135 
136     // Create the handler
137     OpenRegionHandler handler =
138       new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) {
139         @Override
140         HRegion openRegion() {
141           // Fake failure of opening a region due to an IOE, which is caught
142           return null;
143         }
144     };
145     handler.process();
146 
147     // Handler should have transitioned it to FAILED_OPEN
148     RegionTransitionData data =
149       ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName());
150     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, data.getEventType());
151   }
152   
153   @Test
154   public void testFailedUpdateMeta() throws Exception {
155     Server server = new MockServer(HTU);
156     RegionServerServices rsServices = new MockRegionServerServices();
157 
158     // Create it OFFLINE, which is what it expects
159     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
160 
161     // Create the handler
162     OpenRegionHandler handler =
163       new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) {
164         @Override
165         boolean updateMeta(final HRegion r) {
166           // Fake failure of updating META
167           return false;
168         }
169     };
170     handler.process();
171 
172     // Handler should have transitioned it to FAILED_OPEN
173     RegionTransitionData data =
174       ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName());
175     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, data.getEventType());
176   }
177   
178 }