2 * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.md.sal.trace.closetracker.impl;
10 import static java.util.Arrays.asList;
11 import static java.util.Collections.emptyList;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.Arrays;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
22 import java.util.concurrent.ConcurrentSkipListSet;
23 import javax.annotation.concurrent.ThreadSafe;
26 * Registry of {@link CloseTracked} instances.
28 * @author Michael Vorburger.ch
31 public class CloseTrackedRegistry<T extends CloseTracked<T>> {
33 private final Object anchor;
34 private final String createDescription;
36 private final Set<CloseTracked<T>> tracked =
37 new ConcurrentSkipListSet<>(Comparator.comparingInt(System::identityHashCode));
39 private final boolean isDebugContextEnabled;
45 * object where this registry is stored in, used for human output in
46 * logging and other output
47 * @param createDescription
48 * description of creator of instances of this registry, typically
49 * e.g. name of method in the anchor class
50 * @param isDebugContextEnabled
51 * whether or not the call stack should be preserved; this is (of
52 * course) an expensive operation, and should only be used during
55 public CloseTrackedRegistry(Object anchor, String createDescription, boolean isDebugContextEnabled) {
57 this.createDescription = createDescription;
58 this.isDebugContextEnabled = isDebugContextEnabled;
61 public boolean isDebugContextEnabled() {
62 return isDebugContextEnabled;
65 public Object getAnchor() {
69 public String getCreateDescription() {
70 return createDescription;
73 // package protected, not public; only CloseTrackedTrait invokes this
74 void add(CloseTracked<T> closeTracked) {
75 tracked.add(closeTracked);
78 // package protected, not public; only CloseTrackedTrait invokes this
79 void remove(CloseTracked<T> closeTracked) {
80 tracked.remove(closeTracked);
84 * Creates and returns a "report" of (currently) tracked but not (yet) closed
87 * @return Set of CloseTrackedRegistryReportEntry, of which each the stack trace
88 * element identifies a unique allocation context (or an empty List if
89 * debugContextEnabled is false), and value is the number of open
90 * instances created at that place in the code.
92 // For some reason, FB sees 'map' as useless but it clearly isn't.
93 @SuppressFBWarnings("UC_USELESS_OBJECT")
94 public Set<CloseTrackedRegistryReportEntry<T>> getAllUnique() {
95 Map<List<StackTraceElement>, Long> map = new HashMap<>();
96 Set<CloseTracked<T>> copyOfTracked = new HashSet<>(tracked);
97 for (CloseTracked<T> closeTracked : copyOfTracked) {
98 final StackTraceElement[] stackTraceArray = closeTracked.getAllocationContextStackTrace();
99 List<StackTraceElement> stackTraceElements =
100 stackTraceArray != null ? Arrays.asList(stackTraceArray) : Collections.emptyList();
101 map.merge(stackTraceElements, 1L, (oldValue, value) -> oldValue + 1);
104 Set<CloseTrackedRegistryReportEntry<T>> report = new HashSet<>();
105 map.forEach((stackTraceElements, number) -> copyOfTracked.stream().filter(closeTracked -> {
106 StackTraceElement[] closeTrackedStackTraceArray = closeTracked.getAllocationContextStackTrace();
107 List<StackTraceElement> closeTrackedStackTraceElements =
108 closeTrackedStackTraceArray != null ? asList(closeTrackedStackTraceArray) : emptyList();
109 return closeTrackedStackTraceElements.equals(stackTraceElements);
110 }).findAny().ifPresent(exampleCloseTracked -> report.add(
111 new CloseTrackedRegistryReportEntry<>(exampleCloseTracked, number, stackTraceElements))));