diff --git a/exist-core/src/main/java/org/exist/storage/dom/DOMFile.java b/exist-core/src/main/java/org/exist/storage/dom/DOMFile.java index 8f83399aae2..16946ace2c0 100644 --- a/exist-core/src/main/java/org/exist/storage/dom/DOMFile.java +++ b/exist-core/src/main/java/org/exist/storage/dom/DOMFile.java @@ -3058,7 +3058,7 @@ protected final class DOMPage implements Cacheable { // set to true if the page has been removed from the cache boolean invalidated = false; -// private final ThreadLocal lastFound = ThreadLocal.withInitial(() -> 0); + private final ThreadLocal lastFound = ThreadLocal.withInitial(() -> 0); DOMPage() { this.page = createNewPage(); @@ -3105,10 +3105,33 @@ Page createNewPage() { } } + /** + * Optimize scanning for records in a page + * Based on the fact that we are looking for the same thing again, + * Or we are looking for something after the last thing. + * + * So, start the scan where we left off before. + * + * @param targetId the tuple id we are looking for in the page + * + * @return a record describing the tuple, if we found it, otherwise null + */ RecordPos findRecord(final short targetId) { - final int dlen = pageHeader.getDataLength(); + final int startScan = lastFound.get(); + RecordPos rec = findRecordInRange(targetId, startScan, pageHeader.getDataLength()); + if (rec == null) { + rec = findRecordInRange(targetId, 0, startScan); + } + if (rec != null) { + // start from here again next time; step back over the tuple id + lastFound.set(rec.offset - LENGTH_TID); + } + return rec; + } + + RecordPos findRecordInRange(final short targetId, final int from, final int to) { RecordPos rec = null; - for (int pos = 0; pos < dlen;) { + for (int pos = from; pos < to;) { final short tupleID = ByteConversion.byteToShort(data, pos); pos += LENGTH_TID; if (ItemId.matches(tupleID, targetId)) { @@ -3139,67 +3162,6 @@ RecordPos findRecord(final short targetId) { return rec; } -// /** -// * Optimize scanning for records in a page -// * Based on the fact that we are looking for the same thing again, -// * Or we are looking for something after the last thing. -// * -// * So, start the scan where we left off before. -// * -// * @param targetId the tuple id we are looking for in the page -// * -// * @return a record describing the tuple, if we found it, otherwise null -// */ -// RecordPos findRecord(final short targetId) { -// final int startScan = lastFound.get(); -// try { -// RecordPos rec = findRecordInRange(targetId, startScan, pageHeader.getDataLength()); -// if (rec == null) { -// rec = findRecordInRange(targetId, 0, startScan); -// } -// if (rec != null) { -// // start from here again next time; step back over the tuple id -// lastFound.set(rec.offset - LENGTH_TID); -// } -// return rec; -// } catch (ArrayIndexOutOfBoundsException e) { -// throw e; -// } -// } -// -// RecordPos findRecordInRange(final short targetId, final int from, final int to) { -// RecordPos rec = null; -// for (int pos = from; pos < to;) { -// final short tupleID = ByteConversion.byteToShort(data, pos); -// pos += LENGTH_TID; -// if (ItemId.matches(tupleID, targetId)) { -// if (ItemId.isLink(tupleID)) { -// rec = new RecordPos(pos, this, tupleID, true); -// } else { -// rec = new RecordPos(pos, this, tupleID); -// } -// break; -// } else if (ItemId.isLink(tupleID)) { -// pos += LENGTH_FORWARD_LOCATION; -// } else { -// final short vlen = ByteConversion.byteToShort(data, pos); -// pos += LENGTH_DATA_LENGTH; -// if (vlen < 0) { -// LOG.error("page = {}; pos = {}; vlen = {}; tupleID = {}; target = {}", page.getPageNum(), pos, vlen, tupleID, targetId); -// } -// if (ItemId.isRelocated(tupleID)) { -// pos += LENGTH_ORIGINAL_LOCATION + vlen; -// } else { -// pos += vlen; -// } -// if (vlen == OVERFLOW) { -// pos += LENGTH_OVERFLOW_LOCATION; -// } -// } -// } -// return rec; -// } - @Override public long getKey() { return page.getPageNum();