//
// To support writing VERY large data, we override the output stream so
// that we
// we do the page writes incrementally while the data is being
// marshalled.
DataByteArrayOutputStream out = new DataByteArrayOutputStream(pageFile.getPageSize() * 2) {
Page current = copy;
@SuppressWarnings("unchecked")
@Override
protected void onWrite() throws IOException {
// Are we at an overflow condition?
final int pageSize = pageFile.getPageSize();
if (pos >= pageSize) {
// If overflow is allowed
if (overflow) {
do {
Page next;
if (current.getType() == Page.PAGE_PART_TYPE) {
next = load(current.getNext(), null);
} else {
next = allocate();
}
next.txId = current.txId;
// Write the page header
int oldPos = pos;
pos = 0;
current.makePagePart(next.getPageId(), getWriteTransactionId());
current.write(this);
// Do the page write..
byte[] data = new byte[pageSize];
System.arraycopy(buf, 0, data, 0, pageSize);
Transaction.this.write(current, data);
// make the new link visible
pageFile.addToCache(current);
// Reset for the next page chunk
pos = 0;
// The page header marshalled after the data is written.
skip(Page.PAGE_HEADER_SIZE);
// Move the overflow data after the header.
System.arraycopy(buf, pageSize, buf, pos, oldPos - pageSize);
pos += oldPos - pageSize;
current = next;
} while (pos > pageSize);
} else {
throw new PageOverflowIOException("Page overflow.");
}
}
}
@Override
public void close() throws IOException {
super.close();
// We need to free up the rest of the page chain..
if (current.getType() == Page.PAGE_PART_TYPE) {
free(current.getNext());
}
current.makePageEnd(pos, getWriteTransactionId());
// make visible as end page
pageFile.addToCache(current);
// Write the header..
pos = 0;
current.write(this);
Transaction.this.write(current, buf);
}
};
// The page header marshaled after the data is written.
out.skip(Page.PAGE_HEADER_SIZE);
return out;
}