All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taobao.metamorphosis.utils.MetaZookeeper Maven / Gradle / Ivy

There is a newer version: 1.4.6.2
Show newest version
/*
 * (C) 2007-2012 Alibaba Group Holding Limited.
 * 
 * Licensed 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.
 * Authors:
 *   wuhua  , boyan 
 */
package com.taobao.metamorphosis.utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.metamorphosis.cluster.Broker;
import com.taobao.metamorphosis.cluster.Cluster;
import com.taobao.metamorphosis.cluster.Partition;
import com.taobao.metamorphosis.cluster.json.TopicBroker;


/**
 * Meta??zookeeper?????ĸ?????
 * 
 * @author boyan([email protected])
 * @date 2011-12-15
 * 
 */
public class MetaZookeeper {

    static{
        if(Thread.getDefaultUncaughtExceptionHandler()==null){
            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    logger.warn("Thread terminated with exception: "+ t.getName(),e);
                }
            });
        }
    }

    private volatile ZkClient zkClient;

    private static Log logger = LogFactory.getLog(MetaZookeeper.class);
    public final String metaRoot;
    public final String consumersPath;
    public final String brokerIdsPath;
    @Deprecated
    public final String brokerTopicsPath;
    // added by dennis,sinace 1.4.3
    public final String brokerTopicsPubPath;
    public final String brokerTopicsSubPath;


    public ZkClient getZkClient() {
        return this.zkClient;
    }


    public void setZkClient(final ZkClient zkClient) {
        this.zkClient = zkClient;
    }


    public MetaZookeeper(final ZkClient zkClient, final String root) {
        this.zkClient = zkClient;
        this.metaRoot = this.normalize(root);
        this.consumersPath = this.metaRoot + "/consumers";
        this.brokerIdsPath = this.metaRoot + "/brokers/ids";
        this.brokerTopicsPath = this.metaRoot + "/brokers/topics";
        this.brokerTopicsPubPath = this.metaRoot + "/brokers/topics-pub";
        this.brokerTopicsSubPath = this.metaRoot + "/brokers/topics-sub";
    }


    private String normalize(final String root) {
        if (root.startsWith("/")) {
            return this.removeLastSlash(root);
        }
        else {
            return "/" + this.removeLastSlash(root);
        }
    }


    private String removeLastSlash(final String root) {
        if (root.endsWith("/")) {
            return root.substring(0, root.lastIndexOf("/"));
        }
        else {
            return root;
        }
    }

    public class ZKGroupDirs {
        public ZKGroupDirs(final String group) {
            this.consumerGroupDir = this.consumerDir + "/" + group;
            this.consumerRegistryDir = this.consumerGroupDir + "/ids";
        }

        public String consumerDir = MetaZookeeper.this.consumersPath;
        public String consumerGroupDir;
        public String consumerRegistryDir;
    }

    public class ZKGroupTopicDirs extends ZKGroupDirs {
        public ZKGroupTopicDirs(final String topic, final String group) {
            super(group);
            this.consumerOffsetDir = this.consumerGroupDir + "/offsets/" + topic;
            this.consumerOwnerDir = this.consumerGroupDir + "/owners/" + topic;
        }

        public String consumerOffsetDir;
        public String consumerOwnerDir;
    }


    /**
     * ????broker??Ⱥ,????slave??master
     * 
     * @param zkClient
     * @return
     */
    public Cluster getCluster() {
        final Cluster cluster = new Cluster();
        final List nodes = ZkUtils.getChildren(this.zkClient, this.brokerIdsPath);
        for (final String node : nodes) {
            // String brokerZKString = readData(zkClient, brokerIdsPath + "/" +
            // node);
            final int brokerId = Integer.parseInt(node);
            final Set brokers = this.getBrokersById(brokerId);
            if (brokers != null && !brokers.isEmpty()) {
                cluster.addBroker(brokerId, brokers);
            }
        }
        return cluster;
    }


    /**
     * ??zk??ѯһ??id?µ?brokers,????master??һ??????slave
     * */
    public Set getBrokersById(final int brokerId) {
        final Set set = new HashSet();
        final Broker masterBroker = this.getMasterBrokerById(brokerId);
        final Set slaveBrokers = this.getSlaveBrokersById(brokerId);
        if (masterBroker != null) {
            set.add(masterBroker);
        }
        if (slaveBrokers != null && !slaveBrokers.isEmpty()) {
            set.addAll(slaveBrokers);
        }
        return set;
    }


    /**
     * ??zk??ѯmaster broker,???????򷵻?null
     * */
    public Broker getMasterBrokerById(final int brokerId) {
        final String brokersString = ZkUtils.readDataMaybeNull(this.zkClient, this.brokerIdsPathOf(brokerId, -1));
        if (StringUtils.isNotBlank(brokersString)) {
            return new Broker(brokerId, brokersString);
        }
        return null;
    }


    /**
     * ??zk??ѯslave broker,???????򷵻?null
     * */
    private Set getSlaveBrokersById(final int brokerId) {
        final Set ret = new HashSet();
        final List brokers = ZkUtils.getChildren(this.zkClient, this.brokerIdsPath + "/" + brokerId);
        if (brokers == null) {
            return ret;
        }
        for (final String broker : brokers) {
            if (broker.startsWith("slave")) {
                int slaveId = -1;
                try {
                    slaveId = Integer.parseInt(broker.substring(5));
                    if (slaveId < 0) {
                        logger.warn("skip invalid slave path:" + broker);
                        continue;
                    }
                }
                catch (final Exception e) {
                    logger.warn("skip invalid slave path:" + broker);
                    continue;
                }
                final String brokerData =
                        ZkUtils.readDataMaybeNull(this.zkClient, this.brokerIdsPath + "/" + brokerId + "/" + broker);
                if (StringUtils.isNotBlank(brokerData)) {
                    ret.add(new Broker(brokerId, brokerData + "?slaveId=" + slaveId));
                }
            }
        }
        return ret;
    }


    /**
     * ???ط?????ָ????topic??????master brokers
     * */
    public Map getMasterBrokersByTopic(final String topic) {
        final Map ret = new TreeMap();
        final List brokerIds = ZkUtils.getChildren(this.zkClient, this.brokerTopicsPubPath + "/" + topic);
        if (brokerIds == null) {
            return ret;
        }
        for (final String brokerIdStr : brokerIds) {
            if (!brokerIdStr.endsWith("-m")) {
                continue;
            }
            final int brokerId = Integer.parseInt(StringUtils.split(brokerIdStr, "-")[0]);
            final Broker broker = this.getMasterBrokerById(brokerId);
            if (broker != null) {
                ret.put(brokerId, broker.getZKString());
            }
        }
        return ret;

    }


    /**
     * ????master??topic??partitionӳ???map
     * 
     * @param zkClient
     * @param topics
     * @return
     */
    public Map> getPartitionsForTopicsFromMaster(final Collection topics) {
        final Map> ret = new HashMap>();
        for (final String topic : topics) {
            List partList = null;
            final List brokers = ZkUtils.getChildren(this.zkClient, this.brokerTopicsPubPath + "/" + topic);
            for (final String broker : brokers) {
                final String[] brokerStrs = StringUtils.split(broker, "-");
                if (this.isMaster(brokerStrs)) {
                    String path = this.brokerTopicsPubPath + "/" + topic + "/" + broker;
                    String brokerData = ZkUtils.readData(this.zkClient, path);
                    try {
                        final TopicBroker topicBroker = TopicBroker.parse(brokerData);
                        if (topicBroker == null) {
                            logger.warn("Null broker data for path:" + path);
                            continue;
                        }
                        for (int part = 0; part < topicBroker.getNumParts(); part++) {
                            if (partList == null) {
                                partList = new ArrayList();
                            }
                            final Partition partition = new Partition(Integer.parseInt(brokerStrs[0]), part);
                            if (!partList.contains(partition)) {
                                partList.add(partition);
                            }
                        }
                    }
                    catch (Exception e) {
                        logger.error("A serious error occurred,could not parse broker data at path=" + path
                            + ",and broker data is:" + brokerData, e);
                    }
                }
            }
            if (partList != null) {
                Collections.sort(partList);
                ret.put(topic, partList);
            }
        }
        return ret;
    }


    private boolean isMaster(final String[] brokerStrs) {
        return brokerStrs != null && brokerStrs.length == 2 && brokerStrs[1].equals("m");
    }


    /**
     * ????һ??broker??????????topics
     * 
     * */
    public Set getTopicsByBrokerIdFromMaster(final int brokerId) {
        final Set set = new HashSet();
        final List allTopics = ZkUtils.getChildren(this.zkClient, this.brokerTopicsSubPath);
        for (final String topic : allTopics) {
            final List brokers = ZkUtils.getChildren(this.zkClient, this.brokerTopicsSubPath + "/" + topic);
            if (brokers != null && brokers.size() > 0) {
                for (final String broker : brokers) {
                    if ((String.valueOf(brokerId) + "-m").equals(broker)) {
                        set.add(topic);
                    }
                }
            }
        }
        return set;
    }


    /**
     * ????һ??master ?µ?topic??partitionӳ???map
     * 
     * @param zkClient
     * @param topics
     * @return
     */
    public Map> getPartitionsForSubTopicsFromMaster(final Collection topics,
        final int brokerId) {
        final Map> ret = new HashMap>();
        if (topics != null) {
            for (final String topic : topics) {
                List partList = null;
                final String dataString =
                        ZkUtils.readDataMaybeNull(this.zkClient, this.brokerTopicsPathOf(topic, false, brokerId, -1));
                if (StringUtils.isBlank(dataString)) {
                    continue;
                }
                try {
                    final TopicBroker topicBroker = TopicBroker.parse(dataString);
                    if (topicBroker == null) {
                        continue;
                    }
                    for (int part = 0; part < topicBroker.getNumParts(); part++) {
                        if (partList == null) {
                            partList = new ArrayList();
                        }
                        partList.add(new Partition(brokerId, part));
                    }
                    if (partList != null) {
                        Collections.sort(partList);
                        ret.put(topic, partList);
                    }
                }
                catch (Exception e) {
                    throw new IllegalStateException("Parse data to TopicBroker failed,data is:" + dataString, e);
                }
            }
        }
        return ret;
    }


    /**
     * ????һ??master?µ?topic??partitionӳ???map
     * 
     * @param zkClient
     * @param topics
     * @return
     */
    public Map> getPartitionStringsForSubTopicsFromMaster(final Collection topics,
        final int brokerId) {
        final Map> ret = new HashMap>();
        final Map> tmp = this.getPartitionsForSubTopicsFromMaster(topics, brokerId);
        if (tmp != null && !tmp.isEmpty()) {
            for (final Map.Entry> each : tmp.entrySet()) {
                final String topic = each.getKey();
                List list = ret.get(topic);
                if (list == null) {
                    list = new ArrayList();
                }
                for (final Partition partition : each.getValue()) {
                    list.add(partition.getBrokerId() + "-" + partition.getPartition());
                }
                if (list != null) {
                    Collections.sort(list);
                    ret.put(topic, list);
                }
            }
        }
        return ret;
    }


    /**
     * ????topic??partitionӳ???map. ????master??slave??????partitions
     * 
     * @param zkClient
     * @param topics
     * @return
     */
    public Map> getPartitionStringsForSubTopics(final Collection topics) {
        final Map> ret = new HashMap>();
        for (final String topic : topics) {
            List partList = null;
            final List brokers = ZkUtils.getChildren(this.zkClient, this.brokerTopicsSubPath + "/" + topic);
            for (final String broker : brokers) {
                final String[] tmp = StringUtils.split(broker, "-");
                if (tmp != null && tmp.length == 2) {
                    String path = this.brokerTopicsSubPath + "/" + topic + "/" + broker;
                    String brokerData = ZkUtils.readData(this.zkClient, path);
                    try {
                        final TopicBroker topicBroker = TopicBroker.parse(brokerData);
                        if (topicBroker == null) {
                            logger.warn("Null broker data for path:" + path);
                            continue;
                        }
                        for (int part = 0; part < topicBroker.getNumParts(); part++) {
                            if (partList == null) {
                                partList = new ArrayList();
                            }

                            final String partitionString = tmp[0] + "-" + part;
                            if (!partList.contains(partitionString)) {
                                partList.add(partitionString);
                            }
                        }
                    }
                    catch (Exception e) {
                        logger.error("A serious error occurred,could not parse broker data at path=" + path
                            + ",and broker data is:" + brokerData, e);
                    }
                }
                else {
                    logger.warn("skip invalid topics path:" + broker);
                }
            }
            if (partList != null) {
                Collections.sort(partList);
                ret.put(topic, partList);
            }
        }
        return ret;
    }


    /**
     * brokerId ??zk??ע???path
     * 
     * @param brokerId
     * @param slaveId
     *            slave???, С??0??ʾmaster
     * 
     * */
    public String brokerIdsPathOf(final int brokerId, final int slaveId) {
        return this.brokerIdsPath + "/" + brokerId + (slaveId >= 0 ? "/slave" + slaveId : "/master");
    }


    /**
     * Master config file checksum path
     * 
     * @param brokerId
     * @return
     */
    public String masterConfigChecksum(final int brokerId) {
        return this.brokerIdsPath + "/" + brokerId + "/master_config_checksum";
    }


    /**
     * topic ??zk??ע???path
     * 
     * @param topic
     * @param brokerId
     * @param slaveId
     *            slave???, С??0??ʾmaster
     * */
    @Deprecated
    public String brokerTopicsPathOf(final String topic, final int brokerId, final int slaveId) {
        return this.brokerTopicsPath + "/" + topic + "/" + brokerId + (slaveId >= 0 ? "-s" + slaveId : "-m");
    }


    /**
     * 
     * Returns topic path in zk
     * 
     * @since 1.4.3
     * @param topic
     * @param brokerId
     * @param slaveId
     *            slave???, С??0??ʾmaster
     * */
    public String brokerTopicsPathOf(final String topic, boolean publish, final int brokerId, final int slaveId) {
        String parent = publish ? this.brokerTopicsPubPath : this.brokerTopicsSubPath;
        return parent + "/" + topic + "/" + brokerId + (slaveId >= 0 ? "-s" + slaveId : "-m");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy