
org.zbus.mq.disk.DiskQueueIndex Maven / Gradle / Ivy
package org.zbus.mq.disk;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.zbus.kit.log.Logger;
public class DiskQueueIndex {
static final Logger log = Logger.getLogger(DiskQueueIndex.class);
private static final String MAGIC = "v100";
private static final String INDEX_FILE_SUFFIX = ".idx";
private static final int EXT_ITEM_SIZE = 256;
private static final int EXT_ITEM_CNT = 4;
private static final int INDEX_SIZE = 32 + EXT_ITEM_SIZE*EXT_ITEM_CNT;
private static final int FLAG_OFFSET = 4;
private static final int READ_NUM_OFFSET = 8;
private static final int READ_POS_OFFSET = 12;
private static final int READ_CNT_OFFSET = 16;
private static final int WRITE_NUM_OFFSET = 20;
private static final int WRITE_POS_OFFSET = 24;
private static final int WRITE_CNT_OFFSET = 28;
private static final int EXT_OFFSET = 32;
private String[] extentions = new String[EXT_ITEM_CNT];
private int flag; // 4
private volatile int readNum; // 8
private volatile int readPosition; // 12
private volatile int readCounter; // 16
private volatile int writeNum; // 20
private volatile int writePosition; // 24
private volatile int writeCounter; // 28
private RandomAccessFile indexFile;
private FileChannel fileChannel;
// 读写分离
private MappedByteBuffer writeIndex;
private MappedByteBuffer readIndex;
public DiskQueueIndex(String indexFilePath) {
File file = new File(indexFilePath);
try {
if (file.exists()) {
this.indexFile = new RandomAccessFile(file, "rw");
byte[] bytes = new byte[4];
this.indexFile.read(bytes, 0, 4);
if (!MAGIC.equals(new String(bytes))) {
throw new IllegalArgumentException("version mismatch");
}
long size = indexFile.length();
if(size < INDEX_SIZE){
indexFile.setLength(INDEX_SIZE);
indexFile.seek(size);
indexFile.write(new byte[(int)(INDEX_SIZE-size)]);
}
indexFile.seek(4);
this.flag = indexFile.readInt();
this.readNum = indexFile.readInt();
this.readPosition = indexFile.readInt();
this.readCounter = indexFile.readInt();
this.writeNum = indexFile.readInt();
this.writePosition = indexFile.readInt();
this.writeCounter = indexFile.readInt();
this.readExt();
this.fileChannel = indexFile.getChannel();
this.writeIndex = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, INDEX_SIZE);
this.writeIndex = writeIndex.load();
this.readIndex = (MappedByteBuffer) writeIndex.duplicate();
} else {
this.indexFile = new RandomAccessFile(file, "rw");
this.fileChannel = indexFile.getChannel();
this.writeIndex = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, INDEX_SIZE);
this.readIndex = (MappedByteBuffer) writeIndex.duplicate();
putMagic();
putFlag(0);
putReadNum(0);
putReadPosition(0);
putReadCounter(0);
putWriteNum(0);
putWritePosition(0);
putWriteCounter(0);
this.initExt();
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public static boolean isIndexFile(String fileName) {
return fileName.endsWith(INDEX_FILE_SUFFIX);
}
public static String parseQueueName(String indexFileName) {
String fileName = indexFileName.substring(0, indexFileName.lastIndexOf('.'));
return fileName;
}
public static String formatIndexFilePath(String queueName, String fileBackupDir) {
return fileBackupDir + File.separator + String.format("%s%s", queueName, INDEX_FILE_SUFFIX);
}
public int getFlag(){
return this.flag;
}
public int getReadNum() {
return this.readNum;
}
public int getReadPosition() {
return this.readPosition;
}
public int getReadCounter() {
return this.readCounter;
}
public int getWriteNum() {
return this.writeNum;
}
public int getWritePosition() {
return this.writePosition;
}
public int getWriteCounter() {
return this.writeCounter;
}
public void putMagic() {
this.writeIndex.position(0);
this.writeIndex.put(MAGIC.getBytes());
}
public void putFlag(int flag){
this.writeIndex.position(FLAG_OFFSET);
this.writeIndex.putInt(flag);
this.flag = flag;
}
public void putWritePosition(int writePosition) {
this.writeIndex.position(WRITE_POS_OFFSET);
this.writeIndex.putInt(writePosition);
this.writePosition = writePosition;
}
public void putWriteNum(int writeNum) {
this.writeIndex.position(WRITE_NUM_OFFSET);
this.writeIndex.putInt(writeNum);
this.writeNum = writeNum;
}
public void putWriteCounter(int writeCounter) {
this.writeIndex.position(WRITE_CNT_OFFSET);
this.writeIndex.putInt(writeCounter);
this.writeCounter = writeCounter;
}
public void putReadNum(int readNum) {
this.readIndex.position(READ_NUM_OFFSET);
this.readIndex.putInt(readNum);
this.readNum = readNum;
}
public void putReadPosition(int readPosition) {
this.readIndex.position(READ_POS_OFFSET);
this.readIndex.putInt(readPosition);
this.readPosition = readPosition;
}
public void putReadCounter(int readCounter) {
this.readIndex.position(READ_CNT_OFFSET);
this.readIndex.putInt(readCounter);
this.readCounter = readCounter;
}
private void initExt(){
for(int i=0; i= EXT_ITEM_CNT){
throw new IllegalArgumentException("idx invalid");
}
this.indexFile.seek(EXT_OFFSET + EXT_ITEM_SIZE*idx);
int len = indexFile.readByte();
if(len <= 0){
this.extentions[idx] = null;
return;
}
if(len > EXT_ITEM_SIZE -1){
throw new IOException("lenght of ext1 invalid, too long");
}
byte[] bb = new byte[len];
this.indexFile.read(bb, 0, len);
this.extentions[idx] = new String(bb);
}
public void putExt(int idx, String value){
if(idx < 0 || idx >= EXT_ITEM_CNT){
throw new IllegalArgumentException("idx invalid");
}
this.extentions[idx] = value;
this.readIndex.position(EXT_OFFSET + EXT_ITEM_SIZE*idx);
if(value == null){
this.readIndex.put((byte)0);
return;
}
if(value.length() > EXT_ITEM_SIZE - 1){
throw new IllegalArgumentException(value + " too long");
}
this.readIndex.put((byte)value.length());
this.readIndex.put(value.getBytes());
}
public String getExt(int idx){
if(idx < 0 || idx >= EXT_ITEM_CNT){
throw new IllegalArgumentException("idx invalid");
}
return this.extentions[idx];
}
public void reset() {
int size = writeCounter - readCounter;
putReadCounter(0);
putWriteCounter(size);
if (size == 0 && readNum == writeNum) {
putReadPosition(0);
putWritePosition(0);
}
}
public void sync() {
if (writeIndex != null) {
writeIndex.force();
}
}
public void close() {
try {
if (writeIndex == null) {
return;
}
sync();
AccessController.doPrivileged(new PrivilegedAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy