This adds a "minimum open number of transactions" option to
trace:transactions and print out a clear final message indicating
whether any leaks were found or not.
JIRA: CONTROLLER-1765
Change-Id: Ie9f4ee263ed7defcb84c8b82dc8ec6f1f81ba07d
Signed-off-by: Michael Vorburger <vorburger@redhat.com>
Signed-off-by: Stephen Kitt <skitt@redhat.com>
/**
* Prints a human-readable "report" of all opened but not closed transactions,
* including transactions chains and transactions opened by them, onto the printStream.
/**
* Prints a human-readable "report" of all opened but not closed transactions,
* including transactions chains and transactions opened by them, onto the printStream.
+ * @param minOpenTransactions minimum open number of transactions (leaks with fewer are not printed)
* @return true if there were any open transactions, false if none
*/
* @return true if there were any open transactions, false if none
*/
- boolean printOpenTransactions(PrintStream printStream);
+ boolean printOpenTransactions(PrintStream printStream, int minOpenTransactions);
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.core</artifactId>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.core</artifactId>
- <!-- TODO remove <version> once https://git.opendaylight.org/gerrit/#/c/62397/ is merged-->
- <version>4.0.9</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<exclusions>
<exclusion>
<groupId>*</groupId>
import java.util.List;
import org.apache.karaf.shell.api.action.Action;
import java.util.List;
import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
+ "if transaction-debug-context-enabled is true in mdsaltrace_config.xml")
public class PrintOpenTransactionsCommand implements Action {
+ "if transaction-debug-context-enabled is true in mdsaltrace_config.xml")
public class PrintOpenTransactionsCommand implements Action {
+ @Argument(index = 0, name = "minOpenTransactions", required = false, multiValued = false,
+ description = "Minimum open number of transactions (leaks with fewer are suppressed)")
+ Integer minOpenTransactions = 1;
+
@Reference
private List<TracingDOMDataBroker> tracingDOMDataBrokers;
@Reference
private List<TracingDOMDataBroker> tracingDOMDataBrokers;
@Override
@SuppressWarnings("checkstyle:RegexpSingleLineJava")
public Object execute() {
@Override
@SuppressWarnings("checkstyle:RegexpSingleLineJava")
public Object execute() {
+ boolean hasFound = false;
for (TracingDOMDataBroker tracingDOMDataBroker : tracingDOMDataBrokers) {
for (TracingDOMDataBroker tracingDOMDataBroker : tracingDOMDataBrokers) {
- tracingDOMDataBroker.printOpenTransactions(System.out);
+ hasFound |= tracingDOMDataBroker.printOpenTransactions(System.out, minOpenTransactions);
+ }
+ if (hasFound) {
+ System.out.println(
+ "Actually did find real leaks with more than " + minOpenTransactions + " open transactions");
+ } else {
+ System.out.println(
+ "Did not find any real leaks with more than " + minOpenTransactions + " open transactions");
return child.startsWith(parent.substring(parentOffset), childOffset);
}
return child.startsWith(parent.substring(parentOffset), childOffset);
}
- @SuppressWarnings("checkstyle:hiddenField")
+ @SuppressWarnings({ "checkstyle:hiddenField", "hiding" })
public boolean subtreesOverlap(YangInstanceIdentifier iid, LogicalDatastoreType store) {
if (this.store != null && !this.store.equals(store)) {
return false;
public boolean subtreesOverlap(YangInstanceIdentifier iid, LogicalDatastoreType store) {
if (this.store != null && !this.store.equals(store)) {
return false;
return isParent(iidString, otherIidString) || isParent(otherIidString, iidString);
}
return isParent(iidString, otherIidString) || isParent(otherIidString, iidString);
}
- @SuppressWarnings("checkstyle:hiddenField")
+ @SuppressWarnings({ "checkstyle:hiddenField", "hiding" })
public boolean eventIsOfInterest(YangInstanceIdentifier iid, LogicalDatastoreType store) {
if (this.store != null && !this.store.equals(store)) {
return false;
public boolean eventIsOfInterest(YangInstanceIdentifier iid, LogicalDatastoreType store) {
if (this.store != null && !this.store.equals(store)) {
return false;
- public boolean printOpenTransactions(PrintStream ps) {
+ public boolean printOpenTransactions(PrintStream ps, int minOpenTXs) {
if (transactionChainsRegistry.getAllUnique().isEmpty()
&& readOnlyTransactionsRegistry.getAllUnique().isEmpty()
&& writeTransactionsRegistry.getAllUnique().isEmpty()
if (transactionChainsRegistry.getAllUnique().isEmpty()
&& readOnlyTransactionsRegistry.getAllUnique().isEmpty()
&& writeTransactionsRegistry.getAllUnique().isEmpty()
ps.println("[NB: If no stack traces are shown below, then "
+ "enable transaction-debug-context-enabled in mdsaltrace_config.xml]");
ps.println();
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, " ");
+ // Flag to track if we really found any real leaks with more (or equal) to minOpenTXs
+ boolean hasFound = print(readOnlyTransactionsRegistry, ps, " ", minOpenTXs);
+ hasFound |= print(writeTransactionsRegistry, ps, " ", minOpenTXs);
+ hasFound |= print(readWriteTransactionsRegistry, ps, " ", minOpenTXs);
// Now print details for each non-closed TransactionChain
// incl. in turn each ones own read/Write[Only]TransactionsRegistry
// Now print details for each non-closed TransactionChain
// incl. in turn each ones own read/Write[Only]TransactionsRegistry
ps.println(" " + transactionChainsRegistry.getAnchor() + " : "
+ transactionChainsRegistry.getCreateDescription());
}
ps.println(" " + transactionChainsRegistry.getAnchor() + " : "
+ transactionChainsRegistry.getCreateDescription());
}
- entries.forEach(entry -> {
+ for (CloseTrackedRegistryReportEntry<TracingTransactionChain> entry : entries) {
ps.println(" " + entry.getNumberAddedNotRemoved() + "x TransactionChains opened but not closed here:");
printStackTraceElements(ps, " ", entry.getStackTraceElements());
@SuppressWarnings("resource")
TracingTransactionChain txChain = (TracingTransactionChain) entry
.getExampleCloseTracked().getRealCloseTracked();
ps.println(" " + entry.getNumberAddedNotRemoved() + "x TransactionChains opened but not closed here:");
printStackTraceElements(ps, " ", entry.getStackTraceElements());
@SuppressWarnings("resource")
TracingTransactionChain txChain = (TracingTransactionChain) entry
.getExampleCloseTracked().getRealCloseTracked();
- printRegistryOpenTransactions(txChain.getReadOnlyTransactionsRegistry(), ps, " ");
- printRegistryOpenTransactions(txChain.getWriteTransactionsRegistry(), ps, " ");
- printRegistryOpenTransactions(txChain.getReadWriteTransactionsRegistry(), ps, " ");
- });
+ hasFound |= print(txChain.getReadOnlyTransactionsRegistry(), ps, " ", minOpenTXs);
+ hasFound |= print(txChain.getWriteTransactionsRegistry(), ps, " ", minOpenTXs);
+ hasFound |= print(txChain.getReadWriteTransactionsRegistry(), ps, " ", minOpenTXs);
+ }
- private <T extends CloseTracked<T>> void printRegistryOpenTransactions(
- CloseTrackedRegistry<T> registry, PrintStream ps, String indent) {
+ private <T extends CloseTracked<T>> boolean print(
+ CloseTrackedRegistry<T> registry, PrintStream ps, String indent, int minOpenTransactions) {
Set<CloseTrackedRegistryReportEntry<T>> unsorted = registry.getAllUnique();
Set<CloseTrackedRegistryReportEntry<T>> unsorted = registry.getAllUnique();
+ if (unsorted.size() < minOpenTransactions) {
+ return false;
+ }
List<CloseTrackedRegistryReportEntry<T>> entries = new ArrayList<>(unsorted);
entries.sort((o1, o2) -> Long.compare(o2.getNumberAddedNotRemoved(), o1.getNumberAddedNotRemoved()));
List<CloseTrackedRegistryReportEntry<T>> entries = new ArrayList<>(unsorted);
entries.sort((o1, o2) -> Long.compare(o2.getNumberAddedNotRemoved(), o1.getNumberAddedNotRemoved()));
if (!entries.isEmpty()) {
ps.println();
}
if (!entries.isEmpty()) {
ps.println();
}
}
private void printStackTraceElements(PrintStream ps, String indent, List<StackTraceElement> stackTraceElements) {
}
private void printStackTraceElements(PrintStream ps, String indent, List<StackTraceElement> stackTraceElements) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
- boolean printReturnValue = tracingBroker.printOpenTransactions(ps);
+ boolean printReturnValue = tracingBroker.printOpenTransactions(ps, 1);
String output = new String(baos.toByteArray(), UTF_8);
assertThat(printReturnValue).isTrue();
String output = new String(baos.toByteArray(), UTF_8);
assertThat(printReturnValue).isTrue();