/** Creates a delta sequence by concatenating contiguous sequences. */ public static DeltaSequence join(DeltaSequence first, DeltaSequence... rest) { ImmutableList.Builder<TransformedWaveletDelta> builder = ImmutableList.builder(); builder.addAll(first); long expectedBeginVersion = first.getEndVersion().getVersion(); for (DeltaSequence s : rest) { Preconditions.checkArgument(s.getStartVersion() == expectedBeginVersion, "Sequences are not contiguous, expected start version %s for sequence %s", expectedBeginVersion, s); builder.addAll(s); expectedBeginVersion = s.getEndVersion().getVersion(); } return new DeltaSequence(builder.build(), false); }
@Override public String toString() { if (isEmpty()) { return "[DeltaSequence empty]"; } return "[DeltaSequence " + deltas.size() + " deltas, v " + getStartVersion() + " -> " + getEndVersion() + ": " + deltas + "]"; } }
/** * Returns the {@link HashedVersion} of the wavelet after all deltas have been * applied. */ public HashedVersion getVersionAfterDeltas() { return deltas.isEmpty() ? snapshotAfterDeltas.getHashedVersion() : deltas.getEndVersion(); }
/** * Sends deltas for this subscription (if appropriate). * * If the update contains a delta for a wavelet where the delta is actually * from this client, the delta is dropped. If there's an outstanding submit * request the delta is queued until the submit finishes. */ public synchronized void onUpdate(WaveletName waveletName, DeltaSequence deltas) { Preconditions.checkArgument(!deltas.isEmpty()); WaveletChannelState state; try { state = channels.get(waveletName.waveletId); } catch (ExecutionException ex) { throw new RuntimeException(ex); } checkUpdateVersion(waveletName, deltas, state); state.lastVersion = deltas.getEndVersion(); if (state.hasOutstandingSubmit) { state.heldBackDeltas.addAll(deltas); } else { List<TransformedWaveletDelta> filteredDeltas = filterOwnDeltas(deltas, state); if (!filteredDeltas.isEmpty()) { sendUpdate(waveletName, filteredDeltas, null); } } }
/** * Appends the given deltas to the deltas already stored. Updates the latest * snapshot and latest version as well. This method will make a copy of the * snapshot. * * @param updatedSnapshot the snapshot after deltas have been applied * @param newDeltas the deltas that have been applied since the last call to * appendDeltas. */ public void appendDeltas(ReadableWaveletData updatedSnapshot, DeltaSequence newDeltas) { HashedVersion newEndVersion = newDeltas.getEndVersion(); Preconditions.checkArgument( !newDeltas.isEmpty(), "There were no new deltas passed to appendDeltas"); Preconditions.checkArgument(updatedSnapshot.getVersion() == newEndVersion.getVersion(), String.format("Version of snapshot %s doesn't match the HashedVersion %s", updatedSnapshot.getVersion(), newEndVersion)); Preconditions.checkArgument(areContiguousToCurrentVersion(newDeltas), String.format( "Deltas are not contiguous to the current version(%s) %s", getVersionAfterDeltas(), deltas)); WaveletName updatedWaveletName = WaveletDataUtil.waveletNameOf(updatedSnapshot); Preconditions.checkArgument(updatedWaveletName.equals(waveletName), String.format( "Updated wavelet doesn't have the same name as with which this class has been " + "instantiated. %s != %s", updatedWaveletName, waveletName)); // TODO(ljvderijk): This should actually be applying the deltas, however // they do not contain a timestamp at this time. snapshotAfterDeltas = WaveletDataUtil.copyWavelet(updatedSnapshot); deltas = DeltaSequence.join(deltas, newDeltas); }
/** * Synchronizes the wavelet version and ensures that the deltas are * contiguous. * * @param waveletName the wavelet name. * @param newDeltas the new deltas. */ public void syncWaveletVersion(WaveletName waveletName, DeltaSequence newDeltas) { HashedVersion expectedVersion; PerWavelet waveletInfo = getWavelet(waveletName); synchronized (waveletInfo) { expectedVersion = waveletInfo.getCurrentVersion(); Preconditions.checkState(expectedVersion.getVersion() == newDeltas.getStartVersion(), "Expected deltas starting at version %s, got %s", expectedVersion, newDeltas.getStartVersion()); waveletInfo.setCurrentVersion(newDeltas.getEndVersion()); } }
/** * Constructs a {@link WaveletAndDeltas} from wavelet data and a tail of the * sequence of transformed deltas leading to that snapshot. Takes a copy of * the WaveletData so that operations can happily applied to it. * * The resulting version of the last delta must match the snapshot's version. * * @param snapshot the state of the wavelet after the deltas have been * applied. * @param deltas the deltas in the order they have been applied to the * wavelet. * @throws OperationException if the operations can not be rolled back to * create a snapshot before the deltas have been applied. */ public static WaveletAndDeltas create(ReadableWaveletData snapshot, DeltaSequence deltas) throws OperationException { HashedVersion endVersion = deltas.isEmpty() ? snapshot.getHashedVersion() : deltas.getEndVersion(); Preconditions.checkArgument(snapshot.getVersion() == endVersion.getVersion(), String.format("Version of snapshot %s doesn't match the end version %s", snapshot.getVersion(), endVersion)); ObservableWaveletData preDeltaWavelet = WaveletDataUtil.copyWavelet(snapshot); rollback(preDeltaWavelet, deltas); ObservableWaveletData postDeltaWavelet = WaveletDataUtil.copyWavelet(snapshot); return new WaveletAndDeltas(preDeltaWavelet, postDeltaWavelet, deltas); }
public void testJoinValidSequencesAllowed() { DeltaSequence s1 = DeltaSequence.of(delta1); DeltaSequence s2 = DeltaSequence.of(delta2, delta3); DeltaSequence joined = DeltaSequence.join(s1, s2); assertEquals(delta1.getAppliedAtVersion(), joined.getStartVersion()); assertEquals(delta3.getResultingVersion(), joined.getEndVersion()); assertEquals(ImmutableList.of(delta1, delta2, delta3), joined); }
public void testJoinValidSequencesAllowed() { DeltaSequence s1 = DeltaSequence.of(delta1); DeltaSequence s2 = DeltaSequence.of(delta2, delta3); DeltaSequence joined = DeltaSequence.join(s1, s2); assertEquals(delta1.getAppliedAtVersion(), joined.getStartVersion()); assertEquals(delta3.getResultingVersion(), joined.getEndVersion()); assertEquals(ImmutableList.of(delta1, delta2, delta3), joined); }
public void testValidSequenceAllowed() { DeltaSequence deltaseq = DeltaSequence.of(twoDeltas); assertEquals(2, deltaseq.size()); assertEquals(START_VERSION, deltaseq.getStartVersion()); assertEquals(delta2.getResultingVersion(), deltaseq.getEndVersion()); }
public void testValidSequenceAllowed() { DeltaSequence deltaseq = DeltaSequence.of(twoDeltas); assertEquals(2, deltaseq.size()); assertEquals(START_VERSION, deltaseq.getStartVersion()); assertEquals(delta2.getResultingVersion(), deltaseq.getEndVersion()); }
public void testEmptySequence() { DeltaSequence empty = DeltaSequence.empty(); assertEquals(ImmutableList.<ProtocolWaveletDelta>of(), empty); assertTrue(empty.isEmpty()); assertEquals(0, empty.size()); try { empty.getStartVersion(); fail("Expected illegal state exception"); } catch (IllegalStateException expected) { } try { empty.getEndVersion(); fail("Expected illegal state exception"); } catch (IllegalStateException expected) { } }
public void testEmptySequence() { DeltaSequence empty = DeltaSequence.empty(); assertEquals(ImmutableList.<ProtocolWaveletDelta>of(), empty); assertTrue(empty.isEmpty()); assertEquals(0, empty.size()); try { empty.getStartVersion(); fail("Expected illegal state exception"); } catch (IllegalStateException expected) { } try { empty.getEndVersion(); fail("Expected illegal state exception"); } catch (IllegalStateException expected) { } }
/** * Tests DeltaSequence.subList() on both empty and nonempty delta sequences. */ public void testSubList() { DeltaSequence empty = DeltaSequence.empty(); assertEquals(empty, empty.subList(0, 0)); DeltaSequence deltaseq = DeltaSequence.of(twoDeltas); assertEquals(twoDeltas, deltaseq.subList(0, twoDeltas.size())); assertEquals(empty, deltaseq.subList(0, 0)); // Construct a sublist with just the first delta. DeltaSequence subDeltas = deltaseq.subList(0, 1); assertEquals(START_VERSION + 5, subDeltas.getEndVersion().getVersion()); assertEquals(deltaseq.getStartVersion(), subDeltas.getStartVersion()); assertEquals(ImmutableList.of(delta1), subDeltas); }
/** * Tests DeltaSequence.subList() on both empty and nonempty delta sequences. */ public void testSubList() { DeltaSequence empty = DeltaSequence.empty(); assertEquals(empty, empty.subList(0, 0)); DeltaSequence deltaseq = DeltaSequence.of(twoDeltas); assertEquals(twoDeltas, deltaseq.subList(0, twoDeltas.size())); assertEquals(empty, deltaseq.subList(0, 0)); // Construct a sublist with just the first delta. DeltaSequence subDeltas = deltaseq.subList(0, 1); assertEquals(START_VERSION + 5, subDeltas.getEndVersion().getVersion()); assertEquals(deltaseq.getStartVersion(), subDeltas.getStartVersion()); assertEquals(ImmutableList.of(delta1), subDeltas); }