2 * Copyright (c) 2016 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 com.google.common.base.Preconditions.checkState;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.collect.ClassToInstanceMap;
15 import com.google.common.util.concurrent.FluentFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.EnumMap;
22 import java.util.concurrent.atomic.AtomicLong;
23 import org.opendaylight.mdsal.common.api.CommitInfo;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
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.DOMDataTreeReadWriteTransaction;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeServiceExtension;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
37 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
38 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
41 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
43 private final DOMDataTreeService dataTreeService;
44 private final Object txChainIdentifier;
45 private final AtomicLong txNum = new AtomicLong();
46 private final DOMTransactionChainListener txChainListener;
47 private final CachedDataTreeService cachedDataTreeService;
48 private TransactionChainWriteTransaction writeTx;
49 private TransactionChainReadTransaction readTx;
50 private FluentFuture<? extends CommitInfo> writeTxCommitFuture;
51 private boolean finished = false;
53 public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
54 final DOMDataTreeService dataTreeService, final DOMTransactionChainListener txChainListener) {
55 this.dataTreeService = requireNonNull(dataTreeService);
56 this.txChainIdentifier = requireNonNull(txChainIdentifier);
57 this.txChainListener = txChainListener;
58 this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
62 public DOMDataTreeReadTransaction newReadOnlyTransaction() {
66 readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
67 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
68 writeTxCommitFuture, this);
74 public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
78 writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
79 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
80 cachedDataTreeService), this);
86 public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
90 ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
91 newTransactionIdentifier(), cachedDataTreeService);
92 TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
93 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxCommitFuture, this);
95 writeTx = readWriteTx;
100 public void close() {
102 // already closed, do nothing
107 checkWriteTxClosed();
108 writeTxCommitFuture.addCallback(new FutureCallback<CommitInfo>() {
110 public void onSuccess(final CommitInfo result) {
111 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
115 public void onFailure(final Throwable throwable) {
116 // We don't have to do nothing here,
117 // tx should take car of it
119 }, MoreExecutors.directExecutor());
121 cachedDataTreeService.closeProducers();
125 public void closeReadTransaction() {
129 public void closeWriteTransaction(final FluentFuture<? extends CommitInfo> commitFuture) {
130 writeTxCommitFuture = commitFuture;
134 private Object newTransactionIdentifier() {
135 return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
138 private void checkWriteTxClosed() {
139 checkState(writeTx == null);
142 private void checkReadTxClosed() {
143 checkState(readTx == null);
146 private void checkRunning() {
147 checkState(!finished);
150 public void transactionFailed(final DOMDataTreeTransaction tx, final Throwable cause) {
151 txChainListener.onTransactionChainFailed(this, tx, cause);
152 if (writeTx != null) {
155 if (readTx != null) {
158 cachedDataTreeService.closeProducers();
162 static class CachedDataTreeService implements DOMDataTreeService {
164 private final DOMDataTreeService delegateTreeService;
165 private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
166 new EnumMap<>(LogicalDatastoreType.class);
168 CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
169 this.delegateTreeService = delegateTreeService;
172 void closeProducers() {
173 producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
177 public <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener,
178 final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges,
179 final Collection<DOMDataTreeProducer> producers) throws DOMDataTreeLoopException {
180 return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
184 public ClassToInstanceMap<DOMDataTreeServiceExtension> getExtensions() {
185 return delegateTreeService.getExtensions();
189 public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
190 checkState(subtrees.size() == 1);
191 NoopCloseDataProducer producer = null;
192 for (final DOMDataTreeIdentifier treeId : subtrees) {
193 producer = new NoopCloseDataProducer(delegateTreeService.createProducer(Collections.singleton(treeId)));
194 producersMap.putIfAbsent(treeId.getDatastoreType(),
197 return verifyNotNull(producer);
200 static class NoopCloseDataProducer implements DOMDataTreeProducer {
202 private final DOMDataTreeProducer delegateTreeProducer;
204 NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
205 this.delegateTreeProducer = delegateTreeProducer;
209 public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
210 return delegateTreeProducer.createTransaction(isolated);
214 public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
215 return delegateTreeProducer.createProducer(subtrees);
219 public void close() throws DOMDataTreeProducerException {
223 public void closeDelegate() {
225 delegateTreeProducer.close();
226 } catch (final DOMDataTreeProducerException e) {
227 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);