Bump odlparent to 6.0.0
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / DOMBrokerTransactionChain.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.databroker;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.Collection;
18 import java.util.Map;
19 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
20 import java.util.concurrent.atomic.AtomicLong;
21 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
22 import org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
25 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
26 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
28 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 final class DOMBrokerTransactionChain extends AbstractDOMTransactionFactory<DOMStoreTransactionChain>
33         implements DOMTransactionChain {
34     private enum State {
35         RUNNING,
36         CLOSING,
37         CLOSED,
38         FAILED,
39     }
40
41     private static final AtomicIntegerFieldUpdater<DOMBrokerTransactionChain> COUNTER_UPDATER =
42             AtomicIntegerFieldUpdater.newUpdater(DOMBrokerTransactionChain.class, "counter");
43     private static final AtomicReferenceFieldUpdater<DOMBrokerTransactionChain, State> STATE_UPDATER =
44             AtomicReferenceFieldUpdater.newUpdater(DOMBrokerTransactionChain.class, State.class, "state");
45     private static final Logger LOG = LoggerFactory.getLogger(DOMBrokerTransactionChain.class);
46     private final AtomicLong txNum = new AtomicLong();
47     private final AbstractDOMBroker broker;
48     private final DOMTransactionChainListener listener;
49     private final long chainId;
50
51     private volatile State state = State.RUNNING;
52     private volatile int counter = 0;
53
54     /**
55      * Constructs an instance.
56      *
57      * @param chainId
58      *            ID of transaction chain
59      * @param chains
60      *            Backing {@link DOMStoreTransactionChain}s.
61      * @param listener
62      *            Listener, which listens on transaction chain events.
63      * @throws NullPointerException
64      *             If any of arguments is null.
65      */
66     DOMBrokerTransactionChain(final long chainId, final Map<LogicalDatastoreType, DOMStoreTransactionChain> chains,
67             final AbstractDOMBroker broker, final DOMTransactionChainListener listener) {
68         super(chains);
69         this.chainId = chainId;
70         this.broker = requireNonNull(broker);
71         this.listener = requireNonNull(listener);
72     }
73
74     private void checkNotFailed() {
75         checkState(state != State.FAILED, "Transaction chain has failed");
76     }
77
78     @Override
79     protected Object newTransactionIdentifier() {
80         return "DOM-CHAIN-" + chainId + "-" + txNum.getAndIncrement();
81     }
82
83     @Override
84     public FluentFuture<? extends CommitInfo> commit(
85             final DOMDataTreeWriteTransaction transaction, final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
86         checkNotFailed();
87         checkNotClosed();
88
89         final FluentFuture<? extends CommitInfo> ret = broker.commit(transaction, cohorts);
90
91         COUNTER_UPDATER.incrementAndGet(this);
92         ret.addCallback(new FutureCallback<CommitInfo>() {
93             @Override
94             public void onSuccess(final CommitInfo result) {
95                 transactionCompleted();
96             }
97
98             @Override
99             public void onFailure(final Throwable failure) {
100                 transactionFailed(transaction, failure);
101             }
102         }, MoreExecutors.directExecutor());
103
104         return ret;
105     }
106
107     @Override
108     public void close() {
109         final boolean success = STATE_UPDATER.compareAndSet(this, State.RUNNING, State.CLOSING);
110         if (!success) {
111             LOG.debug("Chain {} is no longer running", this);
112             return;
113         }
114
115         super.close();
116         for (DOMStoreTransactionChain subChain : getTxFactories().values()) {
117             subChain.close();
118         }
119
120         if (counter == 0) {
121             finishClose();
122         }
123     }
124
125     private void finishClose() {
126         state = State.CLOSED;
127         listener.onTransactionChainSuccessful(this);
128     }
129
130     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
131             justification = "https://github.com/spotbugs/spotbugs/issues/811")
132     private void transactionCompleted() {
133         if (COUNTER_UPDATER.decrementAndGet(this) == 0 && state == State.CLOSING) {
134             finishClose();
135         }
136     }
137
138     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
139             justification = "https://github.com/spotbugs/spotbugs/issues/811")
140     private void transactionFailed(final DOMDataTreeWriteTransaction tx, final Throwable cause) {
141         state = State.FAILED;
142         LOG.debug("Transaction chain {} failed.", this, cause);
143         listener.onTransactionChainFailed(this, tx, cause);
144     }
145 }