Bug 5699 - Migrate existing code to use new sharding apis
[mdsal.git] / dom / mdsal-dom-broker / src / main / java / org / opendaylight / mdsal / dom / broker / ShardedDOMTransactionChainAdapter.java
1 /*
2  * Copyright (c) 2016 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.mdsal.dom.broker;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.EnumMap;
18 import java.util.Map;
19 import java.util.concurrent.atomic.AtomicLong;
20 import javax.annotation.Nonnull;
21 import javax.annotation.Nullable;
22 import org.opendaylight.mdsal.common.api.AsyncTransaction;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.common.api.TransactionChainListener;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
34 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36
37 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
38
39     private final DOMDataTreeService dataTreeService;
40     private final Object txChainIdentifier;
41     private final AtomicLong txNum = new AtomicLong();
42     private final TransactionChainListener txChainListener;
43     private final CachedDataTreeService cachedDataTreeService;
44     private TransactionChainWriteTransaction writeTx;
45     private TransactionChainReadTransaction readTx;
46     private ListenableFuture<Void> writeTxSubmitFuture;
47     private boolean finished = false;
48
49     public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
50                                              final DOMDataTreeService dataTreeService,
51                                              final TransactionChainListener txChainListener) {
52         Preconditions.checkNotNull(dataTreeService);
53         Preconditions.checkNotNull(txChainIdentifier);
54         this.dataTreeService = dataTreeService;
55         this.txChainIdentifier = txChainIdentifier;
56         this.txChainListener = txChainListener;
57         this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
58     }
59
60     @Override
61     public DOMDataTreeReadTransaction newReadOnlyTransaction() {
62         checkRunning();
63         checkReadTxClosed();
64         checkWriteTxClosed();
65         readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
66                 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
67                 writeTxSubmitFuture, this);
68
69         return readTx;
70     }
71
72     @Override
73     public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
74         checkRunning();
75         checkWriteTxClosed();
76         checkReadTxClosed();
77         writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
78                 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
79                         cachedDataTreeService), this);
80
81         return writeTx;
82     }
83
84     @Override
85     public void close() {
86         if (finished = true) {
87             // already closed, do nothing
88             return;
89         }
90
91         checkReadTxClosed();
92         checkWriteTxClosed();
93         Futures.addCallback(writeTxSubmitFuture, new FutureCallback<Void>() {
94             @Override
95             public void onSuccess(@Nullable final Void result) {
96                 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
97             }
98
99             @Override
100             public void onFailure(final Throwable t) {
101                 // We don't have to do nothing here,
102                 // tx should take car of it
103             }
104         });
105
106         cachedDataTreeService.closeProducers();
107         finished = true;
108     }
109
110     public void closeReadTransaction() {
111         readTx = null;
112     }
113
114     public void closeWriteTransaction(final ListenableFuture<Void> submitFuture) {
115         writeTxSubmitFuture = submitFuture;
116         writeTx = null;
117     }
118
119     private Object newTransactionIdentifier() {
120         return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
121     }
122
123     private void checkWriteTxClosed() {
124         Preconditions.checkState(writeTx == null);
125     }
126
127     private void checkReadTxClosed() {
128         Preconditions.checkState(readTx == null);
129     }
130
131     private void checkRunning() {
132         Preconditions.checkState(finished == false);
133     }
134
135     public void transactionFailed(final AsyncTransaction<?, ?> tx, final Throwable cause) {
136         txChainListener.onTransactionChainFailed(this, tx, cause);
137         if (writeTx != null) {
138             writeTx.cancel();
139         }
140         if (readTx != null) {
141             readTx.close();
142         }
143         cachedDataTreeService.closeProducers();
144         finished = true;
145     }
146
147     static class CachedDataTreeService implements DOMDataTreeService {
148
149         private final DOMDataTreeService delegateTreeService;
150         private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
151                 new EnumMap<>(LogicalDatastoreType.class);
152
153         CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
154             this.delegateTreeService = delegateTreeService;
155         }
156
157         void closeProducers() {
158             producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
159         }
160
161         @Nonnull
162         @Override
163         public <T extends DOMDataTreeListener> ListenerRegistration<T>
164         registerListener(@Nonnull final T listener, @Nonnull final Collection<DOMDataTreeIdentifier> subtrees,
165                          final boolean allowRxMerges, @Nonnull final Collection<DOMDataTreeProducer> producers)
166                 throws DOMDataTreeLoopException {
167             return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
168         }
169
170         @Override
171         public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
172             Preconditions.checkState(subtrees.size() == 1);
173             NoopCloseDataProducer producer = null;
174             for (final DOMDataTreeIdentifier treeId : subtrees) {
175                 producer =
176                         new NoopCloseDataProducer(delegateTreeService.createProducer(Collections.singleton(treeId)));
177                 producersMap.putIfAbsent(treeId.getDatastoreType(),
178                         producer);
179             }
180             return producer;
181         }
182
183         static class NoopCloseDataProducer implements DOMDataTreeProducer {
184
185             private final DOMDataTreeProducer delegateTreeProducer;
186
187             NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
188                 this.delegateTreeProducer = delegateTreeProducer;
189             }
190
191             @Nonnull
192             @Override
193             public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
194                 return delegateTreeProducer.createTransaction(isolated);
195             }
196
197             @Nonnull
198             @Override
199             public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
200                 return delegateTreeProducer.createProducer(subtrees);
201             }
202
203             @Override
204             public void close() throws DOMDataTreeProducerException {
205                 // noop
206             }
207
208             public void closeDelegate() {
209                 try {
210                     delegateTreeProducer.close();
211                 } catch (final DOMDataTreeProducerException e) {
212                     throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);
213                 }
214             }
215         }
216     }
217 }