--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright © 2017 Red Hat 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>bundle-parent</artifactId>
+ <version>1.8.2-SNAPSHOT</version>
+ <relativePath />
+ </parent>
+
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-trace-cli</artifactId>
+ <version>1.5.2-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-trace-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <!-- This bundle works with Karaf 3 and 4.0, see https://wiki.opendaylight.org/view/Karaf_4_migration#Karaf_CLI_commands -->
+ <Import-Package>
+ org.apache.karaf.shell.commands;version="[3.0.0,4.1)",
+ org.apache.karaf.shell.console;version="[3.0.0,4.1)",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <configuration>
+ <failOnError>true</failOnError>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import javax.annotation.Nonnull;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
import org.opendaylight.controller.md.sal.trace.api.TracingDOMDataBroker;
+import org.opendaylight.controller.md.sal.trace.closetracker.impl.CloseTracked;
import org.opendaylight.controller.md.sal.trace.closetracker.impl.CloseTrackedRegistry;
+import org.opendaylight.controller.md.sal.trace.closetracker.impl.CloseTrackedRegistryReportEntry;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsaltrace.rev160908.Config;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
*
* <p>In addition, it (optionally) can also keep track of the stack trace of all new transaction allocations
* (including TransactionChains, and transactions created in turn from them), in order to detect and report leaks
- * results from transactions which were not closed.
+ * from transactions which were not closed.
*
* <h1>Wiring:</h1>
* TracingBroker is designed to be easy to use. In fact, for bundles using Blueprint to inject their DataBroker
* {@code
* <dependency>
* <groupId>org.opendaylight.controller</groupId>
- * <artifactId>mdsal-trace-features</artifactId>
+ * <artifactId>features-mdsal-trace</artifactId>
+ * <version>1.7.0-SNAPSHOT</version>
* <classifier>features</classifier>
* <type>xml</type>
* <scope>runtime</scope>
- * <version>0.1.6-SNAPSHOT</version>
* </dependency>
* }
* </pre>
* </li>
* <li>
- * Then just load the odl-mdsal-trace feature before your feature and you're done.
+ * Then just "feature:install odl-mdsal-trace" before you install your "real" feature(s) and you're done.
+ * Beware that with Karaf 4 due to <a href="https://bugs.opendaylight.org/show_bug.cgi?id=9068">Bug 9068</a>
+ * you'll probably have to use feature:install's --no-auto-refresh flag when installing your "real" feature.
* </li>
* </ol>
* This works because the mdsaltrace-impl bundle registers its service implementing DOMDataBroker with a higher
} else {
this.isDebugging = false;
}
- this.transactionChainsRegistry = new CloseTrackedRegistry<>(this, "createTransactionChain", isDebugging);
- this.readOnlyTransactionsRegistry = new CloseTrackedRegistry<>(this, "newReadOnlyTransaction", isDebugging);
- this.writeTransactionsRegistry = new CloseTrackedRegistry<>(this, "newWriteOnlyTransaction", isDebugging);
- this.readWriteTransactionsRegistry = new CloseTrackedRegistry<>(this, "newReadWriteTransaction", isDebugging);
+ final String db = "DataBroker";
+ this.transactionChainsRegistry = new CloseTrackedRegistry<>(db, "createTransactionChain()", isDebugging);
+ this.readOnlyTransactionsRegistry = new CloseTrackedRegistry<>(db, "newReadOnlyTransaction()", isDebugging);
+ this.writeTransactionsRegistry = new CloseTrackedRegistry<>(db, "newWriteOnlyTransaction()", isDebugging);
+ this.readWriteTransactionsRegistry = new CloseTrackedRegistry<>(db, "newReadWriteTransaction()", isDebugging);
}
private void configure(Config config) {
return res;
}
+ @Override
public boolean printOpenTransactions(PrintStream ps) {
if (transactionChainsRegistry.getAllUnique().isEmpty()
&& readOnlyTransactionsRegistry.getAllUnique().isEmpty()
return false;
}
- ps.println(getClass().getSimpleName() + " found not yet (or never..) closed transaction[chain]s");
+ ps.println(getClass().getSimpleName() + " found some not yet (or never..) closed transaction[chain]s!");
+ ps.println("[NB: If no stack traces are shown below, then "
+ + "enable transaction-debug-context-enabled in mdsaltrace_config.xml]");
ps.println();
- printRegistryOpenTransactions(readOnlyTransactionsRegistry, ps, "");
- printRegistryOpenTransactions(writeTransactionsRegistry, ps, "");
- printRegistryOpenTransactions(readWriteTransactionsRegistry, ps, "");
+ printRegistryOpenTransactions(readOnlyTransactionsRegistry, ps, " ");
+ printRegistryOpenTransactions(writeTransactionsRegistry, ps, " ");
+ printRegistryOpenTransactions(readWriteTransactionsRegistry, ps, " ");
// Now print details for each non-closed TransactionChain
// incl. in turn each ones own read/Write[Only]TransactionsRegistry
- ps.println(transactionChainsRegistry.getCreateDescription());
- transactionChainsRegistry.getAllUnique().forEach(entry -> {
- ps.println(" " + entry.getNumberAddedNotRemoved() + "x TransactionChains opened, which are not closed:");
- entry.getStackTraceElements().forEach(line -> ps.println(" " + line));
+ Set<CloseTrackedRegistryReportEntry<TracingTransactionChain>>
+ entries = transactionChainsRegistry.getAllUnique();
+ if (!entries.isEmpty()) {
+ ps.println(" " + transactionChainsRegistry.getAnchor() + " : "
+ + transactionChainsRegistry.getCreateDescription());
+ }
+ entries.forEach(entry -> {
+ ps.println(" " + entry.getNumberAddedNotRemoved() + "x TransactionChains opened but not closed here:");
+ entry.getStackTraceElements().forEach(line -> ps.println(" " + line));
@SuppressWarnings("resource")
TracingTransactionChain txChain = (TracingTransactionChain) entry
.getExampleCloseTracked().getRealCloseTracked();
- printRegistryOpenTransactions(txChain.getReadOnlyTransactionsRegistry(), ps, " ");
- printRegistryOpenTransactions(txChain.getWriteTransactionsRegistry(), ps, " ");
- printRegistryOpenTransactions(txChain.getReadWriteTransactionsRegistry(), ps, " ");
+ printRegistryOpenTransactions(txChain.getReadOnlyTransactionsRegistry(), ps, " ");
+ printRegistryOpenTransactions(txChain.getWriteTransactionsRegistry(), ps, " ");
+ printRegistryOpenTransactions(txChain.getReadWriteTransactionsRegistry(), ps, " ");
});
ps.println();
return true;
}
- private void printRegistryOpenTransactions(CloseTrackedRegistry<?> registry, PrintStream ps, String indent) {
- ps.println(indent + registry.getCreateDescription());
- registry.getAllUnique().forEach(entry -> {
+ private <T extends CloseTracked<T>> void printRegistryOpenTransactions(
+ CloseTrackedRegistry<T> registry, PrintStream ps, String indent) {
+ Set<CloseTrackedRegistryReportEntry<T>> entries = registry.getAllUnique();
+ if (!entries.isEmpty()) {
+ ps.println(indent + registry.getAnchor() + " : " + registry.getCreateDescription());
+ }
+ entries.forEach(entry -> {
ps.println(indent + " " + entry.getNumberAddedNotRemoved()
+ "x transactions opened here, which are not closed:");
- entry.getStackTraceElements().forEach(line -> ps.print(" " + line));
+ entry.getStackTraceElements().forEach(line -> ps.println(indent + " " + line));
});
- ps.println();
+ if (!entries.isEmpty()) {
+ ps.println();
+ }
}
}