/** * Copyright (C) 2010-2013 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. */ package com.alibaba.rocketmq.store; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.rocketmq.common.UtilAll; import com.alibaba.rocketmq.common.constant.LoggerName; /** * 记录存储模型最终一致的时间点 * * @author shijia.wxr<vintage.wang@gmail.com> * @since 2013-7-21 */ public class StoreCheckpoint { private static final Logger log = LoggerFactory.getLogger(LoggerName.StoreLoggerName); private final RandomAccessFile randomAccessFile; private final FileChannel fileChannel; private final MappedByteBuffer mappedByteBuffer; private volatile long physicMsgTimestamp = 0; private volatile long logicsMsgTimestamp = 0; private volatile long indexMsgTimestamp = 0; public StoreCheckpoint(final String scpPath) throws IOException { File file = new File(scpPath); MapedFile.ensureDirOK(file.getParent()); boolean fileExists = file.exists(); this.randomAccessFile = new RandomAccessFile(file, "rw"); this.fileChannel = this.randomAccessFile.getChannel(); this.mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, MapedFile.OS_PAGE_SIZE); if (fileExists) { log.info("store checkpoint file exists, " + scpPath); this.physicMsgTimestamp = this.mappedByteBuffer.getLong(0); this.logicsMsgTimestamp = this.mappedByteBuffer.getLong(8); this.indexMsgTimestamp = this.mappedByteBuffer.getLong(16); log.info("store checkpoint file physicMsgTimestamp " + this.physicMsgTimestamp + ", " + UtilAll.timeMillisToHumanString(this.physicMsgTimestamp)); log.info("store checkpoint file logicsMsgTimestamp " + this.logicsMsgTimestamp + ", " + UtilAll.timeMillisToHumanString(this.logicsMsgTimestamp)); log.info("store checkpoint file indexMsgTimestamp " + this.indexMsgTimestamp + ", " + UtilAll.timeMillisToHumanString(this.indexMsgTimestamp)); } else { log.info("store checkpoint file not exists, " + scpPath); } } public void shutdown() { this.flush(); // unmap mappedByteBuffer MapedFile.clean(this.mappedByteBuffer); try { this.fileChannel.close(); } catch (IOException e) { e.printStackTrace(); } } public void flush() { this.mappedByteBuffer.putLong(0, this.physicMsgTimestamp); this.mappedByteBuffer.putLong(8, this.logicsMsgTimestamp); this.mappedByteBuffer.putLong(16, this.indexMsgTimestamp); this.mappedByteBuffer.force(); } public long getPhysicMsgTimestamp() { return physicMsgTimestamp; } public void setPhysicMsgTimestamp(long physicMsgTimestamp) { this.physicMsgTimestamp = physicMsgTimestamp; } public long getLogicsMsgTimestamp() { return logicsMsgTimestamp; } public void setLogicsMsgTimestamp(long logicsMsgTimestamp) { this.logicsMsgTimestamp = logicsMsgTimestamp; } public long getMinTimestampIndex() { return Math.min(Math.min(this.physicMsgTimestamp, this.logicsMsgTimestamp), this.indexMsgTimestamp); } public long getMinTimestamp() { return Math.min(this.physicMsgTimestamp, this.logicsMsgTimestamp); } public long getIndexMsgTimestamp() { return indexMsgTimestamp; } public void setIndexMsgTimestamp(long indexMsgTimestamp) { this.indexMsgTimestamp = indexMsgTimestamp; } }