Example #1
0
  /**
   * Finds range of server deltas needed to transform against, then transforms all client ops
   * against the server ops.
   */
  private VersionedWaveletDelta transformSubmittedDelta(
      WaveletDelta submittedDelta, HashedVersion appliedVersion)
      throws OperationException, InvalidHashException {

    NavigableSet<VersionedWaveletDelta> serverDeltas =
        deserializedTransformedDeltas.tailSet(
            deserializedTransformedDeltas.floor(
                emptyDeserializedDeltaAtVersion(appliedVersion.getVersion())),
            true);

    if (serverDeltas.size() == 0) {
      LOG.warning("Got empty server set, but not sumbitting to head! " + submittedDelta);
      // Not strictly an invalid hash, but it's a related issue
      throw new InvalidHashException("Cannot submit to head");
    }

    // Confirm that the target version/hash of this delta is valid.
    if (!serverDeltas.first().version.equals(appliedVersion)) {
      LOG.warning(
          "Mismatched hashes: expected: "
              + serverDeltas.first().version
              + " got: "
              + appliedVersion);
      // Don't leak the hash to the client in the error message.
      throw new InvalidHashException("Mismatched hashes at version " + appliedVersion.getVersion());
    }

    ParticipantId clientAuthor = submittedDelta.getAuthor();
    List<WaveletOperation> clientOps = submittedDelta.getOperations();
    for (VersionedWaveletDelta d : serverDeltas) {
      // If the client delta transforms to nothing before we've traversed all the server
      // deltas, return the version at which the delta was obliterated (rather than the
      // current version) to ensure that delta submission is idempotent.
      if (clientOps.isEmpty()) {
        return new VersionedWaveletDelta(new WaveletDelta(clientAuthor, clientOps), d.version);
      }
      ParticipantId serverAuthor = d.delta.getAuthor();
      List<WaveletOperation> serverOps = d.delta.getOperations();
      if (clientAuthor.equals(serverAuthor) && clientOps.equals(serverOps)) {
        return d;
      }
      clientOps = transformOps(clientOps, clientAuthor, serverOps, serverAuthor);
    }
    return new VersionedWaveletDelta(new WaveletDelta(clientAuthor, clientOps), currentVersion);
  }
Example #2
0
  /**
   * Commit an applied delta to this wavelet container.
   *
   * @param appliedDelta to commit
   * @param transformedDelta of the applied delta
   * @return result of the application
   */
  protected DeltaApplicationResult commitAppliedDelta(
      ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta, WaveletDelta transformedDelta) {

    ProtocolWaveletDelta transformedProtocolDelta =
        WaveletOperationSerializer.serialize(transformedDelta, currentVersion);
    transformedDeltas.add(transformedProtocolDelta);
    deserializedTransformedDeltas.add(new VersionedWaveletDelta(transformedDelta, currentVersion));
    appliedDeltas.add(appliedDelta);

    HashedVersion newVersion =
        HASHED_HISTORY_VERSION_FACTORY.create(
            appliedDelta.getByteArray(), currentVersion, transformedDelta.getOperations().size());
    currentVersion = newVersion;

    return new DeltaApplicationResult(
        appliedDelta, transformedProtocolDelta, WaveletOperationSerializer.serialize(newVersion));
  }