/*
* (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>
*/
package com.taobao.metamorphosis.metaslave;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.taobao.metamorphosis.client.RemotingClientWrapper;
import com.taobao.metamorphosis.client.consumer.ConsumerConfig;
import com.taobao.metamorphosis.client.consumer.ConsumerZooKeeper;
import com.taobao.metamorphosis.client.consumer.FetchManager;
import com.taobao.metamorphosis.client.consumer.LoadBalanceStrategy;
import com.taobao.metamorphosis.client.consumer.SubscriberInfo;
import com.taobao.metamorphosis.client.consumer.storage.OffsetStorage;
import com.taobao.metamorphosis.cluster.Cluster;
import com.taobao.metamorphosis.exception.MetaClientException;
import com.taobao.metamorphosis.utils.MetaZookeeper;
import com.taobao.metamorphosis.utils.MetaZookeeper.ZKGroupDirs;
import com.taobao.metamorphosis.utils.MetaZookeeper.ZKGroupTopicDirs;
import com.taobao.metamorphosis.utils.ZkUtils.ZKConfig;
/**
* Ϊslave������Ϣ��չ��ConsumerZooKeeper
*
* @author ��
* @since 2011-6-27 ����03:04:11
*/
public class SlaveConsumerZooKeeper extends ConsumerZooKeeper {
private static final Log log = LogFactory.getLog(SlaveConsumerZooKeeper.class);
private final int brokerId;
public SlaveConsumerZooKeeper(final MetaZookeeper metaZookeeper, final RemotingClientWrapper remotingClient,
final ZkClient zkClient, final ZKConfig zkConfig, final int brokerId) {
super(metaZookeeper, remotingClient, zkClient, zkConfig);
this.brokerId = brokerId;
}
@Override
public void registerConsumer(final ConsumerConfig consumerConfig, final FetchManager fetchManager,
final ConcurrentHashMap<String, SubscriberInfo> topicSubcriberRegistry, final OffsetStorage offsetStorage,
final LoadBalanceStrategy loadBalanceStrategy) throws Exception {
final FutureTask<ZKLoadRebalanceListener> task =
new FutureTask<ZKLoadRebalanceListener>(new Callable<ZKLoadRebalanceListener>() {
@Override
public ZKLoadRebalanceListener call() throws Exception {
final ZKGroupDirs dirs =
SlaveConsumerZooKeeper.this.metaZookeeper.new ZKGroupDirs(consumerConfig.getGroup());
final String consumerUUID = SlaveConsumerZooKeeper.this.getConsumerUUID(consumerConfig);
final String consumerUUIDString = consumerConfig.getGroup() + "_" + consumerUUID;
final ZKLoadRebalanceListener loadBalanceListener =
new SlaveZKLoadRebalanceListener(fetchManager, dirs, consumerUUIDString,
consumerConfig, offsetStorage, topicSubcriberRegistry, loadBalanceStrategy);
loadBalanceListener.start();
return SlaveConsumerZooKeeper.this.registerConsumerInternal(loadBalanceListener);
}
});
final FutureTask<ZKLoadRebalanceListener> existsTask =
this.consumerLoadBalanceListeners.putIfAbsent(fetchManager, task);
if (existsTask == null) {
task.run();
}
else {
throw new MetaClientException("Consumer has been already registed");
}
}
// slaveֻѡȡmaster��ص�partition,�����ӵ�������Щpartition
class SlaveZKLoadRebalanceListener extends ZKLoadRebalanceListener {
public SlaveZKLoadRebalanceListener(final FetchManager fetchManager, final ZKGroupDirs dirs,
final String consumerIdString, final ConsumerConfig consumerConfig, final OffsetStorage offsetStorage,
final ConcurrentHashMap<String, SubscriberInfo> topicSubcriberRegistry,
final LoadBalanceStrategy loadBalanceStrategy) {
super(fetchManager, dirs, consumerIdString, consumerConfig, offsetStorage, topicSubcriberRegistry,
loadBalanceStrategy);
}
@Override
protected Map<String, List<String>> getConsumersPerTopic(final String group) throws Exception {
// ֻ����slave����
final List<String> topics = this.getTopics(this.consumerIdString);
final Map<String/* topic */, List<String>/* consumerId */> rt = new HashMap<String, List<String>>();
List<String> list;
for (final String topic : topics) {
list = new ArrayList<String>();
list.add(this.consumerIdString);
rt.put(topic, list);
}
return rt;
}
@Override
protected Map<String, List<String>> getPartitionStringsForTopics(final Map<String, String> myConsumerPerTopicMap) {
// ֻ����master��Ӧ��partition
final Map<String, List<String>> ret =
SlaveConsumerZooKeeper.this.metaZookeeper.getPartitionStringsForSubTopicsFromMaster(
myConsumerPerTopicMap.keySet(), SlaveConsumerZooKeeper.this.brokerId);
if (log.isDebugEnabled()) {
log.debug("getPartitionStringsForTopics,topics:" + myConsumerPerTopicMap.keySet() + ",brokerId:"
+ SlaveConsumerZooKeeper.this.brokerId + ",result:" + ret);
}
return ret;
}
@Override
protected void updateFetchRunner(final Cluster cluster) throws Exception {
super.updateFetchRunner(cluster.masterCluster());
}
@Override
protected boolean checkClusterChange(final Cluster cluster) {
// ȷ����Ⱥ�б仯�����Ҽ���Լ���Ӧ��master,���ⲻ��ص�master���˵���slaveҲ����
return super.checkClusterChange(cluster)
&& cluster.getMasterBroker(SlaveConsumerZooKeeper.this.brokerId) == null;
}
@Override
protected boolean ownPartition(final ZKGroupTopicDirs topicDirs, final String partition,
final String topic, final String consumerThreadId) throws Exception {
// ��owner partition,��������slave���ܶ���
super.addPartitionTopicInfo(topicDirs, partition, topic, consumerThreadId);
return true;
}
}
}