From: Michael Vorburger Date: Thu, 24 Aug 2017 20:37:51 +0000 (+0200) Subject: Bug 9060: TracingBroker with transaction-debug-context-enabled X-Git-Tag: release/oxygen~126 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=42d888e224d77ec341a0ac3a34c46ff215d63c44 Bug 9060: TracingBroker with transaction-debug-context-enabled This is one of a serious of commits which is part of a solution I'm proposing in order to be able to detect OOM issues such as Bug 9034, based on using the mdsal-trace DataBroker. Change-Id: If62b7f76ea03d8cabe0c5a2088983275cfe50e44 Signed-off-by: Michael Vorburger --- diff --git a/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang b/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang index ce72da7508..5c6b09b5bf 100644 --- a/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang +++ b/opendaylight/md-sal/mdsal-trace/api/src/main/yang/mdsaltrace.yang @@ -18,11 +18,18 @@ module mdsaltrace { } container config { + // TODO leaf enabled ... leaf-list registration-watches { type string; } leaf-list write-watches { type string; } + leaf transaction-debug-context-enabled { + default false; + type boolean; + description "Enable or disable transaction context debug. This will preserve the call site trace for + transactions, so that the original caller of un-close'd() transaction can be identified"; + } } } diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/AbstractCloseTracked.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/AbstractCloseTracked.java new file mode 100644 index 0000000000..5673c8e793 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/AbstractCloseTracked.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Red Hat, 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.trace.closetracker.impl; + +import java.time.Instant; +import javax.annotation.Nullable; + +/** + * Convenience abstract base class for {@link CloseTracked} implementors. + * + * @author Michael Vorburger.ch + */ +public abstract class AbstractCloseTracked> implements CloseTracked { + + private final CloseTrackedTrait closeTracker; + + protected AbstractCloseTracked(CloseTrackedRegistry transactionChainRegistry) { + this.closeTracker = new CloseTrackedTrait<>(transactionChainRegistry); + } + + protected void removeFromTrackedRegistry() { + closeTracker.removeFromTrackedRegistry(); + } + + @Override + public final Instant getObjectCreated() { + return closeTracker.getObjectCreated(); + } + + @Override + public @Nullable Throwable getAllocationContext() { + return closeTracker.getAllocationContext(); + } +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTracked.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTracked.java new file mode 100644 index 0000000000..6d8524fb3d --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTracked.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017 Red Hat, 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.trace.closetracker.impl; + +import java.time.Instant; +import javax.annotation.Nullable; + +/** + * Object which can track where it has been created, and if it has been correctly closed. + * + *

Includes preserving the context of the call stack which created this object, and the instant it was created. + * + * @author Michael Vorburger.ch + */ +public interface CloseTracked> { + + Instant getObjectCreated(); + + @Nullable Throwable getAllocationContext(); + +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedRegistry.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedRegistry.java new file mode 100644 index 0000000000..9364a57ae0 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedRegistry.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017 Red Hat, 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.trace.closetracker.impl; + +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Registry of {@link CloseTracked} instances. + * + * @author Michael Vorburger.ch + */ +@ThreadSafe +public class CloseTrackedRegistry> { + + // unused OK for now, at least we'll be able to see this in HPROF heap dumps and know what is which + private final @SuppressWarnings("unused") Object anchor; + private final @SuppressWarnings("unused") String createDescription; + + private final Set> tracked = new ConcurrentSkipListSet<>( + (o1, o2) -> o1.getObjectCreated().compareTo(o2.getObjectCreated())); + + private final boolean isDebugContextEnabled; + + /** + * Constructor. + * + * @param anchor + * object where this registry is stored in, used for human output in + * logging and other output + * @param createDescription + * description of creator of instances of this registry, typically + * e.g. name of method in the anchor class + * @param isDebugContextEnabled + * whether or not the call stack should be preserved; this is (of + * course) an expensive operation, and should only be used during + * troubleshooting + */ + public CloseTrackedRegistry(Object anchor, String createDescription, boolean isDebugContextEnabled) { + this.anchor = anchor; + this.createDescription = createDescription; + this.isDebugContextEnabled = isDebugContextEnabled; + } + + public boolean isDebugContextEnabled() { + return isDebugContextEnabled; + } + + // package protected, not public; only CloseTrackedTrait invokes this + void add(CloseTracked closeTracked) { + tracked.add(closeTracked); + } + + // package protected, not public; only CloseTrackedTrait invokes this + void remove(CloseTracked closeTracked) { + tracked.remove(closeTracked); + } + + // TODO Later add methods to dump & query what's not closed, by creation time, incl. creation stack trace + + // TODO we could even support add/close of Object instead of CloseTracked, by creating a wrapper? + +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedTrait.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedTrait.java new file mode 100644 index 0000000000..9f2237d269 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/CloseTrackedTrait.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 Red Hat, 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.trace.closetracker.impl; + +import java.time.Instant; +import java.util.Objects; +import javax.annotation.Nullable; + +/** + * Implementation of {@link CloseTracked} which can be used as a field in + * another class which implements {@link CloseTracked} and delegates its methods + * to this. + * + *

This is useful if that class already has another parent class. + * If it does not, then it's typically more convenient to just extend AbstractCloseTracked. + * + * @author Michael Vorburger.ch + */ +public class CloseTrackedTrait> implements CloseTracked { + + private final Instant created; + private final @Nullable Throwable allocationContext; + private final CloseTrackedRegistry closeTrackedRegistry; + + public CloseTrackedTrait(CloseTrackedRegistry transactionChainRegistry) { + this.created = Instant.now(); + if (transactionChainRegistry.isDebugContextEnabled()) { + this.allocationContext = new Throwable("allocated at"); + } else { + this.allocationContext = null; + } + this.closeTrackedRegistry = Objects.requireNonNull(transactionChainRegistry, "transactionChainRegistry"); + this.closeTrackedRegistry.add(this); + } + + @Override + public Instant getObjectCreated() { + return created; + } + + @Override + public Throwable getAllocationContext() { + return allocationContext; + } + + public void removeFromTrackedRegistry() { + closeTrackedRegistry.remove(this); + } + +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/package-info.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/package-info.java new file mode 100644 index 0000000000..60d9674549 --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/closetracker/impl/package-info.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2017 Red Hat, 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 + */ + +/** + * Utilities to track (non) "closing" of objects. + */ +// This generic infra may be moved somewhere else, later +@org.eclipse.jdt.annotation.NonNullByDefault +package org.opendaylight.controller.md.sal.trace.closetracker.impl; diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/AbstractTracingWriteTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/AbstractTracingWriteTransaction.java new file mode 100644 index 0000000000..a06ee5edfe --- /dev/null +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/AbstractTracingWriteTransaction.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Red Hat, 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.trace.dom.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +abstract class AbstractTracingWriteTransaction implements DOMDataWriteTransaction { + + private final DOMDataWriteTransaction delegate; + private final TracingBroker tracingBroker; + private final List logs = new ArrayList<>(); + + AbstractTracingWriteTransaction(DOMDataWriteTransaction delegate, TracingBroker tracingBroker) { + this.delegate = Objects.requireNonNull(delegate); + this.tracingBroker = Objects.requireNonNull(tracingBroker); + } + + private void recordOp(LogicalDatastoreType store, YangInstanceIdentifier yiid, String method, + NormalizedNode node) { + if (!tracingBroker.isWriteWatched(yiid, store)) { + return; + } + + final Object value = node != null ? node.getValue() : null; + + if (value != null && value instanceof ImmutableSet && ((Set)value).isEmpty()) { + if (TracingBroker.LOG.isDebugEnabled()) { + TracingBroker.LOG.debug("Empty data set write to {}", tracingBroker.toPathString(yiid)); + } + } else { + StringBuilder sb = new StringBuilder(); + sb.append("Method \"").append(method); + sb.append("\" to ").append(store); + sb.append(" at ").append(tracingBroker.toPathString(yiid)).append('.'); + sb.append(" Data: "); + if (node != null) { + sb.append(node.getValue()); + } else { + sb.append("null"); + } + sb.append(" Stack:").append(tracingBroker.getStackSummary()); + synchronized (this) { + logs.add(sb.toString()); + } + } + } + + private synchronized void logOps() { + synchronized (this) { + logs.forEach(log -> TracingBroker.LOG.warn(log)); + logs.clear(); + } + } + + @Override + public void put(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { + recordOp(store, yiid, "put", node); + delegate.put(store, yiid, node); + } + + @Override + public void merge(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { + recordOp(store, yiid, "merge", node); + delegate.merge(store, yiid, node); + } + + @Override + public boolean cancel() { + synchronized (this) { + logs.clear(); + } + boolean result = delegate.cancel(); + return result; + } + + @Override + public void delete(LogicalDatastoreType store, YangInstanceIdentifier yiid) { + recordOp(store, yiid, "delete", null); + delegate.delete(store, yiid); + } + + @Override + public CheckedFuture submit() { + logOps(); + return delegate.submit(); + } + + @Override + public ListenableFuture> commit() { + logOps(); + return delegate.commit(); + } + + @Override + public Object getIdentifier() { + return delegate.getIdentifier(); + } +} diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java index 7feb361db2..2e16b0ca0f 100644 --- a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingBroker.java @@ -28,6 +28,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; 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.CloseTrackedRegistry; 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; @@ -99,6 +100,11 @@ public class TracingBroker implements TracingDOMDataBroker { private final List registrationWatches = new ArrayList<>(); private final List writeWatches = new ArrayList<>(); + private final boolean isDebugging; + private final CloseTrackedRegistry transactionChainsRegistry; + private final CloseTrackedRegistry readOnlyTransactionsRegistry; + private final CloseTrackedRegistry writeTransactionsRegistry; + private final CloseTrackedRegistry readWriteTransactionsRegistry; private class Watch { final String iidString; @@ -161,6 +167,16 @@ public class TracingBroker implements TracingDOMDataBroker { this.delegate = Objects.requireNonNull(delegate); this.codec = Objects.requireNonNull(codec); configure(config); + + if (config.isTransactionDebugContextEnabled() != null) { + this.isDebugging = config.isTransactionDebugContextEnabled(); + } 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); } private void configure(Config config) { @@ -244,8 +260,8 @@ public class TracingBroker implements TracingDOMDataBroker { } - void toPathString(YangInstanceIdentifier yiid, StringBuilder sb) { - InstanceIdentifier iid = codec.fromYangInstanceIdentifier(yiid); + private void toPathString(YangInstanceIdentifier yiid, StringBuilder sb) { + InstanceIdentifier iid = codec.fromYangInstanceIdentifier(yiid); if (null == iid) { reconstructIidPathString(yiid, sb); } else { @@ -278,12 +294,12 @@ public class TracingBroker implements TracingDOMDataBroker { @Override public DOMDataReadWriteTransaction newReadWriteTransaction() { - return new TracingReadWriteTransaction(delegate.newReadWriteTransaction(), this); + return new TracingReadWriteTransaction(delegate.newReadWriteTransaction(), this, readWriteTransactionsRegistry); } @Override public DOMDataWriteTransaction newWriteOnlyTransaction() { - return new TracingWriteTransaction(delegate.newWriteOnlyTransaction(), this); + return new TracingWriteTransaction(delegate.newWriteOnlyTransaction(), this, writeTransactionsRegistry); } @Override @@ -299,12 +315,13 @@ public class TracingBroker implements TracingDOMDataBroker { @Override public DOMTransactionChain createTransactionChain(TransactionChainListener transactionChainListener) { - return new TracingTransactionChain(delegate.createTransactionChain(transactionChainListener), this); + return new TracingTransactionChain( + delegate.createTransactionChain(transactionChainListener), this, transactionChainsRegistry); } @Override public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return new TracingReadOnlyTransaction(delegate.newReadOnlyTransaction(), this); + return new TracingReadOnlyTransaction(delegate.newReadOnlyTransaction(), this, readOnlyTransactionsRegistry); } @Nonnull diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadOnlyTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadOnlyTransaction.java index a93f7f9c43..6bc6d66493 100644 --- a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadOnlyTransaction.java +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadOnlyTransaction.java @@ -12,15 +12,21 @@ import com.google.common.util.concurrent.CheckedFuture; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.trace.closetracker.impl.AbstractCloseTracked; +import org.opendaylight.controller.md.sal.trace.closetracker.impl.CloseTrackedRegistry; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -class TracingReadOnlyTransaction implements DOMDataReadOnlyTransaction { +class TracingReadOnlyTransaction + extends AbstractCloseTracked + implements DOMDataReadOnlyTransaction { private final DOMDataReadOnlyTransaction delegate; private final TracingBroker tracingBroker; - TracingReadOnlyTransaction(DOMDataReadOnlyTransaction delegate, TracingBroker tracingBroker) { + TracingReadOnlyTransaction(DOMDataReadOnlyTransaction delegate, TracingBroker tracingBroker, + CloseTrackedRegistry readOnlyTransactionsRegistry) { + super(readOnlyTransactionsRegistry); this.delegate = delegate; this.tracingBroker = tracingBroker; } @@ -44,6 +50,7 @@ class TracingReadOnlyTransaction implements DOMDataReadOnlyTransaction { @Override public void close() { delegate.close(); + super.removeFromTrackedRegistry(); } } diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java index b770e5da37..68c4786317 100644 --- a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingReadWriteTransaction.java @@ -9,19 +9,32 @@ package org.opendaylight.controller.md.sal.trace.dom.impl; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.time.Instant; import java.util.Objects; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +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.CloseTrackedTrait; +import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -class TracingReadWriteTransaction extends TracingWriteTransaction implements DOMDataReadWriteTransaction { +class TracingReadWriteTransaction + extends AbstractTracingWriteTransaction + implements DOMDataReadWriteTransaction, CloseTracked { + private final CloseTrackedTrait closeTracker; private final DOMDataReadWriteTransaction delegate; - TracingReadWriteTransaction(DOMDataReadWriteTransaction delegate, TracingBroker tracingBroker) { + TracingReadWriteTransaction(DOMDataReadWriteTransaction delegate, TracingBroker tracingBroker, + CloseTrackedRegistry readWriteTransactionsRegistry) { super(delegate, tracingBroker); + this.closeTracker = new CloseTrackedTrait<>(readWriteTransactionsRegistry); this.delegate = Objects.requireNonNull(delegate); } @@ -35,4 +48,32 @@ class TracingReadWriteTransaction extends TracingWriteTransaction implements DOM public CheckedFuture exists(LogicalDatastoreType store, YangInstanceIdentifier yiid) { return delegate.exists(store, yiid); } + + @Override + public CheckedFuture submit() { + closeTracker.removeFromTrackedRegistry(); + return super.submit(); + } + + @Override + public ListenableFuture> commit() { + closeTracker.removeFromTrackedRegistry(); + return super.commit(); + } + + @Override + public boolean cancel() { + closeTracker.removeFromTrackedRegistry(); + return super.cancel(); + } + + @Override + public Instant getObjectCreated() { + return closeTracker.getObjectCreated(); + } + + @Override + public Throwable getAllocationContext() { + return closeTracker.getAllocationContext(); + } } diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingTransactionChain.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingTransactionChain.java index b158dbcf4a..c8f4539cc7 100644 --- a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingTransactionChain.java +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingTransactionChain.java @@ -12,35 +12,52 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; 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.closetracker.impl.AbstractCloseTracked; +import org.opendaylight.controller.md.sal.trace.closetracker.impl.CloseTrackedRegistry; -class TracingTransactionChain implements DOMTransactionChain { +class TracingTransactionChain extends AbstractCloseTracked implements DOMTransactionChain { private final DOMTransactionChain delegate; private final TracingBroker tracingBroker; + private final CloseTrackedRegistry readOnlyTransactionsRegistry; + private final CloseTrackedRegistry writeTransactionsRegistry; + private final CloseTrackedRegistry readWriteTransactionsRegistry; - TracingTransactionChain(DOMTransactionChain delegate, TracingBroker tracingBroker) { + TracingTransactionChain(DOMTransactionChain delegate, TracingBroker tracingBroker, + CloseTrackedRegistry transactionChainsRegistry) { + super(transactionChainsRegistry); this.delegate = Objects.requireNonNull(delegate); this.tracingBroker = Objects.requireNonNull(tracingBroker); + + final boolean isDebugging = transactionChainsRegistry.isDebugContextEnabled(); + this.readOnlyTransactionsRegistry = new CloseTrackedRegistry<>(this, "newReadOnlyTransaction", isDebugging); + this.writeTransactionsRegistry = new CloseTrackedRegistry<>(this, "newWriteOnlyTransaction", isDebugging); + this.readWriteTransactionsRegistry = new CloseTrackedRegistry<>(this, "newReadWriteTransaction", isDebugging); } @Override + @SuppressWarnings("resource") public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return new TracingReadOnlyTransaction(delegate.newReadOnlyTransaction(), tracingBroker); + final DOMDataReadOnlyTransaction tx = delegate.newReadOnlyTransaction(); + return new TracingReadOnlyTransaction(tx, tracingBroker, readOnlyTransactionsRegistry); } @Override public DOMDataReadWriteTransaction newReadWriteTransaction() { - return new TracingReadWriteTransaction(delegate.newReadWriteTransaction(), tracingBroker); + return new TracingReadWriteTransaction(delegate.newReadWriteTransaction(), tracingBroker, + readWriteTransactionsRegistry); } @Override public DOMDataWriteTransaction newWriteOnlyTransaction() { - return new TracingWriteTransaction(delegate.newWriteOnlyTransaction(), tracingBroker); + final DOMDataWriteTransaction tx = delegate.newWriteOnlyTransaction(); + return new TracingWriteTransaction(tx, tracingBroker, writeTransactionsRegistry); } @Override public void close() { delegate.close(); + super.removeFromTrackedRegistry(); } } diff --git a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java index a895e983c2..123129ce15 100644 --- a/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java +++ b/opendaylight/md-sal/mdsal-trace/dom-impl/src/main/java/org/opendaylight/controller/md/sal/trace/dom/impl/TracingWriteTransaction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved. + * Copyright (c) 2017 Red Hat, 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, @@ -7,111 +7,54 @@ */ package org.opendaylight.controller.md.sal.trace.dom.impl; -import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; - +import java.time.Instant; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +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.CloseTrackedTrait; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -class TracingWriteTransaction implements DOMDataWriteTransaction { - - private final DOMDataWriteTransaction delegate; - private final TracingBroker tracingBroker; - private final List logs = new ArrayList<>(); - - TracingWriteTransaction(DOMDataWriteTransaction delegate, TracingBroker tracingBroker) { - this.delegate = Objects.requireNonNull(delegate); - this.tracingBroker = Objects.requireNonNull(tracingBroker); - } - - private void recordOp(LogicalDatastoreType store, YangInstanceIdentifier yiid, - String method, NormalizedNode node) { - if (!tracingBroker.isWriteWatched(yiid, store)) { - return; - } - Object value = null; - if (node != null) { - value = node.getValue(); - } +class TracingWriteTransaction extends AbstractTracingWriteTransaction + implements CloseTracked { - if (value != null && value instanceof ImmutableSet && ((Set)value).isEmpty()) { - if (tracingBroker.LOG.isDebugEnabled()) { - tracingBroker.LOG.debug("Empty data set write to {}", tracingBroker.toPathString(yiid)); - } - } else { - StringBuilder sb = new StringBuilder(); - sb.append("Method \"").append(method); - sb.append("\" to ").append(store); - sb.append(" at ").append(tracingBroker.toPathString(yiid)).append('.'); - sb.append(" Data: "); - if (node != null) { - sb.append(node.getValue()); - } else { - sb.append("null"); - } - sb.append(" Stack:").append(tracingBroker.getStackSummary()); - synchronized (this) { - logs.add(sb.toString()); - } - } - } + private final CloseTrackedTrait closeTracker; - private synchronized void logOps() { - for (String log : logs) { - tracingBroker.LOG.warn(log); - } - logs.clear(); + TracingWriteTransaction(DOMDataWriteTransaction delegate, TracingBroker tracingBroker, + CloseTrackedRegistry writeTransactionsRegistry) { + super(delegate, tracingBroker); + this.closeTracker = new CloseTrackedTrait<>(writeTransactionsRegistry); } @Override - public void put(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { - recordOp(store, yiid, "put", node); - delegate.put(store, yiid, node); + public CheckedFuture submit() { + closeTracker.removeFromTrackedRegistry(); + return super.submit(); } @Override - public void merge(LogicalDatastoreType store, YangInstanceIdentifier yiid, NormalizedNode node) { - recordOp(store, yiid, "merge", node); - delegate.merge(store, yiid, node); + public ListenableFuture> commit() { + closeTracker.removeFromTrackedRegistry(); + return super.commit(); } @Override public boolean cancel() { - logs.clear(); - return delegate.cancel(); - } - - @Override - public void delete(LogicalDatastoreType store, YangInstanceIdentifier yiid) { - recordOp(store, yiid, "delete", null); - delegate.delete(store, yiid); + closeTracker.removeFromTrackedRegistry(); + return super.cancel(); } @Override - public CheckedFuture submit() { - logOps(); - return delegate.submit(); + public Instant getObjectCreated() { + return closeTracker.getObjectCreated(); } @Override - public ListenableFuture> commit() { - logOps(); - return delegate.commit(); + public Throwable getAllocationContext() { + return closeTracker.getAllocationContext(); } - @Override - public Object getIdentifier() { - return delegate.getIdentifier(); - } }