package com.ctriposs.tsdb.common; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import com.ctriposs.tsdb.util.FileUtil; public class MapFileStorage implements IStorage { private RandomAccessFile raf; private FileChannel fileChannel; private ThreadLocalByteBuffer threadLocalBuffer; private MappedByteBuffer mappedByteBuffer; private String fullFileName; public MapFileStorage(String dir, long time, String suffix, long capacity) throws IOException { File backFile = new File(dir); if (!backFile.exists()) { backFile.mkdirs(); } fullFileName = dir + time + "-" + suffix; raf = new RandomAccessFile(fullFileName, "rw"); fileChannel = raf.getChannel(); mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, capacity); threadLocalBuffer = new ThreadLocalByteBuffer(mappedByteBuffer); } public MapFileStorage(File file) throws IOException { raf = new RandomAccessFile(file, "rw"); fullFileName = file.getPath(); mappedByteBuffer = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, file.length()); threadLocalBuffer = new ThreadLocalByteBuffer(mappedByteBuffer); } private ByteBuffer getLocal(long position) { ByteBuffer buffer = threadLocalBuffer.get(); buffer.position((int)position); return buffer; } @Override public void close() throws IOException { if (this.fileChannel != null) { this.fileChannel.close(); } if (raf != null) { raf.close(); } //implies system GC try { FileUtil.unmap(mappedByteBuffer); } catch (Throwable e) { throw new IOException(e); } threadLocalBuffer.set(null); threadLocalBuffer = null; } @Override public void get(long position, byte[] dest) throws IOException { ByteBuffer buffer = this.getLocal(position); buffer.get(dest); } @Override public void put(long position, byte[] source) throws IOException { ByteBuffer buffer = this.getLocal(position); buffer.put(source); } @Override public void put(long position, ByteBuffer source) throws IOException { ByteBuffer buffer = this.getLocal(position); buffer.put(source); } @Override public void free() { MappedByteBuffer buffer = (MappedByteBuffer) threadLocalBuffer.getSourceBuffer(); buffer.clear(); try { fileChannel.truncate(0); } catch (IOException e) { } } private static class ThreadLocalByteBuffer extends ThreadLocal<ByteBuffer> { private ByteBuffer _src; public ThreadLocalByteBuffer(ByteBuffer src) { _src = src; } public ByteBuffer getSourceBuffer() { return _src; } @Override protected synchronized ByteBuffer initialValue() { return _src.duplicate(); } } @Override public String getName() { return fullFileName; } }