2 * Copyright (c) 2014 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.controller.md.sal.dom.store.impl;
10 import static com.google.common.base.Preconditions.checkNotNull;
11 import static com.google.common.base.Preconditions.checkState;
12 import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.increase;
14 import java.util.concurrent.Callable;
15 import java.util.concurrent.atomic.AtomicLong;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
18 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
19 import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
20 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
21 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
22 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
23 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
24 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
25 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
26 import org.opendaylight.yangtools.concepts.Identifiable;
27 import org.opendaylight.yangtools.concepts.ListenerRegistration;
28 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import com.google.common.base.Optional;
38 import com.google.common.primitives.UnsignedLong;
39 import com.google.common.util.concurrent.Futures;
40 import com.google.common.util.concurrent.ListenableFuture;
41 import com.google.common.util.concurrent.ListeningExecutorService;
43 public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener {
45 private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
47 private final AtomicLong txCounter = new AtomicLong(0);
49 private DataAndMetadataSnapshot snapshot;
50 private ModificationApplyOperation operation;
52 private final ListeningExecutorService executor;
53 private final String name;
55 private SchemaContext schemaContext;
57 public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) {
58 this.executor = executor;
60 this.operation = new AllwaysFailOperation();
61 this.snapshot = DataAndMetadataSnapshot.createEmpty();
65 public String getIdentifier() {
70 public DOMStoreReadTransaction newReadOnlyTransaction() {
71 return new SnapshotBackedReadTransaction(nextIdentifier(), snapshot);
75 public DOMStoreReadWriteTransaction newReadWriteTransaction() {
76 return new SnapshotBackedReadWriteTransaction(nextIdentifier(), snapshot, this, operation);
80 public DOMStoreWriteTransaction newWriteOnlyTransaction() {
81 return new SnaphostBackedWriteTransaction(nextIdentifier(), snapshot, this, operation);
85 public synchronized void onGlobalContextUpdated(final SchemaContext ctx) {
86 operation = SchemaAwareApplyOperationRoot.from(ctx);
91 public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
92 final InstanceIdentifier path, final L listener, final DataChangeScope scope) {
96 private synchronized DOMStoreThreePhaseCommitCohort submit(
97 final SnaphostBackedWriteTransaction snaphostBackedWriteTransaction) {
98 return new ThreePhaseCommitImpl(snaphostBackedWriteTransaction);
101 private Object nextIdentifier() {
102 return name + "-" + txCounter.getAndIncrement();
105 private static class SnapshotBackedReadTransaction implements DOMStoreReadTransaction {
107 private DataAndMetadataSnapshot stableSnapshot;
108 private final Object identifier;
110 public SnapshotBackedReadTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot) {
111 this.identifier = identifier;
112 this.stableSnapshot = snapshot;
116 public Object getIdentifier() {
121 public void close() {
122 stableSnapshot = null;
126 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final InstanceIdentifier path) {
127 checkNotNull(path, "Path must not be null.");
128 checkState(stableSnapshot != null, "Transaction is closed");
129 return Futures.immediateFuture(NormalizedNodeUtils.findNode(stableSnapshot.getDataTree(), path));
133 public String toString() {
134 return "SnapshotBackedReadTransaction [id =" + identifier + "]";
139 private static class SnaphostBackedWriteTransaction implements DOMStoreWriteTransaction {
141 private MutableDataTree mutableTree;
142 private final Object identifier;
143 private InMemoryDOMDataStore store;
145 private boolean ready = false;
147 public SnaphostBackedWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot,
148 final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
149 this.identifier = identifier;
150 mutableTree = MutableDataTree.from(snapshot, applyOper);
155 public Object getIdentifier() {
160 public void close() {
161 this.mutableTree = null;
166 public void write(final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
168 mutableTree.write(path, data);
172 public void delete(final InstanceIdentifier path) {
174 mutableTree.delete(path);
177 protected boolean isReady() {
181 protected void checkNotReady() {
182 checkState(!ready, "Transaction is ready. No further modifications allowed.");
186 public synchronized DOMStoreThreePhaseCommitCohort ready() {
188 LOG.debug("Store transaction: {} : Ready",getIdentifier());
190 return store.submit(this);
193 protected MutableDataTree getMutatedView() {
198 public String toString() {
199 return "SnaphostBackedWriteTransaction [id=" + getIdentifier() + ", ready=" + isReady() + "]";
204 private static class SnapshotBackedReadWriteTransaction extends SnaphostBackedWriteTransaction implements
205 DOMStoreReadWriteTransaction {
207 protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot,
208 final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) {
209 super(identifier, snapshot, store, applyOper);
213 public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final InstanceIdentifier path) {
214 return Futures.immediateFuture(getMutatedView().read(path));
218 public String toString() {
219 return "SnapshotBackedReadWriteTransaction [id=" + getIdentifier() + ", ready=" + isReady() + "]";
224 private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort {
226 private final SnaphostBackedWriteTransaction transaction;
227 private final NodeModification modification;
229 private DataAndMetadataSnapshot storeSnapshot;
230 private Optional<StoreMetadataNode> proposedSubtree;
232 public ThreePhaseCommitImpl(final SnaphostBackedWriteTransaction writeTransaction) {
233 this.transaction = writeTransaction;
234 this.modification = transaction.getMutatedView().getRootModification();
238 public ListenableFuture<Boolean> canCommit() {
239 final DataAndMetadataSnapshot snapshotCapture = snapshot;
240 final ModificationApplyOperation snapshotOperation = operation;
242 return executor.submit(new Callable<Boolean>() {
245 public Boolean call() throws Exception {
246 boolean applicable = snapshotOperation.isApplicable(modification, Optional.of(snapshotCapture.getMetadataTree()));
247 LOG.debug("Store Transcation: {} : canCommit : {}",transaction.getIdentifier(),applicable);
254 public ListenableFuture<Void> preCommit() {
255 storeSnapshot = snapshot;
256 return executor.submit(new Callable<Void>() {
259 public Void call() throws Exception {
260 StoreMetadataNode metadataTree = storeSnapshot.getMetadataTree();
261 proposedSubtree = operation.apply(modification, Optional.of(metadataTree),increase(metadataTree.getSubtreeVersion()));
268 public ListenableFuture<Void> abort() {
269 storeSnapshot = null;
270 proposedSubtree = null;
271 return Futures.<Void> immediateFuture(null);
275 public ListenableFuture<Void> commit() {
276 checkState(proposedSubtree != null);
277 checkState(storeSnapshot != null);
278 // return ImmediateFuture<>;
279 InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree);
280 return Futures.<Void> immediateFuture(null);
285 private synchronized void commit(final DataAndMetadataSnapshot storeSnapshot,
286 final Optional<StoreMetadataNode> proposedSubtree) {
287 //LOG.info("Updating Store snaphot.");
288 checkState(snapshot == storeSnapshot, "Store snapshot and transaction snapshot differs");
289 snapshot = DataAndMetadataSnapshot.builder().setMetadataTree(proposedSubtree.get())
290 .setSchemaContext(schemaContext).build();
293 private class AllwaysFailOperation implements ModificationApplyOperation {
296 public Optional<StoreMetadataNode> apply(final NodeModification modification,
297 final Optional<StoreMetadataNode> storeMeta,final UnsignedLong subtreeVersion) {
298 throw new IllegalStateException("Schema Context is not available.");
302 public boolean isApplicable(final NodeModification modification, final Optional<StoreMetadataNode> storeMetadata) {
303 throw new IllegalStateException("Schema Context is not available.");
307 public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
308 throw new IllegalStateException("Schema Context is not available.");
312 public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
313 throw new IllegalStateException("Schema Context is not available.");