View Javadoc

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