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
9 package org.opendaylight.mdsal.dom.broker;
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 com.google.common.util.concurrent.MoreExecutors;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.EnumMap;
20 import java.util.concurrent.atomic.AtomicLong;
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import org.opendaylight.mdsal.common.api.AsyncTransaction;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.mdsal.common.api.TransactionChainListener;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
39 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
41 private final DOMDataTreeService dataTreeService;
42 private final Object txChainIdentifier;
43 private final AtomicLong txNum = new AtomicLong();
44 private final TransactionChainListener txChainListener;
45 private final CachedDataTreeService cachedDataTreeService;
46 private TransactionChainWriteTransaction writeTx;
47 private TransactionChainReadTransaction readTx;
48 private ListenableFuture<Void> writeTxSubmitFuture;
49 private boolean finished = false;
51 public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
52 final DOMDataTreeService dataTreeService,
53 final TransactionChainListener txChainListener) {
54 Preconditions.checkNotNull(dataTreeService);
55 Preconditions.checkNotNull(txChainIdentifier);
56 this.dataTreeService = dataTreeService;
57 this.txChainIdentifier = txChainIdentifier;
58 this.txChainListener = txChainListener;
59 this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
63 public DOMDataTreeReadTransaction newReadOnlyTransaction() {
67 readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
68 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
69 writeTxSubmitFuture, this);
75 public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
79 writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
80 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
81 cachedDataTreeService), this);
87 public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
91 ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
92 newTransactionIdentifier(), cachedDataTreeService);
93 TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
94 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxSubmitFuture, this);
96 writeTx = readWriteTx;
101 public void close() {
103 // already closed, do nothing
108 checkWriteTxClosed();
109 Futures.addCallback(writeTxSubmitFuture, new FutureCallback<Void>() {
111 public void onSuccess(@Nullable final Void result) {
112 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
116 public void onFailure(final Throwable throwable) {
117 // We don't have to do nothing here,
118 // tx should take car of it
120 }, MoreExecutors.directExecutor());
122 cachedDataTreeService.closeProducers();
126 public void closeReadTransaction() {
130 public void closeWriteTransaction(final ListenableFuture<Void> submitFuture) {
131 writeTxSubmitFuture = submitFuture;
135 private Object newTransactionIdentifier() {
136 return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
139 private void checkWriteTxClosed() {
140 Preconditions.checkState(writeTx == null);
143 private void checkReadTxClosed() {
144 Preconditions.checkState(readTx == null);
147 private void checkRunning() {
148 Preconditions.checkState(!finished);
151 public void transactionFailed(final AsyncTransaction<?, ?> tx, final Throwable cause) {
152 txChainListener.onTransactionChainFailed(this, tx, cause);
153 if (writeTx != null) {
156 if (readTx != null) {
159 cachedDataTreeService.closeProducers();
163 static class CachedDataTreeService implements DOMDataTreeService {
165 private final DOMDataTreeService delegateTreeService;
166 private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
167 new EnumMap<>(LogicalDatastoreType.class);
169 CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
170 this.delegateTreeService = delegateTreeService;
173 void closeProducers() {
174 producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
179 public <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(
180 @Nonnull final T listener, @Nonnull final Collection<DOMDataTreeIdentifier> subtrees,
181 final boolean allowRxMerges, @Nonnull final Collection<DOMDataTreeProducer> producers)
182 throws DOMDataTreeLoopException {
183 return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
187 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
188 Preconditions.checkState(subtrees.size() == 1);
189 NoopCloseDataProducer producer = null;
190 for (final DOMDataTreeIdentifier treeId : subtrees) {
192 new NoopCloseDataProducer(delegateTreeService.createProducer(Collections.singleton(treeId)));
193 producersMap.putIfAbsent(treeId.getDatastoreType(),
199 static class NoopCloseDataProducer implements DOMDataTreeProducer {
201 private final DOMDataTreeProducer delegateTreeProducer;
203 NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
204 this.delegateTreeProducer = delegateTreeProducer;
209 public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
210 return delegateTreeProducer.createTransaction(isolated);
215 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
216 return delegateTreeProducer.createProducer(subtrees);
220 public void close() throws DOMDataTreeProducerException {
224 public void closeDelegate() {
226 delegateTreeProducer.close();
227 } catch (final DOMDataTreeProducerException e) {
228 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);