private void doRegistration(final ActorRef shard, final YangInstanceIdentifier path) { Future<Object> future = actorContext.executeOperationAsync( shard, new RegisterDataTreeChangeListener(path, dataChangeListenerActor), actorContext.getDatastoreContext().getShardInitializationTimeout()); future.onComplete( new OnComplete<Object>() { @Override public void onComplete(final Throwable failure, final Object result) { if (failure != null) { LOG.error( "Failed to register DataTreeChangeListener {} at path {}", getInstance(), path.toString(), failure); } else { RegisterDataTreeChangeListenerReply reply = (RegisterDataTreeChangeListenerReply) result; setListenerRegistrationActor( actorContext.actorSelection(reply.getListenerRegistrationPath())); } } }, actorContext.getClientDispatcher()); }
void init(final String shardName, final YangInstanceIdentifier treeId) { Future<ActorRef> findFuture = actorContext.findLocalShardAsync(shardName); findFuture.onComplete( new OnComplete<ActorRef>() { @Override public void onComplete(final Throwable failure, final ActorRef shard) { if (failure instanceof LocalShardNotFoundException) { LOG.debug( "No local shard found for {} - DataTreeChangeListener {} at path {} " + "cannot be registered", shardName, getInstance(), treeId); } else if (failure != null) { LOG.error( "Failed to find local shard {} - DataTreeChangeListener {} at path {} " + "cannot be registered: {}", shardName, getInstance(), treeId, failure); } else { doRegistration(shard, treeId); } } }, actorContext.getClientDispatcher()); }
final TransactionContextWrapper newTransactionContextWrapper( final TransactionProxy parent, final String shardName) { final TransactionContextWrapper transactionContextWrapper = new TransactionContextWrapper(parent.getIdentifier(), actorContext); Future<PrimaryShardInfo> findPrimaryFuture = findPrimaryShard(shardName, parent.getIdentifier()); if (findPrimaryFuture.isCompleted()) { Try<PrimaryShardInfo> maybe = findPrimaryFuture.value().get(); if (maybe.isSuccess()) { onFindPrimaryShardSuccess(maybe.get(), parent, shardName, transactionContextWrapper); } else { onFindPrimaryShardFailure( maybe.failed().get(), parent, shardName, transactionContextWrapper); } } else { findPrimaryFuture.onComplete( new OnComplete<PrimaryShardInfo>() { @Override public void onComplete( final Throwable failure, final PrimaryShardInfo primaryShardInfo) { if (failure == null) { onFindPrimaryShardSuccess( primaryShardInfo, parent, shardName, transactionContextWrapper); } else { onFindPrimaryShardFailure(failure, parent, shardName, transactionContextWrapper); } } }, actorContext.getClientDispatcher()); } return transactionContextWrapper; }
@Override public ListenableFuture<Boolean> canCommit() { if (LOG.isDebugEnabled()) { LOG.debug("Tx {} canCommit", transactionId); } final SettableFuture<Boolean> returnFuture = SettableFuture.create(); // The first phase of canCommit is to gather the list of cohort actor paths that will // participate in the commit. buildCohortPathsList combines the cohort path Futures into // one Future which we wait on asynchronously here. The cohort actor paths are // extracted from ReadyTransactionReply messages by the Futures that were obtained earlier // and passed to us from upstream processing. If any one fails then we'll fail canCommit. buildCohortList() .onComplete( new OnComplete<Void>() { @Override public void onComplete(Throwable failure, Void notUsed) throws Throwable { if (failure != null) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: a cohort Future failed: {}", transactionId, failure); } returnFuture.setException(failure); } else { finishCanCommit(returnFuture); } } }, actorContext.getClientDispatcher()); return returnFuture; }
private ListenableFuture<Void> voidOperation( final String operationName, final Object message, final Class<?> expectedResponseClass, final boolean propagateException, final OperationCallback callback) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {} {}", transactionId, operationName); } final SettableFuture<Void> returnFuture = SettableFuture.create(); // The cohort actor list should already be built at this point by the canCommit phase but, // if not for some reason, we'll try to build it here. if (cohorts != null) { finishVoidOperation( operationName, message, expectedResponseClass, propagateException, returnFuture, callback); } else { buildCohortList() .onComplete( new OnComplete<Void>() { @Override public void onComplete(Throwable failure, Void notUsed) throws Throwable { if (failure != null) { if (LOG.isDebugEnabled()) { LOG.debug( "Tx {}: a {} cohort path Future failed: {}", transactionId, operationName, failure); } if (propagateException) { returnFuture.setException(failure); } else { returnFuture.set(null); } } else { finishVoidOperation( operationName, message, expectedResponseClass, propagateException, returnFuture, callback); } } }, actorContext.getClientDispatcher()); } return returnFuture; }
private Future<Void> buildCohortList() { Future<Iterable<ActorSelection>> combinedFutures = Futures.sequence(cohortFutures, actorContext.getClientDispatcher()); return combinedFutures.transform( new AbstractFunction1<Iterable<ActorSelection>, Void>() { @Override public Void apply(Iterable<ActorSelection> actorSelections) { cohorts = Lists.newArrayList(actorSelections); if (LOG.isDebugEnabled()) { LOG.debug("Tx {} successfully built cohort path list: {}", transactionId, cohorts); } return null; } }, TransactionReadyReplyMapper.SAME_FAILURE_TRANSFORMER, actorContext.getClientDispatcher()); }
private Future<Iterable<Object>> invokeCohorts(Object message) { List<Future<Object>> futureList = Lists.newArrayListWithCapacity(cohorts.size()); for (ActorSelection cohort : cohorts) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: Sending {} to cohort {}", transactionId, message, cohort); } futureList.add( actorContext.executeOperationAsync( cohort, message, actorContext.getTransactionCommitOperationTimeout())); } return Futures.sequence(futureList, actorContext.getClientDispatcher()); }
private void finishVoidOperation( final String operationName, final Object message, final Class<?> expectedResponseClass, final boolean propagateException, final SettableFuture<Void> returnFuture, final OperationCallback callback) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {} finish {}", transactionId, operationName); } callback.run(); Future<Iterable<Object>> combinedFuture = invokeCohorts(message); combinedFuture.onComplete( new OnComplete<Iterable<Object>>() { @Override public void onComplete(Throwable failure, Iterable<Object> responses) throws Throwable { Throwable exceptionToPropagate = failure; if (exceptionToPropagate == null) { for (Object response : responses) { if (!response.getClass().equals(expectedResponseClass)) { exceptionToPropagate = new IllegalArgumentException( String.format("Unexpected response type %s", response.getClass())); break; } } } if (exceptionToPropagate != null) { if (LOG.isDebugEnabled()) { LOG.debug( "Tx {}: a {} cohort Future failed: {}", transactionId, operationName, exceptionToPropagate); } if (propagateException) { // We don't log the exception here to avoid redundant logging since we're // propagating to the caller in MD-SAL core who will log it. returnFuture.setException(exceptionToPropagate); } else { // Since the caller doesn't want us to propagate the exception we'll also // not log it normally. But it's usually not good to totally silence // exceptions so we'll log it to debug level. if (LOG.isDebugEnabled()) { LOG.debug( String.format("%s failed", message.getClass().getSimpleName()), exceptionToPropagate); } returnFuture.set(null); } callback.failure(); } else { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: {} succeeded", transactionId, operationName); } returnFuture.set(null); callback.success(); } } }, actorContext.getClientDispatcher()); }
private void finishCanCommit(final SettableFuture<Boolean> returnFuture) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {} finishCanCommit", transactionId); } // For empty transactions return immediately if (cohorts.size() == 0) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: canCommit returning result: {}", transactionId, true); } returnFuture.set(Boolean.TRUE); return; } final Object message = new CanCommitTransaction(transactionId).toSerializable(); final Iterator<ActorSelection> iterator = cohorts.iterator(); final OnComplete<Object> onComplete = new OnComplete<Object>() { @Override public void onComplete(Throwable failure, Object response) throws Throwable { if (failure != null) { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: a canCommit cohort Future failed: {}", transactionId, failure); } returnFuture.setException(failure); return; } boolean result = true; if (response.getClass().equals(CanCommitTransactionReply.SERIALIZABLE_CLASS)) { CanCommitTransactionReply reply = CanCommitTransactionReply.fromSerializable(response); if (!reply.getCanCommit()) { result = false; } } else { LOG.error("Unexpected response type {}", response.getClass()); returnFuture.setException( new IllegalArgumentException( String.format("Unexpected response type %s", response.getClass()))); return; } if (iterator.hasNext() && result) { Future<Object> future = actorContext.executeOperationAsync( iterator.next(), message, actorContext.getTransactionCommitOperationTimeout()); future.onComplete(this, actorContext.getClientDispatcher()); } else { if (LOG.isDebugEnabled()) { LOG.debug("Tx {}: canCommit returning result: {}", transactionId, result); } returnFuture.set(Boolean.valueOf(result)); } } }; Future<Object> future = actorContext.executeOperationAsync( iterator.next(), message, actorContext.getTransactionCommitOperationTimeout()); future.onComplete(onComplete, actorContext.getClientDispatcher()); }