View Javadoc

1   /**
2    * Copyright 2010 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.master;
21  
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.executor.HBaseEventHandler.HBaseEventType;
29  import org.apache.hadoop.hbase.master.handler.MasterCloseRegionHandler;
30  import org.apache.hadoop.hbase.master.handler.MasterOpenRegionHandler;
31  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper;
32  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper.ZNodePathAndData;
33  import org.apache.zookeeper.KeeperException;
34  import org.apache.zookeeper.WatchedEvent;
35  import org.apache.zookeeper.Watcher;
36  import org.apache.zookeeper.Watcher.Event.EventType;
37  
38  /**
39   * Watches the UNASSIGNED znode in ZK for the master, and handles all events 
40   * relating to region transitions.
41   */
42  public class ZKUnassignedWatcher implements Watcher {
43    private static final Log LOG = LogFactory.getLog(ZKUnassignedWatcher.class);
44  
45    private ZooKeeperWrapper zkWrapper;
46    String serverName;
47    ServerManager serverManager;
48  
49    public static void start(Configuration conf, HMaster master) 
50    throws IOException {
51      new ZKUnassignedWatcher(conf, master);
52      LOG.debug("Started ZKUnassigned watcher");
53    }
54  
55    public ZKUnassignedWatcher(Configuration conf, HMaster master) 
56    throws IOException {
57      this.serverName = master.getHServerAddress().toString();
58      this.serverManager = master.getServerManager();
59      zkWrapper = ZooKeeperWrapper.getInstance(conf, HMaster.class.getName());
60      String unassignedZNode = zkWrapper.getRegionInTransitionZNode();
61      
62      // If the UNASSIGNED ZNode exists and this is a fresh cluster start, then 
63      // delete it.
64      if(master.isClusterStartup() && zkWrapper.exists(unassignedZNode, false)) {
65        LOG.info("Cluster start, but found " + unassignedZNode + ", deleting it.");
66        try {
67          zkWrapper.deleteZNode(unassignedZNode, true);
68        } catch (KeeperException e) {
69          LOG.error("Could not delete znode " + unassignedZNode, e);
70          throw new IOException(e);
71        } catch (InterruptedException e) {
72          LOG.error("Could not delete znode " + unassignedZNode, e);
73          throw new IOException(e);
74        }
75      }
76      
77      // If the UNASSIGNED ZNode does not exist, create it.
78      zkWrapper.createZNodeIfNotExists(unassignedZNode);
79      
80      // TODO: get the outstanding changes in UNASSIGNED
81  
82      // Set a watch on Zookeeper's UNASSIGNED node if it exists.
83      zkWrapper.registerListener(this);
84    }
85  
86    /**
87     * This is the processing loop that gets triggered from the ZooKeeperWrapper.
88     * This zookeeper events process function dies the following:
89     *   - WATCHES the following events: NodeCreated, NodeDataChanged, NodeChildrenChanged
90     *   - IGNORES the following events: None, NodeDeleted
91     */
92    @Override
93    public synchronized void process(WatchedEvent event) {
94      EventType type = event.getType();
95      LOG.debug("ZK-EVENT-PROCESS: Got zkEvent " + type +
96                " state:" + event.getState() +
97                " path:" + event.getPath());
98  
99      // Handle the ignored events
100     if(type.equals(EventType.None)       ||
101        type.equals(EventType.NodeDeleted)) {
102       return;
103     }
104 
105     // check if the path is for the UNASSIGNED directory we care about
106     if(event.getPath() == null ||
107        !event.getPath().startsWith(zkWrapper.getZNodePathForHBase(
108            zkWrapper.getRegionInTransitionZNode()))) {
109       return;
110     }
111 
112     try
113     {
114       /*
115        * If a node is created in the UNASSIGNED directory in zookeeper, then:
116        *   1. watch its updates (this is an unassigned region).
117        *   2. read to see what its state is and handle as needed (state may have
118        *      changed before we started watching it)
119        */
120       if(type.equals(EventType.NodeCreated)) {
121         zkWrapper.watchZNode(event.getPath());
122         handleRegionStateInZK(event.getPath());
123       }
124       /*
125        * Data on some node has changed. Read to see what the state is and handle
126        * as needed.
127        */
128       else if(type.equals(EventType.NodeDataChanged)) {
129         handleRegionStateInZK(event.getPath());
130       }
131       /*
132        * If there were some nodes created then watch those nodes
133        */
134       else if(type.equals(EventType.NodeChildrenChanged)) {
135         List<ZNodePathAndData> newZNodes =
136             zkWrapper.watchAndGetNewChildren(event.getPath());
137         for(ZNodePathAndData zNodePathAndData : newZNodes) {
138           LOG.debug("Handling updates for znode: " + zNodePathAndData.getzNodePath());
139           handleRegionStateInZK(zNodePathAndData.getzNodePath(),
140               zNodePathAndData.getData());
141         }
142       }
143     }
144     catch (IOException e)
145     {
146       LOG.error("Could not process event from ZooKeeper", e);
147     }
148   }
149 
150   /**
151    * Read the state of a node in ZK, and do the needful. We want to do the
152    * following:
153    *   1. If region's state is updated as CLOSED, invoke the ClosedRegionHandler.
154    *   2. If region's state is updated as OPENED, invoke the OpenRegionHandler.
155    * @param zNodePath
156    * @throws IOException
157    */
158   private void handleRegionStateInZK(String zNodePath) throws IOException {
159     byte[] data = zkWrapper.readZNode(zNodePath, null);
160     handleRegionStateInZK(zNodePath, data);
161   }
162   
163   private void handleRegionStateInZK(String zNodePath, byte[] data) {
164     // a null value is set when a node is created, we don't need to handle this
165     if(data == null) {
166       return;
167     }
168     String rgnInTransitNode = zkWrapper.getRegionInTransitionZNode();
169     String region = zNodePath.substring(
170         zNodePath.indexOf(rgnInTransitNode) + rgnInTransitNode.length() + 1);
171     HBaseEventType rsEvent = HBaseEventType.fromByte(data[0]);
172     LOG.debug("Got event type [ " + rsEvent + " ] for region " + region);
173 
174     // if the node was CLOSED then handle it
175     if(rsEvent == HBaseEventType.RS2ZK_REGION_CLOSED) {
176       new MasterCloseRegionHandler(rsEvent, serverManager, serverName, region, data).submit();
177     }
178     // if the region was OPENED then handle that
179     else if(rsEvent == HBaseEventType.RS2ZK_REGION_OPENED || 
180             rsEvent == HBaseEventType.RS2ZK_REGION_OPENING) {
181       new MasterOpenRegionHandler(rsEvent, serverManager, serverName, region, data).submit();
182     }
183   }
184 }
185