}
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";
+ }
}
}
--- /dev/null
+/*
+ * 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<T extends AbstractCloseTracked<T>> implements CloseTracked<T> {
+
+ private final CloseTrackedTrait<T> closeTracker;
+
+ protected AbstractCloseTracked(CloseTrackedRegistry<T> 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();
+ }
+}
--- /dev/null
+/*
+ * 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.
+ *
+ * <p>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<T extends CloseTracked<T>> {
+
+ Instant getObjectCreated();
+
+ @Nullable Throwable getAllocationContext();
+
+}
--- /dev/null
+/*
+ * 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<T extends CloseTracked<T>> {
+
+ // 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<CloseTracked<T>> 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<T> closeTracked) {
+ tracked.add(closeTracked);
+ }
+
+ // package protected, not public; only CloseTrackedTrait invokes this
+ void remove(CloseTracked<T> 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?
+
+}
--- /dev/null
+/*
+ * 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.
+ *
+ * <p>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<T extends CloseTracked<T>> implements CloseTracked<T> {
+
+ private final Instant created;
+ private final @Nullable Throwable allocationContext;
+ private final CloseTrackedRegistry<T> closeTrackedRegistry;
+
+ public CloseTrackedTrait(CloseTrackedRegistry<T> 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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<String> 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<Void, TransactionCommitFailedException> submit() {
+ logOps();
+ return delegate.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ logOps();
+ return delegate.commit();
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return delegate.getIdentifier();
+ }
+}
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;
private final List<Watch> registrationWatches = new ArrayList<>();
private final List<Watch> writeWatches = new ArrayList<>();
+ private final boolean isDebugging;
+ private final CloseTrackedRegistry<TracingTransactionChain> transactionChainsRegistry;
+ private final CloseTrackedRegistry<TracingReadOnlyTransaction> readOnlyTransactionsRegistry;
+ private final CloseTrackedRegistry<TracingWriteTransaction> writeTransactionsRegistry;
+ private final CloseTrackedRegistry<TracingReadWriteTransaction> readWriteTransactionsRegistry;
private class Watch {
final String iidString;
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) {
}
- 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 {
@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
@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
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<TracingReadOnlyTransaction>
+ implements DOMDataReadOnlyTransaction {
private final DOMDataReadOnlyTransaction delegate;
private final TracingBroker tracingBroker;
- TracingReadOnlyTransaction(DOMDataReadOnlyTransaction delegate, TracingBroker tracingBroker) {
+ TracingReadOnlyTransaction(DOMDataReadOnlyTransaction delegate, TracingBroker tracingBroker,
+ CloseTrackedRegistry<TracingReadOnlyTransaction> readOnlyTransactionsRegistry) {
+ super(readOnlyTransactionsRegistry);
this.delegate = delegate;
this.tracingBroker = tracingBroker;
}
@Override
public void close() {
delegate.close();
+ super.removeFromTrackedRegistry();
}
}
*/
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 AbstractTracingWriteTransaction
+ implements DOMDataReadWriteTransaction, CloseTracked<TracingReadWriteTransaction> {
-class TracingReadWriteTransaction extends TracingWriteTransaction implements DOMDataReadWriteTransaction {
-
+ private final CloseTrackedTrait<TracingReadWriteTransaction> closeTracker;
private final DOMDataReadWriteTransaction delegate;
- TracingReadWriteTransaction(DOMDataReadWriteTransaction delegate, TracingBroker tracingBroker) {
+ TracingReadWriteTransaction(DOMDataReadWriteTransaction delegate, TracingBroker tracingBroker,
+ CloseTrackedRegistry<TracingReadWriteTransaction> readWriteTransactionsRegistry) {
super(delegate, tracingBroker);
+ this.closeTracker = new CloseTrackedTrait<>(readWriteTransactionsRegistry);
this.delegate = Objects.requireNonNull(delegate);
}
public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store, YangInstanceIdentifier yiid) {
return delegate.exists(store, yiid);
}
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ closeTracker.removeFromTrackedRegistry();
+ return super.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> 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();
+ }
}
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<TracingTransactionChain> implements DOMTransactionChain {
private final DOMTransactionChain delegate;
private final TracingBroker tracingBroker;
+ private final CloseTrackedRegistry<TracingReadOnlyTransaction> readOnlyTransactionsRegistry;
+ private final CloseTrackedRegistry<TracingWriteTransaction> writeTransactionsRegistry;
+ private final CloseTrackedRegistry<TracingReadWriteTransaction> readWriteTransactionsRegistry;
- TracingTransactionChain(DOMTransactionChain delegate, TracingBroker tracingBroker) {
+ TracingTransactionChain(DOMTransactionChain delegate, TracingBroker tracingBroker,
+ CloseTrackedRegistry<TracingTransactionChain> 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();
}
}
/*
- * 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,
*/
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<String> 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<TracingWriteTransaction> {
- 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<TracingWriteTransaction> closeTracker;
- private synchronized void logOps() {
- for (String log : logs) {
- tracingBroker.LOG.warn(log);
- }
- logs.clear();
+ TracingWriteTransaction(DOMDataWriteTransaction delegate, TracingBroker tracingBroker,
+ CloseTrackedRegistry<TracingWriteTransaction> 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<Void, TransactionCommitFailedException> 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<RpcResult<TransactionStatus>> 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<Void, TransactionCommitFailedException> submit() {
- logOps();
- return delegate.submit();
+ public Instant getObjectCreated() {
+ return closeTracker.getObjectCreated();
}
@Override
- public ListenableFuture<RpcResult<TransactionStatus>> commit() {
- logOps();
- return delegate.commit();
+ public Throwable getAllocationContext() {
+ return closeTracker.getAllocationContext();
}
- @Override
- public Object getIdentifier() {
- return delegate.getIdentifier();
- }
}