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