2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.dom.broker;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.Throwables;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.concurrent.Callable;
15 import java.util.concurrent.ExecutionException;
16 import org.opendaylight.mdsal.common.api.CommitInfo;
17 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
18 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
19 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
20 import org.opendaylight.yangtools.util.DurationStatisticsTracker;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * Implementation of blocking three-phase commit-coordination tasks without support of cancellation.
27 sealed class CommitCoordinationTask implements Callable<CommitInfo> {
28 static final class WithTracker extends CommitCoordinationTask {
29 private final DurationStatisticsTracker commitStatTracker;
31 WithTracker(final DOMDataTreeWriteTransaction transaction, final DOMStoreThreePhaseCommitCohort cohort,
32 final DurationStatisticsTracker commitStatTracker) {
33 super(transaction, cohort);
34 this.commitStatTracker = requireNonNull(commitStatTracker);
38 public CommitInfo call() throws TransactionCommitFailedException {
39 final long startTime = System.nanoTime();
44 commitStatTracker.addDuration(System.nanoTime() - startTime);
55 private static final Logger LOG = LoggerFactory.getLogger(CommitCoordinationTask.class);
57 private final DOMStoreThreePhaseCommitCohort cohort;
58 private final DOMDataTreeWriteTransaction tx;
60 CommitCoordinationTask(final DOMDataTreeWriteTransaction transaction, final DOMStoreThreePhaseCommitCohort cohort) {
61 tx = requireNonNull(transaction, "transaction must not be null");
62 this.cohort = requireNonNull(cohort, "cohort must not be null");
66 public CommitInfo call() throws TransactionCommitFailedException {
67 var phase = Phase.CAN_COMMIT;
69 LOG.debug("Transaction {}: canCommit Started", tx.getIdentifier());
72 phase = Phase.PRE_COMMIT;
73 LOG.debug("Transaction {}: preCommit Started", tx.getIdentifier());
76 phase = Phase.DO_COMMIT;
77 LOG.debug("Transaction {}: doCommit Started", tx.getIdentifier());
80 LOG.debug("Transaction {}: doCommit completed", tx.getIdentifier());
81 return CommitInfo.empty();
82 } catch (final TransactionCommitFailedException e) {
83 LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), phase, e);
90 * Invokes canCommit on underlying cohort and blocks till the result is returned.
93 * Valid state transition is from SUBMITTED to CAN_COMMIT, if currentPhase is not SUBMITTED throws
94 * IllegalStateException.
96 * @throws TransactionCommitFailedException If cohort fails Commit
98 @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
99 private void canCommitBlocking() throws TransactionCommitFailedException {
100 final var future = cohort.canCommit();
101 final Boolean result;
103 result = future.get();
104 } catch (InterruptedException | ExecutionException e) {
105 throw TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER.apply(e);
108 if (!Boolean.TRUE.equals(result)) {
109 throw new TransactionCommitFailedException("Can Commit failed, no detailed cause available.");
114 * Invokes preCommit on underlying cohort and blocks until the result is returned.
117 * Valid state transition is from CAN_COMMIT to PRE_COMMIT, if current state is not CAN_COMMIT throws
118 * IllegalStateException.
120 * @throws TransactionCommitFailedException If cohort fails preCommit
122 @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
123 private void preCommitBlocking() throws TransactionCommitFailedException {
125 cohort.preCommit().get();
126 } catch (InterruptedException | ExecutionException e) {
127 throw TransactionCommitFailedExceptionMapper.PRE_COMMIT_MAPPER.apply(e);
132 * Invokes commit on underlying cohort and blocks until result is returned.
135 * Valid state transition is from PRE_COMMIT to COMMIT, if not throws IllegalStateException.
137 * @throws TransactionCommitFailedException If cohort fails preCommit
139 @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE")
140 private void commitBlocking() throws TransactionCommitFailedException {
142 cohort.commit().get();
143 } catch (InterruptedException | ExecutionException e) {
144 throw TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER.apply(e);
149 * Aborts transaction.
152 * Invokes {@link DOMStoreThreePhaseCommitCohort#abort()} on underlying cohort, blocks the results. If
153 * abort failed throws IllegalStateException, which will contains originalCause as suppressed Exception.
156 * If abort was successful throws supplied exception
158 * @param originalCause Exception which should be used to fail transaction for consumers of transaction future
159 * and listeners of transaction failure.
160 * @throws IllegalStateException if abort failed.
161 * @throws TransactionCommitFailedException on invocation of this method.
163 private void abortBlocking(final TransactionCommitFailedException originalCause)
164 throws TransactionCommitFailedException {
165 Exception cause = originalCause;
167 cohort.abort().get();
168 } catch (InterruptedException | ExecutionException e) {
169 LOG.error("Tx: {} Error during Abort.", tx.getIdentifier(), e);
170 cause = new IllegalStateException("Abort failed.", e);
171 cause.addSuppressed(e);
173 Throwables.propagateIfPossible(cause, TransactionCommitFailedException.class);