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.coordination.ZkCoordinatedStateManager;
29  import org.apache.hadoop.hbase.coordination.ZkOpenRegionCoordination;
30  import org.apache.hadoop.hbase.executor.EventType;
31  import org.apache.hadoop.hbase.regionserver.HRegion;
32  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
33  import org.apache.hadoop.hbase.testclassification.MediumTests;
34  import org.apache.hadoop.hbase.util.Bytes;
35  import org.apache.hadoop.hbase.util.MockServer;
36  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
37  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
38  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
39  import org.apache.zookeeper.KeeperException;
40  import org.apache.zookeeper.KeeperException.NodeExistsException;
41  import org.junit.AfterClass;
42  import org.junit.Before;
43  import org.junit.BeforeClass;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  
47  /**
48   * Test of the {@link OpenRegionHandler}.
49   */
50  @Category(MediumTests.class)
51  public class TestOpenRegionHandler {
52    static final Log LOG = LogFactory.getLog(TestOpenRegionHandler.class);
53    private final static HBaseTestingUtility HTU = HBaseTestingUtility.createLocalHTU();
54    private static HTableDescriptor TEST_HTD;
55    private HRegionInfo TEST_HRI;
56  
57    private int testIndex = 0;
58  
59    @BeforeClass public static void before() throws Exception {
60      HTU.getConfiguration().setBoolean("hbase.assignment.usezk", true);
61      HTU.startMiniZKCluster();
62      TEST_HTD = new HTableDescriptor(TableName.valueOf("TestOpenRegionHandler.java"));
63      HColumnDescriptor fam = new HColumnDescriptor("fam");
64      TEST_HTD.addFamily(fam);
65    }
66  
67    @AfterClass public static void after() throws IOException {
68      TEST_HTD = null;
69      HTU.shutdownMiniZKCluster();
70    }
71  
72    /**
73     * Before each test, use a different HRI, so the different tests
74     * don't interfere with each other. This allows us to use just
75     * a single ZK cluster for the whole suite.
76     */
77    @Before
78    public void setupHRI() {
79      TEST_HRI = new HRegionInfo(TEST_HTD.getTableName(),
80        Bytes.toBytes(testIndex),
81        Bytes.toBytes(testIndex + 1));
82      testIndex++;
83    }
84  
85    /**
86     * Test the openregionhandler can deal with its znode being yanked out from
87     * under it.
88     * @see <a href="https://issues.apache.org/jira/browse/HBASE-3627">HBASE-3627</a>
89     * @throws IOException
90     * @throws NodeExistsException
91     * @throws KeeperException
92     */
93    @Test public void testYankingRegionFromUnderIt()
94    throws IOException, NodeExistsException, KeeperException {
95      final Server server = new MockServer(HTU);
96      final RegionServerServices rss = HTU.createMockRegionServerService();
97  
98      HTableDescriptor htd = TEST_HTD;
99      final HRegionInfo hri = TEST_HRI;
100     HRegion region =
101          HRegion.createHRegion(hri, HTU.getDataTestDir(), HTU
102             .getConfiguration(), htd);
103     assertNotNull(region);
104     try {
105       ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
106       csm.initialize(server);
107       csm.start();
108 
109       ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
110         new ZkOpenRegionCoordination.ZkOpenRegionDetails();
111       zkCrd.setServerName(server.getServerName());
112 
113       OpenRegionHandler handler = new OpenRegionHandler(server, rss, hri,
114         htd, -1, csm.getOpenRegionCoordination(), zkCrd) {
115         HRegion openRegion() {
116           // Open region first, then remove znode as though it'd been hijacked.
117           HRegion region = super.openRegion();
118 
119           // Don't actually open region BUT remove the znode as though it'd
120           // been hijacked on us.
121           ZooKeeperWatcher zkw = this.server.getZooKeeper();
122           String node = ZKAssign.getNodeName(zkw, hri.getEncodedName());
123           try {
124             ZKUtil.deleteNodeFailSilent(zkw, node);
125           } catch (KeeperException e) {
126             throw new RuntimeException("Ugh failed delete of " + node, e);
127           }
128           return region;
129         }
130       };
131       rss.getRegionsInTransitionInRS().put(
132         hri.getEncodedNameAsBytes(), Boolean.TRUE);
133       // Call process without first creating OFFLINE region in zk, see if
134       // exception or just quiet return (expected).
135       handler.process();
136       rss.getRegionsInTransitionInRS().put(
137         hri.getEncodedNameAsBytes(), Boolean.TRUE);
138       ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName());
139       // Call process again but this time yank the zk znode out from under it
140       // post OPENING; again will expect it to come back w/o NPE or exception.
141       handler.process();
142     } finally {
143       HRegion.closeHRegion(region);
144     }
145   }
146   
147   /**
148    * Test the openregionhandler can deal with perceived failure of transitioning to OPENED state
149    * due to intermittent zookeeper malfunctioning.
150    * @see <a href="https://issues.apache.org/jira/browse/HBASE-9387">HBASE-9387</a>
151    * @throws IOException
152    * @throws NodeExistsException
153    * @throws KeeperException
154    */
155   @Test
156   public void testRegionServerAbortionDueToFailureTransitioningToOpened()
157       throws IOException, NodeExistsException, KeeperException {
158     final Server server = new MockServer(HTU);
159     final RegionServerServices rss = HTU.createMockRegionServerService();
160 
161     HTableDescriptor htd = TEST_HTD;
162     final HRegionInfo hri = TEST_HRI;
163     HRegion region =
164          HRegion.createHRegion(hri, HTU.getDataTestDir(), HTU
165             .getConfiguration(), htd);
166     assertNotNull(region);
167     try {
168 
169       ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
170       csm.initialize(server);
171       csm.start();
172 
173       ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
174         new ZkOpenRegionCoordination.ZkOpenRegionDetails();
175       zkCrd.setServerName(server.getServerName());
176 
177       ZkOpenRegionCoordination openRegionCoordination =
178         new ZkOpenRegionCoordination(csm, server.getZooKeeper()) {
179         @Override
180         public boolean transitionToOpened(final HRegion r, OpenRegionDetails ord)
181             throws IOException {
182           // remove znode simulating intermittent zookeeper connection issue
183           ZooKeeperWatcher zkw = server.getZooKeeper();
184           String node = ZKAssign.getNodeName(zkw, hri.getEncodedName());
185           try {
186             ZKUtil.deleteNodeFailSilent(zkw, node);
187           } catch (KeeperException e) {
188             throw new RuntimeException("Ugh failed delete of " + node, e);
189           }
190           // then try to transition to OPENED
191           return super.transitionToOpened(r, ord);
192         }
193       };
194 
195       OpenRegionHandler handler = new OpenRegionHandler(server, rss, hri, htd,
196         -1, openRegionCoordination, zkCrd);
197       rss.getRegionsInTransitionInRS().put(
198         hri.getEncodedNameAsBytes(), Boolean.TRUE);
199       // Call process without first creating OFFLINE region in zk, see if
200       // exception or just quiet return (expected).
201       handler.process();
202       rss.getRegionsInTransitionInRS().put(
203         hri.getEncodedNameAsBytes(), Boolean.TRUE);
204       ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName());
205       // Call process again but this time yank the zk znode out from under it
206       // post OPENING; again will expect it to come back w/o NPE or exception.
207       handler.process();
208     } catch (IOException ioe) {
209     } finally {
210       HRegion.closeHRegion(region);
211     }
212     // Region server is expected to abort due to OpenRegionHandler perceiving transitioning
213     // to OPENED as failed
214     // This was corresponding to the second handler.process() call above.
215     assertTrue("region server should have aborted", server.isAborted());
216   }
217   
218   @Test
219   public void testFailedOpenRegion() throws Exception {
220     Server server = new MockServer(HTU);
221     RegionServerServices rsServices = HTU.createMockRegionServerService();
222 
223     // Create it OFFLINE, which is what it expects
224     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
225 
226     ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
227     csm.initialize(server);
228     csm.start();
229 
230     ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
231       new ZkOpenRegionCoordination.ZkOpenRegionDetails();
232     zkCrd.setServerName(server.getServerName());
233 
234     // Create the handler
235     OpenRegionHandler handler =
236       new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD, -1,
237         csm.getOpenRegionCoordination(), zkCrd) {
238         @Override
239         HRegion openRegion() {
240           // Fake failure of opening a region due to an IOE, which is caught
241           return null;
242         }
243     };
244     rsServices.getRegionsInTransitionInRS().put(
245       TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
246     handler.process();
247 
248     // Handler should have transitioned it to FAILED_OPEN
249     RegionTransition rt = RegionTransition.parseFrom(
250       ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName()));
251     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
252   }
253   
254   @Test
255   public void testFailedUpdateMeta() throws Exception {
256     Server server = new MockServer(HTU);
257     RegionServerServices rsServices = HTU.createMockRegionServerService();
258 
259     // Create it OFFLINE, which is what it expects
260     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
261 
262     // Create the handler
263     ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
264     csm.initialize(server);
265     csm.start();
266 
267     ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
268       new ZkOpenRegionCoordination.ZkOpenRegionDetails();
269     zkCrd.setServerName(server.getServerName());
270 
271     OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD,
272       -1, csm.getOpenRegionCoordination(), zkCrd) {
273         @Override
274         boolean updateMeta(final HRegion r, long masterSystemTime) {
275           // Fake failure of updating META
276           return false;
277         }
278     };
279     rsServices.getRegionsInTransitionInRS().put(
280       TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
281     handler.process();
282 
283     // Handler should have transitioned it to FAILED_OPEN
284     RegionTransition rt = RegionTransition.parseFrom(
285       ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName()));
286     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
287   }
288   
289   @Test
290   public void testTransitionToFailedOpenEvenIfCleanupFails() throws Exception {
291     Server server = new MockServer(HTU);
292     RegionServerServices rsServices = HTU.createMockRegionServerService();
293     // Create it OFFLINE, which is what it expects
294     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
295     // Create the handler
296     ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
297     csm.initialize(server);
298     csm.start();
299 
300     ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
301       new ZkOpenRegionCoordination.ZkOpenRegionDetails();
302     zkCrd.setServerName(server.getServerName());
303 
304     OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD,
305       -1, csm.getOpenRegionCoordination(), zkCrd) {
306       @Override
307       boolean updateMeta(HRegion r, long masterSystemTime) {
308         return false;
309       };
310 
311       @Override
312       void cleanupFailedOpen(HRegion region) throws IOException {
313         throw new IOException("FileSystem got closed.");
314       }
315     };
316     rsServices.getRegionsInTransitionInRS().put(TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
317     try {
318       handler.process();
319     } catch (Exception e) {
320       // Ignore the IOException that we have thrown from cleanupFailedOpen
321     }
322     RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(),
323         TEST_HRI.getEncodedName()));
324     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
325   }
326 
327   @Test
328   public void testTransitionToFailedOpenFromOffline() throws Exception {
329     Server server = new MockServer(HTU);
330     RegionServerServices rsServices = HTU.createMockRegionServerService(server.getServerName());
331     // Create it OFFLINE, which is what it expects
332     ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
333     // Create the handler
334     ZkCoordinatedStateManager csm = new ZkCoordinatedStateManager();
335     csm.initialize(server);
336     csm.start();
337 
338     ZkOpenRegionCoordination.ZkOpenRegionDetails zkCrd =
339       new ZkOpenRegionCoordination.ZkOpenRegionDetails();
340     zkCrd.setServerName(server.getServerName());
341 
342     ZkOpenRegionCoordination openRegionCoordination =
343       new ZkOpenRegionCoordination(csm, server.getZooKeeper()) {
344       @Override
345       public boolean transitionFromOfflineToOpening(HRegionInfo regionInfo,
346                                                     OpenRegionDetails ord) {
347         return false;
348       }
349     };
350 
351     OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD,
352       -1, openRegionCoordination, zkCrd);
353     rsServices.getRegionsInTransitionInRS().put(TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
354 
355     handler.process();
356 
357     RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(),
358         TEST_HRI.getEncodedName()));
359     assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
360   }
361 
362 }
363