/*
* (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.client.consumer.storage;
import java.util.Collection;
import org.I0Itec.zkclient.ZkClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.taobao.metamorphosis.client.ZkClientChangedListener;
import com.taobao.metamorphosis.client.consumer.TopicPartitionRegInfo;
import com.taobao.metamorphosis.cluster.Partition;
import com.taobao.metamorphosis.utils.MetaZookeeper;
import com.taobao.metamorphosis.utils.MetaZookeeper.ZKGroupTopicDirs;
import com.taobao.metamorphosis.utils.ZkUtils;
/**
* ����zk��offset�洢��
*
* @author boyan
* @Date 2011-4-28
*
*/
public class ZkOffsetStorage implements OffsetStorage, ZkClientChangedListener {
private volatile ZkClient zkClient;
private final MetaZookeeper metaZookeeper;
@Override
public void onZkClientChanged(final ZkClient newClient) {
log.info("Update ZkOffsetStorage's zkClient...");
this.zkClient = newClient;
}
public ZkOffsetStorage(final MetaZookeeper metaZookeeper, final ZkClient zkClient) {
super();
this.metaZookeeper = metaZookeeper;
this.zkClient = zkClient;
}
static final Log log = LogFactory.getLog(ZkOffsetStorage.class);
@Override
public void commitOffset(final String group, final Collection<TopicPartitionRegInfo> infoList) {
if (this.zkClient == null || infoList == null || infoList.isEmpty()) {
return;
}
for (final TopicPartitionRegInfo info : infoList) {
final String topic = info.getTopic();
final ZKGroupTopicDirs topicDirs = this.metaZookeeper.new ZKGroupTopicDirs(topic, group);
long newOffset = -1;
long msgId = -1;
// ��������֤msgId��offsetһ��
synchronized (info) {
// ֻ�����б����
if (!info.isModified()) {
continue;
}
newOffset = info.getOffset().get();
msgId = info.getMessageId();
// ������ϣ�����Ϊfalse
info.setModified(false);
}
try {
// �洢��zk�������ΪmsgId-offset
// ԭʼֻ��offset����1.4��ʼ��ΪmsgId-offset,Ϊ��ʵ��ͬ������
ZkUtils.updatePersistentPath(this.zkClient, topicDirs.consumerOffsetDir + "/"
+ info.getPartition().toString(), msgId + "-" + newOffset);
}
catch (final Throwable t) {
log.error("exception during commitOffsets", t);
}
if (log.isDebugEnabled()) {
log.debug("Committed offset " + newOffset + " for topic " + info.getTopic());
}
}
}
@Override
public TopicPartitionRegInfo load(final String topic, final String group, final Partition partition) {
final ZKGroupTopicDirs topicDirs = this.metaZookeeper.new ZKGroupTopicDirs(topic, group);
final String znode = topicDirs.consumerOffsetDir + "/" + partition.toString();
final String offsetString = ZkUtils.readDataMaybeNull(this.zkClient, znode);
if (offsetString == null) {
return null;
}
else {
// �����Ͽͻ���
final int index = offsetString.lastIndexOf("-");
if (index > 0) {
// 1.4��ʼ���¿ͻ���
final long msgId = Long.parseLong(offsetString.substring(0, index));
final long offset = Long.parseLong(offsetString.substring(index + 1));
return new TopicPartitionRegInfo(topic, partition, offset, msgId);
}
else {
// �Ͽͻ���
final long offset = Long.parseLong(offsetString);
return new TopicPartitionRegInfo(topic, partition, offset);
}
}
}
@Override
public void close() {
// do nothing
}
@Override
public void initOffset(final String topic, final String group, final Partition partition, final long offset) {
// do nothing
}
}