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;
 }