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); } }
private void commitWithNewTransaction(final Modification modification) { ReadWriteShardDataTreeTransaction tx = store.newReadWriteTransaction(modification.toString(), null); modification.apply(tx.getSnapshot()); try { snapshotCohort.syncCommitTransaction(tx); shardMBean.incrementCommittedTransactionCount(); shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis()); } catch (Exception e) { shardMBean.incrementFailedTransactionsCount(); LOG.error("{}: Failed to commit", persistenceId(), e); } }
@Override protected void onLeaderChanged(String oldLeader, String newLeader) { shardMBean.incrementLeadershipChangeCount(); if (hasLeader() && !isIsolatedLeader()) { messageRetrySupport.retryMessages(); } }
protected Shard(AbstractBuilder<?, ?> builder) { super( builder.getId().toString(), builder.getPeerAddresses(), Optional.of(builder.getDatastoreContext().getShardRaftConfig()), DataStoreVersions.CURRENT_VERSION); this.name = builder.getId().toString(); this.datastoreContext = builder.getDatastoreContext(); this.restoreFromSnapshot = builder.getRestoreFromSnapshot(); setPersistence(datastoreContext.isPersistent()); LOG.info("Shard created : {}, persistent : {}", name, datastoreContext.isPersistent()); store = new ShardDataTree(builder.getSchemaContext(), builder.getTreeType()); shardMBean = ShardMBeanFactory.getShardStatsMBean( name.toString(), datastoreContext.getDataStoreMXBeanType()); shardMBean.setShard(this); if (isMetricsCaptureEnabled()) { getContext().become(new MeteringBehavior(this)); } commitCoordinator = new ShardCommitCoordinator( store, datastoreContext.getShardCommitQueueExpiryTimeoutInMillis(), datastoreContext.getShardTransactionCommitQueueCapacity(), LOG, this.name); setTransactionCommitTimeout(); // create a notifier actor for each cluster member roleChangeNotifier = createRoleChangeNotifier(name.toString()); appendEntriesReplyTracker = new MessageTracker( AppendEntriesReply.class, getRaftActorContext().getConfigParams().getIsolatedCheckIntervalInMillis()); transactionActorFactory = new ShardTransactionActorFactory( store, datastoreContext, new Dispatchers(context().system().dispatchers()) .getDispatcherPath(Dispatchers.DispatcherType.Transaction), self(), getContext(), shardMBean); snapshotCohort = new ShardSnapshotCohort(transactionActorFactory, store, LOG, this.name); messageRetrySupport = new ShardTransactionMessageRetrySupport(this); }
private boolean checkClosed(AbstractShardDataTreeTransaction<?> transaction) { final boolean ret = transaction.isClosed(); if (ret) { shardStats.incrementFailedReadTransactionsCount(); getSender() .tell( new akka.actor.Status.Failure(new ReadFailedException("Transaction is closed")), getSelf()); } return ret; }
@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(); }
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); } }
private void handleCommitTransaction(final CommitTransaction commit) { if (!commitCoordinator.handleCommit(commit.getTransactionID(), getSender(), this)) { shardMBean.incrementFailedTransactionsCount(); } }
@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(); } }