Merge "Netconf testtool stress client"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 20 Apr 2015 15:23:49 +0000 (15:23 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 20 Apr 2015 15:23:50 +0000 (15:23 +0000)
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/DataExistsReply.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/AbstractTransactionProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/OperationCompleterTest.java
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/AbstractDOMStoreTreeChangePublisher.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMStoreTreeChangePublisher.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/netconf/netconf-cli/src/main/java/org/opendaylight/controller/netconf/cli/reader/custom/ConfigReader.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java

index 066f01b092d701b08556c5fd7319db4d64a6859c..81125a7152bf562baede534f7b84b2560f4f9bae 100644 (file)
@@ -137,14 +137,13 @@ public abstract class ShardTransaction extends AbstractUntypedActorWithMetering
         final YangInstanceIdentifier path = message.getPath();
 
         try {
-            Boolean exists = transaction.exists(path).checkedGet();
-            DataExistsReply dataExistsReply = new DataExistsReply(exists);
+            boolean exists = transaction.exists(path).checkedGet();
+            DataExistsReply dataExistsReply = DataExistsReply.create(exists);
             getSender().tell(returnSerialized ? dataExistsReply.toSerializable() :
                 dataExistsReply, getSelf());
         } catch (ReadFailedException e) {
             getSender().tell(new akka.actor.Status.Failure(e),getSelf());
         }
-
     }
 
     private static class ShardTransactionCreator implements Creator<ShardTransaction> {
index 24ca6464543911c9d4c6d05fe1f3f2d8731c920e..0ea865aa07e06b8f201955d9bfcac61c27d83725 100644 (file)
@@ -10,28 +10,47 @@ package org.opendaylight.controller.cluster.datastore.messages;
 
 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
 
-public class DataExistsReply implements SerializableMessage{
+public class DataExistsReply implements SerializableMessage {
     public static final Class<ShardTransactionMessages.DataExistsReply> SERIALIZABLE_CLASS =
             ShardTransactionMessages.DataExistsReply.class;
 
+    private static final DataExistsReply TRUE = new DataExistsReply(true, null);
+    private static final DataExistsReply FALSE = new DataExistsReply(false, null);
+    private static final ShardTransactionMessages.DataExistsReply SERIALIZABLE_TRUE =
+            ShardTransactionMessages.DataExistsReply.newBuilder().setExists(true).build();
+    private static final ShardTransactionMessages.DataExistsReply SERIALIZABLE_FALSE =
+            ShardTransactionMessages.DataExistsReply.newBuilder().setExists(false).build();
+
     private final boolean exists;
 
-    public DataExistsReply(final boolean exists) {
+    private DataExistsReply(final boolean exists, final Void dummy) {
         this.exists = exists;
     }
 
+    /**
+     * @deprecated Use {@link #create(boolean)} instead.
+     * @param exists
+     */
+    @Deprecated
+    public DataExistsReply(final boolean exists) {
+        this(exists, null);
+    }
+
+    public static DataExistsReply create(final boolean exists) {
+        return exists ? TRUE : FALSE;
+    }
+
     public boolean exists() {
         return exists;
     }
 
-    @Override public Object toSerializable() {
-        return ShardTransactionMessages.DataExistsReply.newBuilder()
-            .setExists(exists).build();
+    @Override
+    public Object toSerializable() {
+        return exists ? SERIALIZABLE_TRUE : SERIALIZABLE_FALSE;
     }
 
-    public static DataExistsReply fromSerializable(final Object serializable){
+    public static DataExistsReply fromSerializable(final Object serializable) {
         ShardTransactionMessages.DataExistsReply o = (ShardTransactionMessages.DataExistsReply) serializable;
-        return new DataExistsReply(o.getExists());
+        return create(o.getExists());
     }
-
 }
index 6a1e12a96b6e9cd2eb7a3a89204a87d21a64f1da..aa7ad259b4ea3ed02f79d6c423d15805b4ae3ad3 100644 (file)
@@ -221,18 +221,18 @@ public abstract class AbstractTransactionProxyTest {
     }
 
     protected Future<Object> dataExistsSerializedReply(boolean exists) {
-        return Futures.successful(new DataExistsReply(exists).toSerializable());
+        return Futures.successful(DataExistsReply.create(exists).toSerializable());
     }
 
     protected Future<DataExistsReply> dataExistsReply(boolean exists) {
-        return Futures.successful(new DataExistsReply(exists));
+        return Futures.successful(DataExistsReply.create(exists));
     }
 
     protected Future<BatchedModificationsReply> batchedModificationsReply(int count) {
         return Futures.successful(new BatchedModificationsReply(count));
     }
 
-    protected Future<Object> incompleteFuture(){
+    protected Future<Object> incompleteFuture() {
         return mock(Future.class);
     }
 
index e7afe262b96a6f564b5b672f7473b6c6e12d48db..00900d35fb0a29f9a79ef748ca2916610647c748 100644 (file)
@@ -29,10 +29,10 @@ public class OperationCompleterTest {
 
         OperationCompleter completer = new OperationCompleter(operationLimiter );
 
-        completer.onComplete(null, new DataExistsReply(true));
+        completer.onComplete(null, DataExistsReply.create(true));
         assertEquals("availablePermits", ++availablePermits, operationLimiter.availablePermits());
 
-        completer.onComplete(null, new DataExistsReply(true));
+        completer.onComplete(null, DataExistsReply.create(true));
         assertEquals("availablePermits", ++availablePermits, operationLimiter.availablePermits());
 
         completer.onComplete(null, new IllegalArgumentException());
index f8ac0d849f32845a697f70319aea789949aa2d5b..d191fc397c787ff4120269f7fbdf8c54b24d19ff 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListe
 import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 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.DataTreeCandidate;
@@ -43,7 +42,7 @@ public abstract class AbstractDOMStoreTreeChangePublisher extends AbstractRegist
 
     /**
      * Callback notifying the subclass that the specified registration is being closed and it's user no longer
-     * wishes to receive notifications. This notification is invoked while the {@link ListenerRegistration#close()}
+     * wishes to receive notifications. This notification is invoked while the {@link org.opendaylight.yangtools.concepts.ListenerRegistration#close()}
      * method is executing. Subclasses can use this callback to properly remove any delayed notifications pending
      * towards the registration.
      *
@@ -70,7 +69,7 @@ public abstract class AbstractDOMStoreTreeChangePublisher extends AbstractRegist
     }
 
     @Override
-    public final <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+    public final <L extends DOMDataTreeChangeListener> AbstractDOMDataTreeChangeListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
         // Take the write lock
         takeLock();
         try {
index b617a8087fc771d6f413b1ec6c3dc4e5bf597aa3..354abcf69fe1040a1e24822b7db78aa6e674909d 100644 (file)
@@ -205,8 +205,12 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
     }
 
     @Override
-    public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
-        return changePublisher.registerTreeChangeListener(treeId, listener);
+    public synchronized <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+        /*
+         * Make sure commit is not occurring right now. Listener has to be
+         * registered and its state capture enqueued at a consistent point.
+         */
+        return changePublisher.registerTreeChangeListener(treeId, listener, dataTree.takeSnapshot());
     }
 
     @Override
@@ -224,7 +228,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
         return name + "-" + txCounter.getAndIncrement();
     }
 
-    private static void warnDebugContext(AbstractDOMStoreTransaction<?> transaction) {
+    private static void warnDebugContext(final AbstractDOMStoreTransaction<?> transaction) {
         final Throwable ctx = transaction.getDebugContext();
         if (ctx != null) {
             LOG.warn("Transaction {} has been allocated in the following context", transaction.getIdentifier(), ctx);
index feb1b66dd3738478af4e663e32123d8b41b8142e..2f3b46366a918b9f92d8791c3cf68d39ae6bb3a1 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.base.Optional;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.ExecutorService;
@@ -14,12 +15,15 @@ import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
 import org.opendaylight.controller.sal.core.spi.data.AbstractDOMStoreTreeChangePublisher;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
 import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager.Invoker;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.DefaultDataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +48,7 @@ final class InMemoryDOMStoreTreeChangePublisher extends AbstractDOMStoreTreeChan
 
     @Override
     protected void notifyListeners(final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations, final YangInstanceIdentifier path, final DataTreeCandidateNode node) {
-        final DataTreeCandidate candidate = new DefaultDataTreeCandidate(path, node);
+        final DataTreeCandidate candidate = DataTreeCandidates.newDataTreeCandidate(path, node);
 
         for (AbstractDOMDataTreeChangeListenerRegistration<?> reg : registrations) {
             LOG.debug("Enqueueing candidate {} to registration {}", candidate, registrations);
@@ -59,6 +63,18 @@ final class InMemoryDOMStoreTreeChangePublisher extends AbstractDOMStoreTreeChan
         // FIXME: remove the queue for this registration and make sure we clear it
     }
 
+    <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener, final DataTreeSnapshot snapshot) {
+        final AbstractDOMDataTreeChangeListenerRegistration<L> reg = registerTreeChangeListener(treeId, listener);
+
+        final Optional<NormalizedNode<?, ?>> node = snapshot.readNode(treeId);
+        if (node.isPresent()) {
+            final DataTreeCandidate candidate = DataTreeCandidates.fromNormalizedNode(treeId, node.get());
+            notificationManager.submitNotification(reg, candidate);
+        }
+
+        return reg;
+    }
+
     synchronized void publishChange(@Nonnull final DataTreeCandidate candidate) {
         // Runs synchronized with registrationRemoved()
         processCandidateTree(candidate);
index fb4931098b34776cf334af7ef835323e915661a2..07a9fb7a88a7c5c37a3f748d84c7659e825dc9d5 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
@@ -34,7 +35,8 @@ import org.slf4j.LoggerFactory;
  * Computes data change events for all affected registered listeners in data
  * tree.
  */
-final class ResolveDataChangeEventsTask {
+@Beta
+public final class ResolveDataChangeEventsTask {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
 
     private final DataTreeCandidate candidate;
@@ -42,7 +44,7 @@ final class ResolveDataChangeEventsTask {
 
     private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
 
-    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+    private ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
         this.candidate = Preconditions.checkNotNull(candidate);
         this.listenerRoot = Preconditions.checkNotNull(listenerTree);
     }
index 111a2420c5619a5b464c46b749d295d7a0b25bfb..75582ed72df6061e0a9357394e86bca819be0ae4 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.controller.netconf.cli.reader.custom;
 
 import static org.opendaylight.controller.netconf.cli.io.IOUtil.isSkipInput;
-
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -34,8 +33,10 @@ import org.opendaylight.controller.netconf.cli.reader.AbstractReader;
 import org.opendaylight.controller.netconf.cli.reader.ReadingException;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
@@ -89,7 +90,7 @@ public class ConfigReader extends AbstractReader<DataSchemaNode> {
             filterPartsQNames.add(qName);
         }
 
-        List<NormalizedNode<?, ?>> previous = readInnerNode(rawValue);
+        List<? extends NormalizedNode<?, ?>> previous = readInnerNode(rawValue);
 
         for (final QName qName : Lists.reverse(filterPartsQNames).subList(1, filterPartsQNames.size())) {
             previous = Collections.<NormalizedNode<?, ?>>singletonList(
@@ -99,12 +100,15 @@ public class ConfigReader extends AbstractReader<DataSchemaNode> {
             );
         }
 
-        final DataContainerChild<?, ?> newNode = previous == null ? null
-                : ImmutableContainerNodeBuilder.create()
-                        .withNodeIdentifier(new NodeIdentifier(schemaNode.getQName()))
-                        .withValue((Collection) previous).build();
+        if (previous == null) {
+            return Collections.singletonList(null);
+        }
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder = ImmutableContainerNodeBuilder.create();
+        builder.withNodeIdentifier(new NodeIdentifier(schemaNode.getQName()));
+        builder.withValue((Collection<DataContainerChild<?, ?>>) previous);
 
-        return Collections.<NormalizedNode<?, ?>> singletonList(newNode);
+        return Collections.<NormalizedNode<?, ?>> singletonList(builder.build());
     }
 
     private List<NormalizedNode<?, ?>> readInnerNode(final String pathString) throws ReadingException {
index 4ae65f31f72a6240e92d85be49e07c4f70b3115d..6408fce5d39b199c1105807619bf9e4e0198c4f6 100644 (file)
@@ -55,6 +55,9 @@ public final class XmlUtil {
             factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
             factory.setXIncludeAware(false);
             factory.setExpandEntityReferences(false);
+            // Performance improvement for messages with size <10k according to
+            // https://xerces.apache.org/xerces2-j/faq-performance.html
+            factory.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
         } catch (ParserConfigurationException e) {
             throw new ExceptionInInitializerError(e);
         }