Merge "Refactor integration tests for netconf in netconf-it"
authorTony Tkacik <ttkacik@cisco.com>
Thu, 4 Sep 2014 11:38:22 +0000 (11:38 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 4 Sep 2014 11:38:22 +0000 (11:38 +0000)
29 files changed:
features/mdsal/pom.xml
features/mdsal/src/main/resources/features.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java [deleted file]
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/InMemoryDOMDataStoreConfigProperties.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStoreFactory.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang

index 41f1eab488212d58e28e220080f001db932e7880..c6856c89fb4776718a7ea13cc1074cf71f403e12 100644 (file)
@@ -63,6 +63,8 @@
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-dom-xsql-config</artifactId>
+      <classifier>config</classifier>
+      <type>xml</type>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
index 0176a0388c76f46e57489a6d439446d632ced7e8..408be621f514b279a681bc7cdf6d53158f69fbc7 100644 (file)
@@ -45,6 +45,7 @@
         <feature>war</feature>
         <bundle>mvn:org.opendaylight.controller/sal-rest-connector/${project.version}</bundle>
         <bundle>mvn:com.google.code.gson/gson/${gson.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/yang-data-codec-gson/${yangtools.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
index 1fc32b37d8a364b5e0536480044bed122172e2f2..2e953072681704e6d4b9b3d1251658d59da4f7f7 100644 (file)
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-dom-xsql-config</artifactId>
         <version>${mdsal.version}</version>
+        <classifier>config</classifier>
+        <type>xml</type>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java
new file mode 100644 (file)
index 0000000..79391d4
--- /dev/null
@@ -0,0 +1,46 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.manager.impl.osgi.mapping.RefreshingSCPModuleInfoRegistry;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.*;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class RefreshingSCPModuleInfoRegistryTest {
+    @Test
+    public void testConstructor() throws Exception {
+        ModuleInfoRegistry reg = mock(ModuleInfoRegistry.class);
+        SchemaContextProvider prov = mock(SchemaContextProvider.class);
+        doReturn("string").when(prov).toString();
+
+        BundleContext ctxt = mock(BundleContext.class);
+        Dictionary dict = new Hashtable();
+        ServiceRegistration servReg = mock(ServiceRegistration.class);
+        doReturn(servReg).when(ctxt).registerService(Mockito.any(Class.class), Mockito.any(SchemaContextProvider.class), Mockito.any(Dictionary.class));
+        doReturn(servReg).when(ctxt).registerService(Mockito.anyString(), Mockito.any(Object.class), Mockito.any(Dictionary.class));
+        RefreshingSCPModuleInfoRegistry scpreg = new RefreshingSCPModuleInfoRegistry(reg, prov, ctxt);
+
+        YangModuleInfo modInfo = mock(YangModuleInfo.class);
+        doNothing().when(servReg).setProperties(null);
+        doNothing().when(servReg).unregister();
+        doReturn("").when(modInfo).toString();
+        ObjectRegistration<YangModuleInfo> ymi = mock(ObjectRegistration.class);
+        doReturn(ymi).when(reg).registerModuleInfo(modInfo);
+
+        scpreg.registerModuleInfo(modInfo);
+        scpreg.close();
+
+        Mockito.verify(servReg, Mockito.times(1)).setProperties(null);
+        Mockito.verify(servReg, Mockito.times(1)).unregister();
+    }
+}
index 53f96e44f4105b8ecd3f2125be2360bd54a0b0c4..d4b1d84aa77c5d648291dba26025bad8511618a8 100644 (file)
@@ -145,6 +145,11 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
             bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path));
         }
+
+        @Override
+        public String toString() {
+            return bindingDataChangeListener.getClass().getName();
+        }
     }
 
     private class TranslatedDataChangeEvent implements AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> {
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java
new file mode 100644 (file)
index 0000000..a2db29d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import java.lang.management.ManagementFactory;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Abstract base for an MXBean implementation class.
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ *
+ * @author Thomas Pantelis
+ */
+@Beta
+public abstract class AbstractMXBean {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractMXBean.class);
+
+    public static String BASE_JMX_PREFIX = "org.opendaylight.controller:";
+
+    private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+    private final String mBeanName;
+    private final String mBeanType;
+    private final String mBeanCategory;
+
+    /**
+     * Constructor.
+     *
+     * @param mBeanName Used as the <code>name</code> property in the bean's ObjectName.
+     * @param mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     * @param mBeanCategory Used as the <code>Category</code> property in the bean's ObjectName.
+     */
+    protected AbstractMXBean(@Nonnull String mBeanName, @Nonnull String mBeanType,
+            @Nullable String mBeanCategory) {
+        this.mBeanName = mBeanName;
+        this.mBeanType = mBeanType;
+        this.mBeanCategory = mBeanCategory;
+    }
+
+    private ObjectName getMBeanObjectName() throws MalformedObjectNameException {
+        StringBuilder builder = new StringBuilder(BASE_JMX_PREFIX)
+                .append("type=").append(getMBeanType());
+
+        if(getMBeanCategory() != null) {
+            builder.append(",Category=").append(getMBeanCategory());
+        }
+
+        builder.append(",name=").append(getMBeanName());
+        return new ObjectName(builder.toString());
+    }
+
+    /**
+     * Registers this bean with the platform MBean server with the domain defined by
+     * {@link #BASE_JMX_PREFIX}.
+     *
+     * @return true is successfully registered, false otherwise.
+     */
+    public boolean registerMBean() {
+        boolean registered = false;
+        try {
+            // Object to identify MBean
+            final ObjectName mbeanName = this.getMBeanObjectName();
+
+            LOG.debug("Register MBean {}", mbeanName);
+
+            // unregistered if already registered
+            if(server.isRegistered(mbeanName)) {
+
+                LOG.debug("MBean {} found to be already registered", mbeanName);
+
+                try {
+                    unregisterMBean(mbeanName);
+                } catch(Exception e) {
+
+                    LOG.warn("unregister mbean {} resulted in exception {} ", mbeanName, e);
+                }
+            }
+            server.registerMBean(this, mbeanName);
+            registered = true;
+
+            LOG.debug("MBean {} registered successfully", mbeanName.getCanonicalName());
+        } catch(Exception e) {
+
+            LOG.error("registration failed {}", e);
+
+        }
+        return registered;
+    }
+
+    /**
+     * Unregisters this bean with the platform MBean server.
+     *
+     * @return true is successfully unregistered, false otherwise.
+     */
+    public boolean unregisterMBean() {
+        boolean unregister = false;
+        try {
+            ObjectName mbeanName = this.getMBeanObjectName();
+            unregisterMBean(mbeanName);
+            unregister = true;
+        } catch(Exception e) {
+
+            LOG.error("Failed when unregistering MBean {}", e);
+        }
+
+        return unregister;
+    }
+
+    private void unregisterMBean(ObjectName mbeanName) throws MBeanRegistrationException,
+            InstanceNotFoundException {
+        server.unregisterMBean(mbeanName);
+    }
+
+    /**
+     * Returns the <code>name</code> property of the bean's ObjectName.
+     */
+    public String getMBeanName() {
+        return mBeanName;
+    }
+
+    /**
+     * Returns the <code>type</code> property of the bean's ObjectName.
+     */
+    public String getMBeanType() {
+        return mBeanType;
+    }
+
+    /**
+     * Returns the <code>Category</code> property of the bean's ObjectName.
+     */
+    public String getMBeanCategory() {
+        return mBeanCategory;
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java
new file mode 100644 (file)
index 0000000..9646adc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+
+/**
+ * MXBean interface for {@link QueuedNotificationManager} statistic metrics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface QueuedNotificationManagerMXBean {
+
+    /**
+     * Returns a list of stat instances for each current listener notification task in progress.
+     */
+    List<ListenerNotificationQueueStats> getCurrentListenerQueueStats();
+
+    /**
+     * Returns the configured maximum listener queue size.
+     */
+    int getMaxListenerQueueSize();
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java
new file mode 100644 (file)
index 0000000..e6148fc
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Implementation of the QueuedNotificationManagerMXBean interface.
+ *
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ *
+ * @author Thomas Pantelis
+ */
+public class QueuedNotificationManagerMXBeanImpl extends AbstractMXBean
+                                                 implements QueuedNotificationManagerMXBean {
+
+    private final QueuedNotificationManager<?,?> manager;
+
+    public QueuedNotificationManagerMXBeanImpl( QueuedNotificationManager<?,?> manager,
+            String mBeanName, String mBeanType, String mBeanCategory ) {
+        super(mBeanName, mBeanType, mBeanCategory);
+        this.manager = Preconditions.checkNotNull( manager );
+    }
+
+    @Override
+    public List<ListenerNotificationQueueStats> getCurrentListenerQueueStats() {
+        return manager.getListenerNotificationQueueStats();
+    }
+
+    @Override
+    public int getMaxListenerQueueSize() {
+        return manager.getMaxQueueCapacity();
+    }
+
+    public QueuedNotificationManagerStats toQueuedNotificationManagerStats() {
+        return new QueuedNotificationManagerStats( getMaxListenerQueueSize(),
+                getCurrentListenerQueueStats() );
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java
new file mode 100644 (file)
index 0000000..c6e5006
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+
+/**
+ * A bean class that holds various QueuedNotificationManager statistic metrics. This class is
+ * suitable for mapping to the MXBean CompositeDataSupport type.
+ *
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ * @author Thomas Pantelis
+ * @see QueuedNotificationManagerMXBeanImpl
+ */
+public class QueuedNotificationManagerStats {
+
+    private final int maxListenerQueueSize;
+    private final List<ListenerNotificationQueueStats> currentListenerQueueStats;
+
+    @ConstructorProperties({"maxListenerQueueSize","currentListenerQueueStats"})
+    public QueuedNotificationManagerStats( int maxListenerQueueSize,
+            List<ListenerNotificationQueueStats> currentListenerQueueStats ) {
+        super();
+        this.maxListenerQueueSize = maxListenerQueueSize;
+        this.currentListenerQueueStats = currentListenerQueueStats;
+    }
+
+    public List<ListenerNotificationQueueStats> getCurrentListenerQueueStats() {
+        return currentListenerQueueStats;
+    }
+
+    public int getMaxListenerQueueSize() {
+        return maxListenerQueueSize;
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java
new file mode 100644 (file)
index 0000000..0a766c0
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A bean class that holds various thread executor statistic metrics. This class is suitable for
+ * mapping to the MXBean CompositeDataSupport type;
+ *
+ * @author Thomas Pantelis
+ * @see ThreadExecutorStatsMXBeanImpl
+ */
+public class ThreadExecutorStats {
+
+    private final long activeThreadCount;
+    private final long completedTaskCount;
+    private final long currentQueueSize;
+    private final long maxThreadPoolSize;
+    private final long totalTaskCount;
+    private final long largestThreadPoolSize;
+    private final long maxQueueSize;
+    private final long currentThreadPoolSize;
+
+    // The following fields are defined as Long because they may be null if we can't a value
+    // from the underlying executor.
+    private final Long largestQueueSize;
+    private final Long rejectedTaskCount;
+
+    @ConstructorProperties({"activeThreadCount","currentThreadPoolSize","largestThreadPoolSize",
+        "maxThreadPoolSize","currentQueueSize","largestQueueSize","maxQueueSize",
+        "completedTaskCount","totalTaskCount","rejectedTaskCount"})
+    public ThreadExecutorStats(long activeThreadCount, long currentThreadPoolSize,
+            long largestThreadPoolSize, long maxThreadPoolSize, long currentQueueSize,
+            Long largestQueueSize, long maxQueueSize, long completedTaskCount,
+            long totalTaskCount, Long rejectedTaskCount) {
+        this.activeThreadCount = activeThreadCount;
+        this.currentThreadPoolSize = currentThreadPoolSize;
+        this.largestQueueSize = largestQueueSize;
+        this.largestThreadPoolSize = largestThreadPoolSize;
+        this.maxThreadPoolSize = maxThreadPoolSize;
+        this.currentQueueSize = currentQueueSize;
+        this.maxQueueSize = maxQueueSize;
+        this.completedTaskCount = completedTaskCount;
+        this.totalTaskCount = totalTaskCount;
+        this.rejectedTaskCount = rejectedTaskCount;
+    }
+
+    public long getActiveThreadCount() {
+        return activeThreadCount;
+    }
+
+    public long getCompletedTaskCount() {
+        return completedTaskCount;
+    }
+
+    public Long getRejectedTaskCount() {
+        return rejectedTaskCount;
+    }
+
+    public long getCurrentQueueSize() {
+        return currentQueueSize;
+    }
+
+    public Long getLargestQueueSize() {
+        return largestQueueSize;
+    }
+
+    public long getMaxThreadPoolSize() {
+        return maxThreadPoolSize;
+    }
+
+    public long getTotalTaskCount() {
+        return totalTaskCount;
+    }
+
+    public long getLargestThreadPoolSize() {
+        return largestThreadPoolSize;
+    }
+
+    public long getMaxQueueSize() {
+        return maxQueueSize;
+    }
+
+    public long getCurrentThreadPoolSize() {
+        return currentThreadPoolSize;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java
new file mode 100644 (file)
index 0000000..d30bf88
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+/**
+ * MXBean interface for thread executor statistic metrics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface ThreadExecutorStatsMXBean {
+
+    /**
+     * Returns the current thread pool size.
+     */
+    long getCurrentThreadPoolSize();
+
+    /**
+     * Returns the largest thread pool size.
+     */
+    long getLargestThreadPoolSize();
+
+    /**
+     * Returns the maximum thread pool size.
+     */
+    long getMaxThreadPoolSize();
+
+    /**
+     * Returns the current queue size.
+     */
+    long getCurrentQueueSize();
+
+    /**
+     * Returns the largest queue size, if available.
+     */
+    Long getLargestQueueSize();
+
+    /**
+     * Returns the maximum queue size.
+     */
+    long getMaxQueueSize();
+
+    /**
+     * Returns the active thread count.
+     */
+    long getActiveThreadCount();
+
+    /**
+     * Returns the completed task count.
+     */
+    long getCompletedTaskCount();
+
+    /**
+     * Returns the total task count.
+     */
+    long getTotalTaskCount();
+
+    /**
+     * Returns the rejected task count, if available.
+     */
+    Long getRejectedTaskCount();
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java
new file mode 100644 (file)
index 0000000..b67855d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.common.util.jmx;
+
+import com.google.common.base.Preconditions;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.util.concurrent.CountingRejectedExecutionHandler;
+import org.opendaylight.yangtools.util.concurrent.TrackingLinkedBlockingQueue;
+
+/**
+ * MXBean implementation of the ThreadExecutorStatsMXBean interface that retrieves statistics
+ * from a backing {@link java.util.concurrent.ExecutorService}.
+ *
+ * @author Thomas Pantelis
+ */
+public class ThreadExecutorStatsMXBeanImpl extends AbstractMXBean
+                                           implements ThreadExecutorStatsMXBean {
+
+    private final ThreadPoolExecutor executor;
+
+    /**
+     * Constructs an instance for the given {@link Executor}.
+     *
+     * @param executor the backing {@link Executor}
+     * @param mBeanName Used as the <code>name</code> property in the bean's ObjectName.
+     * @param mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     * @param mBeanCategory Used as the <code>Category</code> property in the bean's ObjectName.
+     */
+    public ThreadExecutorStatsMXBeanImpl(Executor executor, String mBeanName,
+            String mBeanType, @Nullable String mBeanCategory) {
+        super(mBeanName, mBeanType, mBeanCategory);
+
+        Preconditions.checkArgument(executor instanceof ThreadPoolExecutor,
+                "The ExecutorService of type {} is not an instanceof ThreadPoolExecutor",
+                executor.getClass());
+        this.executor = (ThreadPoolExecutor)executor;
+    }
+
+    @Override
+    public long getCurrentThreadPoolSize() {
+        return executor.getPoolSize();
+    }
+
+    @Override
+    public long getLargestThreadPoolSize() {
+        return  executor.getLargestPoolSize();
+    }
+
+    @Override
+    public long getMaxThreadPoolSize() {
+        return executor.getMaximumPoolSize();
+    }
+
+    @Override
+    public long getCurrentQueueSize() {
+        return executor.getQueue().size();
+    }
+
+    @Override
+    public Long getLargestQueueSize() {
+        BlockingQueue<Runnable> queue = executor.getQueue();
+        if(queue instanceof TrackingLinkedBlockingQueue) {
+            return Long.valueOf(((TrackingLinkedBlockingQueue<?>)queue).getLargestQueueSize());
+        }
+
+        return null;
+    }
+
+    @Override
+    public long getMaxQueueSize() {
+        long queueSize = executor.getQueue().size();
+        return executor.getQueue().remainingCapacity() + queueSize;
+    }
+
+    @Override
+    public long getActiveThreadCount() {
+        return executor.getActiveCount();
+    }
+
+    @Override
+    public long getCompletedTaskCount() {
+        return  executor.getCompletedTaskCount();
+    }
+
+    @Override
+    public long getTotalTaskCount() {
+        return executor.getTaskCount();
+    }
+
+    @Override
+    public Long getRejectedTaskCount() {
+        RejectedExecutionHandler rejectedHandler = executor.getRejectedExecutionHandler();
+        if(rejectedHandler instanceof CountingRejectedExecutionHandler) {
+            return Long.valueOf(((CountingRejectedExecutionHandler)rejectedHandler)
+                                                                     .getRejectedTaskCount());
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a {@link ThreadExecutorStats} instance containing a snapshot of the statistic
+     * metrics.
+     */
+    public ThreadExecutorStats toThreadExecutorStats() {
+        return new ThreadExecutorStats(getActiveThreadCount(), getCurrentThreadPoolSize(),
+                getLargestThreadPoolSize(), getMaxThreadPoolSize(), getCurrentQueueSize(),
+                getLargestQueueSize(), getMaxQueueSize(), getCompletedTaskCount(),
+                getTotalTaskCount(), getRejectedTaskCount());
+    }
+}
index 8664e8910b46bda523951f22961d59c13cbaec42..b423bbd0e5c644c147a69398a65da0a564c985a1 100644 (file)
@@ -7,11 +7,13 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
+
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException;
+import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl;
 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.jmx.CommitStatsMXBeanImpl;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService;
@@ -24,6 +26,8 @@ import com.google.common.collect.ImmutableMap;
 public final class DomInmemoryDataBrokerModule extends
         org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomInmemoryDataBrokerModule {
 
+    private static final String JMX_BEAN_TYPE = "DOMDataBroker";
+
     public DomInmemoryDataBrokerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
             final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
@@ -78,7 +82,7 @@ public final class DomInmemoryDataBrokerModule extends
          * nothing on success. The executor queue capacity is bounded and, if the capacity is
          * reached, subsequent submitted tasks will block the caller.
          */
-        Executor listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(
+        ExecutorService listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(
                 getMaxDataBrokerFutureCallbackPoolSize(), getMaxDataBrokerFutureCallbackQueueSize(),
                 "CommitFutures");
 
@@ -87,6 +91,29 @@ public final class DomInmemoryDataBrokerModule extends
                     TransactionCommitDeadlockException.DEADLOCK_EXECUTOR_FUNCTION,
                     listenableFutureExecutor));
 
+        final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl(
+                newDataBroker.getCommitStatsTracker(), JMX_BEAN_TYPE);
+        commitStatsMXBean.registerMBean();
+
+        final ThreadExecutorStatsMXBeanImpl commitExecutorStatsMXBean =
+                new ThreadExecutorStatsMXBeanImpl(commitExecutor, "CommitExecutorStats",
+                        JMX_BEAN_TYPE, null);
+        commitExecutorStatsMXBean.registerMBean();
+
+        final ThreadExecutorStatsMXBeanImpl commitFutureStatsMXBean =
+                new ThreadExecutorStatsMXBeanImpl(listenableFutureExecutor,
+                        "CommitFutureExecutorStats", JMX_BEAN_TYPE, null);
+        commitFutureStatsMXBean.registerMBean();
+
+        newDataBroker.setCloseable(new AutoCloseable() {
+            @Override
+            public void close() {
+                commitStatsMXBean.unregisterMBean();
+                commitExecutorStatsMXBean.unregisterMBean();
+                commitFutureStatsMXBean.unregisterMBean();
+            }
+        });
+
         return newDataBroker;
     }
 }
index d1b9a8f6005097ccc463d87efe2a52d0e3911b4c..d63d6cbe3674fb44e9131e8cbf99dc52453e5ae5 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,6 +41,7 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
     private final DOMDataCommitCoordinatorImpl coordinator;
     private final AtomicLong txNum = new AtomicLong();
     private final AtomicLong chainNum = new AtomicLong();
+    private volatile AutoCloseable closeable;
 
     public DOMDataBrokerImpl(final ImmutableMap<LogicalDatastoreType, DOMStore> datastores,
             final ListeningExecutorService executor) {
@@ -47,6 +49,27 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
         this.coordinator = new DOMDataCommitCoordinatorImpl(executor);
     }
 
+    public void setCloseable(AutoCloseable closeable) {
+        this.closeable = closeable;
+    }
+
+    public DurationStatsTracker getCommitStatsTracker() {
+        return coordinator.getCommitStatsTracker();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+
+        if(closeable != null) {
+            try {
+                closeable.close();
+            } catch(Exception e) {
+                LOG.debug("Error closing instance", e);
+            }
+        }
+    }
+
     @Override
     protected Object newTransactionIdentifier() {
         return "DOM-" + txNum.getAndIncrement();
@@ -82,5 +105,4 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
         LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts);
         return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> absent());
     }
-
 }
index 521e2d0e731af06ac972ce2cce28f75a347ba490..3fde8d360f8af6df8cb0bcd705a9e3289d9fd35e 100644 (file)
@@ -16,6 +16,7 @@ import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
 import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,6 +70,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
     private final ListeningExecutorService executor;
 
+    private final DurationStatsTracker commitStatsTracker = new DurationStatsTracker();
+
     /**
      *
      * Construct DOMDataCommitCoordinator which uses supplied executor to
@@ -80,6 +83,10 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
         this.executor = Preconditions.checkNotNull(executor, "executor must not be null.");
     }
 
+    public DurationStatsTracker getCommitStatsTracker() {
+        return commitStatsTracker;
+    }
+
     @Override
     public CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
             final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final Optional<DOMDataCommitErrorListener> listener) {
@@ -90,7 +97,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
         ListenableFuture<Void> commitFuture = null;
         try {
-            commitFuture = executor.submit(new CommitCoordinationTask(transaction, cohorts, listener));
+            commitFuture = executor.submit(new CommitCoordinationTask(transaction, cohorts,
+                    listener, commitStatsTracker));
         } catch(RejectedExecutionException e) {
             LOG.error("The commit executor's queue is full - submit task was rejected. \n" +
                       executor, e);
@@ -154,21 +162,25 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
         private final DOMDataWriteTransaction tx;
         private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
+        private final DurationStatsTracker commitStatTracker;
 
         @GuardedBy("this")
         private CommitPhase currentPhase;
 
         public CommitCoordinationTask(final DOMDataWriteTransaction transaction,
                 final Iterable<DOMStoreThreePhaseCommitCohort> cohorts,
-                final Optional<DOMDataCommitErrorListener> listener) {
+                final Optional<DOMDataCommitErrorListener> listener,
+                final DurationStatsTracker commitStatTracker) {
             this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null");
             this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null");
             this.currentPhase = CommitPhase.SUBMITTED;
+            this.commitStatTracker = commitStatTracker;
         }
 
         @Override
         public Void call() throws TransactionCommitFailedException {
 
+            long startTime = System.nanoTime();
             try {
                 canCommitBlocking();
                 preCommitBlocking();
@@ -178,6 +190,10 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
                 LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, e);
                 abortBlocking(e);
                 throw e;
+            } finally {
+                if(commitStatTracker != null) {
+                    commitStatTracker.addDuration(System.nanoTime() - startTime);
+                }
             }
         }
 
index b9504e72685f92f401173030af658d34b1982dcf..1c12d20504702eb7bf551922463bac74535f42c9 100644 (file)
@@ -62,12 +62,18 @@ abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChang
         }
     }
 
+    @Override
+    public String toString() {
+        return getDelegate().getClass().getName();
+    }
+
     static final class TranslatingConfigListenerInvoker extends TranslatingListenerInvoker {
 
         public TranslatingConfigListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) {
             super(listener, normalizer);
         }
 
+        @Override
         DataChangeEvent<YangInstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
             return TranslatingDataChangeEvent.createConfiguration(normalizedChange, normalizer);
         }
@@ -85,6 +91,7 @@ abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChang
             super(listener, normalizer);
         }
 
+        @Override
         DataChangeEvent<YangInstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
             return TranslatingDataChangeEvent.createOperational(normalizedChange, normalizer);
         }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java
new file mode 100644 (file)
index 0000000..40dc30e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.broker.impl.jmx;
+
+/**
+ * MXBean interface for retrieving write Tx commit statistics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface CommitStatsMXBean {
+
+    /**
+     * Returns the total number of commits that have occurred.
+     */
+    long getTotalCommits();
+
+    /**
+     * Returns a string representing the time duration of the longest commit, in the appropriate
+     * scaled units, along with the date/time that it occurred.
+     */
+    String getLongestCommitTime();
+
+    /**
+     * Returns a string representing the time duration of the shortest commit, in the appropriate
+     * scaled units, along with the date/time that it occurred.
+     */
+    String getShortestCommitTime();
+
+    /**
+     * Returns a string representing average commit time duration, in the appropriate
+     * scaled units.
+     */
+    String getAverageCommitTime();
+
+    /**
+     * Clears the current stats to their defaults.
+     */
+    void clearStats();
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java
new file mode 100644 (file)
index 0000000..f67f6b0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.broker.impl.jmx;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
+
+/**
+ * Implementation of the CommitStatsMXBean interface.
+ *
+ * @author Thomas Pantelis
+ */
+public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStatsMXBean {
+
+    private final DurationStatsTracker commitStatsTracker;
+
+    /**
+     * Constructor.
+     *
+     * @param commitStatsTracker the DurationStatsTracker used to obtain the stats.
+     * @param mBeanType mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     */
+    public CommitStatsMXBeanImpl(@Nonnull DurationStatsTracker commitStatsTracker,
+            @Nonnull String mBeanType) {
+        super("CommitStats", mBeanType, null);
+        this.commitStatsTracker = commitStatsTracker;
+    }
+
+    @Override
+    public long getTotalCommits() {
+        return commitStatsTracker.getTotalDurations();
+    }
+
+    @Override
+    public String getLongestCommitTime() {
+        return commitStatsTracker.getDisplayableLongestDuration();
+    }
+
+    @Override
+    public String getShortestCommitTime() {
+        return commitStatsTracker.getDisplayableShortestDuration();
+    }
+
+    @Override
+    public String getAverageCommitTime() {
+        return commitStatsTracker.getDisplayableAverageDuration();
+    }
+
+    @Override
+    public void clearStats() {
+        commitStatsTracker.reset();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java
new file mode 100644 (file)
index 0000000..d796930
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.broker.impl.jmx;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
+
+/**
+ * Unit tests for CommitStatsMXBeanImpl.
+ *
+ * @author Thomas Pantelis
+ */
+public class CommitStatsMXBeanImplTest {
+
+    @Test
+    public void test() {
+
+        DurationStatsTracker commitStatsTracker = new DurationStatsTracker();
+        CommitStatsMXBeanImpl bean =
+                new CommitStatsMXBeanImpl(commitStatsTracker, "Test");
+
+        commitStatsTracker.addDuration(100);
+
+        String prefix = "100.0 ns";
+        assertEquals("getTotalCommits", 1L, bean.getTotalCommits());
+        assertEquals("getLongestCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getLongestCommitTime().startsWith("100.0 ns"));
+        assertEquals("getShortestCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getShortestCommitTime().startsWith(prefix));
+        assertEquals("getAverageCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getAverageCommitTime().startsWith(prefix));
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java
new file mode 100644 (file)
index 0000000..12713b2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.sal.core.spi.data.statistics;
+
+import java.util.concurrent.ExecutorService;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+/**
+ * Interface for a class that tracks statistics for a data store.
+ *
+ * @author Thomas Pantelis
+ */
+public interface DOMStoreStatsTracker {
+
+    /**
+     * Sets the executor used for DataChangeListener notifications.
+     *
+     * @param dclExecutor the executor
+     */
+    void setDataChangeListenerExecutor( @Nonnull ExecutorService dclExecutor );
+
+    /**
+     * Sets the executor used internally by the data store.
+     *
+     * @param dsExecutor the executor
+     */
+    void setDataStoreExecutor( @Nonnull ExecutorService dsExecutor );
+
+    /**
+     * Sets the QueuedNotificationManager use for DataChangeListener notifications,
+     *
+     * @param manager the manager
+     */
+    void setNotificationManager( @Nonnull QueuedNotificationManager<?, ?> manager );
+}
index fd1627c6f994677abe043f767519fbb78e2d5eeb..b98844ba641f6e7f585c3c6b687c56d55161933c 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.config.yang.inmemory_datastore_provider;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
+import org.opendaylight.controller.md.sal.dom.store.impl.jmx.InMemoryDataStoreStats;
 
 public class InMemoryConfigDataStoreProviderModule extends org.opendaylight.controller.config.yang.inmemory_datastore_provider.AbstractInMemoryConfigDataStoreProviderModule {
 
@@ -20,9 +22,19 @@ public class InMemoryConfigDataStoreProviderModule extends org.opendaylight.cont
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return InMemoryDOMDataStoreFactory.create("DOM-CFG", getSchemaServiceDependency(),
+
+        InMemoryDOMDataStore dataStore = InMemoryDOMDataStoreFactory.create(
+                "DOM-CFG", getSchemaServiceDependency(),
                 InMemoryDOMDataStoreConfigProperties.create(getMaxDataChangeExecutorPoolSize(),
-                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize()));
+                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize(),
+                        getMaxDataStoreExecutorQueueSize()));
+
+        InMemoryDataStoreStats statsBean = new InMemoryDataStoreStats("InMemoryConfigDataStore",
+                dataStore.getDataChangeListenerNotificationManager(), dataStore.getDomStoreExecutor());
+
+        dataStore.setCloseable(statsBean);
+
+        return dataStore;
     }
 
 }
index 6596acb4e1bbb8caf9336a7e31cad98b521b0948..4532452c65e32521dece928f5b20f00310f3c358 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.config.yang.inmemory_datastore_provider;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
+import org.opendaylight.controller.md.sal.dom.store.impl.jmx.InMemoryDataStoreStats;
 
 public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight.controller.config.yang.inmemory_datastore_provider.AbstractInMemoryOperationalDataStoreProviderModule {
 
@@ -20,9 +22,17 @@ public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return InMemoryDOMDataStoreFactory.create("DOM-OPER", getSchemaServiceDependency(),
+        InMemoryDOMDataStore dataStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", getSchemaServiceDependency(),
                 InMemoryDOMDataStoreConfigProperties.create(getMaxDataChangeExecutorPoolSize(),
-                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize()));
-    }
+                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize(),
+                        getMaxDataStoreExecutorQueueSize()));
+
+
+        InMemoryDataStoreStats statsBean = new InMemoryDataStoreStats("InMemoryOperationalDataStore",
+                dataStore.getDataChangeListenerNotificationManager(), dataStore.getDomStoreExecutor());
 
+        dataStore.setCloseable(statsBean);
+
+        return dataStore;
+    }
 }
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java
deleted file mode 100644 (file)
index 536cfa0..0000000
+++ /dev/null
@@ -1,54 +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 com.google.common.base.Preconditions;
-
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class ChangeListenerNotifyTask implements Runnable {
-    private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerNotifyTask.class);
-
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr;
-    private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
-    private final DataChangeListenerRegistration<?> listener;
-
-    @SuppressWarnings("rawtypes")
-    public ChangeListenerNotifyTask(final DataChangeListenerRegistration<?> listener,
-            final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event,
-            final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
-        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
-        this.listener = Preconditions.checkNotNull(listener);
-        this.event = Preconditions.checkNotNull(event);
-    }
-
-    @Override
-    public void run() {
-        final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> l = listener.getInstance();
-        if (l == null) {
-            LOG.trace("Skipping event delivery to unregistered listener {}", l);
-            return;
-        }
-        LOG.trace("Listener {} event {}", l, event);
-
-        // FIXME: Yo dawg I heard you like queues, so this was queued to be queued
-        notificationMgr.submitNotification(l, event);
-    }
-
-    @Override
-    public String toString() {
-        return "ChangeListenerNotifyTask [listener=" + listener + ", event=" + event + "]";
-    }
-}
index 7ad3b8201e182cff9b3820a9e029f697e4cdb950..476356a19e79113b0b0121662b8842610757d12f 100644 (file)
@@ -7,30 +7,29 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
-import org.opendaylight.yangtools.util.ExecutorServiceUtil;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
-import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
 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;
@@ -40,22 +39,23 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.ExecutorServiceUtil;
+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.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+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;
 
-import javax.annotation.concurrent.GuardedBy;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static com.google.common.base.Preconditions.checkState;
-
 /**
  * In-memory DOM Data Store
  *
@@ -68,18 +68,17 @@ import static com.google.common.base.Preconditions.checkState;
 public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener,
         TransactionReadyPrototype,AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
+    private static final ListenableFuture<Void> SUCCESSFUL_FUTURE = Futures.immediateFuture(null);
 
-    @SuppressWarnings("rawtypes")
-    private static final QueuedNotificationManager.Invoker<AsyncDataChangeListener,
-                                       AsyncDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
-            new QueuedNotificationManager.Invoker<AsyncDataChangeListener,
-                                                  AsyncDataChangeEvent>() {
-
-                @SuppressWarnings("unchecked")
+    private static final Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
+            new Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent>() {
                 @Override
-                public void invokeListener( AsyncDataChangeListener listener,
-                                            AsyncDataChangeEvent notification ) {
-                    listener.onDataChanged(notification);
+                public void invokeListener(final DataChangeListenerRegistration<?> listener,
+                                           final DOMImmutableDataChangeEvent notification ) {
+                    final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> inst = listener.getInstance();
+                    if (inst != null) {
+                        inst.onDataChanged(notification);
+                    }
                 }
             };
 
@@ -88,24 +87,26 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     private final AtomicLong txCounter = new AtomicLong(0);
     private final ListeningExecutorService listeningExecutor;
 
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent>
-                                                              dataChangeListenerNotificationManager;
+    private final QueuedNotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> dataChangeListenerNotificationManager;
     private final ExecutorService dataChangeListenerExecutor;
 
+    private final ExecutorService domStoreExecutor;
+
     private final String name;
 
-    public InMemoryDOMDataStore(final String name, final ListeningExecutorService listeningExecutor,
+    private volatile AutoCloseable closeable;
+
+    public InMemoryDOMDataStore(final String name, final ExecutorService domStoreExecutor,
             final ExecutorService dataChangeListenerExecutor) {
-        this(name, listeningExecutor, dataChangeListenerExecutor,
-                InMemoryDOMDataStoreConfigProperties.DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
+        this(name, domStoreExecutor, dataChangeListenerExecutor,
+             InMemoryDOMDataStoreConfigProperties.DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
     }
 
-    public InMemoryDOMDataStore(final String name, final ListeningExecutorService listeningExecutor,
-            final ExecutorService dataChangeListenerExecutor, int maxDataChangeListenerQueueSize) {
+    public InMemoryDOMDataStore(final String name, final ExecutorService domStoreExecutor,
+            final ExecutorService dataChangeListenerExecutor, final int maxDataChangeListenerQueueSize) {
         this.name = Preconditions.checkNotNull(name);
-        this.listeningExecutor = Preconditions.checkNotNull(listeningExecutor);
-
+        this.domStoreExecutor = Preconditions.checkNotNull(domStoreExecutor);
+        this.listeningExecutor = MoreExecutors.listeningDecorator(this.domStoreExecutor);
         this.dataChangeListenerExecutor = Preconditions.checkNotNull(dataChangeListenerExecutor);
 
         dataChangeListenerNotificationManager =
@@ -114,6 +115,18 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                         "DataChangeListenerQueueMgr");
     }
 
+    public void setCloseable(AutoCloseable closeable) {
+        this.closeable = closeable;
+    }
+
+    public QueuedNotificationManager<?, ?> getDataChangeListenerNotificationManager() {
+        return dataChangeListenerNotificationManager;
+    }
+
+    public ExecutorService getDomStoreExecutor() {
+        return domStoreExecutor;
+    }
+
     @Override
     public final String getIdentifier() {
         return name;
@@ -148,7 +161,16 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     public void close() {
         ExecutorServiceUtil.tryGracefulShutdown(listeningExecutor, 30, TimeUnit.SECONDS);
         ExecutorServiceUtil.tryGracefulShutdown(dataChangeListenerExecutor, 30, TimeUnit.SECONDS);
+
+        if(closeable != null) {
+            try {
+                closeable.close();
+            } catch(Exception e) {
+                LOG.debug("Error closing instance", e);
+            }
+        }
     }
+
     @Override
     public <L extends AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
             final YangInstanceIdentifier path, final L listener, final DataChangeScope scope) {
@@ -175,8 +197,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                         .addCreated(path, data) //
                         .build();
 
-                new ChangeListenerNotifyTask(reg, event,
-                        dataChangeListenerNotificationManager).run();
+                dataChangeListenerNotificationManager.submitNotification(reg, event);
             }
         }
 
@@ -277,7 +298,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         }
 
         public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) {
-            // If commited transaction is latestOutstandingTx we clear
+            // If committed transaction is latestOutstandingTx we clear
             // latestOutstandingTx
             // field in order to base new transactions on Datastore Data Tree
             // directly.
@@ -379,8 +400,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                 @Override
                 public Void call() {
                     candidate = dataTree.prepare(modification);
-                    listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree,
-                            dataChangeListenerNotificationManager);
+                    listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree);
                     return null;
                 }
             });
@@ -389,7 +409,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         @Override
         public ListenableFuture<Void> abort() {
             candidate = null;
-            return Futures.immediateFuture(null);
+            return SUCCESSFUL_FUTURE;
         }
 
         @Override
@@ -402,14 +422,10 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
              */
             synchronized (this) {
                 dataTree.commit(candidate);
-
-                for (ChangeListenerNotifyTask task : listenerResolver.call()) {
-                    LOG.trace("Scheduling invocation of listeners: {}", task);
-                    task.run();
-                }
+                listenerResolver.resolve(dataChangeListenerNotificationManager);
             }
 
-            return Futures.immediateFuture(null);
+            return SUCCESSFUL_FUTURE;
         }
     }
 }
index 6e451ba12b20241d97c2826dce55d3870de0b9cb..be89d53a69b2b99b442c0820781959f30832666f 100644 (file)
@@ -20,15 +20,18 @@ public class InMemoryDOMDataStoreConfigProperties {
     public static final int DEFAULT_MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE = 1000;
     public static final int DEFAULT_MAX_DATA_CHANGE_EXECUTOR_POOL_SIZE = 20;
     public static final int DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE = 1000;
+    public static final int DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE = 5000;
 
     private static final InMemoryDOMDataStoreConfigProperties DEFAULT =
             create(DEFAULT_MAX_DATA_CHANGE_EXECUTOR_POOL_SIZE,
                     DEFAULT_MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE,
-                    DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
+                    DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE,
+                    DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE);
 
     private final int maxDataChangeExecutorQueueSize;
     private final int maxDataChangeExecutorPoolSize;
     private final int maxDataChangeListenerQueueSize;
+    private final int maxDataStoreExecutorQueueSize;
 
     /**
      * Constructs an instance with the given property values.
@@ -39,11 +42,22 @@ public class InMemoryDOMDataStoreConfigProperties {
      *            maximum queue size for the data change notification executor.
      * @param maxDataChangeListenerQueueSize
      *            maximum queue size for the data change listeners.
+     * @param maxDataStoreExecutorQueueSize
+     *            maximum queue size for the data store executor.
      */
+    public static InMemoryDOMDataStoreConfigProperties create(int maxDataChangeExecutorPoolSize,
+            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize,
+            int maxDataStoreExecutorQueueSize) {
+        return new InMemoryDOMDataStoreConfigProperties(maxDataChangeExecutorPoolSize,
+                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize,
+                maxDataStoreExecutorQueueSize);
+    }
+
     public static InMemoryDOMDataStoreConfigProperties create(int maxDataChangeExecutorPoolSize,
             int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize) {
         return new InMemoryDOMDataStoreConfigProperties(maxDataChangeExecutorPoolSize,
-                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize);
+                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize,
+                DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE);
     }
 
     /**
@@ -54,10 +68,12 @@ public class InMemoryDOMDataStoreConfigProperties {
     }
 
     private InMemoryDOMDataStoreConfigProperties(int maxDataChangeExecutorPoolSize,
-            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize) {
+            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize,
+            int maxDataStoreExecutorQueueSize) {
         this.maxDataChangeExecutorQueueSize = maxDataChangeExecutorQueueSize;
         this.maxDataChangeExecutorPoolSize = maxDataChangeExecutorPoolSize;
         this.maxDataChangeListenerQueueSize = maxDataChangeListenerQueueSize;
+        this.maxDataStoreExecutorQueueSize = maxDataStoreExecutorQueueSize;
     }
 
     /**
@@ -80,4 +96,11 @@ public class InMemoryDOMDataStoreConfigProperties {
     public int getMaxDataChangeListenerQueueSize() {
         return maxDataChangeListenerQueueSize;
     }
+
+    /**
+     * Returns the maximum queue size for the data store executor.
+     */
+    public int getMaxDataStoreExecutorQueueSize() {
+        return maxDataStoreExecutorQueueSize;
+    }
 }
index a3512743ed1a34acac5a1923983e06995e0d0f24..052fb2b89ba563c7be55612d75b48625f31de840 100644 (file)
@@ -9,13 +9,11 @@
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
-import com.google.common.util.concurrent.MoreExecutors;
 
 /**
  * A factory for creating InMemoryDOMDataStore instances.
@@ -61,9 +59,12 @@ public final class InMemoryDOMDataStoreFactory {
         ExecutorService dataChangeListenerExecutor = SpecialExecutors.newBlockingBoundedFastThreadPool(
                 dclExecutorMaxPoolSize, dclExecutorMaxQueueSize, name + "-DCL" );
 
+        ExecutorService domStoreExecutor = SpecialExecutors.newBoundedSingleThreadExecutor(
+                actualProperties.getMaxDataStoreExecutorQueueSize(), "DOMStore-" + name );
+
         InMemoryDOMDataStore dataStore = new InMemoryDOMDataStore(name,
-                MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()),
-                dataChangeListenerExecutor, actualProperties.getMaxDataChangeListenerQueueSize());
+                domStoreExecutor, dataChangeListenerExecutor,
+                actualProperties.getMaxDataChangeListenerQueueSize());
 
         if(schemaService != null) {
             schemaService.registerSchemaContextListener(dataStore);
index a4e8c86aa83f1b10f084f86f81a10feb08178d58..5fe9866b12ed0ec6e2a669de4cc7bd3b9957b641 100644 (file)
@@ -12,14 +12,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map.Entry;
-import java.util.concurrent.Callable;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 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.ListenerTree;
@@ -40,35 +36,23 @@ import org.slf4j.LoggerFactory;
  * Computes data change events for all affected registered listeners in data
  * tree.
  */
-final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
 
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
     private final DataTreeCandidate candidate;
     private final ListenerTree listenerRoot;
 
     private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
 
-    @SuppressWarnings("rawtypes")
-    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
-            final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr) {
+    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
         this.candidate = Preconditions.checkNotNull(candidate);
         this.listenerRoot = Preconditions.checkNotNull(listenerTree);
-        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
     }
 
     /**
-     * Resolves and creates Notification Tasks
-     *
-     * Implementation of done as Map-Reduce with two steps: 1. resolving events
-     * and their mapping to listeners 2. merging events affecting same listener
-     *
-     * @return An {@link Iterable} of Notification Tasks which needs to be executed in
-     *         order to delivery data change events.
+     * Resolves and submits notification tasks to the specified manager.
      */
-    @Override
-    public synchronized Iterable<ChangeListenerNotifyTask> call() {
+    public synchronized void resolve(final NotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> manager) {
         try (final Walker w = listenerRoot.getWalker()) {
             // Defensive: reset internal state
             collectedEvents = ArrayListMultimap.create();
@@ -81,7 +65,6 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
              * Convert to tasks, but be mindful of multiple values -- those indicate multiple
              * wildcard matches, which need to be merged.
              */
-            final Collection<ChangeListenerNotifyTask> ret = new ArrayList<>();
             for (Entry<DataChangeListenerRegistration<?>, Collection<DOMImmutableDataChangeEvent>> e : collectedEvents.asMap().entrySet()) {
                 final Collection<DOMImmutableDataChangeEvent> col = e.getValue();
                 final DOMImmutableDataChangeEvent event;
@@ -98,12 +81,8 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
                     event = col.iterator().next();
                 }
 
-                ret.add(new ChangeListenerNotifyTask(e.getKey(), event, notificationMgr));
+                manager.submitNotification(e.getKey(), event);
             }
-
-            // FIXME: so now we have tasks to submit tasks... Inception-style!
-            LOG.debug("Created tasks {}", ret);
-            return ret;
         }
     }
 
@@ -333,10 +312,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         return scope != null;
     }
 
-    @SuppressWarnings("rawtypes")
-    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate,
-            final ListenerTree listenerTree,
-            final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
-        return new ResolveDataChangeEventsTask(candidate, listenerTree, notificationMgr);
+    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+        return new ResolveDataChangeEventsTask(candidate, listenerTree);
     }
 }
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java
new file mode 100644 (file)
index 0000000..b3608ec
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.jmx;
+
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.md.sal.common.util.jmx.QueuedNotificationManagerMXBeanImpl;
+import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+/**
+ * Wrapper class for data store MXbeans.
+ *
+ * @author Thomas Pantelis
+ */
+public class InMemoryDataStoreStats implements AutoCloseable {
+
+    private final ThreadExecutorStatsMXBeanImpl notificationExecutorStatsBean;
+    private final ThreadExecutorStatsMXBeanImpl dataStoreExecutorStatsBean;
+    private final QueuedNotificationManagerMXBeanImpl notificationManagerStatsBean;
+
+    public InMemoryDataStoreStats(String mBeanType, QueuedNotificationManager<?, ?> manager,
+            ExecutorService dataStoreExecutor) {
+
+        this.notificationManagerStatsBean = new QueuedNotificationManagerMXBeanImpl(manager,
+                "notification-manager", mBeanType, null);
+        notificationManagerStatsBean.registerMBean();
+
+        this.notificationExecutorStatsBean = new ThreadExecutorStatsMXBeanImpl(manager.getExecutor(),
+                "notification-executor", mBeanType, null);
+        this.notificationExecutorStatsBean.registerMBean();
+
+        this.dataStoreExecutorStatsBean = new ThreadExecutorStatsMXBeanImpl(dataStoreExecutor,
+                "data-store-executor", mBeanType, null);
+        this.dataStoreExecutorStatsBean.registerMBean();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(notificationExecutorStatsBean != null) {
+            notificationExecutorStatsBean.unregisterMBean();
+        }
+
+        if(dataStoreExecutorStatsBean != null) {
+            dataStoreExecutorStatsBean.unregisterMBean();
+        }
+
+        if(notificationManagerStatsBean != null) {
+            notificationManagerStatsBean.unregisterMBean();
+        }
+    }
+}
index 17c86716d8c65183cf89130bbf9e8aa6c4f561e1..7d19a64446b519ea7795e86d81c6c431599ef7d9 100644 (file)
@@ -52,6 +52,12 @@ module opendaylight-inmemory-datastore-provider {
                 type uint16;
                 description "The maximum queue size for the data change listeners.";
             }
+
+            leaf max-data-store-executor-queue-size {
+                default 5000;
+                type uint16;
+                description "The maximum queue size for the data store executor.";
+            }
     }
 
     // Augments the 'configuration' choice node under modules/module.