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 java.io.IOException;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.HServerInfo;
33  import org.apache.hadoop.hbase.HTableDescriptor;
34  import org.apache.hadoop.hbase.Server;
35  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
36  import org.apache.hadoop.hbase.catalog.CatalogTracker;
37  import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
38  import org.apache.hadoop.hbase.regionserver.CompactionRequestor;
39  import org.apache.hadoop.hbase.regionserver.FlushRequester;
40  import org.apache.hadoop.hbase.regionserver.HRegion;
41  import org.apache.hadoop.hbase.regionserver.RegionServerServices;
42  import org.apache.hadoop.hbase.regionserver.wal.HLog;
43  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
44  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
45  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
46  import org.apache.zookeeper.KeeperException;
47  import org.apache.zookeeper.KeeperException.NodeExistsException;
48  import org.junit.AfterClass;
49  import org.junit.BeforeClass;
50  import org.junit.Test;
51  
52  /**
53   * Test of the {@link OpenRegionHandler}.
54   */
55  public class TestOpenRegionHandler {
56    private static final Log LOG = LogFactory.getLog(TestOpenRegionHandler.class);
57    private final static HBaseTestingUtility HTU = new HBaseTestingUtility();
58  
59    @BeforeClass public static void before() throws Exception {
60      HTU.startMiniZKCluster();
61    }
62  
63    @AfterClass public static void after() throws IOException {
64      HTU.shutdownMiniZKCluster();
65    }
66  
67    /**
68     * Basic mock Server
69     */
70    static class MockServer implements Server {
71      boolean stopped = false;
72      final static String NAME = "MockServer";
73      final ZooKeeperWatcher zk;
74  
75      MockServer() throws ZooKeeperConnectionException, IOException {
76        this.zk =  new ZooKeeperWatcher(HTU.getConfiguration(), NAME, this);
77      }
78  
79      @Override
80      public void abort(String why, Throwable e) {
81        LOG.fatal("Abort why=" + why, e);
82        this.stopped = true;
83      }
84  
85      @Override
86      public void stop(String why) {
87        LOG.debug("Stop why=" + why);
88        this.stopped = true;
89      }
90  
91      @Override
92      public boolean isStopped() {
93        return this.stopped;
94      }
95  
96      @Override
97      public Configuration getConfiguration() {
98        return HTU.getConfiguration();
99      }
100 
101     @Override
102     public ZooKeeperWatcher getZooKeeper() {
103       return this.zk;
104     }
105 
106     @Override
107     public CatalogTracker getCatalogTracker() {
108       // TODO Auto-generated method stub
109       return null;
110     }
111 
112     @Override
113     public String getServerName() {
114       return NAME;
115     }
116   }
117 
118   /**
119    * Basic mock region server services.
120    */
121   static class MockRegionServerServices implements RegionServerServices {
122     final Map<String, HRegion> regions = new HashMap<String, HRegion>();
123     boolean stopping = false;
124 
125     @Override
126     public boolean removeFromOnlineRegions(String encodedRegionName) {
127       return this.regions.remove(encodedRegionName) != null;
128     }
129     
130     @Override
131     public HRegion getFromOnlineRegions(String encodedRegionName) {
132       return this.regions.get(encodedRegionName);
133     }
134     
135     @Override
136     public void addToOnlineRegions(HRegion r) {
137       this.regions.put(r.getRegionInfo().getEncodedName(), r);
138     }
139     
140     @Override
141     public void postOpenDeployTasks(HRegion r, CatalogTracker ct, boolean daughter)
142         throws KeeperException, IOException {
143     }
144     
145     @Override
146     public boolean isStopping() {
147       return this.stopping;
148     }
149     
150     @Override
151     public HLog getWAL() {
152       return null;
153     }
154     
155     @Override
156     public HServerInfo getServerInfo() {
157       return null;
158     }
159     
160     @Override
161     public HBaseRpcMetrics getRpcMetrics() {
162       return null;
163     }
164     
165     @Override
166     public FlushRequester getFlushRequester() {
167       return null;
168     }
169     
170     @Override
171     public CompactionRequestor getCompactionRequester() {
172       return null;
173     }
174   };
175 
176   /**
177    * Test the openregionhandler can deal with its znode being yanked out from
178    * under it.
179    * @see <a href="https://issues.apache.org/jira/browse/HBASE-3627">HBASE-3627</a>
180    * @throws IOException
181    * @throws NodeExistsException
182    * @throws KeeperException
183    */
184   @Test public void testOpenRegionHandlerYankingRegionFromUnderIt()
185   throws IOException, NodeExistsException, KeeperException {
186     final Server server = new MockServer();
187     final RegionServerServices rss = new MockRegionServerServices();
188 
189     HTableDescriptor htd =
190       new HTableDescriptor("testOpenRegionHandlerYankingRegionFromUnderIt");
191     final HRegionInfo hri =
192       new HRegionInfo(htd, HConstants.EMPTY_END_ROW, HConstants.EMPTY_END_ROW);
193     OpenRegionHandler handler = new OpenRegionHandler(server, rss, hri) {
194       HRegion openRegion() {
195         // Open region first, then remove znode as though it'd been hijacked.
196         HRegion region = super.openRegion();
197         // Don't actually open region BUT remove the znode as though it'd
198         // been hijacked on us.
199         ZooKeeperWatcher zkw = this.server.getZooKeeper();
200         String node = ZKAssign.getNodeName(zkw, hri.getEncodedName());
201         try {
202           ZKUtil.deleteNodeFailSilent(zkw, node);
203         } catch (KeeperException e) {
204           throw new RuntimeException("Ugh failed delete of " + node, e);
205         }
206         return region;
207       }
208     };
209     // Call process without first creating OFFLINE region in zk, see if
210     // exception or just quiet return (expected).
211     handler.process();
212     ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName());
213     // Call process again but this time yank the zk znode out from under it
214     // post OPENING; again will expect it to come back w/o NPE or exception.
215     handler.process();
216   }
217 }