Move transaction-invariants into producer 73/46373/2
authorRobert Varga <rovarga@cisco.com>
Tue, 20 Sep 2016 18:48:05 +0000 (20:48 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 3 Oct 2016 13:49:40 +0000 (13:49 +0000)
Instead of re-calculating the context, cache most of the information
required in the InMemoryDOMDataTreeShardProducer, so it can be quickly
reused when creating transactions. This information is calculated when
a producer is created or when the sharding layout changes.

Change-Id: Id2bcab420cf6d1635aba6cd97bf68f1860533780
Signed-off-by: Robert Varga <rovarga@cisco.com>
(cherry picked from commit 5a9368fc20a5a6d403a63fe405b79c55a0a647cc)

15 files changed:
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerMultiShardTest.java
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShard.java
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducer.java
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ModificationContextNodeBuilder.java
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModification.java
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationBuilder.java [deleted file]
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactory.java [new file with mode: 0644]
dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactoryBuilder.java [new file with mode: 0644]
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducerTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InmemoryDOMDataTreeShardWriteTransactionTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/ModificationContextNodeBuilderTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationCursorTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationTest.java
dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/TestUtils.java

index 46ab94cc36795f0cd4fe4e8f84fb26c30db2e6a3..cd5a7169cdcca877e4a3d7c4848b75c00498790c 100644 (file)
@@ -286,13 +286,13 @@ public class ShardedDOMDataTreeProducerMultiShardTest {
     @Test
     public void testMockedSubshards() throws Exception {
         final WriteableDOMDataTreeShard mockedInnerShard = Mockito.mock(WriteableDOMDataTreeShard.class);
+        final DOMDataTreeShardProducer mockedProducer = Mockito.mock(DOMDataTreeShardProducer.class);
+        doReturn(mockedProducer).when(mockedInnerShard).createProducer(anyCollection());
         final ShardedDOMDataTreeProducer shardRegProducer = Mockito.mock(ShardedDOMDataTreeProducer.class);
         doReturn(Collections.singleton(INNER_CONTAINER_ID)).when(shardRegProducer).getSubtrees();
         doNothing().when(shardRegProducer).subshardAdded(anyMap());
 
         dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, mockedInnerShard, shardRegProducer);
-        final DOMDataTreeShardProducer mockedProducer = Mockito.mock(DOMDataTreeShardProducer.class);
-        doReturn(mockedProducer).when(mockedInnerShard).createProducer(any(Collection.class));
 
         final DOMDataTreeShardProducer producer = rootShard.createProducer(Collections.singletonList(TEST_ID));
 
@@ -351,7 +351,7 @@ public class ShardedDOMDataTreeProducerMultiShardTest {
 
     }
 
-    private ContainerNode createCrossShardContainer() {
+    private static ContainerNode createCrossShardContainer() {
         final LeafNode<String> shardedValue1 =
                 ImmutableLeafNodeBuilder.<String>create().withNodeIdentifier(
                         new NodeIdentifier(TestModel.SHARDED_VALUE_1)).withValue("sharded value 1").build();
index 97b2354f9ad1965b42c3ab7d5f67033f361682ac..127821fc099a9bede2d13006aa958173b0e66499 100644 (file)
@@ -18,6 +18,7 @@ import com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -39,12 +40,11 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
 import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @Beta
 public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeShard, SchemaContextListener {
-
-    private static final int DEFAULT_SUBMIT_QUEUE_SIZE = 1000;
-
     private static final class SubshardProducerSpecification {
         private final Collection<DOMDataTreeIdentifier> prefixes = new ArrayList<>(1);
         private final ChildShardContext shard;
@@ -61,17 +61,21 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
             return shard.getShard().createProducer(prefixes);
         }
 
-        public DOMDataTreeIdentifier getPrefix() {
+        DOMDataTreeIdentifier getPrefix() {
             return shard.getPrefix();
         }
     }
 
+    private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataTreeShard.class);
+    private static final int DEFAULT_SUBMIT_QUEUE_SIZE = 1000;
+
     private final DOMDataTreePrefixTable<ChildShardContext> childShardsTable = DOMDataTreePrefixTable.create();
     private final Map<DOMDataTreeIdentifier, ChildShardContext> childShards = new HashMap<>();
-    private final DOMDataTreeIdentifier prefix;
-    private final DataTree dataTree;
+    private final Collection<InMemoryDOMDataTreeShardProducer> producers = new HashSet<>();
     private final InMemoryDOMDataTreeShardChangePublisher shardChangePublisher;
     private final ListeningExecutorService executor;
+    private final DOMDataTreeIdentifier prefix;
+    private final DataTree dataTree;
 
     private InMemoryDOMDataTreeShard(final DOMDataTreeIdentifier prefix, final Executor dataTreeChangeExecutor,
                                      final int maxDataChangeListenerQueueSize, final int submitQueueSize) {
@@ -112,13 +116,59 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
     public void onChildAttached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
         Preconditions.checkArgument(child != this, "Attempted to attach child %s onto self", this);
         reparentChildShards(prefix, child);
-        addChildShard(prefix, child);
+
+        final ChildShardContext context = createContextFor(prefix, child);
+        childShards.put(prefix, context);
+        childShardsTable.store(prefix, context);
+        updateProducers();
     }
 
     @Override
     public void onChildDetached(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
         childShards.remove(prefix);
         childShardsTable.remove(prefix);
+        updateProducers();
+    }
+
+    private void updateProducers() {
+        for (InMemoryDOMDataTreeShardProducer p : producers) {
+            p.setModificationFactory(createModificationFactory(p.getPrefixes()));
+        }
+    }
+
+    @VisibleForTesting
+    ShardDataModificationFactory createModificationFactory(final Collection<DOMDataTreeIdentifier> prefixes) {
+        final Map<DOMDataTreeIdentifier, SubshardProducerSpecification> affected = new HashMap<>();
+        for (final DOMDataTreeIdentifier producerPrefix : prefixes) {
+            for (final ChildShardContext child : childShards.values()) {
+                final DOMDataTreeIdentifier bindPath;
+                if (producerPrefix.contains(child.getPrefix())) {
+                    bindPath = child.getPrefix();
+                } else if (child.getPrefix().contains(producerPrefix)) {
+                    // Bound path is inside subshard
+                    bindPath = producerPrefix;
+                } else {
+                    continue;
+                }
+
+                SubshardProducerSpecification spec = affected.get(child.getPrefix());
+                if (spec == null) {
+                    spec = new SubshardProducerSpecification(child);
+                    affected.put(child.getPrefix(), spec);
+                }
+                spec.addPrefix(bindPath);
+            }
+        }
+
+        final ShardDataModificationFactoryBuilder builder = new ShardDataModificationFactoryBuilder(prefix);
+        for (final SubshardProducerSpecification spec : affected.values()) {
+            final ForeignShardModificationContext foreignContext =
+                    new ForeignShardModificationContext(spec.getPrefix(), spec.createProducer());
+            builder.addSubshard(foreignContext);
+            builder.addSubshard(spec.getPrefix(), foreignContext);
+        }
+
+        return builder.build();
     }
 
     @Override
@@ -127,7 +177,17 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
             Preconditions.checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shart root",
                 prodPrefix, prefix);
         }
-        return new InMemoryDOMDataTreeShardProducer(this, prefixes);
+
+        final InMemoryDOMDataTreeShardProducer ret = new InMemoryDOMDataTreeShardProducer(this, prefixes,
+            createModificationFactory(prefixes));
+        producers.add(ret);
+        return ret;
+    }
+
+    void closeProducer(final InMemoryDOMDataTreeShardProducer producer) {
+        if (!producers.remove(producer)) {
+            LOG.warn("Producer {} not found in shard {}", producer, this);
+        }
     }
 
     @Nonnull
@@ -137,12 +197,6 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
         return shardChangePublisher.registerTreeChangeListener(treeId, listener);
     }
 
-    private void addChildShard(final DOMDataTreeIdentifier prefix, final DOMDataTreeShard child) {
-        final ChildShardContext context = createContextFor(prefix, child);
-        childShards.put(prefix, context);
-        childShardsTable.store(prefix, context);
-    }
-
     private void reparentChildShards(final DOMDataTreeIdentifier newChildPrefix, final DOMDataTreeShard newChild) {
         final Iterator<Entry<DOMDataTreeIdentifier, ChildShardContext>> actualChildren =
                 childShards.entrySet().iterator();
@@ -200,51 +254,11 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
     }
 
     InmemoryDOMDataTreeShardWriteTransaction createTransaction(final String transactionId,
-                                                               final InMemoryDOMDataTreeShardProducer producer,
-                                                               final Collection<DOMDataTreeIdentifier> prefixes,
-                                                               final DataTreeSnapshot snapshot) {
-
-        return createTxForSnapshot(producer, prefixes, (CursorAwareDataTreeSnapshot) snapshot);
-    }
-
-    private InmemoryDOMDataTreeShardWriteTransaction createTxForSnapshot(
-            final InMemoryDOMDataTreeShardProducer producer,
-            final Collection<DOMDataTreeIdentifier> prefixes,
-            final CursorAwareDataTreeSnapshot snapshot) {
-
-        final Map<DOMDataTreeIdentifier, SubshardProducerSpecification> affectedSubshards = new HashMap<>();
-        for (final DOMDataTreeIdentifier producerPrefix : prefixes) {
-            for (final ChildShardContext maybeAffected : childShards.values()) {
-                final DOMDataTreeIdentifier bindPath;
-                if (producerPrefix.contains(maybeAffected.getPrefix())) {
-                    bindPath = maybeAffected.getPrefix();
-                } else if (maybeAffected.getPrefix().contains(producerPrefix)) {
-                    // Bound path is inside subshard
-                    bindPath = producerPrefix;
-                } else {
-                    continue;
-                }
-
-                SubshardProducerSpecification spec = affectedSubshards.get(maybeAffected.getPrefix());
-                if (spec == null) {
-                    spec = new SubshardProducerSpecification(maybeAffected);
-                    affectedSubshards.put(maybeAffected.getPrefix(), spec);
-                }
-                spec.addPrefix(bindPath);
-            }
-        }
+            final InMemoryDOMDataTreeShardProducer producer, final DataTreeSnapshot snapshot) {
+        Preconditions.checkArgument(snapshot instanceof CursorAwareDataTreeSnapshot);
 
-        final ShardRootModificationContext rootContext = new ShardRootModificationContext(prefix, snapshot);
-        final ShardDataModificationBuilder builder = new ShardDataModificationBuilder(rootContext);
-        for (final SubshardProducerSpecification spec : affectedSubshards.values()) {
-            final ForeignShardModificationContext foreignContext =
-                    new ForeignShardModificationContext(spec.getPrefix(), spec.createProducer());
-            builder.addSubshard(foreignContext);
-            builder.addSubshard(spec.getPrefix(), foreignContext);
-        }
-
-        return new InmemoryDOMDataTreeShardWriteTransaction(producer, builder.build(),
-                dataTree, shardChangePublisher, executor);
+        return new InmemoryDOMDataTreeShardWriteTransaction(producer,
+            producer.getModificationFactory().createModification((CursorAwareDataTreeSnapshot)snapshot), dataTree,
+            shardChangePublisher, executor);
     }
-
 }
index 348c46df337054a91fa8f5907d3c86c238f0eed0..f2b5ac042745e8bbf7a0287a8d2a067e95a94806 100644 (file)
@@ -103,10 +103,13 @@ class InMemoryDOMDataTreeShardProducer implements DOMDataTreeShardProducer {
             AtomicReferenceFieldUpdater.newUpdater(InMemoryDOMDataTreeShardProducer.class, State.class, "state");
     private volatile State state;
 
+    private ShardDataModificationFactory modificationFactory;
+
     InMemoryDOMDataTreeShardProducer(final InMemoryDOMDataTreeShard parentShard,
-            final Collection<DOMDataTreeIdentifier> prefixes) {
+        final Collection<DOMDataTreeIdentifier> prefixes, final ShardDataModificationFactory modificationFactory) {
         this.parentShard = Preconditions.checkNotNull(parentShard);
         this.prefixes = ImmutableSet.copyOf(prefixes);
+        this.modificationFactory = Preconditions.checkNotNull(modificationFactory);
         state = idleState;
     }
 
@@ -118,7 +121,7 @@ class InMemoryDOMDataTreeShardProducer implements DOMDataTreeShardProducer {
         InmemoryDOMDataTreeShardWriteTransaction ret;
         do {
             localState = state;
-            ret = parentShard.createTransaction(transactionId, this, prefixes, localState.getSnapshot(transactionId));
+            ret = parentShard.createTransaction(transactionId, this, localState.getSnapshot(transactionId));
         } while (!STATE_UPDATER.compareAndSet(this, localState, new Allocated(ret)));
 
         return ret;
@@ -197,4 +200,12 @@ class InMemoryDOMDataTreeShardProducer implements DOMDataTreeShardProducer {
     public Collection<DOMDataTreeIdentifier> getPrefixes() {
         return prefixes;
     }
+
+    ShardDataModificationFactory getModificationFactory() {
+        return modificationFactory;
+    }
+
+    void setModificationFactory(final ShardDataModificationFactory modificationFactory) {
+        this.modificationFactory = Preconditions.checkNotNull(modificationFactory);
+    }
 }
index a98205df020b56a5d1d7af78357866b7f71ac223..b35aae1903be2fff354af872bc991620e484b3f9 100644 (file)
@@ -8,16 +8,17 @@
 
 package org.opendaylight.mdsal.dom.store.inmemory;
 
+import com.google.common.base.Preconditions;
 import java.util.HashMap;
 import java.util.Map;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
-abstract class ModificationContextNodeBuilder<T extends WriteableModificationNode> {
+abstract class ModificationContextNodeBuilder {
 
     private final Map<PathArgument, InteriorNodeBuilder> interiorChildren = new HashMap<>();
     private final Map<PathArgument, WriteableSubshardBoundaryNode> boundaryChildren = new HashMap<>();
 
-    protected InteriorNodeBuilder getInterior(final PathArgument arg) {
+    protected ModificationContextNodeBuilder getInterior(final PathArgument arg) {
         InteriorNodeBuilder potential = interiorChildren.get(arg);
         if (potential == null) {
             potential = new InteriorNodeBuilder(arg);
@@ -30,30 +31,25 @@ abstract class ModificationContextNodeBuilder<T extends WriteableModificationNod
         boundaryChildren.put(arg, subshardNode);
     }
 
-    final T build() {
+    final Map<PathArgument, WriteableModificationNode> buildChildren() {
         final Map<PathArgument, WriteableModificationNode> builtChildren = new HashMap<>(boundaryChildren);
         for (InteriorNodeBuilder interiorNode : interiorChildren.values()) {
             WriteableModificationNode builded = interiorNode.build();
             builtChildren.put(builded.getIdentifier(), builded);
         }
 
-        return build(builtChildren);
+        return builtChildren;
     }
 
-    abstract T build(Map<PathArgument, WriteableModificationNode> children);
-
-    private static class InteriorNodeBuilder extends ModificationContextNodeBuilder<WritableInteriorNode> {
-
+    private static final class InteriorNodeBuilder extends ModificationContextNodeBuilder {
         private final PathArgument arg;
 
         InteriorNodeBuilder(final PathArgument arg) {
-            this.arg = arg;
+            this.arg = Preconditions.checkNotNull(arg);
         }
 
-        @Override
-        WritableInteriorNode build(final Map<PathArgument, WriteableModificationNode> children) {
-            return new WritableInteriorNode(arg, children);
+        WritableInteriorNode build() {
+            return new WritableInteriorNode(arg, buildChildren());
         }
     }
-
 }
\ No newline at end of file
index 33d596bfec2ac1638d2011be45960aafa7e19f12..514cc1133ad2d7acc1cf6b7ab56f07ee51c5616a 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.collect.ImmutableMap;
 import java.util.Map;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 
@@ -45,16 +44,6 @@ final class ShardDataModification extends WriteableNodeWithSubshard {
         return rootContext.getIdentifier().getRootIdentifier().getLastPathArgument();
     }
 
-    static ShardDataModification from(final ShardRootModificationContext root,
-            final Map<YangInstanceIdentifier, ForeignShardModificationContext> shards) {
-
-        ShardDataModificationBuilder builder = new ShardDataModificationBuilder(root);
-        for (ForeignShardModificationContext subshard : shards.values()) {
-            builder.addSubshard(subshard);
-        }
-        return builder.build();
-    }
-
     DOMDataTreeIdentifier getPrefix() {
         return rootContext.getIdentifier();
     }
diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationBuilder.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationBuilder.java
deleted file mode 100644 (file)
index 1ea21a0..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016 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.mdsal.dom.store.inmemory;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-
-class ShardDataModificationBuilder extends ModificationContextNodeBuilder<ShardDataModification> {
-
-    private final ShardRootModificationContext root;
-    private final Map<DOMDataTreeIdentifier, ForeignShardModificationContext> childShards =
-            new HashMap<>();
-
-    ShardDataModificationBuilder(final ShardRootModificationContext root) {
-        this.root = root;
-    }
-
-    public void addSubshard(final ForeignShardModificationContext value) {
-        WriteableSubshardBoundaryNode leafNode = WriteableSubshardBoundaryNode.from(value);
-        putNode(value.getIdentifier().getRootIdentifier(), leafNode);
-    }
-
-    public void addSubshard(final DOMDataTreeIdentifier prefix, final ForeignShardModificationContext value) {
-        childShards.put(prefix, value);
-    }
-
-    private void putNode(final YangInstanceIdentifier key, final WriteableSubshardBoundaryNode subshardNode) {
-        ModificationContextNodeBuilder<?> current = this;
-        Iterator<PathArgument> toBoundary = toRelative(key).getPathArguments().iterator();
-        while (toBoundary.hasNext()) {
-            PathArgument nextArg = toBoundary.next();
-            if (toBoundary.hasNext()) {
-                current = getInterior(nextArg);
-            } else {
-                current.addBoundary(nextArg, subshardNode);
-            }
-        }
-    }
-
-
-    @Override
-    ShardDataModification build(final Map<PathArgument, WriteableModificationNode> children) {
-        return new ShardDataModification(root, children, childShards);
-    }
-
-    private YangInstanceIdentifier toRelative(final YangInstanceIdentifier key) {
-        return key.relativeTo(root.getIdentifier().getRootIdentifier()).get();
-    }
-}
\ No newline at end of file
diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactory.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactory.java
new file mode 100644 (file)
index 0000000..9b18815
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 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.mdsal.dom.store.inmemory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeSnapshot;
+
+final class ShardDataModificationFactory {
+    private final Map<DOMDataTreeIdentifier, ForeignShardModificationContext> childShards;
+    private final Map<PathArgument, WriteableModificationNode> children;
+    private final DOMDataTreeIdentifier root;
+
+    ShardDataModificationFactory(final DOMDataTreeIdentifier root,
+        final Map<PathArgument, WriteableModificationNode> children,
+        final Map<DOMDataTreeIdentifier, ForeignShardModificationContext> childShards) {
+        this.root = Preconditions.checkNotNull(root);
+        this.children = ImmutableMap.copyOf(children);
+        this.childShards = ImmutableMap.copyOf(childShards);
+    }
+
+    @VisibleForTesting
+    Map<PathArgument, WriteableModificationNode> getChildren() {
+        return children;
+    }
+
+    @VisibleForTesting
+    Map<DOMDataTreeIdentifier, ForeignShardModificationContext> getChildShards() {
+        return childShards;
+    }
+
+    ShardDataModification createModification(final CursorAwareDataTreeSnapshot snapshot) {
+        return new ShardDataModification(new ShardRootModificationContext(root, snapshot), children, childShards);
+    }
+}
diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactoryBuilder.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/ShardDataModificationFactoryBuilder.java
new file mode 100644 (file)
index 0000000..5c75419
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 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.mdsal.dom.store.inmemory;
+
+import com.google.common.base.Preconditions;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+class ShardDataModificationFactoryBuilder extends ModificationContextNodeBuilder
+        implements Builder<ShardDataModificationFactory> {
+
+    private final Map<DOMDataTreeIdentifier, ForeignShardModificationContext> childShards = new HashMap<>();
+    private final DOMDataTreeIdentifier root;
+
+    ShardDataModificationFactoryBuilder(final DOMDataTreeIdentifier root) {
+        this.root = Preconditions.checkNotNull(root);
+    }
+
+    void addSubshard(final ForeignShardModificationContext value) {
+        WriteableSubshardBoundaryNode leafNode = WriteableSubshardBoundaryNode.from(value);
+        putNode(value.getIdentifier().getRootIdentifier(), leafNode);
+    }
+
+    void addSubshard(final DOMDataTreeIdentifier prefix, final ForeignShardModificationContext value) {
+        childShards.put(prefix, value);
+    }
+
+    private void putNode(final YangInstanceIdentifier key, final WriteableSubshardBoundaryNode subshardNode) {
+        final Iterator<PathArgument> toBoundary = toRelative(key).getPathArguments().iterator();
+        if (toBoundary.hasNext()) {
+            ModificationContextNodeBuilder current = this;
+            while (true) {
+                final PathArgument nextArg = toBoundary.next();
+                if (!toBoundary.hasNext()) {
+                    current.addBoundary(nextArg, subshardNode);
+                    break;
+                }
+
+                current = getInterior(nextArg);
+            }
+        }
+    }
+
+    @Override
+    public ShardDataModificationFactory build() {
+        return new ShardDataModificationFactory(root, buildChildren(), childShards);
+    }
+
+    private YangInstanceIdentifier toRelative(final YangInstanceIdentifier key) {
+        return key.relativeTo(root.getRootIdentifier()).get();
+    }
+}
\ No newline at end of file
index 0115866eb4f422033d5115ac5550c39ad9695dbd..2286082a9fa34d07e30fdc1f7e9701f038c5b5a6 100644 (file)
@@ -9,16 +9,15 @@ package org.opendaylight.mdsal.dom.store.inmemory;
 
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyCollectionOf;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.DOM_DATA_TREE_IDENTIFIER;
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.resetMocks;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import org.junit.Test;
-import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.CursorAwareDataTreeSnapshot;
 
 public class InMemoryDOMDataTreeShardProducerTest {
@@ -33,18 +32,19 @@ public class InMemoryDOMDataTreeShardProducerTest {
 
         doReturn(inmemoryDOMDataTreeShardWriteTransaction).when(inMemoryDOMDataTreeShard)
                 .createTransaction(any(String.class), any(InMemoryDOMDataTreeShardProducer.class),
-                        anyCollectionOf((DOMDataTreeIdentifier.class)), any(CursorAwareDataTreeSnapshot.class));
+                        any(CursorAwareDataTreeSnapshot.class));
 
         final InMemoryDOMDataTreeShardProducer inMemoryDOMDataTreeShardProducer =
                 new InMemoryDOMDataTreeShardProducer(inMemoryDOMDataTreeShard,
-                        ImmutableSet.of(DOM_DATA_TREE_IDENTIFIER));
+                        ImmutableSet.of(DOM_DATA_TREE_IDENTIFIER),
+                        new ShardDataModificationFactory(DOM_DATA_TREE_IDENTIFIER, ImmutableMap.of(),
+                            ImmutableMap.of()));
 
         assertNotNull(inMemoryDOMDataTreeShardProducer.createTransaction());
         verify(inMemoryDOMDataTreeShard).createTransaction(
                 any(String.class),
                 any(InMemoryDOMDataTreeShardProducer.class),
-                anyCollectionOf(DOMDataTreeIdentifier.class),
                 any(CursorAwareDataTreeSnapshot.class));
         resetMocks();
     }
-}
\ No newline at end of file
+}
index f9b4d4ee0482a80b5f58233e219d886ee1c6737a..72cbf4a6c43ffe23f80cc89f6cc765a6e52d47ea 100644 (file)
@@ -41,7 +41,7 @@ public class InMemoryDOMDataTreeShardTest {
     public void basicTest() throws Exception {
         final InMemoryDOMDataTreeShard inMemoryDOMDataTreeShard =
                 InMemoryDOMDataTreeShard.create(DOM_DATA_TREE_IDENTIFIER,
-                        MoreExecutors.newDirectExecutorService(), 1);
+                        MoreExecutors.directExecutor(), 1);
 
         final DOMDataTreeIdentifier domDataTreeIdentifier =
                 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
@@ -60,12 +60,15 @@ public class InMemoryDOMDataTreeShardTest {
         assertEquals(prefixes.toString(), inMemoryDOMDataTreeShard.createProducer(prefixes).getPrefixes().toString());
 
         final InMemoryDOMDataTreeShardProducer mockProducer = mock(InMemoryDOMDataTreeShardProducer.class);
+        doReturn(prefixes).when(mockProducer).getPrefixes();
+        doReturn(inMemoryDOMDataTreeShard.createModificationFactory(prefixes))
+            .when(mockProducer).getModificationFactory();
 
         inMemoryDOMDataTreeShard.onGlobalContextUpdated(createTestContext());
-        inMemoryDOMDataTreeShard.createTransaction("", mockProducer, prefixes, mock(CursorAwareDataTreeSnapshot.class));
+        inMemoryDOMDataTreeShard.createTransaction("", mockProducer, mock(CursorAwareDataTreeSnapshot.class));
 
         final DOMDataTreeChangeListener domDataTreeChangeListener = mock(DOMDataTreeChangeListener.class);
-        final ListenerRegistration listenerRegistration = mock(ListenerRegistration.class);
+        final ListenerRegistration<?> listenerRegistration = mock(ListenerRegistration.class);
         doReturn(listenerRegistration).when(domDataTreeShard).registerTreeChangeListener(any(), any());
         doNothing().when(domDataTreeChangeListener).onDataTreeChanged(any());
         inMemoryDOMDataTreeShard.registerTreeChangeListener(YangInstanceIdentifier.EMPTY, domDataTreeChangeListener);
@@ -88,10 +91,13 @@ public class InMemoryDOMDataTreeShardTest {
         final InmemoryDOMDataTreeShardWriteTransaction inmemoryDOMDataTreeShardWriteTransaction =
                 mock(InmemoryDOMDataTreeShardWriteTransaction.class);
         doReturn(dataTreeModification).when(inmemoryDOMDataTreeShardWriteTransaction).getRootModification();
-        final InMemoryDOMDataTreeShardProducer mockProducer = mock(InMemoryDOMDataTreeShardProducer.class);
         final Collection<DOMDataTreeIdentifier> prefixes = ImmutableList.of(DOM_DATA_TREE_IDENTIFIER);
+        final InMemoryDOMDataTreeShardProducer mockProducer = mock(InMemoryDOMDataTreeShardProducer.class);
+        doReturn(prefixes).when(mockProducer).getPrefixes();
+        doReturn(inMemoryDOMDataTreeShard.createModificationFactory(prefixes))
+            .when(mockProducer).getModificationFactory();
 
-        inMemoryDOMDataTreeShard.createTransaction("", mockProducer, prefixes, mock(CursorAwareDataTreeSnapshot.class));
+        inMemoryDOMDataTreeShard.createTransaction("", mockProducer, mock(CursorAwareDataTreeSnapshot.class));
     }
 
     @After
index 9d63ce294fffd43e1e3c0a927436a1b0a7162592..39f3277212aa35d9a79347424c5041d2b810d9fa 100644 (file)
@@ -66,7 +66,7 @@ public class InmemoryDOMDataTreeShardWriteTransactionTest {
         doReturn("testDataTreeModification").when(dataTreeModification).toString();
         doReturn(dataTreeModification).when(SHARD_ROOT_MODIFICATION_CONTEXT).ready();
         doReturn(DOM_DATA_TREE_IDENTIFIER).when(SHARD_ROOT_MODIFICATION_CONTEXT).getIdentifier();
-        shardDataModification = ShardDataModification.from(SHARD_ROOT_MODIFICATION_CONTEXT,
+        shardDataModification = TestUtils.createModification(SHARD_ROOT_MODIFICATION_CONTEXT,
                 ImmutableMap.of(YANG_INSTANCE_IDENTIFIER, FOREIGN_SHARD_MODIFICATION_CONTEXT));
         final DataTreeModificationCursor dataTreeModificationCursor = mock(DataTreeModificationCursor.class);
         doReturn(DataTreeModificationCursorAdaptor.of( dataTreeModificationCursor))
index aacbcfb2a3948597ba67d27178635c8c67c2cf85..e2282a410ed5d717dfea941fd86cf593497a03e5 100644 (file)
@@ -7,14 +7,11 @@
  */
 package org.opendaylight.mdsal.dom.store.inmemory;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.DOM_DATA_TREE_IDENTIFIER;
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.DOM_DATA_TREE_SHARD_PRODUCER;
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.PATH_ARGUMENT;
-import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.WRITEABLE_MODIFICATION_NODE;
 
-import java.util.Map;
 import org.junit.Test;
 
 public class ModificationContextNodeBuilderTest extends ModificationContextNodeBuilder {
@@ -28,11 +25,5 @@ public class ModificationContextNodeBuilderTest extends ModificationContextNodeB
         super.addBoundary(PATH_ARGUMENT, writeableSubshardBoundaryNode);
 
         assertNotNull(super.getInterior(PATH_ARGUMENT));
-        assertEquals(WRITEABLE_MODIFICATION_NODE, super.build());
-    }
-
-    @Override
-    WriteableModificationNode build(Map children) {
-        return WRITEABLE_MODIFICATION_NODE;
     }
 }
\ No newline at end of file
index 380ff29d2abb4a558cd7cd6346b8f4b200e911e7..e64842f139260f0dbd9b1b341cb74b113930ec60 100644 (file)
@@ -19,6 +19,7 @@ import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.WRITE_CURSOR_S
 import static org.opendaylight.mdsal.dom.store.inmemory.TestUtils.resetMocks;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import java.lang.reflect.Field;
 import java.util.Deque;
 import java.util.HashMap;
@@ -38,8 +39,9 @@ public class ShardDataModificationCursorTest {
         final ShardRootModificationContext shardRootModificationContext = mock(ShardRootModificationContext.class);
         final Map<PathArgument, WriteableModificationNode> children = new HashMap<>();
         children.put(PATH_ARGUMENT, WRITEABLE_MODIFICATION_NODE);
-        final ShardDataModification root =
-                new ShardDataModificationBuilder(shardRootModificationContext).build(children);
+        final ShardDataModification root =  new ShardDataModification(shardRootModificationContext, children,
+            ImmutableMap.of());
+
         doReturn(dataTreeModificationCursorAdaptor).when(shardRootModificationContext).cursor();
         InmemoryDOMDataTreeShardWriteTransaction inmemoryDOMDataTreeShardWriteTransaction =
                 mock(InmemoryDOMDataTreeShardWriteTransaction.class);
index ed529a0361c47cbb512f64fb9336357f06657252..0939bc04549a248eabffbb1669a75abbaa80d8a3 100644 (file)
@@ -43,7 +43,7 @@ public class ShardDataModificationTest {
     @Before
     public void setUp() throws Exception {
         doReturn(DOM_DATA_TREE_IDENTIFIER).when(SHARD_ROOT_MODIFICATION_CONTEXT).getIdentifier();
-        shardDataModification = ShardDataModification.from(SHARD_ROOT_MODIFICATION_CONTEXT,
+        shardDataModification = TestUtils.createModification(SHARD_ROOT_MODIFICATION_CONTEXT,
                 ImmutableMap.of(YangInstanceIdentifier.of(QName.create("test")), FOREIGN_SHARD_MODIFICATION_CONTEXT));
 
         final Map<DOMDataTreeIdentifier, ForeignShardModificationContext> children =
index 7f05d7acb7561515bcae2c9fb0fe09e2959ced81..649c9947df7bf8658fcd0b025322fcd6d4c911f9 100644 (file)
@@ -13,6 +13,7 @@ import static org.mockito.Mockito.reset;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Map;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor;
@@ -67,4 +68,18 @@ final class TestUtils {
     private TestUtils() throws UnsupportedOperationException {
         throw new UnsupportedOperationException("Utility class should not be instantiated");
     }
-}
\ No newline at end of file
+
+    static ShardDataModification createModification(final ShardRootModificationContext root,
+            final Map<YangInstanceIdentifier, ForeignShardModificationContext> shards) {
+
+        final ShardDataModificationFactoryBuilder builder = new ShardDataModificationFactoryBuilder(
+            root.getIdentifier());
+        for (ForeignShardModificationContext subshard : shards.values()) {
+            builder.addSubshard(subshard);
+        }
+
+        final ShardDataModificationFactory factory = builder.build();
+        return new ShardDataModification(root, factory.getChildren(), factory.getChildShards());
+    }
+
+}