All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.sanenen.sunutils.queue.SQueue Maven / Gradle / Ivy

package cn.sanenen.sunutils.queue;

import cn.hutool.log.Log;
import cn.sanenen.sunutils.queue.data.DataEntity;
import cn.sanenen.sunutils.queue.data.DataIndex;
import cn.sanenen.sunutils.queue.data.FileRunner;
import cn.sanenen.sunutils.queue.exception.FileEOFException;
import cn.sanenen.sunutils.queue.exception.FileFormatException;

import java.io.File;
import java.io.IOException;

/**
 * 完成基于文件的先进先出的读写功能
 * 不允许外部创建 请使用FQS
 *
 * @author sun
 */
public class SQueue {
	private static final Log log = Log.get();
	private static final String dbName = "index.i";

	private final int fileLimitLength;
	private final String path;
	private final DataIndex db;
	/**
	 * 文件操作实例
	 */
	private DataEntity writerHandle;
	private DataEntity readerHandle;
	/**
	 * 文件操作位置信息
	 */
	private int readerIndex;
	private int writerIndex;

	private final Object lock = new Object();

	protected SQueue(String path) throws Exception {
		this(path, 1024 * 1024 * 50);
	}

	/**
	 * 在指定的目录中,以fileLimitLength为单个数据文件的最大大小限制初始化队列存储
	 *
	 * @param dir             队列数据存储的路径
	 * @param fileLimitLength 单个数据文件的大小,不能超过2G
	 */
	protected SQueue(String dir, int fileLimitLength) throws Exception {
		this.fileLimitLength = fileLimitLength;
		File fileDir = new File(dir);
		if (!fileDir.exists() && !fileDir.isDirectory()) {
			if (!fileDir.mkdirs()) {
				throw new IOException("create dir error");
			}
		}
		path = fileDir.getAbsolutePath();
		// 打开db
		db = new DataIndex(path + QueueConstant.FILE_SEPARATOR + dbName);
		writerIndex = db.getWriterIndex();
		readerIndex = db.getReaderIndex();
		writerHandle = createLogEntity(getLogPath(writerIndex),
				writerIndex);
		if (readerIndex == writerIndex) {
			readerHandle = writerHandle;
		} else {
			readerHandle = createLogEntity(getLogPath(readerIndex),
					readerIndex);
		}
	}

	/**
	 * 创建或者获取一个数据读写实例
	 *
	 * @param dbpath     数据文件完整路径含文件名
	 * @param fileNumber 文件编号
	 */
	private DataEntity createLogEntity(String dbpath, int fileNumber) throws IOException,
			FileFormatException {
		return new DataEntity(dbpath, fileNumber, this.fileLimitLength);
	}

	/**
	 * 一个文件的数据写入达到fileLimitLength的时候,滚动到下一个文件实例
	 */
	private void rotateNextLogWriter() throws IOException, FileFormatException {
		writerIndex = writerIndex + 1;
		synchronized (lock) {
			if (readerHandle != writerHandle) {
				writerHandle.close();
			}
			db.putWriterIndex(writerIndex);
			if (readerHandle.getCurrentFileNumber() == writerIndex){
				writerHandle = readerHandle;
			}else {
				writerHandle = createLogEntity(getLogPath(writerIndex), writerIndex);
			}
		}
	}

	private String getLogPath(int index) {
		return path + QueueConstant.FILE_SEPARATOR + "data_" + index + ".d";
	}

	/**
	 * 向队列存储添加一个byte数组
	 *
	 * @param message 数据
	 */
	public synchronized void add(byte[] message) throws IOException, FileFormatException {
		short status = writerHandle.write(message);
		if (status == DataEntity.WRITE_FULL) {
			rotateNextLogWriter();
			status = writerHandle.write(message);
		}
		if (status == DataEntity.WRITE_SUCCESS) {
			db.incrementSize();
		}
	}

	/**
	 * 从队列存储中取出最先入队的数据,并移除它
	 */
	public synchronized byte[] readNextAndRemove() throws IOException, FileFormatException {
		byte[] b = null;
		try {
			b = readerHandle.readNextAndRemove();
		} catch (FileEOFException e) {
			int deleteNum = readerHandle.getCurrentFileNumber();
			int nextFile = deleteNum + 1;
			readerHandle.close();
			FileRunner.addDeleteFile(getLogPath(deleteNum));
			db.putReaderIndex(nextFile);
			synchronized (lock) {
				if (writerHandle.getCurrentFileNumber() == nextFile && writerHandle.getMappedByteBuffer() != null) {
					readerHandle = writerHandle;
				} else {
					readerHandle = createLogEntity(getLogPath(nextFile), nextFile);
				}
			}
			try {
				b = readerHandle.readNextAndRemove();
			} catch (FileEOFException e1) {
				log.error("read new log file FileEOFException error occurred", e1);
			}
		}
		if (b != null) {
			db.decrementSize();
		}
		return b;
	}

	public void close() {
		db.close();
		readerHandle.close();
		writerHandle.close();
	}

	public long getQueueSize() {
		return db.getSize();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy