Package com.taobao.metamorphosis.server

Source Code of com.taobao.metamorphosis.server.BrokerZooKeeper$SessionExpireListener

/*
* (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 <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.server;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.I0Itec.zkclient.IZkStateListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.zookeeper.Watcher.Event.KeeperState;

import com.taobao.gecko.core.util.ConcurrentHashSet;
import com.taobao.metamorphosis.cluster.Broker;
import com.taobao.metamorphosis.cluster.json.TopicBroker;
import com.taobao.metamorphosis.network.RemotingUtils;
import com.taobao.metamorphosis.server.utils.MetaConfig;
import com.taobao.metamorphosis.server.utils.TopicConfig;
import com.taobao.metamorphosis.utils.MetaZookeeper;
import com.taobao.metamorphosis.utils.Utils;
import com.taobao.metamorphosis.utils.ZkUtils;
import com.taobao.metamorphosis.utils.ZkUtils.ZKConfig;


/**
* Broker��ZK������ע��broker��topic��
*
* @author boyan
* @Date 2011-4-25
* @author wuhua
* @Date 2011-6-24
*
*/
public class BrokerZooKeeper implements PropertyChangeListener {
    private final MetaConfig config;
    private ZkClient zkClient;

    private ZKConfig zkConfig;

    private String brokerIdPath;

    private final String masterConfigChecksumPath;

    private final Set<String> topics = new ConcurrentHashSet<String>();

    private final ConcurrentHashMap<String, TopicConfig> cloneTopicConfigs =
            new ConcurrentHashMap<String, TopicConfig>();

    static final Log log = LogFactory.getLog(BrokerZooKeeper.class);

    // private DiamondManager diamondManager;

    private volatile boolean registerBrokerInZkFail = false;

    private MetaZookeeper metaZookeeper;


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


    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals("configFileChecksum") && !this.config.isSlave()) {
            try {
                ZkUtils.updateEphemeralPath(this.zkClient, this.masterConfigChecksumPath,
                    String.valueOf(this.config.getConfigFileChecksum()));
            }
            catch (Exception e) {
                log.error("Update master config file checksum to zk failed", e);
            }
        }
    }


    MetaConfig getConfig() {
        return this.config;
    }


    public MetaZookeeper getMetaZookeeper() {
        return this.metaZookeeper;
    }


    public BrokerZooKeeper(final MetaConfig metaConfig) {
        this.config = metaConfig;
        this.zkConfig = metaConfig.getZkConfig();
        if (this.zkConfig == null) {
            this.zkConfig = this.loadZkConfigFromDiamond();
        }
        this.start(this.zkConfig);
        this.resetBrokerIdPath();
        this.masterConfigChecksumPath = this.metaZookeeper.masterConfigChecksum(this.config.getBrokerId());
        this.config.addPropertyChangeListener("configFileChecksum", this);
    }


    /**
     * ��ʱ��zk.properties�����.Ϊ�˷��㵥Ԫ����
     *
     * @return
     */
    private ZKConfig loadZkConfigFromDiamond() {
        Properties properties;
        try {
            properties = Utils.getResourceAsProperties("server.ini", "GBK");
            final ZKConfig zkConfig = new ZKConfig();
            if (StringUtils.isNotBlank(properties.getProperty("zk.zkConnect"))) {
                zkConfig.zkConnect = properties.getProperty("zk.zkConnect");
            }

            if (StringUtils.isNotBlank(properties.getProperty("zk.zkSessionTimeoutMs"))) {
                zkConfig.zkSessionTimeoutMs = Integer.parseInt(properties.getProperty("zk.zkSessionTimeoutMs"));
            }

            if (StringUtils.isNotBlank(properties.getProperty("zk.zkConnectionTimeoutMs"))) {
                zkConfig.zkConnectionTimeoutMs = Integer.parseInt(properties.getProperty("zk.zkConnectionTimeoutMs"));
            }

            if (StringUtils.isNotBlank(properties.getProperty("zk.zkSyncTimeMs"))) {
                zkConfig.zkSyncTimeMs = Integer.parseInt(properties.getProperty("zk.zkSyncTimeMs"));
            }

            return zkConfig;
        }
        catch (final IOException e) {
            log.error("zk����ʧ��", e);
            return null;
        }
        // ���Դ�diamond��ȡ
        // this.diamondManager =
        // new DefaultDiamondManager(this.config.getDiamondZKGroup(),
        // this.config.getDiamondZKDataId(),
        // new ManagerListener() {
        // @Override
        // public void receiveConfigInfo(final String configInfo) {
        // log.info("Receiving new diamond zk config:" + configInfo);
        // log.info("Closing zk client");
        // try {
        // BrokerZooKeeper.this.unregisterBrokerInZk();
        // BrokerZooKeeper.this.unregisterTopics();
        // BrokerZooKeeper.this.zkClient.close();
        // final Properties properties = new Properties();
        // properties.load(new StringReader(configInfo));
        // final ZKConfig zkConfig = DiamondUtils.getZkConfig(properties);
        // Thread.sleep(zkConfig.zkSyncTimeMs);
        // BrokerZooKeeper.this.start(zkConfig);
        // BrokerZooKeeper.this.reRegisterEveryThing();
        // log.info("Process new diamond zk config successfully");
        // }
        // catch (final Exception e) {
        // log.error("��diamond����zk����ʧ��", e);
        // }
        //
        // }
        //
        //
        // @Override
        // public Executor getExecutor() {
        // return null;
        // }
        // });
        // return null;// DiamondUtils.getZkConfig(this.diamondManager, 10000);
    }


    private void start(final ZKConfig zkConfig) {
        log.info("Initialize zk client...");
        this.zkClient =
                new ZkClient(zkConfig.zkConnect, zkConfig.zkSessionTimeoutMs, zkConfig.zkConnectionTimeoutMs,
                    new ZkUtils.StringSerializer());
        this.zkClient.subscribeStateChanges(new SessionExpireListener());
        this.metaZookeeper = new MetaZookeeper(this.zkClient, zkConfig.zkRoot);
    }


    /**
     * ע��broker��zk
     *
     * @throws Exception
     */
    public void registerBrokerInZk() throws Exception {
        if (!this.zkConfig.zkEnable) {
            return;
        }
        try {
            log.info("Registering broker " + this.brokerIdPath);
            final Broker broker = this.getBroker();

            ZkUtils.createEphemeralPath(this.zkClient, this.brokerIdPath, broker.getZKString());

            // �����Ͽͻ��ˣ���ʱ����
            if (!this.config.isSlave()) {
                ZkUtils.updateEphemeralPath(this.zkClient,
                    this.metaZookeeper.brokerIdsPath + "/" + this.config.getBrokerId(), broker.getZKString());
                log.info("register for old client version " + this.metaZookeeper.brokerIdsPath + "/"
                        + this.config.getBrokerId() + "  succeeded with " + broker);

            }
            log.info("Registering broker " + this.brokerIdPath + " succeeded with " + broker);
            this.registerBrokerInZkFail = false;
        }
        catch (final Exception e) {
            this.registerBrokerInZkFail = true;
            log.error("ע��brokerʧ��");
            throw e;
        }
    }

    // cache it.
    private Broker broker = null;


    public Broker getBroker() throws Exception {
        if (this.broker != null) {
            return this.broker;
        }
        else {
            final String hostName = this.getBrokerHostName();
            this.broker =
                    new Broker(this.config.getBrokerId(), hostName, this.config.getServerPort(),
                        this.config.getSlaveId());
            return this.broker;
        }
    }


    public String getBrokerString() {
        if (this.broker != null) {
            return this.broker.toString();
        }
        else {
            try {
                return this.getBroker().toString();
            }
            catch (Exception e) {
                return null;
            }
        }
    }


    public String getBrokerHostName() throws Exception {
        final String hostName =
                this.config.getHostName() == null ? RemotingUtils.getLocalHost() : this.config.getHostName();
                return hostName;
    }


    public void registerMasterConfigFileChecksumInZk() throws Exception {
        if (!this.zkConfig.zkEnable) {
            return;
        }
        try {
            if (!this.config.isSlave()) {
                ZkUtils.createEphemeralPath(this.zkClient, this.masterConfigChecksumPath,
                    String.valueOf(this.config.getConfigFileChecksum()));
            }
        }
        catch (final Exception e) {
            this.registerBrokerInZkFail = true;
            log.error("ע��brokerʧ��");
            throw e;
        }
    }


    private void unregisterBrokerInZk() throws Exception {
        if (this.registerBrokerInZkFail) {
            log.warn("�ϴ�ע��brokerδ�ɹ�,����Ҫunregister");
            return;
        }
        ZkUtils.deletePath(this.zkClient, this.brokerIdPath);
        if (!this.config.isSlave()) {
            ZkUtils.deletePath(this.zkClient, this.masterConfigChecksumPath);
        }
        // �����Ͽͻ��ˣ���ʱ����.
        if (!this.config.isSlave()) {
            try {
                ZkUtils.deletePath(this.zkClient, this.metaZookeeper.brokerIdsPath + "/" + this.config.getBrokerId());
            }
            catch (final Exception e) {
                // ��slaveʱ��ɾ������,д����ֵ��ȥ
                ZkUtils.updateEphemeralPath(this.zkClient,
                    this.metaZookeeper.brokerIdsPath + "/" + this.config.getBrokerId(), "");
            }
            log.info("delete broker of old client version " + this.metaZookeeper.brokerIdsPath + "/"
                    + this.config.getBrokerId());
        }
    }


    private void unregisterTopics() throws Exception {
        for (final String topic : BrokerZooKeeper.this.topics) {
            this.unregisterTopic(topic);
        }
    }


    public void unregisterEveryThing() {
        try {
            this.unregisterBrokerInZk();
            this.unregisterTopics();
        }
        catch (Exception e) {
            log.error("Unregister broker failed", e);
        }
    }


    private void unregisterTopic(final String topic) {
        try {
            int brokerId = this.config.getBrokerId();
            final String brokerTopicPath =
                    this.metaZookeeper.brokerTopicsPathOf(topic, brokerId, this.config.getSlaveId());
            final String topicPubPath =
                    this.metaZookeeper.brokerTopicsPathOf(topic, true, brokerId, this.config.getSlaveId());
            final String topicSubPath =
                    this.metaZookeeper.brokerTopicsPathOf(topic, false, brokerId, this.config.getSlaveId());

            // Be compatible with the version before 1.4.3
            ZkUtils.deletePath(this.zkClient, brokerTopicPath);

            // added by dennis,since 1.4.3
            ZkUtils.deletePath(this.zkClient, topicPubPath);
            ZkUtils.deletePath(this.zkClient, topicSubPath);
        }
        catch (Exception e) {
            log.error("Unregister topic " + topic + " failed,but don't worry about it.", e);
        }
    }


    /**
     * ע��topic�ͷ�����Ϣ��zk
     *
     * @param topic
     * @param force
     *            TODO
     * @throws Exception
     */
    public void registerTopicInZk(final String topic, boolean force) throws Exception {
        if (force) {
            // This block is not synchronized,because we don't force to register
            // topics frequently except reloading config file.
            TopicConfig oldConfig = this.cloneTopicConfigs.get(topic);
            TopicConfig newConfig = this.config.getTopicConfig(topic);
            if (this.compareTopicConfigs(newConfig, oldConfig)) {
                return;
            }
            else {
                this.unregisterTopic(topic);
                this.topics.add(topic);
                this.registerTopicInZkInternal(topic);
            }
        }
        else {
            if (!this.topics.add(topic)) {
                return;
            }
            else {
                this.registerTopicInZkInternal(topic);
            }
        }
    }


    private boolean compareTopicConfigs(TopicConfig c1, TopicConfig c2) {
        if (c1 == null && c2 != null) {
            return false;
        }
        if (c2 == null && c1 != null) {
            return false;
        }
        // If old and new configs are all null,we have to register it.
        if (c1 == null && c2 == null) {
            return false;
        }
        return c1.equals(c2);
    }


    public ZKConfig getZkConfig() {
        return this.zkConfig;
    }


    public Set<String> getTopics() {
        return this.topics;
    }


    public void reRegisterEveryThing() throws Exception {
        log.info("re-registering broker info in ZK for broker " + BrokerZooKeeper.this.config.getBrokerId());
        BrokerZooKeeper.this.registerBrokerInZk();
        log.info("re-registering broker topics in ZK for broker " + BrokerZooKeeper.this.config.getBrokerId());
        for (final String topic : BrokerZooKeeper.this.topics) {
            BrokerZooKeeper.this.registerTopicInZkInternal(topic);
        }
        this.registerMasterConfigFileChecksumInZk();
        log.info("done re-registering broker");
    }


    private void registerTopicInZkInternal(final String topic) throws Exception {
        if (!this.zkConfig.zkEnable) {
            log.warn("zkEnable is false,so we don't talk to zookeeper.");
            return;
        }
        int brokerId = this.config.getBrokerId();
        int slaveId = this.config.getSlaveId();
        final String brokerTopicPath = this.metaZookeeper.brokerTopicsPathOf(topic, brokerId, slaveId);
        final String topicPubPath = this.metaZookeeper.brokerTopicsPathOf(topic, true, brokerId, slaveId);
        final String topicSubPath = this.metaZookeeper.brokerTopicsPathOf(topic, false, brokerId, slaveId);
        final TopicConfig topicConfig = this.config.getTopicConfig(topic);
        Integer numParts = topicConfig != null ? topicConfig.getNumPartitions() : this.config.getNumPartitions();
        numParts = numParts == null ? this.config.getNumPartitions() : numParts;
        log.info("Begin registering broker topic " + brokerTopicPath + " with " + numParts + " partitions");

        final TopicBroker topicBroker = new TopicBroker(numParts, brokerId + (slaveId >= 0 ? "-s" + slaveId : "-m"));
        log.info("Register broker for topic:" + topicBroker);
        // Be compatible with the version before 1.4.3
        ZkUtils.createEphemeralPath(this.zkClient, brokerTopicPath, String.valueOf(numParts));

        // added by dennis,since 1.4.3
        String topicBrokerJson = topicBroker.toJson();
        if (topicConfig.isAcceptPublish()) {
            ZkUtils.createEphemeralPath(this.zkClient, topicPubPath, topicBrokerJson);
        }
        else {
            ZkUtils.deletePath(this.zkClient, topicPubPath);
        }

        if (topicConfig.isAcceptSubscribe()) {
            ZkUtils.createEphemeralPath(this.zkClient, topicSubPath, topicBrokerJson);
        }
        else {
            ZkUtils.deletePath(this.zkClient, topicSubPath);
        }
        this.cloneTopicConfigs.put(topic, topicConfig.clone());

        log.info("End registering broker topic " + brokerTopicPath);
    }


    public void close(boolean unregister) {
        try {
            if (unregister && this.zkConfig.zkEnable) {
                this.unregisterBrokerInZk();
                this.unregisterTopics();
            }
        }
        catch (final Exception e) {
            log.warn("error on unregisterBrokerInZk", e);
        }
        finally {
            if (this.zkClient != null) {
                log.info("Closing zk client...");
                this.zkClient.close();
            }
        }
    }

    private class SessionExpireListener implements IZkStateListener {

        @Override
        public void handleNewSession() throws Exception {
            BrokerZooKeeper.this.reRegisterEveryThing();

        }


        @Override
        public void handleStateChanged(final KeeperState state) throws Exception {
            // do nothing, since zkclient will do reconnect for us.

        }

    }


    /**
     * ���¼���brokerIdPath
     */
    public void resetBrokerIdPath() {
        this.brokerIdPath = this.metaZookeeper.brokerIdsPathOf(this.config.getBrokerId(), this.config.getSlaveId());
    }
}
TOP

Related Classes of com.taobao.metamorphosis.server.BrokerZooKeeper$SessionExpireListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.