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.collect.ClassToInstanceMap;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.EnumMap;
21 import java.util.concurrent.atomic.AtomicLong;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import org.opendaylight.mdsal.common.api.AsyncTransaction;
25 import org.opendaylight.mdsal.common.api.CommitInfo;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.mdsal.common.api.TransactionChainListener;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
37 import org.opendaylight.mdsal.dom.api.DOMDataTreeServiceExtension;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
39 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
40 import org.opendaylight.yangtools.concepts.ListenerRegistration;
42 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
44 private final DOMDataTreeService dataTreeService;
45 private final Object txChainIdentifier;
46 private final AtomicLong txNum = new AtomicLong();
47 private final TransactionChainListener txChainListener;
48 private final CachedDataTreeService cachedDataTreeService;
49 private TransactionChainWriteTransaction writeTx;
50 private TransactionChainReadTransaction readTx;
51 private ListenableFuture<? extends CommitInfo> writeTxCommitFuture;
52 private boolean finished = false;
54 public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
55 final DOMDataTreeService dataTreeService,
56 final TransactionChainListener txChainListener) {
57 Preconditions.checkNotNull(dataTreeService);
58 Preconditions.checkNotNull(txChainIdentifier);
59 this.dataTreeService = dataTreeService;
60 this.txChainIdentifier = txChainIdentifier;
61 this.txChainListener = txChainListener;
62 this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
66 public DOMDataTreeReadTransaction newReadOnlyTransaction() {
70 readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
71 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
72 writeTxCommitFuture, this);
78 public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
82 writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
83 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
84 cachedDataTreeService), this);
90 public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
94 ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
95 newTransactionIdentifier(), cachedDataTreeService);
96 TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
97 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxCommitFuture, this);
99 writeTx = readWriteTx;
104 public void close() {
106 // already closed, do nothing
111 checkWriteTxClosed();
112 Futures.addCallback(writeTxCommitFuture, new FutureCallback<CommitInfo>() {
114 public void onSuccess(@Nullable final CommitInfo result) {
115 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
119 public void onFailure(final Throwable throwable) {
120 // We don't have to do nothing here,
121 // tx should take car of it
123 }, MoreExecutors.directExecutor());
125 cachedDataTreeService.closeProducers();
129 public void closeReadTransaction() {
133 public void closeWriteTransaction(final ListenableFuture<? extends CommitInfo> commitFuture) {
134 writeTxCommitFuture = commitFuture;
138 private Object newTransactionIdentifier() {
139 return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
142 private void checkWriteTxClosed() {
143 Preconditions.checkState(writeTx == null);
146 private void checkReadTxClosed() {
147 Preconditions.checkState(readTx == null);
150 private void checkRunning() {
151 Preconditions.checkState(!finished);
154 public void transactionFailed(final AsyncTransaction<?, ?> tx, final Throwable cause) {
155 txChainListener.onTransactionChainFailed(this, tx, cause);
156 if (writeTx != null) {
159 if (readTx != null) {
162 cachedDataTreeService.closeProducers();
166 static class CachedDataTreeService implements DOMDataTreeService {
168 private final DOMDataTreeService delegateTreeService;
169 private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
170 new EnumMap<>(LogicalDatastoreType.class);
172 CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
173 this.delegateTreeService = delegateTreeService;
176 void closeProducers() {
177 producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
182 public <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(
183 @Nonnull final T listener, @Nonnull final Collection<DOMDataTreeIdentifier> subtrees,
184 final boolean allowRxMerges, @Nonnull final Collection<DOMDataTreeProducer> producers)
185 throws DOMDataTreeLoopException {
186 return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
191 public Map<Class<? extends DOMDataTreeServiceExtension>, DOMDataTreeServiceExtension> getSupportedExtensions() {
192 return delegateTreeService.getSupportedExtensions();
196 public ClassToInstanceMap<DOMDataTreeServiceExtension> getExtensions() {
197 return delegateTreeService.getExtensions();
201 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
202 Preconditions.checkState(subtrees.size() == 1);
203 NoopCloseDataProducer producer = null;
204 for (final DOMDataTreeIdentifier treeId : subtrees) {
206 new NoopCloseDataProducer(delegateTreeService.createProducer(Collections.singleton(treeId)));
207 producersMap.putIfAbsent(treeId.getDatastoreType(),
213 static class NoopCloseDataProducer implements DOMDataTreeProducer {
215 private final DOMDataTreeProducer delegateTreeProducer;
217 NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
218 this.delegateTreeProducer = delegateTreeProducer;
223 public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
224 return delegateTreeProducer.createTransaction(isolated);
229 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
230 return delegateTreeProducer.createProducer(subtrees);
234 public void close() throws DOMDataTreeProducerException {
238 public void closeDelegate() {
240 delegateTreeProducer.close();
241 } catch (final DOMDataTreeProducerException e) {
242 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);