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.store.inmemory;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.ListeningExecutorService;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.Map.Entry;
19 import java.util.concurrent.atomic.AtomicLong;
20 import org.opendaylight.mdsal.common.api.ReadFailedException;
21 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
22 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor;
23 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
24 import org.opendaylight.yangtools.concepts.Identifiable;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
29 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 class InmemoryDOMDataTreeShardWriteTransaction implements DOMDataTreeShardWriteTransaction, Identifiable<String> {
35 private static final Logger LOG = LoggerFactory.getLogger(InmemoryDOMDataTreeShardWriteTransaction.class);
37 private enum SimpleCursorOperation {
40 void applyOnLeaf(final DOMDataTreeWriteCursor cursor, final PathArgument child,
41 final NormalizedNode<?, ?> data) {
42 cursor.merge(child, data);
47 void applyOnLeaf(final DOMDataTreeWriteCursor cursor, final PathArgument child,
48 final NormalizedNode<?, ?> data) {
54 void applyOnLeaf(final DOMDataTreeWriteCursor cursor, final PathArgument child,
55 final NormalizedNode<?, ?> data) {
56 cursor.write(child, data);
60 abstract void applyOnLeaf(DOMDataTreeWriteCursor cursor, PathArgument child, NormalizedNode<?, ?> data);
62 void apply(final DOMDataTreeWriteCursor cursor, final YangInstanceIdentifier path,
63 final NormalizedNode<?, ?> data) {
65 final Iterator<PathArgument> it = path.getPathArguments().iterator();
68 final PathArgument currentArg = it.next();
70 applyOnLeaf(cursor, currentArg, data);
74 // We need to enter one level deeper, we are not at leaf (modified) node
75 cursor.enter(currentArg);
80 cursor.exit(enterCount);
84 private static final AtomicLong COUNTER = new AtomicLong();
86 private final ArrayList<DOMStoreThreePhaseCommitCohort> cohorts = new ArrayList<>();
87 private final InMemoryDOMDataTreeShardChangePublisher changePublisher;
88 private final InMemoryDOMDataTreeShardProducer producer;
89 private final ShardDataModification modification;
90 private final ListeningExecutorService executor;
91 private final DataTree rootShardDataTree;
92 private final String identifier;
94 private DataTreeModification rootModification = null;
95 private DOMDataTreeWriteCursor cursor;
96 private boolean finished = false;
98 InmemoryDOMDataTreeShardWriteTransaction(final InMemoryDOMDataTreeShardProducer producer,
99 final ShardDataModification root,
100 final DataTree rootShardDataTree,
101 final InMemoryDOMDataTreeShardChangePublisher changePublisher,
102 final ListeningExecutorService executor) {
103 this.producer = producer;
104 this.modification = Preconditions.checkNotNull(root);
105 this.rootShardDataTree = Preconditions.checkNotNull(rootShardDataTree);
106 this.changePublisher = Preconditions.checkNotNull(changePublisher);
107 this.identifier = "INMEMORY-SHARD-TX-" + COUNTER.getAndIncrement();
108 LOG.debug("Shard transaction{} created", identifier);
109 this.executor = executor;
113 public String getIdentifier() {
117 private DOMDataTreeWriteCursor getCursor() {
118 if (cursor == null) {
119 cursor = new ShardDataModificationCursor(modification, this);
124 void delete(final YangInstanceIdentifier path) {
125 final YangInstanceIdentifier relativePath = toRelative(path);
126 Preconditions.checkArgument(!YangInstanceIdentifier.EMPTY.equals(relativePath),
127 "Deletion of shard root is not allowed");
128 SimpleCursorOperation.DELETE.apply(getCursor(), relativePath , null);
131 void merge(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
132 SimpleCursorOperation.MERGE.apply(getCursor(), toRelative(path), data);
135 void write(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
136 SimpleCursorOperation.DELETE.apply(getCursor(), toRelative(path), data);
139 private YangInstanceIdentifier toRelative(final YangInstanceIdentifier path) {
140 final Optional<YangInstanceIdentifier> relative =
141 path.relativeTo(modification.getPrefix().getRootIdentifier());
142 Preconditions.checkArgument(relative.isPresent());
143 return relative.get();
146 public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(final YangInstanceIdentifier path) {
147 throw new UnsupportedOperationException("Not implemented yet");
150 public CheckedFuture<Boolean, ReadFailedException> exists(final YangInstanceIdentifier path) {
151 throw new UnsupportedOperationException("Not implemented yet");
155 public void close() {
156 Preconditions.checkState(!finished, "Attempting to close an already finished transaction.");
157 modification.closeTransactions();
158 if (cursor != null) {
161 producer.transactionAborted(this);
165 void cursorClosed() {
166 Preconditions.checkNotNull(cursor);
167 modification.closeCursor();
171 public boolean isFinished() {
176 public void ready() {
177 Preconditions.checkState(!finished, "Attempting to ready an already finished transaction.");
178 Preconditions.checkState(cursor == null, "Attempting to ready a transaction that has an open cursor.");
179 Preconditions.checkNotNull(modification, "Attempting to ready an empty transaction.");
181 LOG.debug("Readying open transaction on shard {}", modification.getPrefix());
182 rootModification = modification.seal();
184 producer.transactionReady(this, rootModification);
185 cohorts.add(new InMemoryDOMDataTreeShardThreePhaseCommitCohort(
186 rootShardDataTree, rootModification, changePublisher));
187 for (final Entry<DOMDataTreeIdentifier, ForeignShardModificationContext> entry :
188 modification.getChildShards().entrySet()) {
189 cohorts.add(new ForeignShardThreePhaseCommitCohort(entry.getKey(), entry.getValue()));
195 public ListenableFuture<Void> submit() {
196 LOG.debug("Submitting open transaction on shard {}", modification.getPrefix());
198 Preconditions.checkNotNull(cohorts);
199 Preconditions.checkState(!cohorts.isEmpty(), "Transaction was not readied yet.");
201 return executor.submit(new ShardSubmitCoordinationTask(modification.getPrefix(), cohorts, this));
205 public ListenableFuture<Boolean> validate() {
206 LOG.debug("CanCommit on open transaction on shard {}", modification.getPrefix());
207 return executor.submit(new ShardCanCommitCoordinationTask(modification.getPrefix(), cohorts));
211 public ListenableFuture<Void> prepare() {
212 LOG.debug("PreCommit on open transaction on shard {}", modification.getPrefix());
213 return executor.submit(new ShardPreCommitCoordinationTask(modification.getPrefix(), cohorts));
217 public ListenableFuture<Void> commit() {
218 LOG.debug("Commit open transaction on shard {}", modification.getPrefix());
219 return executor.submit(new ShardCommitCoordinationTask(modification.getPrefix(), cohorts, this));
222 DataTreeModification getRootModification() {
223 Preconditions.checkNotNull(rootModification, "Transaction wasn't sealed yet");
224 return rootModification;
227 void transactionCommited(final InmemoryDOMDataTreeShardWriteTransaction tx) {
228 producer.onTransactionCommited(tx);
232 public DOMDataTreeWriteCursor createCursor(final DOMDataTreeIdentifier prefix) {
233 Preconditions.checkState(!finished, "Transaction is finished/closed already.");
234 Preconditions.checkState(cursor == null, "Previous cursor wasn't closed");
235 final DOMDataTreeWriteCursor ret = getCursor();
236 final YangInstanceIdentifier relativePath = toRelative(prefix.getRootIdentifier());
237 ret.enter(relativePath.getPathArguments());