void scanLoadPageMap(final long from, final long timestamp, final int recordSize) throws PersistitIOException {
        read(from, PM.OVERHEAD);
        final int count = PM.getEntryCount(_readBuffer);
        if (count * PM.ENTRY_SIZE + PM.OVERHEAD != recordSize) {
            throw new CorruptJournalException("Invalid record size " + recordSize + " for PM record at "
                    + addressToString(from, timestamp));
        }

        long address = from + PM.OVERHEAD;
        int index = 0;
        int loaded = 0;

        for (int remaining = count; remaining > 0; remaining--) {
            if (index == loaded) {
                final int loadedSize = Math.min((_readBuffer.capacity() / PM.ENTRY_SIZE), remaining) * PM.ENTRY_SIZE;
                read(address, loadedSize);
                address += loadedSize;
                index = 0;
                loaded = loadedSize / PM.ENTRY_SIZE;
                if (loaded <= 0) {
                    throw new CorruptJournalException("Could not load PageMap segment in entry "
                            + (count - remaining + 1) + " at " + addressToString(from, timestamp));
                }
            }
            final int volumeHandle = PM.getEntryVolumeHandle(_readBuffer, index);
            final Volume volume = _handleToVolumeMap.get(volumeHandle);
            if (volume == null) {
                throw new CorruptJournalException("Page map refers to undefined volume handle " + volumeHandle
                        + " in entry " + (count - remaining + 1) + " at " + addressToString(from, timestamp));
            }
            final long pageAddress = PM.getEntryPageAddress(_readBuffer, index);
            final long pageTimestamp = PM.getEntryTimestamp(_readBuffer, index);
            final long journalAddress = PM.getEntryJournalAddress(_readBuffer, index);
            final PageNode pageNode = new PageNode(volumeHandle, pageAddress, journalAddress, pageTimestamp);
            final PageNode lastPageNode;
            boolean linked = false;
            //
            // The following logic places the recovered PageNode in either the
            // page map or the branch map. The timestamp written in the PM
            // record determines which map receives the page, corresponding with
            // two different recovery scenarios.
            //
            // In one scenario, the PM was written as part of a normal rollover,
            // and all pages in it are part of the recovered history. In this
            // the timestamp at the time the PM record is written will be larger
            // than any existing page, and therefore the page will be added to
            // the page map.
            //
            // However, if the PM record was written immediately after a dirty
            // startup, the PM's timestamp will be consistent with the recovery
            // checkpoint, and there will be pages with timestamps after that.
            // Those pages are part of the branch; they are retained in the
            // recovery state solely to allow long-record recovery, and will
            // then be discarded.
            //
            // Because pre-2.4.1 PM records were written with a timestamp of
            // zero, this is handled as a special case. All pages from such
            // journals are recovered.
            //
            if (timestamp != 0 && timestamp < pageTimestamp) {
                lastPageNode = _branchMap.get(pageNode);
                if (lastPageNode == null || journalAddress > lastPageNode.getJournalAddress()) {
                    pageNode.setPrevious(lastPageNode);
                    _branchMap.put(pageNode, pageNode);
                    linked = true;
                }
            } else {
                lastPageNode = _pageMap.get(pageNode);
                if (lastPageNode == null || journalAddress > lastPageNode.getJournalAddress()) {
                    pageNode.setPrevious(lastPageNode);
                    _pageMap.put(pageNode, pageNode);
                    linked = true;
                }
            }
            if (!linked) {
                for (PageNode pn = lastPageNode; pn != null; pn = pn.getPrevious()) {
                    if (journalAddress == pn.getJournalAddress()) {
                        // TODO - redundant entry
                        break;
                    }
                    if (pn.getPrevious() == null || journalAddress > pn.getPrevious().getJournalAddress()) {
                        pageNode.setPrevious(pn.getPrevious());
                        pn.setPrevious(pageNode);
                        break;
                    }
                }
            }

            index++;
        }
    }