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.DOMDataTreeServiceExtension;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
37 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
38 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
42 private final DOMDataTreeService dataTreeService;
43 private final Object txChainIdentifier;
44 private final AtomicLong txNum = new AtomicLong();
45 private final TransactionChainListener txChainListener;
46 private final CachedDataTreeService cachedDataTreeService;
47 private TransactionChainWriteTransaction writeTx;
48 private TransactionChainReadTransaction readTx;
49 private ListenableFuture<Void> writeTxSubmitFuture;
50 private boolean finished = false;
52 public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
53 final DOMDataTreeService dataTreeService,
54 final TransactionChainListener txChainListener) {
55 Preconditions.checkNotNull(dataTreeService);
56 Preconditions.checkNotNull(txChainIdentifier);
57 this.dataTreeService = dataTreeService;
58 this.txChainIdentifier = txChainIdentifier;
59 this.txChainListener = txChainListener;
60 this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
64 public DOMDataTreeReadTransaction newReadOnlyTransaction() {
68 readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
69 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
70 writeTxSubmitFuture, this);
76 public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
80 writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
81 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
82 cachedDataTreeService), this);
88 public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
92 ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
93 newTransactionIdentifier(), cachedDataTreeService);
94 TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
95 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxSubmitFuture, this);
97 writeTx = readWriteTx;
102 public void close() {
104 // already closed, do nothing
109 checkWriteTxClosed();
110 Futures.addCallback(writeTxSubmitFuture, new FutureCallback<Void>() {
112 public void onSuccess(@Nullable final Void result) {
113 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
117 public void onFailure(final Throwable throwable) {
118 // We don't have to do nothing here,
119 // tx should take car of it
121 }, MoreExecutors.directExecutor());
123 cachedDataTreeService.closeProducers();
127 public void closeReadTransaction() {
131 public void closeWriteTransaction(final ListenableFuture<Void> submitFuture) {
132 writeTxSubmitFuture = submitFuture;
136 private Object newTransactionIdentifier() {
137 return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
140 private void checkWriteTxClosed() {
141 Preconditions.checkState(writeTx == null);
144 private void checkReadTxClosed() {
145 Preconditions.checkState(readTx == null);
148 private void checkRunning() {
149 Preconditions.checkState(!finished);
152 public void transactionFailed(final AsyncTransaction<?, ?> tx, final Throwable cause) {
153 txChainListener.onTransactionChainFailed(this, tx, cause);
154 if (writeTx != null) {
157 if (readTx != null) {
160 cachedDataTreeService.closeProducers();
164 static class CachedDataTreeService implements DOMDataTreeService {
166 private final DOMDataTreeService delegateTreeService;
167 private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
168 new EnumMap<>(LogicalDatastoreType.class);
170 CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
171 this.delegateTreeService = delegateTreeService;
174 void closeProducers() {
175 producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
180 public <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(
181 @Nonnull final T listener, @Nonnull final Collection<DOMDataTreeIdentifier> subtrees,
182 final boolean allowRxMerges, @Nonnull final Collection<DOMDataTreeProducer> producers)
183 throws DOMDataTreeLoopException {
184 return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
188 public Map<Class<? extends DOMDataTreeServiceExtension>, DOMDataTreeServiceExtension> getSupportedExtensions() {
189 return delegateTreeService.getSupportedExtensions();
193 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
194 Preconditions.checkState(subtrees.size() == 1);
195 NoopCloseDataProducer producer = null;
196 for (final DOMDataTreeIdentifier treeId : subtrees) {
198 new NoopCloseDataProducer(delegateTreeService.createProducer(Collections.singleton(treeId)));
199 producersMap.putIfAbsent(treeId.getDatastoreType(),
205 static class NoopCloseDataProducer implements DOMDataTreeProducer {
207 private final DOMDataTreeProducer delegateTreeProducer;
209 NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
210 this.delegateTreeProducer = delegateTreeProducer;
215 public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
216 return delegateTreeProducer.createTransaction(isolated);
221 public DOMDataTreeProducer createProducer(@Nonnull final Collection<DOMDataTreeIdentifier> subtrees) {
222 return delegateTreeProducer.createProducer(subtrees);
226 public void close() throws DOMDataTreeProducerException {
230 public void closeDelegate() {
232 delegateTreeProducer.close();
233 } catch (final DOMDataTreeProducerException e) {
234 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);