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 java.util.Objects.requireNonNull;
13 import com.google.common.collect.ClassToInstanceMap;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.FutureCallback;
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 org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeServiceExtension;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
37 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
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 DOMTransactionChainListener txChainListener;
46 private final CachedDataTreeService cachedDataTreeService;
47 private TransactionChainWriteTransaction writeTx;
48 private TransactionChainReadTransaction readTx;
49 private FluentFuture<? extends CommitInfo> writeTxCommitFuture;
50 private boolean finished = false;
52 public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
53 final DOMDataTreeService dataTreeService, final DOMTransactionChainListener txChainListener) {
54 this.dataTreeService = requireNonNull(dataTreeService);
55 this.txChainIdentifier = requireNonNull(txChainIdentifier);
56 this.txChainListener = txChainListener;
57 this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
61 public DOMDataTreeReadTransaction newReadOnlyTransaction() {
65 readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
66 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
67 writeTxCommitFuture, this);
73 public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
77 writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
78 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
79 cachedDataTreeService), this);
85 public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
89 ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
90 newTransactionIdentifier(), cachedDataTreeService);
91 TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
92 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxCommitFuture, this);
94 writeTx = readWriteTx;
101 // already closed, do nothing
106 checkWriteTxClosed();
107 writeTxCommitFuture.addCallback(new FutureCallback<CommitInfo>() {
109 public void onSuccess(final CommitInfo result) {
110 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
114 public void onFailure(final Throwable throwable) {
115 // We don't have to do nothing here,
116 // tx should take car of it
118 }, MoreExecutors.directExecutor());
120 cachedDataTreeService.closeProducers();
124 public void closeReadTransaction() {
128 public void closeWriteTransaction(final FluentFuture<? extends CommitInfo> commitFuture) {
129 writeTxCommitFuture = commitFuture;
133 private Object newTransactionIdentifier() {
134 return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
137 private void checkWriteTxClosed() {
138 checkState(writeTx == null);
141 private void checkReadTxClosed() {
142 checkState(readTx == null);
145 private void checkRunning() {
146 checkState(!finished);
149 public void transactionFailed(final DOMDataTreeTransaction tx, final Throwable cause) {
150 txChainListener.onTransactionChainFailed(this, tx, cause);
151 if (writeTx != null) {
154 if (readTx != null) {
157 cachedDataTreeService.closeProducers();
161 private static class CachedDataTreeService implements DOMDataTreeService {
163 private final DOMDataTreeService delegateTreeService;
164 private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
165 new EnumMap<>(LogicalDatastoreType.class);
167 CachedDataTreeService(final DOMDataTreeService delegateTreeService) {
168 this.delegateTreeService = delegateTreeService;
171 void closeProducers() {
172 producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
176 public <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener,
177 final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges,
178 final Collection<DOMDataTreeProducer> producers) throws DOMDataTreeLoopException {
179 return delegateTreeService.registerListener(listener, subtrees, allowRxMerges, producers);
183 public ClassToInstanceMap<DOMDataTreeServiceExtension> getExtensions() {
184 return delegateTreeService.getExtensions();
188 public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
189 checkState(subtrees.size() == 1);
190 DOMDataTreeIdentifier treeId = subtrees.iterator().next();
191 NoopCloseDataProducer producer = new NoopCloseDataProducer(delegateTreeService.createProducer(
192 Collections.singleton(treeId)));
193 producersMap.putIfAbsent(treeId.getDatastoreType(), producer);
198 private static final class NoopCloseDataProducer implements DOMDataTreeProducer {
199 private final DOMDataTreeProducer delegateTreeProducer;
201 NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
202 this.delegateTreeProducer = delegateTreeProducer;
206 public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
207 return delegateTreeProducer.createTransaction(isolated);
211 public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
212 return delegateTreeProducer.createProducer(subtrees);
216 public void close() {
220 public void closeDelegate() {
222 delegateTreeProducer.close();
223 } catch (final DOMDataTreeProducerException e) {
224 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);