BUG-5280: refactor CohortEntry
[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
9 package org.opendaylight.controller.cluster.databroker;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.util.Collection;
16 import java.util.Map;
17 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
18 import java.util.concurrent.atomic.AtomicLong;
19 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
23 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
24 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
25 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
26 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 final class DOMBrokerTransactionChain extends AbstractDOMTransactionFactory<DOMStoreTransactionChain>
31         implements DOMTransactionChain {
32     private static enum State {
33         RUNNING,
34         CLOSING,
35         CLOSED,
36         FAILED,
37     }
38
39     private static final AtomicIntegerFieldUpdater<DOMBrokerTransactionChain> COUNTER_UPDATER =
40             AtomicIntegerFieldUpdater.newUpdater(DOMBrokerTransactionChain.class, "counter");
41     private static final AtomicReferenceFieldUpdater<DOMBrokerTransactionChain, State> STATE_UPDATER =
42             AtomicReferenceFieldUpdater.newUpdater(DOMBrokerTransactionChain.class, State.class, "state");
43     private static final Logger LOG = LoggerFactory.getLogger(DOMBrokerTransactionChain.class);
44     private final AtomicLong txNum = new AtomicLong();
45     private final AbstractDOMBroker broker;
46     private final TransactionChainListener listener;
47     private final long chainId;
48
49     private volatile State state = State.RUNNING;
50     private volatile int counter = 0;
51
52     /**
53      *
54      * @param chainId
55      *            ID of transaction chain
56      * @param chains
57      *            Backing {@link DOMStoreTransactionChain}s.
58      * @param listener
59      *            Listener, which listens on transaction chain events.
60      * @throws NullPointerException
61      *             If any of arguments is null.
62      */
63     public DOMBrokerTransactionChain(final long chainId,
64                                      final Map<LogicalDatastoreType, DOMStoreTransactionChain> chains,
65                                      AbstractDOMBroker broker, final TransactionChainListener listener) {
66         super(chains);
67         this.chainId = chainId;
68         this.broker = Preconditions.checkNotNull(broker);
69         this.listener = Preconditions.checkNotNull(listener);
70     }
71
72     private void checkNotFailed() {
73         Preconditions.checkState(state != State.FAILED, "Transaction chain has failed");
74     }
75
76     @Override
77     protected Object newTransactionIdentifier() {
78         return "DOM-CHAIN-" + chainId + "-" + txNum.getAndIncrement();
79     }
80
81     @Override
82     public CheckedFuture<Void, TransactionCommitFailedException> submit(
83             final DOMDataWriteTransaction transaction, final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
84         checkNotFailed();
85         checkNotClosed();
86
87         final CheckedFuture<Void, TransactionCommitFailedException> ret = broker.submit(transaction, cohorts);
88
89         COUNTER_UPDATER.incrementAndGet(this);
90         Futures.addCallback(ret, new FutureCallback<Void>() {
91             @Override
92             public void onSuccess(final Void result) {
93                 transactionCompleted();
94             }
95
96             @Override
97             public void onFailure(final Throwable t) {
98                 transactionFailed(transaction, t);
99             }
100         });
101
102         return ret;
103     }
104
105     @Override
106     public void close() {
107         final boolean success = STATE_UPDATER.compareAndSet(this, State.RUNNING, State.CLOSING);
108         if (!success) {
109             LOG.debug("Chain {} is no longer running", this);
110             return;
111         }
112
113         super.close();
114         for (DOMStoreTransactionChain subChain : getTxFactories().values()) {
115             subChain.close();
116         }
117
118         if (counter == 0) {
119             finishClose();
120         }
121     }
122
123     private void finishClose() {
124         state = State.CLOSED;
125         listener.onTransactionChainSuccessful(this);
126     }
127
128     private void transactionCompleted() {
129         if (COUNTER_UPDATER.decrementAndGet(this) == 0 && state == State.CLOSING) {
130             finishClose();
131         }
132     }
133
134     private void transactionFailed(final DOMDataWriteTransaction tx, final Throwable cause) {
135         state = State.FAILED;
136         LOG.debug("Transaction chain {} failed.", this, cause);
137         listener.onTransactionChainFailed(this, tx, cause);
138     }
139 }