TrackingPageIO extends PageIO { @Nullable public Long findNextChangedPage(ByteBuffer buf, long start, long curSnapshotTag, long lastSuccessfulSnapshotTag, int pageSize) throws TrackingPageIsCorruptedException { if (isCorrupted(buf)) throw TrackingPageIsCorruptedException.INSTANCE; long lastTag = validateSnapshotTag(buf, curSnapshotTag + 1, lastSuccessfulSnapshotTag, pageSize); if (lastTag >= 0) throw new TrackingPageIsCorruptedException(lastTag, curSnapshotTag); int cntOfPage = countOfPageToTrack(pageSize); long trackingPage = trackingPageFor(start, pageSize); if (start == trackingPage) return trackingPage; if (countOfChangedPage(buf, curSnapshotTag, pageSize) <= 0) return null; int idxToStartTest = (PageIdUtils.pageIndex(start) - COUNT_OF_EXTRA_PAGE) % cntOfPage; int zeroIdx = useLeftHalf(curSnapshotTag) ? BITMAP_OFFSET : BITMAP_OFFSET + SIZE_FIELD_SIZE + (cntOfPage >> 3); int startIdx = zeroIdx + (idxToStartTest >> 3); int idx = startIdx; int stopIdx = zeroIdx + (cntOfPage >> 3); while (idx < stopIdx) { byte byteToTest = buf.get(idx); if (byteToTest != 0) { int foundSetBit; if ((foundSetBit = foundSetBit(byteToTest, idx == startIdx ? (idxToStartTest & 0b111) : 0)) != -1) { long foundPageId = PageIdUtils.pageId( PageIdUtils.partId(start), PageIdUtils.flag(start), PageIdUtils.pageIndex(trackingPage) + ((idx - zeroIdx) << 3) + foundSetBit); assert wasChanged(buf, foundPageId, curSnapshotTag, lastSuccessfulSnapshotTag, pageSize); assert trackingPageFor(foundPageId, pageSize) == trackingPage; return foundPageId; } } idx++; } return null; } protected  TrackingPageIO(int ver); long markChanged(ByteBuffer buf, long pageId, long nextSnapshotTag, long lastSuccessfulSnapshotTag, int pageSize); boolean isCorrupted(ByteBuffer buf); void resetCorruptFlag(ByteBuffer buf); void resetCorruptFlag(long addr); boolean wasChanged(ByteBuffer buf, long pageId, long curSnapshotTag, long lastSuccessfulSnapshotTag, int pageSize); short countOfChangedPage(ByteBuffer buf, long snapshotTag, int pageSize); long trackingPageFor(long pageId, int pageSize); int countOfPageToTrack(int pageSize); @Nullable Long findNextChangedPage(ByteBuffer buf, long start, long curSnapshotTag,
        long lastSuccessfulSnapshotTag, int pageSize); static final IOVersions<TrackingPageIO> VERSIONS; static final long CORRUPT_FLAG_MASK; static final long CORRUPT_FLAG_FILTER_MASK; static final int LAST_SNAPSHOT_TAG_OFFSET; static final int SIZE_FIELD_OFFSET; static final int SIZE_FIELD_SIZE; static final int BITMAP_OFFSET; static final int COUNT_OF_EXTRA_PAGE; }
@Test public void testFindNextChangedPage() throws Exception { ByteBuffer buf = createBuffer(); for (int i = 0; i < 101; i++) checkFindingRandomly(buf, i); }