Example #1
0
  @Override
  protected void onStateChanged() {
    boolean isLeader = isLeader();
    boolean hasLeader = hasLeader();
    changeSupport.onLeadershipChange(isLeader, hasLeader);
    treeChangeSupport.onLeadershipChange(isLeader, hasLeader);

    // If this actor is no longer the leader close all the transaction chains
    if (!isLeader) {
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            "{}: onStateChanged: Closing all transaction chains because shard {} is no longer the leader",
            persistenceId(),
            getId());
      }

      store.closeAllTransactionChains();

      commitCoordinator.abortPendingTransactions(
          "The transacton was aborted due to inflight leadership change.", this);
    }

    if (hasLeader && !isIsolatedLeader()) {
      messageRetrySupport.retryMessages();
    }
  }
Example #2
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 #3
0
  private void finishCommit(
      @Nonnull final ActorRef sender,
      @Nonnull final String transactionID,
      @Nonnull final CohortEntry cohortEntry) {
    LOG.debug(
        "{}: Finishing commit for transaction {}", persistenceId(), cohortEntry.getTransactionID());

    try {
      cohortEntry.commit();

      sender.tell(CommitTransactionReply.INSTANCE.toSerializable(), getSelf());

      shardMBean.incrementCommittedTransactionCount();
      shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis());

    } catch (Exception e) {
      sender.tell(new akka.actor.Status.Failure(e), getSelf());

      LOG.error(
          "{}, An exception occurred while committing transaction {}",
          persistenceId(),
          transactionID,
          e);
      shardMBean.incrementFailedTransactionsCount();
    } finally {
      commitCoordinator.currentTransactionComplete(transactionID, true);
    }
  }
Example #4
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 #5
0
 protected void handleBatchedModificationsLocal(BatchedModifications batched, ActorRef sender) {
   try {
     commitCoordinator.handleBatchedModifications(batched, sender, this);
   } catch (Exception e) {
     LOG.error(
         "{}: Error handling BatchedModifications for Tx {}",
         persistenceId(),
         batched.getTransactionID(),
         e);
     sender.tell(new akka.actor.Status.Failure(e), getSelf());
   }
 }
Example #6
0
  private void finishCommit(@Nonnull final ActorRef sender, final @Nonnull String transactionID) {
    // With persistence enabled, this method is called via applyState by the leader strategy
    // after the commit has been replicated to a majority of the followers.

    CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
    if (cohortEntry == null) {
      // The transaction is no longer the current commit. This can happen if the transaction
      // was aborted prior, most likely due to timeout in the front-end. We need to finish
      // committing the transaction though since it was successfully persisted and replicated
      // however we can't use the original cohort b/c it was already preCommitted and may
      // conflict with the current commit or may have been aborted so we commit with a new
      // transaction.
      cohortEntry = commitCoordinator.getAndRemoveCohortEntry(transactionID);
      if (cohortEntry != null) {
        try {
          store.applyForeignCandidate(transactionID, cohortEntry.getCandidate());
        } catch (DataValidationFailedException e) {
          shardMBean.incrementFailedTransactionsCount();
          LOG.error("{}: Failed to re-apply transaction {}", persistenceId(), transactionID, e);
        }

        sender.tell(CommitTransactionReply.INSTANCE.toSerializable(), getSelf());
      } else {
        // This really shouldn't happen - it likely means that persistence or replication
        // took so long to complete such that the cohort entry was expired from the cache.
        IllegalStateException ex =
            new IllegalStateException(
                String.format(
                    "%s: Could not finish committing transaction %s - no CohortEntry found",
                    persistenceId(), transactionID));
        LOG.error(ex.getMessage());
        sender.tell(new akka.actor.Status.Failure(ex), getSelf());
      }
    } else {
      finishCommit(sender, transactionID, cohortEntry);
    }
  }
Example #7
0
  protected void onDatastoreContext(DatastoreContext context) {
    datastoreContext = context;

    commitCoordinator.setQueueCapacity(datastoreContext.getShardTransactionCommitQueueCapacity());

    setTransactionCommitTimeout();

    if (datastoreContext.isPersistent() && !persistence().isRecoveryApplicable()) {
      setPersistence(true);
    } else if (!datastoreContext.isPersistent() && persistence().isRecoveryApplicable()) {
      setPersistence(false);
    }

    updateConfigParams(datastoreContext.getShardRaftConfig());
  }
Example #8
0
  @Override
  public void postStop() {
    LOG.info("Stopping Shard {}", persistenceId());

    super.postStop();

    messageRetrySupport.close();

    if (txCommitTimeoutCheckSchedule != null) {
      txCommitTimeoutCheckSchedule.cancel();
    }

    commitCoordinator.abortPendingTransactions("Transaction aborted due to shutdown.", this);

    shardMBean.unregisterMBean();
  }
Example #9
0
 @Override
 protected void pauseLeader(Runnable operation) {
   LOG.debug("{}: In pauseLeader, operation: {}", persistenceId(), operation);
   commitCoordinator.setRunOnPendingTransactionsComplete(operation);
 }
Example #10
0
 void doAbortTransaction(final String transactionID, final ActorRef sender) {
   commitCoordinator.handleAbort(transactionID, sender, this);
 }
Example #11
0
 private void handleCanCommitTransaction(final CanCommitTransaction canCommit) {
   LOG.debug("{}: Can committing transaction {}", persistenceId(), canCommit.getTransactionID());
   commitCoordinator.handleCanCommit(canCommit.getTransactionID(), getSender(), this);
 }
Example #12
0
 private void handleCommitTransaction(final CommitTransaction commit) {
   if (!commitCoordinator.handleCommit(commit.getTransactionID(), getSender(), this)) {
     shardMBean.incrementFailedTransactionsCount();
   }
 }
Example #13
0
 public int getCohortCacheSize() {
   return commitCoordinator.getCohortCacheSize();
 }
Example #14
0
 public int getPendingTxCommitQueueSize() {
   return commitCoordinator.getQueueSize();
 }
Example #15
0
  @Override
  public void onReceiveCommand(final Object message) throws Exception {

    MessageTracker.Context context = appendEntriesReplyTracker.received(message);

    if (context.error().isPresent()) {
      LOG.trace(
          "{} : AppendEntriesReply failed to arrive at the expected interval {}",
          persistenceId(),
          context.error());
    }

    try {
      if (CreateTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
        handleCreateTransaction(message);
      } else if (BatchedModifications.class.isInstance(message)) {
        handleBatchedModifications((BatchedModifications) message);
      } else if (message instanceof ForwardedReadyTransaction) {
        handleForwardedReadyTransaction((ForwardedReadyTransaction) message);
      } else if (message instanceof ReadyLocalTransaction) {
        handleReadyLocalTransaction((ReadyLocalTransaction) message);
      } else if (CanCommitTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
        handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message));
      } else if (CommitTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
        handleCommitTransaction(CommitTransaction.fromSerializable(message));
      } else if (AbortTransaction.SERIALIZABLE_CLASS.isInstance(message)) {
        handleAbortTransaction(AbortTransaction.fromSerializable(message));
      } else if (CloseTransactionChain.SERIALIZABLE_CLASS.isInstance(message)) {
        closeTransactionChain(CloseTransactionChain.fromSerializable(message));
      } else if (message instanceof RegisterChangeListener) {
        changeSupport.onMessage((RegisterChangeListener) message, isLeader(), hasLeader());
      } else if (message instanceof RegisterDataTreeChangeListener) {
        treeChangeSupport.onMessage(
            (RegisterDataTreeChangeListener) message, isLeader(), hasLeader());
      } else if (message instanceof UpdateSchemaContext) {
        updateSchemaContext((UpdateSchemaContext) message);
      } else if (message instanceof PeerAddressResolved) {
        PeerAddressResolved resolved = (PeerAddressResolved) message;
        setPeerAddress(resolved.getPeerId().toString(), resolved.getPeerAddress());
      } else if (message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) {
        commitCoordinator.checkForExpiredTransactions(transactionCommitTimeout, this);
      } else if (message instanceof DatastoreContext) {
        onDatastoreContext((DatastoreContext) message);
      } else if (message instanceof RegisterRoleChangeListener) {
        roleChangeNotifier.get().forward(message, context());
      } else if (message instanceof FollowerInitialSyncUpStatus) {
        shardMBean.setFollowerInitialSyncStatus(
            ((FollowerInitialSyncUpStatus) message).isInitialSyncDone());
        context().parent().tell(message, self());
      } else if (GET_SHARD_MBEAN_MESSAGE.equals(message)) {
        sender().tell(getShardMBean(), self());
      } else if (message instanceof GetShardDataTree) {
        sender().tell(store.getDataTree(), self());
      } else if (message instanceof ServerRemoved) {
        context().parent().forward(message, context());
      } else if (ShardTransactionMessageRetrySupport.TIMER_MESSAGE_CLASS.isInstance(message)) {
        messageRetrySupport.onTimerMessage(message);
      } else {
        super.onReceiveCommand(message);
      }
    } finally {
      context.done();
    }
  }