public static int binarySearch( @NotNull final IByteIterableComparator comparator, final ByteIterable key, int low, int high, final int bytesPerLong, Log log, long startAddress) { final LogCache cache = log.cache; final int pageSize = log.getCachePageSize(); final int mask = pageSize - 1; // page size is always a power of 2 long leftAddress = -1L; byte[] leftPage = null; long rightAddress = -1L; byte[] rightPage = null; final BinarySearchIterator it = new BinarySearchIterator(pageSize); while (low <= high) { final int mid = (low + high + 1) >>> 1; final long midAddress = startAddress + (mid * bytesPerLong); it.offset = ((int) midAddress) & mask; it.address = midAddress - it.offset; boolean loaded = false; if (it.address == leftAddress) { it.page = leftPage; } else if (it.address == rightAddress) { it.page = rightPage; } else { it.page = cache.getPage(log, it.address).getBytesUnsafe(); loaded = true; } final int cmp; final long address; final byte[] page; if (pageSize - it.offset < bytesPerLong) { final long nextAddress = (address = it.address) + pageSize; if (rightAddress == nextAddress) { it.nextPage = rightPage; } else { it.nextPage = cache.getPage(log, nextAddress).getBytesUnsafe(); loaded = true; } page = it.page; cmp = comparator.compare(LongBinding.entryToUnsignedLong(it.asCompound(), bytesPerLong), key); } else { cmp = comparator.compare(LongBinding.entryToUnsignedLong(it, bytesPerLong), key); page = it.page; address = it.address; } if (cmp < 0) { // left < right low = mid + 1; if (loaded) { leftAddress = it.address; leftPage = it.page; } } else if (cmp > 0) { // left > right high = mid - 1; if (loaded) { rightAddress = address; rightPage = page; } } else { return mid; // key found } } return -(low + 1); // key not found. }
@Override public long nextLong(final int length) { final long result = LongBinding.entryToUnsignedLong(page, offset, length); offset += length; return result; }