in environment/src/main/java/jetbrains/exodus/tree/btree/BTreeDupMutable.java [66:125]
public long save() {
if (address != Loggable.NULL_ADDRESS) {
throw new IllegalStateException("Duplicates sub-tree already saved");
}
final BasePageMutable rootPage = getRoot();
final byte type = rootPage.isBottom() ? BTreeBase.LEAF_DUP_BOTTOM_ROOT : BTreeBase.LEAF_DUP_INTERNAL_ROOT;
final ByteIterable keyIterable = CompressedUnsignedLongByteIterable.getIterable(key.getLength());
ByteIterable sizeIterable;
long startAddress = log.getWrittenHighAddress(); // remember high address before saving the data
final ByteIterable rootDataIterable = rootPage.getData();
ByteIterable[] iterables;
long result;
final boolean canRetry;
var expired = getExpiredLoggables();
if (log.isLastWrittenFileAddress(startAddress)) {
sizeIterable = CompressedUnsignedLongByteIterable.getIterable(size << 1);
iterables = new ByteIterable[]{keyIterable, key, sizeIterable, rootDataIterable};
result = log.tryWrite(type, structureId, new CompoundByteIterable(iterables), expired);
if (result >= 0) {
address = result;
return result;
} else {
canRetry = false;
}
} else {
canRetry = true;
}
if (!log.isLastWrittenFileAddress(startAddress)) {
final byte writtenType = log.getWrittenLoggableType(startAddress, BTreeBase.DUP_LEAF);
if (NullLoggable.isNullLoggable(writtenType)) {
final long lengthBound = log.getFileLengthBound();
final long alignment = startAddress % lengthBound;
startAddress += (lengthBound - alignment);
if (log.getWrittenHighAddress() < startAddress) {
throw new IllegalStateException("Address alignment underflow: start address " + startAddress + ", alignment " + alignment);
}
}
}
sizeIterable = CompressedUnsignedLongByteIterable.getIterable((size << 1) + 1);
final ByteIterable offsetIterable =
CompressedUnsignedLongByteIterable.getIterable(log.getWrittenHighAddress() - startAddress);
iterables = new ByteIterable[]{keyIterable, key, sizeIterable, offsetIterable, rootDataIterable};
final ByteIterable data = new CompoundByteIterable(iterables);
result = canRetry ? log.tryWrite(type, structureId, data, expired) : log.writeContinuously(type, structureId, data, expired);
if (result < 0) {
if (canRetry) {
iterables[3] = CompressedUnsignedLongByteIterable.getIterable(log.getWrittenHighAddress() - startAddress);
result = log.writeContinuously(type, structureId, new CompoundByteIterable(iterables), expired);
if (result < 0) {
throw new TooBigLoggableException();
}
} else {
throw new TooBigLoggableException();
}
}
address = result;
return result;
}