Example #1
0
  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());
      }
    }
  }
Example #2
0
  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());
      }
    }
  }
Example #3
0
  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());
  }
Example #8
0
 {
   ActorSelection selection = getContext().actorSelection("/user/another");
   selection.tell(new Identify(identifyId), getSelf());
 }