From 8d160966fa8752235d01bb8dc57c11391b86f187 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 19 May 2014 11:56:10 +0200 Subject: [PATCH] BUG-509: Move DataTree concepts into separate package Create a new package for the data tree and related concepts to clean out interactions. Also create and document the API and hide implementation classes from the user itself. Change-Id: I69f2a9b7bcac863b531f46f669bfd2fcfcd5b743 Signed-off-by: Robert Varga --- .../impl/DataPreconditionFailedException.java | 50 ------- .../md/sal/dom/store/impl/DataTree.java | 120 ----------------- .../dom/store/impl/InMemoryDOMDataStore.java | 123 +++++++---------- .../store/impl/OperationWithModification.java | 5 +- .../impl/ResolveDataChangeEventsTask.java | 78 +++-------- .../store/impl/SchemaAwareApplyOperation.java | 11 +- .../tree/DataPreconditionFailedException.java | 31 +++++ .../md/sal/dom/store/impl/tree/DataTree.java | 51 +++++++ .../store/impl/tree/DataTreeCandidate.java | 28 ++++ .../dom/store/impl/tree/DataTreeFactory.java | 20 +++ .../store/impl/tree/DataTreeModification.java | 23 ++++ .../dom/store/impl/tree/DataTreeSnapshot.java | 37 +++++ .../ModificationApplyOperation.java | 7 +- .../dom/store/impl/{ => tree}/StoreUtils.java | 2 +- .../tree/data/AbstractDataTreeCandidate.java | 33 +++++ .../impl/tree/data/InMemoryDataTree.java | 127 ++++++++++++++++++ .../tree/data/InMemoryDataTreeCandidate.java | 32 +++++ .../tree/data/InMemoryDataTreeFactory.java | 35 +++++ .../data/InMemoryDataTreeModification.java} | 65 +++++---- .../tree/data/InMemoryDataTreeSnapshot.java | 45 +++++++ .../tree/{ => data}/ModificationType.java | 2 +- .../tree/{ => data}/NodeModification.java | 3 +- .../impl/tree/data/NoopDataTreeCandidate.java | 31 +++++ .../tree/{ => data}/StoreMetadataNode.java | 3 +- .../{ => data}/StoreNodeCompositeBuilder.java | 2 +- .../data}/ModificationMetadataTreeTest.java | 43 +++--- 26 files changed, 643 insertions(+), 364 deletions(-) delete mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataPreconditionFailedException.java delete mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTree.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataPreconditionFailedException.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTree.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidate.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeFactory.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeModification.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeSnapshot.java rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/{ => tree}/ModificationApplyOperation.java (92%) rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/{ => tree}/StoreUtils.java (98%) create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/{DataTreeModification.java => tree/data/InMemoryDataTreeModification.java} (75%) create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/{ => data}/ModificationType.java (91%) rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/{ => data}/NodeModification.java (97%) create mode 100644 opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/{ => data}/StoreMetadataNode.java (97%) rename opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/{ => data}/StoreNodeCompositeBuilder.java (97%) rename opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/{ => tree/data}/ModificationMetadataTreeTest.java (86%) diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataPreconditionFailedException.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataPreconditionFailedException.java deleted file mode 100644 index 6baf7647bd..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataPreconditionFailedException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.sal.dom.store.impl; - -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; - -public class DataPreconditionFailedException extends Exception { - - /** - * - */ - private static final long serialVersionUID = 596430355175413427L; - private final InstanceIdentifier path; - - public DataPreconditionFailedException(final InstanceIdentifier path) { - this.path = path; - } - - public DataPreconditionFailedException(final InstanceIdentifier path,final String message) { - super(message); - this.path = path; - } - - - public DataPreconditionFailedException(final InstanceIdentifier path,final Throwable cause) { - super(cause); - this.path = path; - } - - public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause) { - super(message, cause); - this.path = path; - } - - public DataPreconditionFailedException(final InstanceIdentifier path,final String message, final Throwable cause, final boolean enableSuppression, - final boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - this.path = path; - } - - public InstanceIdentifier getPath() { - return path; - } - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTree.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTree.java deleted file mode 100644 index 3124199006..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTree.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.sal.dom.store.impl; - -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - -/** - * Read-only snapshot of the data tree. - */ -final class DataTree { - public static final class Snapshot { - private final SchemaContext schemaContext; - private final StoreMetadataNode rootNode; - - @VisibleForTesting - Snapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode) { - this.schemaContext = Preconditions.checkNotNull(schemaContext); - this.rootNode = Preconditions.checkNotNull(rootNode); - } - - public SchemaContext getSchemaContext() { - return schemaContext; - } - - public Optional> readNode(final InstanceIdentifier path) { - return NormalizedNodeUtils.findNode(rootNode.getData(), path); - } - - // FIXME: this is a leak of information - @Deprecated - StoreMetadataNode getRootNode() { - return rootNode; - } - - @Override - public String toString() { - return rootNode.getSubtreeVersion().toString(); - } - } - - private static final Logger LOG = LoggerFactory.getLogger(DataTree.class); - private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true); - private StoreMetadataNode rootNode; - private SchemaContext currentSchemaContext; - - private DataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) { - this.rootNode = Preconditions.checkNotNull(rootNode); - this.currentSchemaContext = schemaContext; - } - - public synchronized void setSchemaContext(final SchemaContext newSchemaContext) { - Preconditions.checkNotNull(newSchemaContext); - - LOG.info("Attepting to install schema context {}", newSchemaContext); - - /* - * FIXME: we should walk the schema contexts, both current and new and see - * whether they are compatible here. Reject incompatible changes. - */ - - // Ready to change the context now, make sure no operations are running - rwLock.writeLock().lock(); - try { - this.currentSchemaContext = newSchemaContext; - } finally { - rwLock.writeLock().unlock(); - } - } - - public static DataTree create(final SchemaContext schemaContext) { - final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME); - final NormalizedNode data = Builders.containerBuilder().withNodeIdentifier(root).build(); - - return new DataTree(StoreMetadataNode.createEmpty(data), schemaContext); - } - - public Snapshot takeSnapshot() { - rwLock.readLock().lock(); - - try { - return new Snapshot(currentSchemaContext, rootNode); - } finally { - rwLock.readLock().unlock(); - } - } - - public void commitSnapshot(Snapshot currentSnapshot, StoreMetadataNode newDataTree) { - // Ready to change the context now, make sure no operations are running - rwLock.writeLock().lock(); - try { - Preconditions.checkState(currentSnapshot.rootNode == rootNode, - String.format("Store snapshot %s and transaction snapshot %s differ.", - rootNode, currentSnapshot.rootNode)); - - this.rootNode = newDataTree; - } finally { - rwLock.writeLock().unlock(); - } - } -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 427e7a00db..7d647af539 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.increase; import java.util.Collections; import java.util.concurrent.Callable; @@ -17,10 +16,16 @@ import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationApplyOperation; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.InMemoryDataTreeFactory; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode; import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; @@ -56,7 +61,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private final String name; private final AtomicLong txCounter = new AtomicLong(0); private final ListenerTree listenerTree = ListenerTree.create(); - private final DataTree dataTree = DataTree.create(null); + private final DataTree dataTree = InMemoryDataTreeFactory.getInstance().create(); private ModificationApplyOperation operationTree = new AlwaysFailOperation(); public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) { @@ -145,28 +150,6 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch return name + "-" + txCounter.getAndIncrement(); } - private void commit(final DataTree.Snapshot currentSnapshot, final StoreMetadataNode newDataTree, - final ResolveDataChangeEventsTask listenerResolver) { - LOG.debug("Updating Store snaphot version: {} with version:{}", currentSnapshot, newDataTree.getSubtreeVersion()); - - if (LOG.isTraceEnabled()) { - LOG.trace("Data Tree is {}", StoreUtils.toStringTree(newDataTree.getData())); - } - - /* - * The commit has to occur atomically with regard to listener - * registrations. - */ - synchronized (this) { - dataTree.commitSnapshot(currentSnapshot, newDataTree); - - for (ChangeListenerNotifyTask task : listenerResolver.call()) { - LOG.trace("Scheduling invocation of listeners: {}", task); - executor.submit(task); - } - } - } - private static abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction { private final Object identifier; @@ -198,9 +181,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private static final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements DOMStoreReadTransaction { - private DataTree.Snapshot stableSnapshot; + private DataTreeSnapshot stableSnapshot; - public SnapshotBackedReadTransaction(final Object identifier, final DataTree.Snapshot snapshot) { + public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) { super(identifier); this.stableSnapshot = Preconditions.checkNotNull(snapshot); LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot); @@ -226,10 +209,10 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private InMemoryDOMDataStore store; private boolean ready = false; - public SnapshotBackedWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot, + public SnapshotBackedWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) { super(identifier); - mutableTree = DataTreeModification.from(snapshot, applyOper); + mutableTree = snapshot.newModification(applyOper); this.store = store; LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot); } @@ -308,7 +291,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private static class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements DOMStoreReadWriteTransaction { - protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTree.Snapshot snapshot, + protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) { super(identifier, snapshot, store, applyOper); } @@ -317,7 +300,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public ListenableFuture>> read(final InstanceIdentifier path) { LOG.trace("Tx: {} Read: {}", getIdentifier(), path); try { - return Futures.immediateFuture(getMutatedView().read(path)); + return Futures.immediateFuture(getMutatedView().readNode(path)); } catch (Exception e) { LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); throw e; @@ -328,62 +311,47 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { private final SnapshotBackedWriteTransaction transaction; - private final NodeModification modification; + private final DataTreeModification modification; - private DataTree.Snapshot storeSnapshot; - private Optional proposedSubtree; private ResolveDataChangeEventsTask listenerResolver; + private DataTreeCandidate candidate; public ThreePhaseCommitImpl(final SnapshotBackedWriteTransaction writeTransaction) { this.transaction = writeTransaction; - this.modification = transaction.getMutatedView().getRootModification(); + this.modification = transaction.getMutatedView(); } @Override public ListenableFuture canCommit() { - final DataTree.Snapshot snapshotCapture = dataTree.takeSnapshot(); - final ModificationApplyOperation snapshotOperation = operationTree; - return executor.submit(new Callable() { - @Override - public Boolean call() throws Exception { - Boolean applicable = false; + public Boolean call() { try { - snapshotOperation.checkApplicable(PUBLIC_ROOT_PATH, modification, - Optional.of(snapshotCapture.getRootNode())); - applicable = true; + dataTree.validate(modification); + LOG.debug("Store Transaction: {} can be committed", transaction.getIdentifier()); + return true; } catch (DataPreconditionFailedException e) { LOG.warn("Store Tx: {} Data Precondition failed for {}.",transaction.getIdentifier(),e.getPath(),e); - applicable = false; + return false; } - LOG.debug("Store Transaction: {} : canCommit : {}", transaction.getIdentifier(), applicable); - return applicable; } }); } @Override public ListenableFuture preCommit() { - storeSnapshot = dataTree.takeSnapshot(); - if (modification.getModificationType() == ModificationType.UNMODIFIED) { - return Futures.immediateFuture(null); - } return executor.submit(new Callable() { - @Override - public Void call() throws Exception { - StoreMetadataNode metadataTree = storeSnapshot.getRootNode(); + public Void call() { + candidate = dataTree.prepare(modification); - proposedSubtree = operationTree.apply(modification, Optional.of(metadataTree), - increase(metadataTree.getSubtreeVersion())); + listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree); - listenerResolver = ResolveDataChangeEventsTask.create() // - .setRootPath(PUBLIC_ROOT_PATH) // - .setBeforeRoot(Optional.of(metadataTree)) // - .setAfterRoot(proposedSubtree) // - .setModificationRoot(modification) // - .setListenerRoot(listenerTree); +// .setRootPath(PUBLIC_ROOT_PATH) // +// .setBeforeRoot(Optional.of(metadataTree)) // +// .setAfterRoot(proposedSubtree) // +// .setModificationRoot(modification.getRootModification()) // +// .setListenerRoot(listenerTree); return null; } @@ -392,24 +360,33 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public ListenableFuture abort() { - storeSnapshot = null; - proposedSubtree = null; + if (candidate != null) { + candidate.close(); + candidate = null; + } + return Futures. immediateFuture(null); } @Override public ListenableFuture commit() { - if (modification.getModificationType() == ModificationType.UNMODIFIED) { - return Futures.immediateFuture(null); + checkState(candidate != null, "Proposed subtree must be computed"); + + /* + * The commit has to occur atomically with regard to listener + * registrations. + */ + synchronized (this) { + dataTree.commit(candidate); + + for (ChangeListenerNotifyTask task : listenerResolver.call()) { + LOG.trace("Scheduling invocation of listeners: {}", task); + executor.submit(task); + } } - checkState(proposedSubtree != null, "Proposed subtree must be computed"); - checkState(storeSnapshot != null, "Proposed subtree must be computed"); - // return ImmediateFuture<>; - InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(), listenerResolver); return Futures. immediateFuture(null); } - } private static final class AlwaysFailOperation implements ModificationApplyOperation { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/OperationWithModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/OperationWithModification.java index 780291e70f..153df768ae 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/OperationWithModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/OperationWithModification.java @@ -7,8 +7,9 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationApplyOperation; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java index 44d50166af..db9bb0fef2 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder; -import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.append; +import static org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils.append; import java.util.Collection; import java.util.Collections; @@ -22,11 +22,12 @@ import java.util.concurrent.Callable; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder; import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; @@ -38,6 +39,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -62,61 +64,18 @@ import com.google.common.collect.Multimap; * * */ -public class ResolveDataChangeEventsTask implements Callable> { +final class ResolveDataChangeEventsTask implements Callable> { private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class); private static final DOMImmutableDataChangeEvent NO_CHANGE = builder(DataChangeScope.BASE).build(); - private InstanceIdentifier rootPath; - private ListenerTree listenerRoot; - private NodeModification modificationRoot; - private Optional beforeRoot; - private Optional afterRoot; private final Multimap events = HashMultimap.create(); + private final DataTreeCandidate candidate; + private final ListenerTree listenerRoot; - protected InstanceIdentifier getRootPath() { - return rootPath; - } - - protected ResolveDataChangeEventsTask setRootPath(final InstanceIdentifier rootPath) { - this.rootPath = rootPath; - return this; - } - - protected ListenerTree getListenerRoot() { - return listenerRoot; - } - - protected ResolveDataChangeEventsTask setListenerRoot(final ListenerTree listenerRoot) { - this.listenerRoot = listenerRoot; - return this; - } - - protected NodeModification getModificationRoot() { - return modificationRoot; - } - - protected ResolveDataChangeEventsTask setModificationRoot(final NodeModification modificationRoot) { - this.modificationRoot = modificationRoot; - return this; - } - - protected Optional getBeforeRoot() { - return beforeRoot; - } - - protected ResolveDataChangeEventsTask setBeforeRoot(final Optional beforeRoot) { - this.beforeRoot = beforeRoot; - return this; - } - - protected Optional getAfterRoot() { - return afterRoot; - } - - protected ResolveDataChangeEventsTask setAfterRoot(final Optional afterRoot) { - this.afterRoot = afterRoot; - return this; - } + public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) { + this.candidate = Preconditions.checkNotNull(candidate); + this.listenerRoot = Preconditions.checkNotNull(listenerTree); + } /** * Resolves and creates Notification Tasks @@ -129,11 +88,10 @@ public class ResolveDataChangeEventsTask implements Callable call() { - LOG.trace("Resolving events for {}", modificationRoot); - try (final Walker w = listenerRoot.getWalker()) { - resolveAnyChangeEvent(rootPath, Collections.singleton(w.getRootNode()), modificationRoot, beforeRoot, - afterRoot); + resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), + candidate.getModificationRoot(), Optional.fromNullable(candidate.getBeforeRoot()), + Optional.fromNullable(candidate.getAfterRoot())); return createNotificationTasks(); } } @@ -556,7 +514,7 @@ public class ResolveDataChangeEventsTask implements Callable data); + void write(InstanceIdentifier path, NormalizedNode data); + void seal(); +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeSnapshot.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeSnapshot.java new file mode 100644 index 0000000000..4f3512807f --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeSnapshot.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +import com.google.common.base.Optional; + +/** + * Read-only snapshot of a {@link DataTree}. The snapshot is stable and isolated, + * e.g. data tree changes occurring after the snapshot has been taken are not + * visible through the snapshot. + */ +public interface DataTreeSnapshot { + /** + * Read a particular node from the snapshot. + * + * @param path Path of the node + * @return Optional result encapsulating the presence and value of the node + */ + Optional> readNode(InstanceIdentifier path); + + /** + * Create a new data tree modification based on this snapshot, using the + * specified data application strategy. + * + * @param strategy data modification strategy + * @return A new data tree modification + */ + DataTreeModification newModification(ModificationApplyOperation applyOper); +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationApplyOperation.java similarity index 92% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationApplyOperation.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationApplyOperation.java index 361be6800c..50d404981b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationApplyOperation.java @@ -5,11 +5,10 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl; +package org.opendaylight.controller.md.sal.dom.store.impl.tree; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreUtils.java similarity index 98% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreUtils.java index e1da9a7381..7e783f927d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/StoreUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreUtils.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl; +package org.opendaylight.controller.md.sal.dom.store.impl.tree; import java.util.Set; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java new file mode 100644 index 0000000000..b2faf79565 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +import com.google.common.base.Preconditions; + +abstract class AbstractDataTreeCandidate implements DataTreeCandidate { + private final InstanceIdentifier rootPath; + private final NodeModification modificationRoot; + + protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath, NodeModification modificationRoot) { + this.rootPath = Preconditions.checkNotNull(rootPath); + this.modificationRoot = Preconditions.checkNotNull(modificationRoot); + } + + @Override + public final InstanceIdentifier getRootPath() { + return rootPath; + } + + @Override + public final NodeModification getModificationRoot() { + return modificationRoot; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java new file mode 100644 index 0000000000..1f2a775cdc --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +/** + * Read-only snapshot of the data tree. + */ +final class InMemoryDataTree implements DataTree { + private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTree.class); + private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build(); + + private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true); + private StoreMetadataNode rootNode; + private SchemaContext currentSchemaContext; + + public InMemoryDataTree(StoreMetadataNode rootNode, final SchemaContext schemaContext) { + this.rootNode = Preconditions.checkNotNull(rootNode); + this.currentSchemaContext = schemaContext; + } + + @Override + public synchronized void setSchemaContext(final SchemaContext newSchemaContext) { + Preconditions.checkNotNull(newSchemaContext); + + LOG.info("Attepting to install schema context {}", newSchemaContext); + + /* + * FIXME: we should walk the schema contexts, both current and new and see + * whether they are compatible here. Reject incompatible changes. + */ + + // Ready to change the context now, make sure no operations are running + rwLock.writeLock().lock(); + try { + this.currentSchemaContext = newSchemaContext; + } finally { + rwLock.writeLock().unlock(); + } + } + + @Override + public InMemoryDataTreeSnapshot takeSnapshot() { + rwLock.readLock().lock(); + try { + return new InMemoryDataTreeSnapshot(currentSchemaContext, rootNode); + } finally { + rwLock.readLock().unlock(); + } + } + + @Override + public void validate(DataTreeModification modification) throws DataPreconditionFailedException { + Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass()); + + final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification; + m.getStrategy().checkApplicable(PUBLIC_ROOT_PATH, m.getRootModification(), Optional.of(rootNode)); + } + + @Override + public synchronized DataTreeCandidate prepare(DataTreeModification modification) { + Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass()); + + final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification; + final NodeModification root = m.getRootModification(); + + if (root.getModificationType() == ModificationType.UNMODIFIED) { + return new NoopDataTreeCandidate(PUBLIC_ROOT_PATH, root); + } + + rwLock.writeLock().lock(); + try { + // FIXME: rootNode needs to be a read-write snapshot here... + final Optional newRoot = m.getStrategy().apply(m.getRootModification(), Optional.of(rootNode), StoreUtils.increase(rootNode.getSubtreeVersion())); + Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node"); + return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, rootNode, newRoot.get()); + } finally { + rwLock.writeLock().unlock(); + } + } + + @Override + public synchronized void commit(DataTreeCandidate candidate) { + if (candidate instanceof NoopDataTreeCandidate) { + return; + } + + Preconditions.checkArgument(candidate instanceof InMemoryDataTreeCandidate, "Invalid candidate class %s", candidate.getClass()); + final InMemoryDataTreeCandidate c = (InMemoryDataTreeCandidate)candidate; + + LOG.debug("Updating Store snapshot version: {} with version:{}", rootNode.getSubtreeVersion(), c.getAfterRoot().getSubtreeVersion()); + + if (LOG.isTraceEnabled()) { + LOG.trace("Data Tree is {}", StoreUtils.toStringTree(c.getAfterRoot().getData())); + } + + // Ready to change the context now, make sure no operations are running + rwLock.writeLock().lock(); + try { + Preconditions.checkState(c.getBeforeRoot() == rootNode, + String.format("Store snapshot %s and transaction snapshot %s differ.", rootNode, c.getBeforeRoot())); + this.rootNode = c.getAfterRoot(); + } finally { + rwLock.writeLock().unlock(); + } + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java new file mode 100644 index 0000000000..93719b7f53 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeCandidate.java @@ -0,0 +1,32 @@ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +import com.google.common.base.Preconditions; + +final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate { + private final StoreMetadataNode newRoot; + private final StoreMetadataNode oldRoot; + + InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot, + final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) { + super(rootPath, modificationRoot); + this.newRoot = Preconditions.checkNotNull(newRoot); + this.oldRoot = Preconditions.checkNotNull(oldRoot); + } + + @Override + public void close() { + // FIXME: abort operation here :) + } + + @Override + public StoreMetadataNode getBeforeRoot() { + return oldRoot; + } + + @Override + public StoreMetadataNode getAfterRoot() { + return newRoot; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java new file mode 100644 index 0000000000..7614611ab2 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeFactory.java @@ -0,0 +1,35 @@ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeFactory; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * A factory for creating in-memory data trees. + */ +public final class InMemoryDataTreeFactory implements DataTreeFactory { + private static final InMemoryDataTreeFactory INSTANCE = new InMemoryDataTreeFactory(); + + private InMemoryDataTreeFactory() { + // Never instantiated externally + } + + @Override + public InMemoryDataTree create() { + final NodeIdentifier root = new NodeIdentifier(SchemaContext.NAME); + final NormalizedNode data = Builders.containerBuilder().withNodeIdentifier(root).build(); + + return new InMemoryDataTree(StoreMetadataNode.createEmpty(data), null); + } + + /** + * Get an instance of this factory. This method cannot fail. + * + * @return Data tree factory instance. + */ + public static final InMemoryDataTreeFactory getInstance() { + return INSTANCE; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTreeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java similarity index 75% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTreeModification.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java index 15dcc964cb..bedf76172a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DataTreeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java @@ -5,15 +5,17 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl; +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; import static com.google.common.base.Preconditions.checkState; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.OperationWithModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationApplyOperation; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils; import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; @@ -26,38 +28,43 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -/** - * Class encapsulation of set of modifications to a base tree. This tree is backed - * by a read-only snapshot and tracks modifications on top of that. The modification - * has the ability to rebase itself on a new snapshot. - */ -class DataTreeModification { - private static final Logger LOG = LoggerFactory.getLogger(DataTreeModification.class); +final class InMemoryDataTreeModification implements DataTreeModification { + private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTreeModification.class); /* * FIXME: the thread safety of concurrent write/delete/read/seal operations * needs to be evaluated. */ - private static final AtomicIntegerFieldUpdater SEALED_UPDATER = - AtomicIntegerFieldUpdater.newUpdater(DataTreeModification.class, "sealed"); + private static final AtomicIntegerFieldUpdater SEALED_UPDATER = + AtomicIntegerFieldUpdater.newUpdater(InMemoryDataTreeModification.class, "sealed"); private volatile int sealed = 0; private final ModificationApplyOperation strategyTree; - private final DataTree.Snapshot snapshot; + private final InMemoryDataTreeSnapshot snapshot; private final NodeModification rootNode; - private DataTreeModification(final DataTree.Snapshot snapshot, final ModificationApplyOperation strategyTree) { + InMemoryDataTreeModification(final InMemoryDataTreeSnapshot snapshot, final ModificationApplyOperation resolver) { this.snapshot = Preconditions.checkNotNull(snapshot); - this.strategyTree = Preconditions.checkNotNull(strategyTree); + this.strategyTree = Preconditions.checkNotNull(resolver); this.rootNode = NodeModification.createUnmodified(snapshot.getRootNode()); } - public void write(final InstanceIdentifier path, final NormalizedNode value) { + NodeModification getRootModification() { + return rootNode; + } + + ModificationApplyOperation getStrategy() { + return strategyTree; + } + + @Override + public void write(final InstanceIdentifier path, final NormalizedNode value) { checkSealed(); resolveModificationFor(path).write(value); } - public void merge(final InstanceIdentifier path, final NormalizedNode data) { + @Override + public void merge(final InstanceIdentifier path, final NormalizedNode data) { checkSealed(); mergeImpl(resolveModificationFor(path),data); } @@ -75,12 +82,14 @@ class DataTreeModification { op.merge(data); } - public void delete(final InstanceIdentifier path) { + @Override + public void delete(final InstanceIdentifier path) { checkSealed(); resolveModificationFor(path).delete(); } - public Optional> read(final InstanceIdentifier path) { + @Override + public Optional> readNode(final InstanceIdentifier path) { Entry modification = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE); Optional result = resolveSnapshot(modification); @@ -128,11 +137,8 @@ class DataTreeModification { return OperationWithModification.from(operation, modification); } - public static DataTreeModification from(final DataTree.Snapshot snapshot, final ModificationApplyOperation resolver) { - return new DataTreeModification(snapshot, resolver); - } - - public void seal() { + @Override + public void seal() { final boolean success = SEALED_UPDATER.compareAndSet(this, 0, 1); Preconditions.checkState(success, "Attempted to seal an already-sealed Data Tree."); rootNode.seal(); @@ -142,13 +148,14 @@ class DataTreeModification { checkState(sealed == 0, "Data Tree is sealed. No further modifications allowed."); } - @Deprecated - protected NodeModification getRootModification() { - return rootNode; - } - @Override public String toString() { return "MutableDataTree [modification=" + rootNode + "]"; } + + @Override + public DataTreeModification newModification(ModificationApplyOperation applyOper) { + // FIXME: transaction chaining + throw new UnsupportedOperationException("Implement this as part of transaction chaining"); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java new file mode 100644 index 0000000000..96f1565659 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeSnapshot.java @@ -0,0 +1,45 @@ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationApplyOperation; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +final class InMemoryDataTreeSnapshot implements DataTreeSnapshot { + private final SchemaContext schemaContext; + private final StoreMetadataNode rootNode; + + InMemoryDataTreeSnapshot(final SchemaContext schemaContext, final StoreMetadataNode rootNode) { + this.schemaContext = Preconditions.checkNotNull(schemaContext); + this.rootNode = Preconditions.checkNotNull(rootNode); + } + + StoreMetadataNode getRootNode() { + return rootNode; + } + + SchemaContext getSchemaContext() { + return schemaContext; + } + + @Override + public Optional> readNode(final InstanceIdentifier path) { + return NormalizedNodeUtils.findNode(rootNode.getData(), path); + } + + @Override + public InMemoryDataTreeModification newModification(ModificationApplyOperation applyOper) { + return new InMemoryDataTreeModification(this, applyOper); + } + + @Override + public String toString() { + return rootNode.getSubtreeVersion().toString(); + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationType.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationType.java similarity index 91% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationType.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationType.java index b16e907120..9d2e965ff7 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationType.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationType.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl.tree; +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; public enum ModificationType { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java similarity index 97% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java index 4f650c1711..71897e8098 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/NodeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl.tree; +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; import static com.google.common.base.Preconditions.checkState; @@ -14,6 +14,7 @@ import java.util.Map; import javax.annotation.concurrent.GuardedBy; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java new file mode 100644 index 0000000000..1782da2835 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +final class NoopDataTreeCandidate extends AbstractDataTreeCandidate { + protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) { + super(rootPath, modificationRoot); + } + + @Override + public void close() { + // NO-OP + } + + @Override + public StoreMetadataNode getBeforeRoot() { + return null; + } + + @Override + public StoreMetadataNode getAfterRoot() { + return null; + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreMetadataNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java similarity index 97% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreMetadataNode.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java index b8ad7368b5..abccf1db16 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreMetadataNode.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl.tree; +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; import static com.google.common.base.Preconditions.checkState; @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreNodeCompositeBuilder.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java similarity index 97% rename from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreNodeCompositeBuilder.java rename to opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java index a66a1d5b1c..5f086b6614 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/StoreNodeCompositeBuilder.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.md.sal.dom.store.impl.tree; +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationMetadataTreeTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java similarity index 86% rename from opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationMetadataTreeTest.java rename to opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java index efa5068fb6..bc27c55155 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/ModificationMetadataTreeTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationMetadataTreeTest.java @@ -1,4 +1,11 @@ -package org.opendaylight.controller.md.sal.dom.store.impl; +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.dom.store.impl.tree.data; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -19,7 +26,10 @@ import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.ma import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.SchemaAwareApplyOperationRoot; +import org.opendaylight.controller.md.sal.dom.store.impl.TestModel; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; @@ -137,10 +147,10 @@ public class ModificationMetadataTreeTest { @Test public void basicReadWrites() { - DataTreeModification modificationTree = DataTreeModification.from(new DataTree.Snapshot(schemaContext, + DataTreeModification modificationTree = new InMemoryDataTreeModification(new InMemoryDataTreeSnapshot(schemaContext, StoreMetadataNode.createRecursively(createDocumentOne(), UnsignedLong.valueOf(5))), new SchemaAwareApplyOperationRoot(schemaContext)); - Optional> originalBarNode = modificationTree.read(OUTER_LIST_2_PATH); + Optional> originalBarNode = modificationTree.readNode(OUTER_LIST_2_PATH); assertTrue(originalBarNode.isPresent()); assertSame(BAR_NODE, originalBarNode.get()); @@ -149,13 +159,13 @@ public class ModificationMetadataTreeTest { // reads node to /outer-list/1/inner_list/two/value // and checks if node is already present - Optional> barTwoCModified = modificationTree.read(TWO_TWO_VALUE_PATH); + Optional> barTwoCModified = modificationTree.readNode(TWO_TWO_VALUE_PATH); assertTrue(barTwoCModified.isPresent()); assertEquals(ImmutableNodes.leafNode(VALUE_QNAME, "test"), barTwoCModified.get()); // delete node to /outer-list/1/inner_list/two/value modificationTree.delete(TWO_TWO_VALUE_PATH); - Optional> barTwoCAfterDelete = modificationTree.read(TWO_TWO_VALUE_PATH); + Optional> barTwoCAfterDelete = modificationTree.readNode(TWO_TWO_VALUE_PATH); assertFalse(barTwoCAfterDelete.isPresent()); } @@ -164,7 +174,8 @@ public class ModificationMetadataTreeTest { /** * Creates empty Snapshot with associated schema context. */ - DataTree t = DataTree.create(schemaContext); + DataTree t = InMemoryDataTreeFactory.getInstance().create(); + t.setSchemaContext(schemaContext); /** * @@ -172,9 +183,7 @@ public class ModificationMetadataTreeTest { * context. * */ - DataTreeModification modificationTree = DataTreeModification.from(t.takeSnapshot(), new SchemaAwareApplyOperationRoot( - schemaContext)); - return modificationTree; + return t.takeSnapshot().newModification(new SchemaAwareApplyOperationRoot(schemaContext)); } @Test @@ -195,14 +204,14 @@ public class ModificationMetadataTreeTest { /** * Reads list node from /test/outer-list */ - Optional> potentialOuterList = modificationTree.read(OUTER_LIST_PATH); + Optional> potentialOuterList = modificationTree.readNode(OUTER_LIST_PATH); assertTrue(potentialOuterList.isPresent()); /** * Reads container node from /test and verifies that it contains test * node */ - Optional> potentialTest = modificationTree.read(TEST_PATH); + Optional> potentialTest = modificationTree.readNode(TEST_PATH); ContainerNode containerTest = assertPresentAndType(potentialTest, ContainerNode.class); /** @@ -219,8 +228,8 @@ public class ModificationMetadataTreeTest { public void writeSubtreeReadChildren() { DataTreeModification modificationTree = createEmptyModificationTree(); modificationTree.write(TEST_PATH, createTestContainer()); - Optional> potential = modificationTree.read(TWO_TWO_PATH); - MapEntryNode node = assertPresentAndType(potential, MapEntryNode.class); + Optional> potential = modificationTree.readNode(TWO_TWO_PATH); + assertPresentAndType(potential, MapEntryNode.class); } @Test @@ -229,11 +238,11 @@ public class ModificationMetadataTreeTest { modificationTree.write(TEST_PATH, createTestContainer()); // We verify data are present - Optional> potentialBeforeDelete = modificationTree.read(TWO_TWO_PATH); - MapEntryNode node = assertPresentAndType(potentialBeforeDelete, MapEntryNode.class); + Optional> potentialBeforeDelete = modificationTree.readNode(TWO_TWO_PATH); + assertPresentAndType(potentialBeforeDelete, MapEntryNode.class); modificationTree.delete(TWO_TWO_PATH); - Optional> potentialAfterDelete = modificationTree.read(TWO_TWO_PATH); + Optional> potentialAfterDelete = modificationTree.readNode(TWO_TWO_PATH); assertFalse(potentialAfterDelete.isPresent()); } -- 2.36.6