Bug 499: Improved data change listener tree management
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / InMemoryDOMDataStore.java
index 39299ab1bdaefa1cea0626c60b7c7a697c46d9fd..0cd00cad7e6ec9609a03bac044f1ac613edf32c2 100644 (file)
@@ -17,9 +17,9 @@ 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.ListenerRegistrationNode;
+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.TreeNodeUtils;
 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;
@@ -97,13 +97,15 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     @Override
     public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
             final InstanceIdentifier path, final L listener, final DataChangeScope scope) {
-
-        Optional<ListenerRegistrationNode> listenerNode = TreeNodeUtils.findNode(listenerTree, path);
-        checkState(listenerNode.isPresent());
+        LOG.debug("{}: Registering data change listener {} for {}",name,listener,path);
+        ListenerRegistrationNode listenerNode = listenerTree;
+        for(PathArgument arg :path.getPath()) {
+            listenerNode = listenerNode.ensureChild(arg);
+        }
         synchronized (listener) {
             notifyInitialState(path, listener);
         }
-        return listenerNode.get().registerDataChangeListener(listener, scope);
+        return listenerNode.registerDataChangeListener(path,listener, scope);
     }
 
     private void notifyInitialState(final InstanceIdentifier path,
@@ -125,8 +127,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     }
 
     private synchronized DOMStoreThreePhaseCommitCohort submit(
-            final SnaphostBackedWriteTransaction snaphostBackedWriteTransaction) {
-        return new ThreePhaseCommitImpl(snaphostBackedWriteTransaction);
+            final SnaphostBackedWriteTransaction writeTx) {
+        LOG.debug("Tx: {} is submitted. Modifications: {}",writeTx.getIdentifier(),writeTx.getMutatedView());
+        return new ThreePhaseCommitImpl(writeTx);
     }
 
     private Object nextIdentifier() {
@@ -136,6 +139,10 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     private synchronized void commit(final DataAndMetadataSnapshot currentSnapshot,
             final StoreMetadataNode newDataTree, final Iterable<ChangeListenerNotifyTask> listenerTasks) {
         LOG.debug("Updating Store snaphot version: {} with version:{}",currentSnapshot.getMetadataTree().getSubtreeVersion(),newDataTree.getSubtreeVersion());
+
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Data Tree is {}",StoreUtils.toStringTree(newDataTree));
+        }
         checkState(snapshot == currentSnapshot, "Store snapshot and transaction snapshot differs");
         snapshot = DataAndMetadataSnapshot.builder() //
                 .setMetadataTree(newDataTree) //
@@ -156,6 +163,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         public SnapshotBackedReadTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot) {
             this.identifier = identifier;
             this.stableSnapshot = snapshot;
+            LOG.debug("ReadOnly Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion());
+
         }
 
         @Override
@@ -195,6 +204,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
             this.identifier = identifier;
             mutableTree = MutableDataTree.from(snapshot, applyOper);
             this.store = store;
+            LOG.debug("Write Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion());
         }
 
         @Override
@@ -301,6 +311,9 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         @Override
         public ListenableFuture<Void> preCommit() {
             storeSnapshot = snapshot;
+            if(modification.getModificationType() == ModificationType.UNMODIFIED) {
+                return Futures.immediateFuture(null);
+            }
             return executor.submit(new Callable<Void>() {
 
 
@@ -312,7 +325,6 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                     proposedSubtree = operationTree.apply(modification, Optional.of(metadataTree),
                             increase(metadataTree.getSubtreeVersion()));
 
-
                     listenerTasks = DataChangeEventResolver.create() //
                             .setRootPath(PUBLIC_ROOT_PATH) //
                             .setBeforeRoot(Optional.of(metadataTree)) //
@@ -335,8 +347,12 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
 
         @Override
         public ListenableFuture<Void> commit() {
-            checkState(proposedSubtree != null);
-            checkState(storeSnapshot != null);
+            if(modification.getModificationType() == ModificationType.UNMODIFIED) {
+                return Futures.immediateFuture(null);
+            }
+
+            checkState(proposedSubtree != null,"Proposed subtree must be computed");
+            checkState(storeSnapshot != null,"Proposed subtree must be computed");
             // return ImmediateFuture<>;
             InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(),listenerTasks);
             return Futures.<Void> immediateFuture(null);