return new AppenderAndCachedDeltas(
new Appender(createObject(null), 0, 0),
ImmutableList.<ChangeData<String>>of(), makeProvider(deltaIterator));
} else {
SnapshotEntry snapshotEntry = getSnapshotEntryAtOrBefore(null);
StateAndVersion state = createObject(snapshotEntry);
long snapshotVersion = state.getVersion();
long snapshotBytes = snapshotEntry == null ? 0 : estimateSizeBytes(snapshotEntry);
// Read deltas between snapshot and current version. Since we determine
// the current version by reading the first delta (in our reverse
// iterator), we always read at least one delta even if none are needed to
// reconstruct the current version.
DeltaEntry finalDelta = deltaIterator.nextEntry();
long currentVersion = finalDelta.getResultingVersion();
if (currentVersion == snapshotVersion) {
// We read a delta but it precedes the snapshot. It still has to go
// into deltasRead in our AppenderAndCachedDeltas to ensure that there
// is no gap between deltasRead and reverseIterator.
log.info("Prepared appender; snapshotVersion=currentVersion=" + currentVersion);
checkDeltaDoesNotExist(snapshotVersion);
return new AppenderAndCachedDeltas(
new Appender(state, snapshotBytes, 0),
ImmutableList.of(finalDelta.data), makeProvider(deltaIterator));
} else {
// We need to apply the delta and perhaps others. Collect them.
ImmutableList.Builder<ChangeData<String>> deltaAccu = ImmutableList.builder();
deltaAccu.add(finalDelta.data);
long totalDeltaBytesSinceSnapshot = estimateSizeBytes(finalDelta);
{
DeltaEntry delta = finalDelta;
while (delta.version != snapshotVersion) {
delta = deltaIterator.nextEntry();
deltaAccu.add(delta.data);
totalDeltaBytesSinceSnapshot += estimateSizeBytes(delta);
}
}
ImmutableList<ChangeData<String>> reverseDeltas = deltaAccu.build();
// Now iterate forward and apply the deltas.
for (ChangeData<String> delta : Lists.reverse(reverseDeltas)) {
try {
state.apply(delta);
} catch (ChangeRejected e) {
throw new RuntimeException("Corrupt snapshot or delta history: "
+ objectId + " rejected delta " + delta + ": " + state);
}
}
log.info("Prepared appender; snapshotVersion=" + snapshotVersion
+ ", " + reverseDeltas.size() + " deltas");
checkDeltaDoesNotExist(state.getVersion());
return new AppenderAndCachedDeltas(
new Appender(state, snapshotBytes, totalDeltaBytesSinceSnapshot),
reverseDeltas, makeProvider(deltaIterator));
}
}