package io.trygvis.btree; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.NoSuchElementException; public class HeapPage { public static final int headerSize = 4; public static final int FREE_POSITION_INDEX = 0; public static final int itemSize = 4; // The page number in a heap file final long pageNumber; final ByteBuffer bytes; int freePosition; private HeapPage(long pageNumber, ByteBuffer bytes, int freePosition) { this.pageNumber = pageNumber; this.bytes = bytes; this.freePosition = freePosition; } public static HeapPage heapPageFromBytes(int pageNumber, ByteBuffer bytes) { int freePosition = bytes.getInt(); return new HeapPage(pageNumber, bytes, freePosition); } public static HeapPage blankHeapPage(ByteBuffer bytes) { return new HeapPage(-1, bytes, bytes.capacity()); } public void append(byte[] item) { // System.out.println("io.trygvis.btree.HeapPage.append"); int bytesFree = bytesFree(); int bytesRequested = item.length; if (bytesRequested > bytesFree) { throw new PageOverflowException(bytesFree, bytesRequested); } freePosition -= itemSize; bytes.position(freePosition); bytes.putInt(item.length); freePosition -= bytesRequested; bytes.position(freePosition); bytes.put(item); bytes.putInt(FREE_POSITION_INDEX, freePosition); } public int bytesFree() { return freePosition - headerSize; } public Iterable bufferIterator() { return new Iterable() { @Override public Iterator iterator() { return new Iterator() { private int position; private ByteBuffer next; { position = bytes.capacity(); next = findNext(); } private ByteBuffer findNext() { if (position == headerSize) { return null; } int size = bytes.getInt(position - itemSize); if (size == 0) { return null; } position -= itemSize + size; ByteBuffer copy = bytes.duplicate(); copy.position(position); copy.limit(position + size); return copy.slice(); } public boolean hasNext() { return next != null; } @Override public ByteBuffer next() { if (next == null) { throw new NoSuchElementException(); } ByteBuffer n = next; next = findNext(); return n; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }; } public static class PageOverflowException extends RuntimeException { public final int bytesFree; public final int bytesRequested; public PageOverflowException(int bytesFree, int bytesRequested) { super("Not enough room on page, bytes free=" + bytesFree + ", requested = " + bytesRequested); this.bytesFree = bytesFree; this.bytesRequested = bytesRequested; } } }