BUG-2138: Add shard DTO classes to spi
[mdsal.git] / dom / mdsal-dom-inmemory-datastore / src / main / java / org / opendaylight / mdsal / dom / store / inmemory / InMemoryDOMDataTreeShard.java
index 97b2354f9ad1965b42c3ab7d5f67033f361682ac..6449653ad7207b9da94067befae64a404c47f7f2 100644 (file)
@@ -15,9 +15,9 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.common.util.concurrent.ListeningExecutorService;
 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;
@@ -28,6 +28,11 @@ import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
 import org.opendaylight.mdsal.dom.spi.DOMDataTreePrefixTable;
+import org.opendaylight.mdsal.dom.spi.shard.ChildShardContext;
+import org.opendaylight.mdsal.dom.spi.shard.ForeignShardModificationContext;
+import org.opendaylight.mdsal.dom.spi.shard.ReadableWriteableDOMDataTreeShard;
+import org.opendaylight.mdsal.dom.spi.shard.SubshardProducerSpecification;
+import org.opendaylight.mdsal.dom.spi.shard.WriteableDOMDataTreeShard;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.util.concurrent.CountingRejectedExecutionHandler;
 import org.opendaylight.yangtools.util.concurrent.FastThreadPoolExecutor;
@@ -39,39 +44,22 @@ 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 Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataTreeShard.class);
     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;
-
-        SubshardProducerSpecification(final ChildShardContext subshard) {
-            this.shard = Preconditions.checkNotNull(subshard);
-        }
-
-        void addPrefix(final DOMDataTreeIdentifier prefix) {
-            prefixes.add(prefix);
-        }
-
-        DOMDataTreeShardProducer createProducer() {
-            return shard.getShard().createProducer(prefixes);
-        }
-
-        public DOMDataTreeIdentifier getPrefix() {
-            return shard.getPrefix();
-        }
-    }
-
     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,22 +100,79 @@ 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
+    InMemoryShardDataModificationFactory 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 InmemoryShardDataModificationFactoryBuilder builder =
+                new InmemoryShardDataModificationFactoryBuilder(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
     public InMemoryDOMDataTreeShardProducer createProducer(final Collection<DOMDataTreeIdentifier> prefixes) {
         for (final DOMDataTreeIdentifier prodPrefix : prefixes) {
             Preconditions.checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shart root",
-                prodPrefix, prefix);
+                    prodPrefix, prefix);
+        }
+
+        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);
         }
-        return new InMemoryDOMDataTreeShardProducer(this, prefixes);
     }
 
     @Nonnull
@@ -137,12 +182,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();
@@ -173,9 +212,9 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha
     }
 
     private static ChildShardContext createContextFor(final DOMDataTreeIdentifier prefix,
-            final DOMDataTreeShard child) {
+                                                      final DOMDataTreeShard child) {
         Preconditions.checkArgument(child instanceof WriteableDOMDataTreeShard,
-            "Child %s is not a writable shared", child);
+                "Child %s is not a writable shared", child);
         return new ChildShardContext(prefix, (WriteableDOMDataTreeShard) child);
     }
 
@@ -200,51 +239,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;
-                }
+            final InMemoryDOMDataTreeShardProducer producer, final DataTreeSnapshot snapshot) {
+        Preconditions.checkArgument(snapshot instanceof CursorAwareDataTreeSnapshot);
 
-                SubshardProducerSpecification spec = affectedSubshards.get(maybeAffected.getPrefix());
-                if (spec == null) {
-                    spec = new SubshardProducerSpecification(maybeAffected);
-                    affectedSubshards.put(maybeAffected.getPrefix(), spec);
-                }
-                spec.addPrefix(bindPath);
-            }
-        }
-
-        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);
     }
-
 }