View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.master;
19  
20  import static org.junit.Assert.assertNotSame;
21  
22  import org.apache.hadoop.hbase.exceptions.DeserializationException;
23  import org.apache.hadoop.hbase.HRegionInfo;
24  import org.apache.hadoop.hbase.RegionTransition;
25  import org.apache.hadoop.hbase.ServerName;
26  import org.apache.hadoop.hbase.executor.EventType;
27  import org.apache.hadoop.hbase.master.RegionState.State;
28  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
29  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
30  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
31  import org.apache.zookeeper.KeeperException;
32  
33  /**
34   * Package scoped mocking utility.
35   */
36  public class Mocking {
37  
38    static void waitForRegionFailedToCloseAndSetToPendingClose(
39        AssignmentManager am, HRegionInfo hri) throws InterruptedException {
40      // Since region server is fake, sendRegionClose will fail, and closing
41      // region will fail. For testing purpose, moving it back to pending close
42      boolean wait = true;
43      while (wait) {
44        RegionState state = am.getRegionStates().getRegionState(hri);
45        if (state != null && state.isFailedClose()){
46          am.getRegionStates().updateRegionState(hri, State.PENDING_CLOSE);
47          wait = false;
48        } else {
49          Thread.sleep(1);
50        }
51      }
52    }
53  
54    static void waitForRegionPendingOpenInRIT(AssignmentManager am, String encodedName)
55      throws InterruptedException {
56      // We used to do a check like this:
57      //!Mocking.verifyRegionState(this.watcher, REGIONINFO, EventType.M_ZK_REGION_OFFLINE)) {
58      // There is a race condition with this: because we may do the transition to
59      // RS_ZK_REGION_OPENING before the RIT is internally updated. We need to wait for the
60      // RIT to be as we need it to be instead. This cannot happen in a real cluster as we
61      // update the RIT before sending the openRegion request.
62  
63      boolean wait = true;
64      while (wait) {
65        RegionState state = am.getRegionStates()
66          .getRegionsInTransition().get(encodedName);
67        if (state != null && state.isPendingOpen()){
68          wait = false;
69        } else {
70          Thread.sleep(1);
71        }
72      }
73    }
74  
75    /**
76     * Fakes the regionserver-side zk transitions of a region open.
77     * @param w ZooKeeperWatcher to use.
78     * @param sn Name of the regionserver doing the 'opening'
79     * @param hri Region we're 'opening'.
80     * @throws KeeperException
81     * @throws DeserializationException
82     */
83    static void fakeRegionServerRegionOpenInZK(HMaster master,  final ZooKeeperWatcher w,
84        final ServerName sn, final HRegionInfo hri)
85      throws KeeperException, DeserializationException, InterruptedException {
86      // Wait till the we region is ready to be open in RIT.
87      waitForRegionPendingOpenInRIT(master.getAssignmentManager(), hri.getEncodedName());
88  
89      // Get current versionid else will fail on transition from OFFLINE to OPENING below
90      int versionid = ZKAssign.getVersion(w, hri);
91      assertNotSame(-1, versionid);
92      // This uglyness below is what the openregionhandler on RS side does.  I
93      // looked at exposing the method over in openregionhandler but its just a
94      // one liner and its deep over in another package so just repeat it below.
95      versionid = ZKAssign.transitionNode(w, hri, sn,
96        EventType.M_ZK_REGION_OFFLINE, EventType.RS_ZK_REGION_OPENING, versionid);
97      assertNotSame(-1, versionid);
98      // Move znode from OPENING to OPENED as RS does on successful open.
99      versionid = ZKAssign.transitionNodeOpened(w, hri, sn, versionid);
100     assertNotSame(-1, versionid);
101     // We should be done now.  The master open handler will notice the
102     // transition and remove this regions znode.
103   }
104 
105   /**
106    * Verifies that the specified region is in the specified state in ZooKeeper.
107    * <p>
108    * Returns true if region is in transition and in the specified state in
109    * ZooKeeper.  Returns false if the region does not exist in ZK or is in
110    * a different state.
111    * <p>
112    * Method synchronizes() with ZK so will yield an up-to-date result but is
113    * a slow read.
114    * @param zkw
115    * @param region
116    * @param expectedState
117    * @return true if region exists and is in expected state
118    * @throws DeserializationException
119    */
120   static boolean verifyRegionState(ZooKeeperWatcher zkw, HRegionInfo region, EventType expectedState)
121   throws KeeperException, DeserializationException {
122     String encoded = region.getEncodedName();
123 
124     String node = ZKAssign.getNodeName(zkw, encoded);
125     zkw.sync(node);
126 
127     // Read existing data of the node
128     byte [] existingBytes = null;
129     try {
130       existingBytes = ZKUtil.getDataAndWatch(zkw, node);
131     } catch (KeeperException.NoNodeException nne) {
132       return false;
133     } catch (KeeperException e) {
134       throw e;
135     }
136     if (existingBytes == null) return false;
137     RegionTransition rt = RegionTransition.parseFrom(existingBytes);
138     return rt.getEventType().equals(expectedState);
139   }
140 }