* Returns the raw data of the next node in document order.
* @return the raw data of the node
*/
public Value next() {
Value nextValue = null;
final Lock lock = db.getLock();
try {
try {
lock.acquire(Lock.READ_LOCK);
} catch (final LockException e) {
LOG.error("Failed to acquire read lock on " + db.getFile().getName());
//TODO : throw exception here ? -pb
return null;
}
db.setOwnerObject(broker);
long backLink = 0;
do {
final DOMFile.DOMFilePageHeader pageHeader = page.getPageHeader();
//Next value larger than length of the current page?
if (offset >= pageHeader.getDataLength()) {
//Load next page in chain
long nextPage = pageHeader.getNextDataPage();
if (nextPage == Paged.Page.NO_PAGE) {
SanityCheck.TRACE("Bad link to next page " + page.page.getPageInfo() +
"; previous: " + pageHeader.getPreviousDataPage() +
"; offset = " + offset + "; lastTupleID = " + lastTupleID);
//TODO : throw exception here ? -pb
return null;
}
pageNum = nextPage;
page = db.getDOMPage(nextPage);
db.addToBuffer(page);
offset = 0;
}
//Extract the tuple id
lastTupleID = ByteConversion.byteToShort(page.data, offset);
offset += DOMFile.LENGTH_TID;
//Check if this is just a link to a relocated node
if(ItemId.isLink(lastTupleID)) {
//Skip this
offset += DOMFile.LENGTH_FORWARD_LOCATION;
continue;
}
//Read data length
short valueLength = ByteConversion.byteToShort(page.data, offset);
offset += DOMFile.LENGTH_DATA_LENGTH;
if (valueLength < 0) {
LOG.error("Got negative length" + valueLength + " at offset " + offset + "!!!");
LOG.debug(db.debugPageContents(page));
//TODO : throw an exception right now ?
}
if (ItemId.isRelocated(lastTupleID)) {
// found a relocated node. Read the original address
backLink = ByteConversion.byteToLong(page.data, offset);
offset += DOMFile.LENGTH_ORIGINAL_LOCATION;
}
//Overflow page? load the overflow value
if (valueLength == DOMFile.OVERFLOW) {
valueLength = DOMFile.LENGTH_OVERFLOW_LOCATION;
final long overflow = ByteConversion.byteToLong(page.data, offset);
offset += DOMFile.LENGTH_OVERFLOW_LOCATION;
try {
final byte[] odata = db.getOverflowValue(overflow);
nextValue = new Value(odata);
} catch(final Exception e) {
LOG.error("Exception while loading overflow value: " + e.getMessage() +
"; originating page: " + page.page.getPageInfo());
}
// normal node
} else {
try {
nextValue = new Value(page.data, offset, valueLength);
offset += valueLength;
} catch(final Exception e) {
LOG.error("Error while deserializing node: " + e.getMessage(), e);
LOG.error("Reading from offset: " + offset + "; len = " + valueLength);
LOG.debug(db.debugPageContents(page));
throw new RuntimeException(e);
}
}
if (nextValue == null) {
LOG.error("illegal node on page " + page.getPageNum() +
"; tupleID = " + ItemId.getId(lastTupleID) +
"; next = " + page.getPageHeader().getNextDataPage() +
"; prev = " + page.getPageHeader().getPreviousDataPage() +
"; offset = " + (offset - valueLength) +
"; len = " + page.getPageHeader().getDataLength());
//TODO : throw exception here ? -pb
return null;
}
if (ItemId.isRelocated(lastTupleID)) {
nextValue.setAddress(backLink);
} else {
nextValue.setAddress(StorageAddress.createPointer((int) pageNum,
ItemId.getId(lastTupleID))
);
}
} while (nextValue == null);
return nextValue;
} finally {
lock.release(Lock.READ_LOCK);
}
}