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>.META.</code> in ZooKeeper to the
115 * specified server address.
116 * @param zookeeper zookeeper reference
117 * @param location The server hosting <code>.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 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>.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 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 }