package com.ctriposs.bigcache.storage; 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; public class MemoryMappedStorage implements IStorage { private RandomAccessFile raf; private ThreadLocalByteBuffer threadLocalBuffer; public MemoryMappedStorage(String dir, int index, int capacity) throws IOException { File backFile = new File(dir); if (!backFile.exists()) { backFile.mkdirs(); } String backFileName = dir + index + "-" + System.currentTimeMillis() + DATA_FILE_SUFFIX; raf = new RandomAccessFile(backFileName, "rw"); MappedByteBuffer mappedByteBuffer = raf.getChannel().map(FileChannel.MapMode.PRIVATE, 0, capacity); threadLocalBuffer = new ThreadLocalByteBuffer(mappedByteBuffer); } private ByteBuffer getLocal(int position) { ByteBuffer buffer = threadLocalBuffer.get(); buffer.position(position); return buffer; } @Override public void close() throws IOException { if (raf != null) { raf.close(); } //implies system GC threadLocalBuffer.set(null); threadLocalBuffer = null; } @Override public void get(int position, byte[] dest) throws IOException { ByteBuffer buffer = this.getLocal(position); buffer.get(dest); } @Override public void put(int position, byte[] source) throws IOException { ByteBuffer buffer = this.getLocal(position); buffer.put(source); } @Override public void free() { MappedByteBuffer buffer = (MappedByteBuffer) threadLocalBuffer.getSourceBuffer(); buffer.clear(); } 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() { ByteBuffer dup = _src.duplicate(); return dup; } } }