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