org.apache.hadoop.hbase.client.ZKAsyncRegistry.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.client.ZKAsyncRegistry.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.hbase.client;

import static org.apache.hadoop.hbase.HConstants.DEFAULT_ZK_SESSION_TIMEOUT;
import static org.apache.hadoop.hbase.HConstants.ZK_SESSION_TIMEOUT;
import static org.apache.hadoop.hbase.HRegionInfo.DEFAULT_REPLICA_ID;
import static org.apache.hadoop.hbase.HRegionInfo.FIRST_META_REGIONINFO;
import static org.apache.hadoop.hbase.client.RegionReplicaUtil.getRegionInfoForDefaultReplica;
import static org.apache.hadoop.hbase.client.RegionReplicaUtil.getRegionInfoForReplica;
import static org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil.lengthOfPBMagic;
import static org.apache.hadoop.hbase.zookeeper.RecoverableZooKeeper.removeMetaData;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;

import org.apache.commons.lang.mutable.MutableInt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundPathable;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.RetryNTimes;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ClusterId;
import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.RegionLocations;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.Threads;
import org.apache.hadoop.hbase.zookeeper.ZKConfig;
import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
import org.apache.zookeeper.data.Stat;

/**
 * Fetch the registry data from zookeeper.
 */
@InterfaceAudience.Private
class ZKAsyncRegistry implements AsyncRegistry {

    private static final Log LOG = LogFactory.getLog(ZKAsyncRegistry.class);

    private final CuratorFramework zk;

    private final ZNodePaths znodePaths;

    ZKAsyncRegistry(Configuration conf) {
        this.znodePaths = new ZNodePaths(conf);
        int zkSessionTimeout = conf.getInt(ZK_SESSION_TIMEOUT, DEFAULT_ZK_SESSION_TIMEOUT);
        int zkRetry = conf.getInt("zookeeper.recovery.retry", 3);
        int zkRetryIntervalMs = conf.getInt("zookeeper.recovery.retry.intervalmill", 1000);
        this.zk = CuratorFrameworkFactory.builder().connectString(ZKConfig.getZKQuorumServersString(conf))
                .sessionTimeoutMs(zkSessionTimeout).retryPolicy(new RetryNTimes(zkRetry, zkRetryIntervalMs))
                .threadFactory(
                        Threads.newDaemonThreadFactory(String.format("ZKClusterRegistry-0x%08x", hashCode())))
                .build();
        this.zk.start();
    }

    private interface CuratorEventProcessor<T> {
        T process(CuratorEvent event) throws Exception;
    }

    private static <T> CompletableFuture<T> exec(BackgroundPathable<?> opBuilder, String path,
            CuratorEventProcessor<T> processor) {
        CompletableFuture<T> future = new CompletableFuture<>();
        try {
            opBuilder.inBackground((client, event) -> {
                try {
                    future.complete(processor.process(event));
                } catch (Exception e) {
                    future.completeExceptionally(e);
                }
            }).withUnhandledErrorListener((msg, e) -> future.completeExceptionally(e)).forPath(path);
        } catch (Exception e) {
            future.completeExceptionally(e);
        }
        return future;
    }

    private static String getClusterId(CuratorEvent event) throws DeserializationException {
        byte[] data = event.getData();
        if (data == null || data.length == 0) {
            return null;
        }
        data = removeMetaData(data);
        return ClusterId.parseFrom(data).toString();
    }

    @Override
    public CompletableFuture<String> getClusterId() {
        return exec(zk.getData(), znodePaths.clusterIdZNode, ZKAsyncRegistry::getClusterId);
    }

    private static ZooKeeperProtos.MetaRegionServer getMetaProto(CuratorEvent event) throws IOException {
        byte[] data = event.getData();
        if (data == null || data.length == 0) {
            return null;
        }
        data = removeMetaData(data);
        int prefixLen = lengthOfPBMagic();
        return ZooKeeperProtos.MetaRegionServer.parser().parseFrom(data, prefixLen, data.length - prefixLen);
    }

    private static void tryComplete(MutableInt remaining, HRegionLocation[] locs,
            CompletableFuture<RegionLocations> future) {
        remaining.decrement();
        if (remaining.intValue() > 0) {
            return;
        }
        future.complete(new RegionLocations(locs));
    }

    private Pair<RegionState.State, ServerName> getStateAndServerName(ZooKeeperProtos.MetaRegionServer proto) {
        RegionState.State state;
        if (proto.hasState()) {
            state = RegionState.State.convert(proto.getState());
        } else {
            state = RegionState.State.OPEN;
        }
        HBaseProtos.ServerName snProto = proto.getServer();
        return Pair.newPair(state,
                ServerName.valueOf(snProto.getHostName(), snProto.getPort(), snProto.getStartCode()));
    }

    @Override
    public CompletableFuture<RegionLocations> getMetaRegionLocation() {
        CompletableFuture<RegionLocations> future = new CompletableFuture<>();
        HRegionLocation[] locs = new HRegionLocation[znodePaths.metaReplicaZNodes.size()];
        MutableInt remaining = new MutableInt(locs.length);
        znodePaths.metaReplicaZNodes.forEach((replicaId, path) -> {
            if (replicaId == DEFAULT_REPLICA_ID) {
                exec(zk.getData(), path, ZKAsyncRegistry::getMetaProto).whenComplete((proto, error) -> {
                    if (error != null) {
                        future.completeExceptionally(error);
                        return;
                    }
                    if (proto == null) {
                        future.completeExceptionally(new IOException("Meta znode is null"));
                        return;
                    }
                    Pair<RegionState.State, ServerName> stateAndServerName = getStateAndServerName(proto);
                    if (stateAndServerName.getFirst() != RegionState.State.OPEN) {
                        future.completeExceptionally(
                                new IOException("Meta region is in state " + stateAndServerName.getFirst()));
                        return;
                    }
                    locs[DEFAULT_REPLICA_ID] = new HRegionLocation(
                            getRegionInfoForDefaultReplica(FIRST_META_REGIONINFO), stateAndServerName.getSecond());
                    tryComplete(remaining, locs, future);
                });
            } else {
                exec(zk.getData(), path, ZKAsyncRegistry::getMetaProto).whenComplete((proto, error) -> {
                    if (future.isDone()) {
                        return;
                    }
                    if (error != null) {
                        LOG.warn("Failed to fetch " + path, error);
                        locs[replicaId] = null;
                    } else if (proto == null) {
                        LOG.warn("Meta znode for replica " + replicaId + " is null");
                        locs[replicaId] = null;
                    } else {
                        Pair<RegionState.State, ServerName> stateAndServerName = getStateAndServerName(proto);
                        if (stateAndServerName.getFirst() != RegionState.State.OPEN) {
                            LOG.warn("Meta region for replica " + replicaId + " is in state "
                                    + stateAndServerName.getFirst());
                            locs[replicaId] = null;
                        } else {
                            locs[replicaId] = new HRegionLocation(
                                    getRegionInfoForReplica(FIRST_META_REGIONINFO, replicaId),
                                    stateAndServerName.getSecond());
                        }
                    }
                    tryComplete(remaining, locs, future);
                });
            }
        });
        return future;
    }

    private static int getCurrentNrHRS(CuratorEvent event) {
        Stat stat = event.getStat();
        return stat != null ? stat.getNumChildren() : 0;
    }

    @Override
    public CompletableFuture<Integer> getCurrentNrHRS() {
        return exec(zk.checkExists(), znodePaths.rsZNode, ZKAsyncRegistry::getCurrentNrHRS);
    }

    private static ZooKeeperProtos.Master getMasterProto(CuratorEvent event) throws IOException {
        byte[] data = event.getData();
        if (data == null || data.length == 0) {
            return null;
        }
        data = removeMetaData(data);
        int prefixLen = lengthOfPBMagic();
        return ZooKeeperProtos.Master.parser().parseFrom(data, prefixLen, data.length - prefixLen);
    }

    @Override
    public CompletableFuture<ServerName> getMasterAddress() {
        return exec(zk.getData(), znodePaths.masterAddressZNode, ZKAsyncRegistry::getMasterProto)
                .thenApply(proto -> {
                    if (proto == null) {
                        return null;
                    }
                    HBaseProtos.ServerName snProto = proto.getMaster();
                    return ServerName.valueOf(snProto.getHostName(), snProto.getPort(), snProto.getStartCode());
                });
    }

    @Override
    public CompletableFuture<Integer> getMasterInfoPort() {
        return exec(zk.getData(), znodePaths.masterAddressZNode, ZKAsyncRegistry::getMasterProto)
                .thenApply(proto -> proto != null ? proto.getInfoPort() : 0);
    }

    @Override
    public void close() {
        zk.close();
    }
}