@Override public void onClosed() { if (connectionTag == expectedTag) { reconnect(null); } else { logger.trace().log("Mux dropping onClosed from defunct view"); } }
@Override public void onException(ChannelException e) { if (connectionTag == expectedTag) { onChannelException(e); } else { logger.trace().log("Mux dropping failure from defunct view"); } }
@Override public void onConnected() { if (connectionTag == expectedTag) { OperationChannelMultiplexerImpl.this.onConnected(); } else { logger.trace().log("Mux dropping onConnected from defunct view"); } }
/** * Receive (transformed) server operation from the wave server, if any is available. * * @return the next server operation, if any is received from the server (and makes it * through transformation), null otherwise */ public WaveletOperation receive() { if (serverOperations.isEmpty()) { return null; } else { WaveletOperation op = serverOperations.remove(0); logger.trace().log("Processing server op ", op); return op; } }
@Override public WaveletOperation receive() { if (state == State.CLOSED) { // TODO(anorth): throw an exception here after Wally doesn't do this. logger.error().log("Cannot receive from closed operation channel: " + this); return null; } else { return cc.receive(); } }
@Override public WaveletOperation peek() { if (state == State.CLOSED) { // TODO(anorth): throw an exception here after Wally doesn't do this. logger.error().log("Cannot peek at closed operation channel: " + this); return null; } else { return cc.peek(); } }
@Override public void onServerDeltas(List<TransformedWaveletDelta> deltas) throws TransformException, OperationException { if (deltas.isEmpty()) { logger.error().log("Unexpected empty deltas."); return; } logger.trace().log("Server deltas received: "); logger.trace().log(deltas.toArray()); for (TransformedWaveletDelta delta : deltas) { transformOperationsAndNotify(delta); } if (!serverOperations.isEmpty()) { onOperationReceived(); } // Re-send any pending client operations. sendDelta(); }
/** * Logs a trace message, evaluating and concatenating components only if trace * is enabled. * * @param components message components, which will be evaluated with * {@link String#valueOf(Object)} */ private void logTrace(Object... components) { if (logger.trace().shouldLog()) { StringBuffer buffer = new StringBuffer(); for (Object c : components) { buffer.append(c); } logger.trace().log(buffer.toString()); } }
@Override public void onCommit(long committedVersion) { // Remove old cache. while (!inferredServerPath.isEmpty()) { AckedDelta d = inferredServerPath.getFirst(); if (d.delta.getResultingVersion() <= committedVersion) { startSignature = d.ack.ackedVersion; inferredServerPath.removeFirst(); } else { break; } } // Remove from acked-but-uncommitted. while (!acks.isEmpty() && acks.getFirst().ackedVersion.getVersion() <= committedVersion) { acks.remove(); } lastCommitVersion = committedVersion; logger.trace().log("onCommit: version =", committedVersion, " serverpathsize =", inferredServerPath.size(), " any unacknowledged ? ", (unacknowledged == null)); triggerUnsavedDataListener(); }
/** * Checks that reconnect versions are strictly increasing and removes any * that are not accepted by the connection's wavelet filter. */ private void checkConnectVersions(Map<WaveletId, List<HashedVersion>> knownWavelets) { Iterator<Map.Entry<WaveletId, List<HashedVersion>>> itr = knownWavelets.entrySet().iterator(); while (itr.hasNext()) { Map.Entry<WaveletId, List<HashedVersion>> entry = itr.next(); WaveletId id = entry.getKey(); if (IdFilter.accepts(waveletFilter, id)) { long prevVersion = NO_VERSION; for (HashedVersion v : entry.getValue()) { if ((prevVersion != NO_VERSION) && (v.getVersion() <= prevVersion)) { throw new IllegalArgumentException("Invalid reconnect versions for " + waveId + id + ": " + entry.getValue()); } prevVersion = v.getVersion(); } } else { // TODO(anorth): throw an IllegalArgumentException here after fixing // all callers to avoid this. logger.error().log( "Mux for " + waveId + " dropping resync versions for filtered wavelet " + id + ", filter " + waveletFilter); itr.remove(); } } }
@Override public void open(Listener openListener, IdFilter waveletFilter, Map<WaveletId, List<HashedVersion>> knownWavelets) { Preconditions.checkState(state == State.INITIAL, "Cannot re-open view channel: %s", this); state = State.CONNECTING; this.openListener = openListener; logger.trace().log("connect: new view channel initialized"); doOpen(waveletFilter, knownWavelets); }
/** * Tests whether or not a delta can be sent. * * @return {@code true} if and only if the buffered client operations can and * should be sent to the server as a delta. */ private boolean isReadyToSend() { boolean ready = !pauseSendForFlush && serverConnection.isOpen(); if (!ready) { logger.trace().log("Not ready to send, pauseSendForFlush is ", pauseSendForFlush, " server connection ", serverConnection.isOpen() ? "IS" : "is NOT", " open"); } return ready; }
@Override public void onUpdate(WaveletId waveletId, List<TransformedWaveletDelta> deltas, HashedVersion lastCommittedVersion, HashedVersion currentVersion) throws ChannelException { if (connectionTag == expectedTag) { removeMissingWavelet(waveletId); maybeResetScheduler(deltas); try { Stacklet stacklet = channels.get(waveletId); if (stacklet == null) { //TODO(user): Figure out the right exception to throw here. throw new IllegalStateException("Received deltas with no stacklet present!"); } stacklet.onWaveletUpdate(deltas, lastCommittedVersion, currentVersion); } catch (ChannelException e) { throw exceptionWithContext(e, waveletId); } } else { logger.trace().log("Mux dropping update from defunct view"); } }
@Override public void send(final WaveletDelta delta) { if (logger.trace().shouldLog()) { logger.trace().log("sending delta: ", delta); } deltaChannel.send(new WaveletDeltaChannel.Transmitter() { public ClientMessage takeMessage() { return new ClientMessage(delta, false); } }); }
/** * Closes this concurrency control. */ public void close() { if (unsavedDataListener != null) { unsavedDataListener.onClose(everythingIsCommitted()); } if (!clientOperationQueue.isEmpty()) { logger.error().log("Concurrency control closed with pending operations. Data has been lost"); } }
@Override public void onWaveletFailed(OperationException failure) { logger.error().log("CcBasedWavelet failed permanently", failure); disconnectedHandler.onWaveDisconnected( new CorruptionDetail(failure.isSchemaViolation() ? ResponseCode.SCHEMA_VIOLATION : ResponseCode.INVALID_OPERATION, "CcBasedWavelet failed", failure)); pipe.close(); } };
private void connect(Map<WaveletId, List<HashedVersion>> knownWavelets) { Preconditions.checkState(state != State.CONNECTED, "Cannot connect already-connected channel"); checkConnectVersions(knownWavelets); logger.trace().log("Multiplexer reconnecting wave " + waveId); viewChannel = viewFactory.create(waveId); viewChannel.open(createViewListener(knownWavelets), waveletFilter, knownWavelets); }
@Override public void send(WaveletOperation... operations) throws ChannelException { if (state == State.CLOSED) { // TODO(anorth): throw an exception here after fixing clients. logger.error().log("Cannot send to closed operation channel: " + this); } else if (accessibility.isWritable()) { try { cc.onClientOperations(operations); } catch (TransformException e) { throw new ChannelException(ResponseCode.INVALID_OPERATION, "Operation channel failed on send: " + this + ", " + deltaChannel + ", " + cc, e, Recoverable.NOT_RECOVERABLE, null, null); } } else { throw new ChannelException(ResponseCode.NOT_AUTHORIZED, "Attempt to write to inaccessible wavelet", null, Recoverable.NOT_RECOVERABLE, null, null); } }
@Override public void onDelta(TransformedWaveletDelta delta) throws ChannelException { try { if (logger.trace().shouldLog()) { logger.trace().log("Received delta: ", delta); } cc.onServerDelta(delta); } catch (TransformException e) { throw new ChannelException(ResponseCode.INVALID_OPERATION, "Operation channel failed on server delta: " + this + ", " + deltaChannel + ", " + cc, e, Recoverable.NOT_RECOVERABLE, null, null); } catch (OperationException e) { throw new ChannelException( e.isSchemaViolation() ? ResponseCode.SCHEMA_VIOLATION : ResponseCode.INVALID_OPERATION, "Operation channel failed on server delta: " + this + ", " + deltaChannel + ", " + cc, e, Recoverable.NOT_RECOVERABLE, null, null); } }
@Override public void onWaveletAdded(CcBasedWavelet wavelet) { if (view.getWavelet(wavelet.getId()) != null) { logger.error().log( "Ignoring new channel for existing wavelet " + wavelet.getId() + " in wave " + view.getWaveId()); } else { if (holder.isExpecting()) { holder.push(wavelet); } else { view.addWavelet(wavelet); } } }