private void handleForwardedReadyTransaction(ForwardedReadyTransaction forwardedReady) { LOG.debug( "{}: handleForwardedReadyTransaction for {}", persistenceId(), forwardedReady.getTransactionID()); boolean isLeaderActive = isLeaderActive(); if (isLeader() && isLeaderActive) { commitCoordinator.handleForwardedReadyTransaction(forwardedReady, getSender(), this); } else { ActorSelection leader = getLeader(); if (!isLeaderActive || leader == null) { messageRetrySupport.addMessageToRetry( forwardedReady, getSender(), "Could not commit transaction " + forwardedReady.getTransactionID()); } else { LOG.debug("{}: Forwarding ForwardedReadyTransaction to leader {}", persistenceId(), leader); ReadyLocalTransaction readyLocal = new ReadyLocalTransaction( forwardedReady.getTransactionID(), forwardedReady.getTransaction().getSnapshot(), forwardedReady.isDoImmediateCommit()); readyLocal.setRemoteVersion(getCurrentBehavior().getLeaderPayloadVersion()); leader.forward(readyLocal, getContext()); } } }
private void handleReadyLocalTransaction(final ReadyLocalTransaction message) { LOG.debug( "{}: handleReadyLocalTransaction for {}", persistenceId(), message.getTransactionID()); boolean isLeaderActive = isLeaderActive(); if (isLeader() && isLeaderActive) { try { commitCoordinator.handleReadyLocalTransaction(message, getSender(), this); } catch (Exception e) { LOG.error( "{}: Error handling ReadyLocalTransaction for Tx {}", persistenceId(), message.getTransactionID(), e); getSender().tell(new akka.actor.Status.Failure(e), getSelf()); } } else { ActorSelection leader = getLeader(); if (!isLeaderActive || leader == null) { messageRetrySupport.addMessageToRetry( message, getSender(), "Could not commit transaction " + message.getTransactionID()); } else { LOG.debug("{}: Forwarding ReadyLocalTransaction to leader {}", persistenceId(), leader); message.setRemoteVersion(getCurrentBehavior().getLeaderPayloadVersion()); leader.forward(message, getContext()); } } }
private void handleBatchedModifications(BatchedModifications batched) { // This message is sent to prepare the modifications transaction directly on the Shard as an // optimization to avoid the extra overhead of a separate ShardTransaction actor. On the last // BatchedModifications message, the caller sets the ready flag in the message indicating // modifications are complete. The reply contains the cohort actor path (this actor) for the // caller // to initiate the 3-phase commit. This also avoids the overhead of sending an additional // ReadyTransaction message. // If we're not the leader then forward to the leader. This is a safety measure - we shouldn't // normally get here if we're not the leader as the front-end (TransactionProxy) should // determine // the primary/leader shard. However with timing and caching on the front-end, there's a small // window where it could have a stale leader during leadership transitions. // boolean isLeaderActive = isLeaderActive(); if (isLeader() && isLeaderActive) { handleBatchedModificationsLocal(batched, getSender()); } else { ActorSelection leader = getLeader(); if (!isLeaderActive || leader == null) { messageRetrySupport.addMessageToRetry( batched, getSender(), "Could not commit transaction " + batched.getTransactionID()); } else { // TODO: what if this is not the first batch and leadership changed in between batched // messages? // We could check if the commitCoordinator already has a cached entry and forward all the // previous // batched modifications. LOG.debug("{}: Forwarding BatchedModifications to leader {}", persistenceId(), leader); leader.forward(batched, getContext()); } } }
@Override protected synchronized void removeRegistration() { if (listenerRegistrationActor != null) { listenerRegistrationActor.tell( CloseDataTreeChangeListenerRegistration.getInstance(), ActorRef.noSender()); listenerRegistrationActor = null; } dataChangeListenerActor.tell(PoisonPill.getInstance(), ActorRef.noSender()); }
/** * Sends a snapshot chunk to a given follower InstallSnapshot should qualify as a heartbeat too. */ private void sendSnapshotChunk(ActorSelection followerActor, String followerId) { try { if (snapshot.isPresent()) { ByteString nextSnapshotChunk = getNextSnapshotChunk(followerId, snapshot.get().getSnapshotBytes()); // Note: the previous call to getNextSnapshotChunk has the side-effect of adding // followerId to the followerToSnapshot map. FollowerToSnapshot followerToSnapshot = mapFollowerToSnapshot.get(followerId); followerActor.tell( new InstallSnapshot( currentTerm(), context.getId(), snapshot.get().getLastIncludedIndex(), snapshot.get().getLastIncludedTerm(), nextSnapshotChunk, followerToSnapshot.incrementChunkIndex(), followerToSnapshot.getTotalChunks(), Optional.of(followerToSnapshot.getLastChunkHashCode())) .toSerializable(), actor()); if (LOG.isDebugEnabled()) { LOG.debug( "{}: InstallSnapshot sent to follower {}, Chunk: {}/{}", logName(), followerActor.path(), followerToSnapshot.getChunkIndex(), followerToSnapshot.getTotalChunks()); } } } catch (IOException e) { LOG.error("{}: InstallSnapshot failed for Leader.", logName(), e); } }
private void setListenerRegistrationActor(final ActorSelection actor) { if (actor == null) { LOG.debug("Ignoring null actor on {}", this); return; } synchronized (this) { if (!isClosed()) { this.listenerRegistrationActor = actor; return; } } // This registration has already been closed, notify the actor actor.tell(CloseDataTreeChangeListenerRegistration.getInstance(), null); }
private void sendAppendEntriesToFollower( ActorSelection followerActor, long followerNextIndex, List<ReplicatedLogEntry> entries, String followerId) { AppendEntries appendEntries = new AppendEntries( currentTerm(), context.getId(), prevLogIndex(followerNextIndex), prevLogTerm(followerNextIndex), entries, context.getCommitIndex(), super.getReplicatedToAllIndex(), context.getPayloadVersion()); if (!entries.isEmpty() || LOG.isTraceEnabled()) { LOG.debug( "{}: Sending AppendEntries to follower {}: {}", logName(), followerId, appendEntries); } followerActor.tell(appendEntries.toSerializable(), actor()); }
{ ActorSelection selection = getContext().actorSelection("/user/another"); selection.tell(new Identify(identifyId), getSelf()); }