001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.zookeeper; 019 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.List; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HConstants; 025import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; 026import org.apache.hadoop.hbase.ServerName; 027import org.apache.hadoop.hbase.client.RegionInfo; 028import org.apache.hadoop.hbase.client.RegionInfoBuilder; 029import org.apache.hadoop.hbase.client.RegionReplicaUtil; 030import org.apache.hadoop.hbase.exceptions.DeserializationException; 031import org.apache.hadoop.hbase.master.RegionState; 032import org.apache.hadoop.hbase.util.Pair; 033import org.apache.yetus.audience.InterfaceAudience; 034import org.apache.zookeeper.KeeperException; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 039 040import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 041import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 042import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos; 043import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos.MetaRegionServer; 044 045/** 046 * Utility class to perform operation (get/wait for/verify/set/delete) on znode in ZooKeeper which 047 * keeps hbase:meta region server location. 048 * <p/> 049 * Stateless class with a bunch of static methods. Doesn't manage resources passed in (e.g. 050 * Connection, ZKWatcher etc). 051 * <p/> 052 * Meta region location is set by <code>RegionServerServices</code>. This class doesn't use ZK 053 * watchers, rather accesses ZK directly. 054 * <p/> 055 * TODO: rewrite using RPC calls to master to find out about hbase:meta. 056 */ 057@InterfaceAudience.Private 058public final class MetaTableLocator { 059 private static final Logger LOG = LoggerFactory.getLogger(MetaTableLocator.class); 060 061 private MetaTableLocator() { 062 } 063 064 /** 065 * Checks if the meta region location is available. 066 * @return true if meta region location is available, false if not 067 */ 068 public static boolean isLocationAvailable(ZKWatcher zkw) { 069 return getMetaRegionLocation(zkw) != null; 070 } 071 072 /** 073 * @param zkw ZooKeeper watcher to be used 074 * @return meta table regions and their locations. 075 */ 076 public static List<Pair<RegionInfo, ServerName>> getMetaRegionsAndLocations(ZKWatcher zkw) { 077 return getMetaRegionsAndLocations(zkw, RegionInfo.DEFAULT_REPLICA_ID); 078 } 079 080 /** 081 * Gets the meta regions and their locations for the given path and replica ID. 082 * 083 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 084 * @param replicaId the ID of the replica 085 * @return meta table regions and their locations. 086 */ 087 public static List<Pair<RegionInfo, ServerName>> getMetaRegionsAndLocations(ZKWatcher zkw, 088 int replicaId) { 089 ServerName serverName = getMetaRegionLocation(zkw, replicaId); 090 List<Pair<RegionInfo, ServerName>> list = new ArrayList<>(1); 091 list.add(new Pair<>(RegionReplicaUtil.getRegionInfoForReplica( 092 RegionInfoBuilder.FIRST_META_REGIONINFO, replicaId), serverName)); 093 return list; 094 } 095 096 /** 097 * Gets the meta regions for the given path with the default replica ID. 098 * 099 * @param zkw ZooKeeper watcher to be used 100 * @return List of meta regions 101 */ 102 public static List<RegionInfo> getMetaRegions(ZKWatcher zkw) { 103 return getMetaRegions(zkw, RegionInfo.DEFAULT_REPLICA_ID); 104 } 105 106 /** 107 * Gets the meta regions for the given path and replica ID. 108 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 109 * @param replicaId the ID of the replica 110 * @return List of meta regions 111 */ 112 public static List<RegionInfo> getMetaRegions(ZKWatcher zkw, int replicaId) { 113 List<Pair<RegionInfo, ServerName>> result; 114 result = getMetaRegionsAndLocations(zkw, replicaId); 115 return getListOfRegionInfos(result); 116 } 117 118 private static List<RegionInfo> getListOfRegionInfos( 119 final List<Pair<RegionInfo, ServerName>> pairs) { 120 if (pairs == null || pairs.isEmpty()) { 121 return Collections.emptyList(); 122 } 123 124 List<RegionInfo> result = new ArrayList<>(pairs.size()); 125 for (Pair<RegionInfo, ServerName> pair : pairs) { 126 result.add(pair.getFirst()); 127 } 128 return result; 129 } 130 131 /** 132 * Gets the meta region location, if available. Does not block. 133 * @param zkw zookeeper connection to use 134 * @return server name or null if we failed to get the data. 135 */ 136 public static ServerName getMetaRegionLocation(final ZKWatcher zkw) { 137 try { 138 RegionState state = getMetaRegionState(zkw); 139 return state.isOpened() ? state.getServerName() : null; 140 } catch (KeeperException ke) { 141 return null; 142 } 143 } 144 145 /** 146 * Gets the meta region location, if available. Does not block. 147 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 148 * @param replicaId the ID of the replica 149 * @return server name 150 */ 151 public static ServerName getMetaRegionLocation(final ZKWatcher zkw, int replicaId) { 152 try { 153 RegionState state = getMetaRegionState(zkw, replicaId); 154 return state.isOpened() ? state.getServerName() : null; 155 } catch (KeeperException ke) { 156 return null; 157 } 158 } 159 160 /** 161 * Gets the meta region location, if available, and waits for up to the specified timeout if not 162 * immediately available. Given the zookeeper notification could be delayed, we will try to get 163 * the latest data. 164 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 165 * @param timeout maximum time to wait, in millis 166 * @return server name for server hosting meta region formatted as per {@link ServerName}, or null 167 * if none available 168 * @throws InterruptedException if interrupted while waiting 169 * @throws NotAllMetaRegionsOnlineException if a meta or root region is not online 170 */ 171 public static ServerName waitMetaRegionLocation(ZKWatcher zkw, long timeout) 172 throws InterruptedException, NotAllMetaRegionsOnlineException { 173 return waitMetaRegionLocation(zkw, RegionInfo.DEFAULT_REPLICA_ID, timeout); 174 } 175 176 /** 177 * Gets the meta region location, if available, and waits for up to the specified timeout if not 178 * immediately available. Given the zookeeper notification could be delayed, we will try to get 179 * the latest data. 180 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 181 * @param replicaId the ID of the replica 182 * @param timeout maximum time to wait, in millis 183 * @return server name for server hosting meta region formatted as per {@link ServerName}, or null 184 * if none available 185 * @throws InterruptedException if waiting for the socket operation fails 186 * @throws NotAllMetaRegionsOnlineException if a meta or root region is not online 187 */ 188 public static ServerName waitMetaRegionLocation(ZKWatcher zkw, int replicaId, long timeout) 189 throws InterruptedException, NotAllMetaRegionsOnlineException { 190 try { 191 if (ZKUtil.checkExists(zkw, zkw.getZNodePaths().baseZNode) == -1) { 192 String errorMsg = "Check the value configured in 'zookeeper.znode.parent'. " + 193 "There could be a mismatch with the one configured in the master."; 194 LOG.error(errorMsg); 195 throw new IllegalArgumentException(errorMsg); 196 } 197 } catch (KeeperException e) { 198 throw new IllegalStateException("KeeperException while trying to check baseZNode:", e); 199 } 200 ServerName sn = blockUntilAvailable(zkw, replicaId, timeout); 201 202 if (sn == null) { 203 throw new NotAllMetaRegionsOnlineException("Timed out; " + timeout + "ms"); 204 } 205 206 return sn; 207 } 208 209 /** 210 * Sets the location of <code>hbase:meta</code> in ZooKeeper to the 211 * specified server address. 212 * @param zookeeper zookeeper reference 213 * @param serverName The server hosting <code>hbase:meta</code> 214 * @param state The region transition state 215 * @throws KeeperException unexpected zookeeper exception 216 */ 217 public static void setMetaLocation(ZKWatcher zookeeper, 218 ServerName serverName, RegionState.State state) throws KeeperException { 219 setMetaLocation(zookeeper, serverName, RegionInfo.DEFAULT_REPLICA_ID, state); 220 } 221 222 /** 223 * Sets the location of <code>hbase:meta</code> in ZooKeeper to the specified server address. 224 * @param zookeeper reference to the {@link ZKWatcher} which also contains configuration and 225 * operation 226 * @param serverName the name of the server 227 * @param replicaId the ID of the replica 228 * @param state the state of the region 229 * @throws KeeperException if a ZooKeeper operation fails 230 */ 231 public static void setMetaLocation(ZKWatcher zookeeper, ServerName serverName, int replicaId, 232 RegionState.State state) throws KeeperException { 233 if (serverName == null) { 234 LOG.warn("Tried to set null ServerName in hbase:meta; skipping -- ServerName required"); 235 return; 236 } 237 LOG.info("Setting hbase:meta (replicaId={}) location in ZooKeeper as {}", replicaId, 238 serverName); 239 // Make the MetaRegionServer pb and then get its bytes and save this as 240 // the znode content. 241 MetaRegionServer pbrsr = MetaRegionServer.newBuilder() 242 .setServer(ProtobufUtil.toServerName(serverName)) 243 .setRpcVersion(HConstants.RPC_CURRENT_VERSION) 244 .setState(state.convert()).build(); 245 byte[] data = ProtobufUtil.prependPBMagic(pbrsr.toByteArray()); 246 try { 247 ZKUtil.setData(zookeeper, 248 zookeeper.getZNodePaths().getZNodeForReplica(replicaId), data); 249 } catch(KeeperException.NoNodeException nne) { 250 if (replicaId == RegionInfo.DEFAULT_REPLICA_ID) { 251 LOG.debug("META region location doesn't exist, create it"); 252 } else { 253 LOG.debug("META region location doesn't exist for replicaId=" + replicaId + 254 ", create it"); 255 } 256 ZKUtil.createAndWatch(zookeeper, zookeeper.getZNodePaths().getZNodeForReplica(replicaId), 257 data); 258 } 259 } 260 261 /** 262 * Load the meta region state from the meta server ZNode. 263 */ 264 public static RegionState getMetaRegionState(ZKWatcher zkw) throws KeeperException { 265 return getMetaRegionState(zkw, RegionInfo.DEFAULT_REPLICA_ID); 266 } 267 268 /** 269 * Load the meta region state from the meta server ZNode. 270 * 271 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 272 * @param replicaId the ID of the replica 273 * @return regionstate 274 * @throws KeeperException if a ZooKeeper operation fails 275 */ 276 public static RegionState getMetaRegionState(ZKWatcher zkw, int replicaId) 277 throws KeeperException { 278 RegionState.State state = RegionState.State.OPEN; 279 ServerName serverName = null; 280 try { 281 byte[] data = ZKUtil.getData(zkw, zkw.getZNodePaths().getZNodeForReplica(replicaId)); 282 if (data != null && data.length > 0 && ProtobufUtil.isPBMagicPrefix(data)) { 283 try { 284 int prefixLen = ProtobufUtil.lengthOfPBMagic(); 285 ZooKeeperProtos.MetaRegionServer rl = 286 ZooKeeperProtos.MetaRegionServer.parser().parseFrom(data, prefixLen, 287 data.length - prefixLen); 288 if (rl.hasState()) { 289 state = RegionState.State.convert(rl.getState()); 290 } 291 HBaseProtos.ServerName sn = rl.getServer(); 292 serverName = ServerName.valueOf( 293 sn.getHostName(), sn.getPort(), sn.getStartCode()); 294 } catch (InvalidProtocolBufferException e) { 295 throw new DeserializationException("Unable to parse meta region location"); 296 } 297 } else { 298 // old style of meta region location? 299 serverName = ProtobufUtil.parseServerNameFrom(data); 300 } 301 } catch (DeserializationException e) { 302 throw ZKUtil.convert(e); 303 } catch (InterruptedException e) { 304 Thread.currentThread().interrupt(); 305 } 306 if (serverName == null) { 307 state = RegionState.State.OFFLINE; 308 } 309 return new RegionState( 310 RegionReplicaUtil.getRegionInfoForReplica( 311 RegionInfoBuilder.FIRST_META_REGIONINFO, replicaId), 312 state, serverName); 313 } 314 315 /** 316 * Deletes the location of <code>hbase:meta</code> in ZooKeeper. 317 * @param zookeeper zookeeper reference 318 * @throws KeeperException unexpected zookeeper exception 319 */ 320 public static void deleteMetaLocation(ZKWatcher zookeeper) 321 throws KeeperException { 322 deleteMetaLocation(zookeeper, RegionInfo.DEFAULT_REPLICA_ID); 323 } 324 325 public static void deleteMetaLocation(ZKWatcher zookeeper, int replicaId) 326 throws KeeperException { 327 if (replicaId == RegionInfo.DEFAULT_REPLICA_ID) { 328 LOG.info("Deleting hbase:meta region location in ZooKeeper"); 329 } else { 330 LOG.info("Deleting hbase:meta for {} region location in ZooKeeper", replicaId); 331 } 332 try { 333 // Just delete the node. Don't need any watches. 334 ZKUtil.deleteNode(zookeeper, zookeeper.getZNodePaths().getZNodeForReplica(replicaId)); 335 } catch(KeeperException.NoNodeException nne) { 336 // Has already been deleted 337 } 338 } 339 /** 340 * Wait until the primary meta region is available. Get the secondary locations as well but don't 341 * block for those. 342 * 343 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and operation 344 * @param timeout maximum time to wait in millis 345 * @param conf the {@link Configuration} to use 346 * @return ServerName or null if we timed out. 347 * @throws InterruptedException if waiting for the socket operation fails 348 */ 349 public static List<ServerName> blockUntilAvailable(final ZKWatcher zkw, final long timeout, 350 Configuration conf) throws InterruptedException { 351 int numReplicasConfigured = 1; 352 353 List<ServerName> servers = new ArrayList<>(); 354 // Make the blocking call first so that we do the wait to know 355 // the znodes are all in place or timeout. 356 ServerName server = blockUntilAvailable(zkw, timeout); 357 358 if (server == null) { 359 return null; 360 } 361 362 servers.add(server); 363 364 try { 365 List<String> metaReplicaNodes = zkw.getMetaReplicaNodes(); 366 numReplicasConfigured = metaReplicaNodes.size(); 367 } catch (KeeperException e) { 368 LOG.warn("Got ZK exception {}", e); 369 } 370 for (int replicaId = 1; replicaId < numReplicasConfigured; replicaId++) { 371 // return all replica locations for the meta 372 servers.add(getMetaRegionLocation(zkw, replicaId)); 373 } 374 return servers; 375 } 376 377 /** 378 * Wait until the meta region is available and is not in transition. 379 * @param zkw zookeeper connection to use 380 * @param timeout maximum time to wait, in millis 381 * @return ServerName or null if we timed out. 382 * @throws InterruptedException if waiting for the socket operation fails 383 */ 384 public static ServerName blockUntilAvailable(final ZKWatcher zkw, final long timeout) 385 throws InterruptedException { 386 return blockUntilAvailable(zkw, RegionInfo.DEFAULT_REPLICA_ID, timeout); 387 } 388 389 /** 390 * Wait until the meta region is available and is not in transition. 391 * @param zkw reference to the {@link ZKWatcher} which also contains configuration and constants 392 * @param replicaId the ID of the replica 393 * @param timeout maximum time to wait in millis 394 * @return ServerName or null if we timed out. 395 * @throws InterruptedException if waiting for the socket operation fails 396 */ 397 public static ServerName blockUntilAvailable(final ZKWatcher zkw, int replicaId, 398 final long timeout) throws InterruptedException { 399 if (timeout < 0) { 400 throw new IllegalArgumentException(); 401 } 402 403 if (zkw == null) { 404 throw new IllegalArgumentException(); 405 } 406 407 long startTime = System.currentTimeMillis(); 408 ServerName sn = null; 409 while (true) { 410 sn = getMetaRegionLocation(zkw, replicaId); 411 if (sn != null || 412 (System.currentTimeMillis() - startTime) > timeout - HConstants.SOCKET_RETRY_WAIT_MS) { 413 break; 414 } 415 Thread.sleep(HConstants.SOCKET_RETRY_WAIT_MS); 416 } 417 return sn; 418 } 419}