ProtocolWaveletDelta protocolDelta =
ByteStringMessage.parseProtocolWaveletDelta(signedDelta.getDelta()).getMessage();
Preconditions.checkArgument(protocolDelta.getOperationCount() > 0, "empty delta");
WaveletDelta transformed = maybeTransformSubmittedDelta(
CoreWaveletOperationSerializer.deserialize(protocolDelta));
// TODO(ljvderijk): a Clock needs to be injected here (Issue 104)
long applicationTimestamp = System.currentTimeMillis();
HashedVersion currentVersion = getCurrentVersion();
// This is always false right now because the current algorithm doesn't transform ops away.
if (transformed.size() == 0) {
Preconditions.checkState(currentVersion.getVersion() != 0,
"currentVersion can not be 0 if delta was transformed");
Preconditions.checkState(
transformed.getTargetVersion().getVersion() <= currentVersion.getVersion());
// The delta was transformed away. That's OK but we don't call either
// applyWaveletOperations(), because that will throw IllegalArgumentException, or
// commitAppliedDelta(), because empty deltas cannot be part of the delta history.
TransformedWaveletDelta emptyDelta = new TransformedWaveletDelta(transformed.getAuthor(),
transformed.getTargetVersion(), applicationTimestamp, transformed);
return new WaveletDeltaRecord(transformed.getTargetVersion(), null, emptyDelta);
}
if (!transformed.getTargetVersion().equals(currentVersion)) {
Preconditions.checkState(
transformed.getTargetVersion().getVersion() < currentVersion.getVersion());
// The delta was a duplicate of an existing server delta.
// We duplicate-eliminate it (don't apply it to the wavelet state and don't store it in
// the delta history) and return the server delta which it was a duplicate of
// (so delta submission becomes idempotent).
ByteStringMessage<ProtocolAppliedWaveletDelta> existingDeltaBytes =
lookupAppliedDelta(transformed.getTargetVersion());
TransformedWaveletDelta dupDelta = lookupTransformedDelta(transformed.getTargetVersion());
LOG.info("Duplicate delta " + dupDelta + " for wavelet " + getWaveletName());
// TODO(anorth): Replace these comparisons with methods on delta classes.
Preconditions.checkState(dupDelta.getAuthor().equals(transformed.getAuthor()),
"Duplicate delta detected but mismatched author, expected %s found %s",
transformed.getAuthor(), dupDelta.getAuthor());
Preconditions.checkState(Iterables.elementsEqual(dupDelta, transformed),
"Duplicate delta detected but mismatched ops, expected %s found %s",
transformed, dupDelta);
return new WaveletDeltaRecord(transformed.getTargetVersion(), existingDeltaBytes, dupDelta);
}
// Build the applied delta to commit
ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta =
AppliedDeltaUtil.buildAppliedDelta(signedDelta, transformed.getTargetVersion(),
transformed.size(), applicationTimestamp);
return applyDelta(appliedDelta, transformed);
}