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      }
85    }
86  
87    /**
88     * Gets the meta region location, if available, and waits for up to the
89     * specified timeout if not immediately available.
90     * Given the zookeeper notification could be delayed, we will try to
91     * get the latest data.
92     * @param timeout maximum time to wait, in millis
93     * @return server name for server hosting meta region formatted as per
94     * {@link ServerName}, or null if none available
95     * @throws InterruptedException if interrupted while waiting
96     */
97    public ServerName waitMetaRegionLocation(long timeout)
98    throws InterruptedException {
99      if (false == checkIfBaseNodeAvailable()) {
100       String errorMsg = "Check the value configured in 'zookeeper.znode.parent'. "
101           + "There could be a mismatch with the one configured in the master.";
102       LOG.error(errorMsg);
103       throw new IllegalArgumentException(errorMsg);
104     }
105     try {
106       return ServerName.parseFrom(super.blockUntilAvailable(timeout, true));
107     } catch (DeserializationException e) {
108       LOG.warn("Failed parse", e);
109       return null;
110     }
111   }
112 
113   /**
114    * Sets the location of <code>hbase:meta</code> in ZooKeeper to the
115    * specified server address.
116    * @param zookeeper zookeeper reference
117    * @param location The server hosting <code>hbase:meta</code>
118    * @throws KeeperException unexpected zookeeper exception
119    */
120   public static void setMetaLocation(ZooKeeperWatcher zookeeper,
121                                      final ServerName location)
122   throws KeeperException {
123     LOG.info("Setting hbase:meta region location in ZooKeeper as " + location);
124     // Make the MetaRegionServer pb and then get its bytes and save this as
125     // the znode content.
126     byte [] data = toByteArray(location);
127     try {
128       ZKUtil.createAndWatch(zookeeper, zookeeper.metaServerZNode, data);
129     } catch(KeeperException.NodeExistsException nee) {
130       LOG.debug("META region location already existed, updated location");
131       ZKUtil.setData(zookeeper, zookeeper.metaServerZNode, data);
132     }
133   }
134 
135   /**
136    * Build up the znode content.
137    * @param sn What to put into the znode.
138    * @return The content of the meta-region-server znode
139    */
140   static byte [] toByteArray(final ServerName sn) {
141     // ZNode content is a pb message preceded by some pb magic.
142     HBaseProtos.ServerName pbsn =
143       HBaseProtos.ServerName.newBuilder()
144                             .setHostName(sn.getHostname())
145                             .setPort(sn.getPort())
146                             .setStartCode(sn.getStartcode())
147                             .build();
148 
149     ZooKeeperProtos.MetaRegionServer pbrsr =
150       ZooKeeperProtos.MetaRegionServer.newBuilder()
151                                       .setServer(pbsn)
152                                       .setRpcVersion(HConstants.RPC_CURRENT_VERSION)
153                                       .build();
154     return ProtobufUtil.prependPBMagic(pbrsr.toByteArray());
155   }
156 
157   /**
158    * Deletes the location of <code>hbase:meta</code> in ZooKeeper.
159    * @param zookeeper zookeeper reference
160    * @throws KeeperException unexpected zookeeper exception
161    */
162   public static void deleteMetaLocation(ZooKeeperWatcher zookeeper)
163   throws KeeperException {
164     LOG.info("Unsetting hbase:meta region location in ZooKeeper");
165     try {
166       // Just delete the node.  Don't need any watches.
167       ZKUtil.deleteNode(zookeeper, zookeeper.metaServerZNode);
168     } catch(KeeperException.NoNodeException nne) {
169       // Has already been deleted
170     }
171   }
172 
173   /**
174    * Wait until the meta region is available.
175    * @param zkw
176    * @param timeout
177    * @return ServerName or null if we timed out.
178    * @throws InterruptedException
179    */
180   public static ServerName blockUntilAvailable(final ZooKeeperWatcher zkw,
181       final long timeout)
182   throws InterruptedException {
183     byte [] data = ZKUtil.blockUntilAvailable(zkw, zkw.metaServerZNode, timeout);
184     if (data == null) return null;
185     try {
186       return ServerName.parseFrom(data);
187     } catch (DeserializationException e) {
188       LOG.warn("Failed parse", e);
189       return null;
190     }
191   }
192 }