@Override public void requestTransformedHistory(HashedVersion startVersion, HashedVersion endVersion, Receiver<TransformedWaveletDelta> receiver) throws AccessControlException, WaveletStateException { awaitLoad(); acquireReadLock(); try { checkStateOk(); checkVersionIsDeltaBoundary(startVersion, "start version"); checkVersionIsDeltaBoundary(endVersion, "end version"); waveletState.getTransformedDeltaHistory(startVersion, endVersion, receiver); } finally { releaseReadLock(); } }
@Override public void run() { try { result.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { LOG.severe("Version " + version, e); } acquireWriteLock(); try { waveletState.flush(version); notifyOfCommit(version, domainsToNotify); } finally { releaseWriteLock(); } } },
protected void notifyOfDeltas(ImmutableList<WaveletDeltaRecord> deltas, ImmutableSet<String> domainsToNotify) { Preconditions.checkState(writeLock.isHeldByCurrentThread(), "must hold write lock"); Preconditions.checkArgument(!deltas.isEmpty(), "empty deltas"); HashedVersion endVersion = deltas.get(deltas.size() - 1).getResultingVersion(); HashedVersion currentVersion = getCurrentVersion(); Preconditions.checkArgument(endVersion.equals(currentVersion), "cannot notify of deltas ending in %s != current version %s", endVersion, currentVersion); notifiee.waveletUpdate(waveletState.getSnapshot(), deltas, domainsToNotify); }
/** * Transform a wavelet delta if it has been submitted against a different head (currentVersion). * Must be called with write lock held. * * @param delta to possibly transform * @return the transformed delta and the version it was applied at * (the version is the current version of the wavelet, unless the delta is * a duplicate in which case it is the version at which it was originally * applied) * @throws InvalidHashException if submitting against same version but different hash * @throws OperationException if transformation fails */ protected WaveletDelta maybeTransformSubmittedDelta(WaveletDelta delta) throws InvalidHashException, OperationException { HashedVersion targetVersion = delta.getTargetVersion(); HashedVersion currentVersion = getCurrentVersion(); if (targetVersion.equals(currentVersion)) { // Applied version is the same, we're submitting against head, don't need to do OT return delta; } else { // Not submitting against head, we need to do OT, but check the versions really are different if (targetVersion.getVersion() == currentVersion.getVersion()) { LOG.warning("Mismatched hash, expected " + currentVersion + ") but delta targets (" + targetVersion + ")"); throw new InvalidHashException(currentVersion, targetVersion); } else { return transformSubmittedDelta(delta); } } }
throws OperationException, InvalidHashException { HashedVersion targetVersion = submittedDelta.getTargetVersion(); HashedVersion currentVersion = getCurrentVersion(); Preconditions.checkArgument(!targetVersion.equals(currentVersion)); ListReceiver<TransformedWaveletDelta> receiver = new ListReceiver<TransformedWaveletDelta>(); clientOps = transformOps(clientOps, serverDelta); targetVersion = serverDelta.getResultingVersion();
/** * Check that a container succeeds when adding non-existent participants and removing existing * participants. */ private void assertSuccessfulApplyWaveletOperations(WaveletContainerImpl with) throws Exception { WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); assertEquals(with.accessSnapshot().getParticipants(), participants); WaveServerTestUtil.applyDeltaToWavelet(with, removeParticipantDelta(with), 0L); assertEquals(with.accessSnapshot().getParticipants(), Collections.emptySet()); }
@Override public void run() { acquireWriteLock(); try { Preconditions.checkState(waveletState == null, "Repeat attempts to set wavelet state"); Preconditions.checkState(state == State.LOADING, "Unexpected state %s", state); waveletState = FutureUtil.getResultOrPropagateException( waveletStateFuture, PersistenceException.class); Preconditions.checkState(waveletState.getWaveletName().equals(getWaveletName()), "Wrong wavelet state, named %s, expected %s", waveletState.getWaveletName(), getWaveletName()); state = State.OK; } catch (PersistenceException e) { LOG.warning("Failed to load wavelet " + getWaveletName(), e); state = State.CORRUPTED; } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOG.warning("Interrupted loading wavelet " + getWaveletName(), e); state = State.CORRUPTED; } catch (RuntimeException e) { // TODO(soren): would be better to terminate the process in this case LOG.severe("Unexpected exception loading wavelet " + getWaveletName(), e); state = State.CORRUPTED; } finally { releaseWriteLock(); } loadLatch.countDown(); } },
/** * Applies a delta to a wavelet container. */ public static void applyDeltaToWavelet(WaveletContainerImpl wavelet, WaveletDelta delta, long applicationTimestamp) throws InvalidProtocolBufferException, OperationException { ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta = buildAppliedDelta(delta, applicationTimestamp); wavelet.applyDelta(appliedDelta, delta); } }
protected void notifyOfCommit(HashedVersion version, ImmutableSet<String> domainsToNotify) { Preconditions.checkState(writeLock.isHeldByCurrentThread(), "must hold write lock"); notifiee.waveletCommitted(getWaveletName(), version, domainsToNotify); }
private static WaveletDelta doubleRemoveParticipantDelta(WaveletContainerImpl target) { return new WaveletDelta(author, target.getCurrentVersion(), doubleRemoveParticipantOps); }
/** * Check that a container succeeds when adding non-existent participants and removing existing * participants. */ private void assertSuccessfulApplyWaveletOperations(WaveletContainerImpl with) throws Exception { WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); assertEquals(with.accessSnapshot().getParticipants(), participants); WaveServerTestUtil.applyDeltaToWavelet(with, removeParticipantDelta(with), 0L); assertEquals(with.accessSnapshot().getParticipants(), Collections.emptySet()); }
/** * Applies a delta to a wavelet container. */ public static void applyDeltaToWavelet(WaveletContainerImpl wavelet, WaveletDelta delta, long applicationTimestamp) throws InvalidProtocolBufferException, OperationException { ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta = buildAppliedDelta(delta, applicationTimestamp); wavelet.applyDelta(appliedDelta, delta); } }
@Override public HashedVersion getLastCommittedVersion() throws WaveletStateException { awaitLoad(); acquireReadLock(); try { checkStateOk(); return waveletState.getLastPersistedVersion(); } finally { releaseReadLock(); } }
private static WaveletDelta doubleRemoveParticipantDelta(WaveletContainerImpl target) { return new WaveletDelta(author, target.getCurrentVersion(), doubleRemoveParticipantOps); }
/** * Check that a container fails when removing non-existent participants and adding duplicate * participants, and that the partipant list is preserved correctly. */ private void assertFailedWaveletOperations(WaveletContainerImpl with) throws Exception { try { WaveServerTestUtil.applyDeltaToWavelet(with, removeParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertNull(localWavelet.accessSnapshot()); WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); try { WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertEquals(with.accessSnapshot().getParticipants(), participants); try { WaveServerTestUtil.applyDeltaToWavelet(with, doubleRemoveParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertEquals(with.accessSnapshot().getParticipants(), participants); }
@Override public boolean isEmpty() throws WaveletStateException { awaitLoad(); acquireReadLock(); try { checkStateOk(); return waveletState.getSnapshot() == null; } finally { releaseReadLock(); } }
private static WaveletDelta addParticipantDelta(WaveletContainerImpl target) { return new WaveletDelta(author, target.getCurrentVersion(), addParticipantOps); }
/** * Check that a container fails when removing non-existent participants and adding duplicate * participants, and that the partipant list is preserved correctly. */ private void assertFailedWaveletOperations(WaveletContainerImpl with) throws Exception { try { WaveServerTestUtil.applyDeltaToWavelet(with, removeParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertNull(localWavelet.accessSnapshot()); WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); try { WaveServerTestUtil.applyDeltaToWavelet(with, addParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertEquals(with.accessSnapshot().getParticipants(), participants); try { WaveServerTestUtil.applyDeltaToWavelet(with, doubleRemoveParticipantDelta(with), 0L); fail("Should fail"); } catch (OperationException e) { // Correct } assertEquals(with.accessSnapshot().getParticipants(), participants); }
@Override public void requestHistory(HashedVersion startVersion, HashedVersion endVersion, Receiver<ByteStringMessage<ProtocolAppliedWaveletDelta>> receiver) throws AccessControlException, WaveletStateException { acquireReadLock(); try { checkStateOk(); checkVersionIsDeltaBoundary(startVersion, "start version"); checkVersionIsDeltaBoundary(endVersion, "end version"); waveletState.getAppliedDeltaHistory(startVersion, endVersion, receiver); } finally { releaseReadLock(); } }
private static WaveletDelta removeParticipantDelta(WaveletContainerImpl target) { return new WaveletDelta(author, target.getCurrentVersion(), removeParticipantOps); }