View Javadoc

1   package org.apache.hadoop.hbase.regionserver;
2   
3   import java.io.ByteArrayOutputStream;
4   import java.io.DataOutputStream;
5   import java.io.IOException;
6   
7   import org.apache.commons.logging.Log;
8   import org.apache.commons.logging.LogFactory;
9   import org.apache.hadoop.conf.Configuration;
10  import org.apache.hadoop.hbase.HBaseConfiguration;
11  import org.apache.hadoop.hbase.HMsg;
12  import org.apache.hadoop.hbase.executor.RegionTransitionEventData;
13  import org.apache.hadoop.hbase.executor.HBaseEventHandler;
14  import org.apache.hadoop.hbase.executor.HBaseEventHandler.HBaseEventType;
15  import org.apache.hadoop.hbase.util.Writables;
16  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWrapper;
17  import org.apache.zookeeper.CreateMode;
18  import org.apache.zookeeper.data.Stat;
19  
20  /**
21   * This is a helper class for region servers to update various states in 
22   * Zookeeper. The various updates are abstracted out here. 
23   * 
24   * The "startRegionXXX" methods are to be called first, followed by the 
25   * "finishRegionXXX" methods. Supports updating zookeeper periodically as a 
26   * part of the "startRegionXXX". Currently handles the following state updates:
27   *   - Close region
28   *   - Open region
29   */
30  // TODO: make this thread local, in which case it is re-usable per thread
31  public class RSZookeeperUpdater {
32    private static final Log LOG = LogFactory.getLog(RSZookeeperUpdater.class);
33    private final String regionServerName;
34    private String regionName = null;
35    private String regionZNode = null;
36    private ZooKeeperWrapper zkWrapper = null;
37    private int zkVersion = 0;
38    HBaseEventType lastUpdatedState;
39  
40    public RSZookeeperUpdater(Configuration conf,
41                              String regionServerName, String regionName) {
42      this(conf, regionServerName, regionName, 0);
43    }
44    
45    public RSZookeeperUpdater(Configuration conf, String regionServerName,
46                              String regionName, int zkVersion) {
47      this.zkWrapper = ZooKeeperWrapper.getInstance(conf, regionServerName);
48      this.regionServerName = regionServerName;
49      this.regionName = regionName;
50      // get the region ZNode we have to create
51      this.regionZNode = zkWrapper.getZNode(zkWrapper.getRegionInTransitionZNode(), regionName);
52      this.zkVersion = zkVersion;
53    }
54    
55    /**
56     * This method updates the various states in ZK to inform the master that the 
57     * region server has started closing the region.
58     * @param updatePeriodically - if true, periodically updates the state in ZK
59     */
60    public void startRegionCloseEvent(HMsg hmsg, boolean updatePeriodically) throws IOException {
61      // if this ZNode already exists, something is wrong
62      if(zkWrapper.exists(regionZNode, true)) {
63        String msg = "ZNode " + regionZNode + " already exists in ZooKeeper, will NOT close region.";
64        LOG.error(msg);
65        throw new IOException(msg);
66      }
67      
68      // create the region node in the unassigned directory first
69      zkWrapper.createZNodeIfNotExists(regionZNode, null, CreateMode.PERSISTENT, true);
70  
71      // update the data for "regionName" ZNode in unassigned to CLOSING
72      updateZKWithEventData(HBaseEventType.RS2ZK_REGION_CLOSING, hmsg);
73      
74      // TODO: implement the updatePeriodically logic here
75    }
76  
77    /**
78     * This method updates the states in ZK to signal that the region has been 
79     * closed. This will stop the periodic updater thread if one was started.
80     * @throws IOException
81     */
82    public void finishRegionCloseEvent(HMsg hmsg) throws IOException {    
83      // TODO: stop the updatePeriodically here
84  
85      // update the data for "regionName" ZNode in unassigned to CLOSED
86      updateZKWithEventData(HBaseEventType.RS2ZK_REGION_CLOSED, hmsg);
87    }
88    
89    /**
90     * This method updates the various states in ZK to inform the master that the 
91     * region server has started opening the region.
92     * @param updatePeriodically - if true, periodically updates the state in ZK
93     */
94    public void startRegionOpenEvent(HMsg hmsg, boolean updatePeriodically) throws IOException {
95      Stat stat = new Stat();
96      byte[] data = zkWrapper.readZNode(regionZNode, stat);
97      // if there is no ZNode for this region, something is wrong
98      if(data == null) {
99        String msg = "ZNode " + regionZNode + " does not exist in ZooKeeper, will NOT open region.";
100       LOG.error(msg);
101       throw new IOException(msg);
102     }
103     // if the ZNode is not in the closed state, something is wrong
104     HBaseEventType rsEvent = HBaseEventType.fromByte(data[0]);
105     if(rsEvent != HBaseEventType.RS2ZK_REGION_CLOSED && rsEvent != HBaseEventType.M2ZK_REGION_OFFLINE) {
106       String msg = "ZNode " + regionZNode + " is not in CLOSED/OFFLINE state (state = " + rsEvent + "), will NOT open region.";
107       LOG.error(msg);
108       throw new IOException(msg);
109     }
110 
111     // get the version to update from ZK
112     zkVersion = stat.getVersion();
113 
114     // update the data for "regionName" ZNode in unassigned to CLOSING
115     updateZKWithEventData(HBaseEventType.RS2ZK_REGION_OPENING, hmsg);
116     
117     // TODO: implement the updatePeriodically logic here
118   }
119   
120   /**
121    * This method updates the states in ZK to signal that the region has been 
122    * opened. This will stop the periodic updater thread if one was started.
123    * @throws IOException
124    */
125   public void finishRegionOpenEvent(HMsg hmsg) throws IOException {
126     // TODO: stop the updatePeriodically here
127 
128     // update the data for "regionName" ZNode in unassigned to CLOSED
129     updateZKWithEventData(HBaseEventType.RS2ZK_REGION_OPENED, hmsg);
130   }
131   
132   public boolean isClosingRegion() {
133     return (lastUpdatedState == HBaseEventType.RS2ZK_REGION_CLOSING);
134   }
135 
136   public boolean isOpeningRegion() {
137     return (lastUpdatedState == HBaseEventType.RS2ZK_REGION_OPENING);
138   }
139 
140   public void abortOpenRegion(HMsg hmsg) throws IOException {
141     LOG.error("Aborting open of region " + regionName);
142 
143     // TODO: stop the updatePeriodically for start open region here
144 
145     // update the data for "regionName" ZNode in unassigned to CLOSED
146     updateZKWithEventData(HBaseEventType.RS2ZK_REGION_CLOSED, hmsg);
147   }
148 
149   private void updateZKWithEventData(HBaseEventType hbEventType, HMsg hmsg) throws IOException {
150     // update the data for "regionName" ZNode in unassigned to "hbEventType"
151     byte[] data = null;
152     try {
153       data = Writables.getBytes(new RegionTransitionEventData(hbEventType, regionServerName, hmsg));
154     } catch (IOException e) {
155       LOG.error("Error creating event data for " + hbEventType, e);
156     }
157     LOG.debug("Updating ZNode " + regionZNode + 
158               " with [" + hbEventType + "]" +
159               " expected version = " + zkVersion);
160     lastUpdatedState = hbEventType;
161     zkWrapper.writeZNode(regionZNode, data, zkVersion, true);
162     zkVersion++;
163   }
164 }