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.zookeeper;
19  
20  import org.apache.hadoop.classification.InterfaceAudience;
21  import org.apache.hadoop.hbase.Abortable;
22  import org.apache.hadoop.hbase.HConstants;
23  import org.apache.hadoop.hbase.exceptions.DeserializationException;
24  import org.apache.hadoop.hbase.ServerName;
25  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
26  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
27  import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
28  import org.apache.zookeeper.KeeperException;
29  
30  /**
31   * Tracks the meta region server location node in zookeeper.
32   * Meta region location is set by <code>RegionServerServices</code>.
33   * This class has a watcher on the meta location and notices changes.
34   */
35  @InterfaceAudience.Private
36  public class MetaRegionTracker extends ZooKeeperNodeTracker {
37    /**
38     * Creates a meta region location tracker.
39     *
40     * <p>After construction, use {@link #start} to kick off tracking.
41     *
42     * @param watcher
43     * @param abortable
44     */
45    public MetaRegionTracker(ZooKeeperWatcher watcher, Abortable abortable) {
46      super(watcher, watcher.metaServerZNode, abortable);
47    }
48  
49    /**
50     * Checks if the meta region location is available.
51     * @return true if meta region location is available, false if not
52     */
53    public boolean isLocationAvailable() {
54      return super.getData(true) != null;
55    }
56  
57    /**
58     * Gets the meta region location, if available.  Does not block.  Sets a watcher.
59     * @return server name or null if we failed to get the data.
60     * @throws InterruptedException
61     */
62    public ServerName getMetaRegionLocation() throws InterruptedException {
63      try {
64        return ServerName.parseFrom(super.getData(true));
65      } catch (DeserializationException e) {
66        LOG.warn("Failed parse", e);
67        return null;
68      }
69    }
70  
71    /**
72     * Gets the meta region location, if available.  Does not block.  Does not set
73     * a watcher (In this regard it differs from {@link #getMetaRegionLocation}.
74     * @param zkw
75     * @return server name or null if we failed to get the data.
76     * @throws KeeperException
77     */
78    public static ServerName getMetaRegionLocation(final ZooKeeperWatcher zkw)
79    throws KeeperException {
80      try {
81        return ServerName.parseFrom(ZKUtil.getData(zkw, zkw.metaServerZNode));
82      } catch (DeserializationException e) {
83        throw ZKUtil.convert(e);
84      } catch (InterruptedException e) {
85        Thread.currentThread().interrupt();
86        return null;
87      }
88    }
89  
90    /**
91     * Gets the meta region location, if available, and waits for up to the
92     * specified timeout if not immediately available.
93     * Given the zookeeper notification could be delayed, we will try to
94     * get the latest data.
95     * @param timeout maximum time to wait, in millis
96     * @return server name for server hosting meta region formatted as per
97     * {@link ServerName}, or null if none available
98     * @throws InterruptedException if interrupted while waiting
99     */
100   public ServerName waitMetaRegionLocation(long timeout)
101   throws InterruptedException {
102     if (false == checkIfBaseNodeAvailable()) {
103       String errorMsg = "Check the value configured in 'zookeeper.znode.parent'. "
104           + "There could be a mismatch with the one configured in the master.";
105       LOG.error(errorMsg);
106       throw new IllegalArgumentException(errorMsg);
107     }
108     try {
109       return ServerName.parseFrom(super.blockUntilAvailable(timeout, true));
110     } catch (DeserializationException e) {
111       LOG.warn("Failed parse", e);
112       return null;
113     }
114   }
115 
116   /**
117    * Sets the location of <code>hbase:meta</code> in ZooKeeper to the
118    * specified server address.
119    * @param zookeeper zookeeper reference
120    * @param location The server hosting <code>hbase:meta</code>
121    * @throws KeeperException unexpected zookeeper exception
122    */
123   public static void setMetaLocation(ZooKeeperWatcher zookeeper,
124                                      final ServerName location)
125   throws KeeperException {
126     LOG.info("Setting hbase:meta region location in ZooKeeper as " + location);
127     // Make the MetaRegionServer pb and then get its bytes and save this as
128     // the znode content.
129     byte [] data = toByteArray(location);
130     try {
131       ZKUtil.createAndWatch(zookeeper, zookeeper.metaServerZNode, data);
132     } catch(KeeperException.NodeExistsException nee) {
133       LOG.debug("META region location already existed, updated location");
134       ZKUtil.setData(zookeeper, zookeeper.metaServerZNode, data);
135     }
136   }
137 
138   /**
139    * Build up the znode content.
140    * @param sn What to put into the znode.
141    * @return The content of the meta-region-server znode
142    */
143   static byte [] toByteArray(final ServerName sn) {
144     // ZNode content is a pb message preceded by some pb magic.
145     HBaseProtos.ServerName pbsn =
146       HBaseProtos.ServerName.newBuilder()
147                             .setHostName(sn.getHostname())
148                             .setPort(sn.getPort())
149                             .setStartCode(sn.getStartcode())
150                             .build();
151 
152     ZooKeeperProtos.MetaRegionServer pbrsr =
153       ZooKeeperProtos.MetaRegionServer.newBuilder()
154                                       .setServer(pbsn)
155                                       .setRpcVersion(HConstants.RPC_CURRENT_VERSION)
156                                       .build();
157     return ProtobufUtil.prependPBMagic(pbrsr.toByteArray());
158   }
159 
160   /**
161    * Deletes the location of <code>hbase:meta</code> in ZooKeeper.
162    * @param zookeeper zookeeper reference
163    * @throws KeeperException unexpected zookeeper exception
164    */
165   public static void deleteMetaLocation(ZooKeeperWatcher zookeeper)
166   throws KeeperException {
167     LOG.info("Unsetting hbase:meta region location in ZooKeeper");
168     try {
169       // Just delete the node.  Don't need any watches.
170       ZKUtil.deleteNode(zookeeper, zookeeper.metaServerZNode);
171     } catch(KeeperException.NoNodeException nne) {
172       // Has already been deleted
173     }
174   }
175 
176   /**
177    * Wait until the meta region is available.
178    * @param zkw
179    * @param timeout
180    * @return ServerName or null if we timed out.
181    * @throws InterruptedException
182    */
183   public static ServerName blockUntilAvailable(final ZooKeeperWatcher zkw,
184       final long timeout)
185   throws InterruptedException {
186     byte [] data = ZKUtil.blockUntilAvailable(zkw, zkw.metaServerZNode, timeout);
187     if (data == null) return null;
188     try {
189       return ServerName.parseFrom(data);
190     } catch (DeserializationException e) {
191       LOG.warn("Failed parse", e);
192       return null;
193     }
194   }
195 }