package com.jivesoftware.os.amza.service.storage.filer; import com.jivesoftware.os.amza.api.filer.IReadable; import com.jivesoftware.os.amza.api.filer.HeapFiler; import java.io.IOException; /** * */ public class HeapBufferedReadable implements IReadable { private final IReadable backingReadable; private final int bufferSize; private long startOfBufferFp; private HeapFiler buffer; public HeapBufferedReadable(IReadable backingReadable, int bufferSize) { this.backingReadable = backingReadable; this.bufferSize = bufferSize; } @Override public long getFilePointer() throws IOException { if (buffer == null) { return backingReadable.getFilePointer(); } return startOfBufferFp + buffer.getFilePointer(); } public HeapFiler ensureHeapFiler(long position, int needed) throws IOException { if (buffer != null && position >= startOfBufferFp && position + needed < (startOfBufferFp + buffer.length())) { buffer.seek(position - startOfBufferFp); return buffer; } else { backingReadable.seek(position); long remaining = length() - position; int nextBufferSize = Math.max(bufferSize, needed); int used = (int) Math.min(remaining, (long) nextBufferSize); if (buffer == null || needed > buffer.leakBytes().length) { byte[] bytes = new byte[nextBufferSize]; backingReadable.read(bytes, 0, used); buffer = HeapFiler.fromBytes(bytes, used); } else { buffer.reset(used); backingReadable.read(buffer.leakBytes(), 0, used); } startOfBufferFp = position; return buffer; } } @Override public void seek(long position) throws IOException { ensureHeapFiler(position, 0); } @Override public int read() throws IOException { return ensureHeapFiler(getFilePointer(), 1).read(); } @Override public int read(byte[] b) throws IOException { return ensureHeapFiler(getFilePointer(), b.length).read(b); } @Override public int read(byte[] b, int _offset, int _len) throws IOException { return ensureHeapFiler(getFilePointer(), _len).read(b, _offset, _len); } @Override public void close() throws IOException { if (buffer != null) { buffer.close(); } backingReadable.close(); } @Override public Object lock() { return backingReadable; } @Override public long length() throws IOException { return backingReadable.length(); } }