package com.jivesoftware.os.amza.service.filer; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * */ public class FileBackedMemMappedByteBufferFactory implements ByteBufferFactory { private final File file; private final long segmentSize; public FileBackedMemMappedByteBufferFactory(File file, long segmentSize) { this.file = file; this.segmentSize = segmentSize; } @Override public ByteBuffer allocate(int index, long length) { try { //System.out.println(String.format("Allocate key=%s length=%s for directories=%s", key, length, Arrays.toString(directories))); ensureDirectory(file.getParentFile()); long segmentOffset = segmentSize * index; long requiredLength = segmentOffset + length; try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { if (requiredLength > raf.length()) { raf.seek(requiredLength - 1); raf.write(0); } raf.seek(segmentOffset); try (FileChannel channel = raf.getChannel()) { return channel.map(FileChannel.MapMode.READ_WRITE, segmentOffset, Math.min(segmentSize, channel.size() - segmentOffset)); } } } catch (IOException e) { throw new RuntimeException(e); } } @Override public ByteBuffer reallocate(int index, ByteBuffer oldBuffer, long newSize) { //System.out.println(String.format("Reallocate key=%s newSize=%s for directories=%s", key, newSize, Arrays.toString(directories))); return allocate(index, newSize); } @Override public long length() { return file.length(); } @Override public long nextLength(int index, long oldLength, long position) { long segmentOffset = segmentSize * index; return Math.min(segmentSize, file.length() - segmentOffset); } @Override public void close(ByteBufferBackedFiler[] filers) throws IOException { if (filers.length > 0) { for (ByteBufferBackedFiler filer : filers) { filer.close(); } ByteBuffer bb = filers[0].buffer; if (bb != null) { DirectBufferCleaner.clean(bb); } } } private void ensureDirectory(File directory) { if (!directory.exists()) { if (!directory.mkdirs()) { if (!directory.exists()) { throw new RuntimeException("Failed to create directory: " + directory); } } } } }