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 java.util.Arrays;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
20 import java.util.concurrent.ConcurrentSkipListSet;
21 import javax.annotation.concurrent.ThreadSafe;
24 * Registry of {@link CloseTracked} instances.
26 * @author Michael Vorburger.ch
29 public class CloseTrackedRegistry<T extends CloseTracked<T>> {
31 private final Object anchor;
32 private final String createDescription;
34 private final Set<CloseTracked<T>> tracked = new ConcurrentSkipListSet<>(
35 (o1, o2) -> Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2)));
37 private final boolean isDebugContextEnabled;
43 * object where this registry is stored in, used for human output in
44 * logging and other output
45 * @param createDescription
46 * description of creator of instances of this registry, typically
47 * e.g. name of method in the anchor class
48 * @param isDebugContextEnabled
49 * whether or not the call stack should be preserved; this is (of
50 * course) an expensive operation, and should only be used during
53 public CloseTrackedRegistry(Object anchor, String createDescription, boolean isDebugContextEnabled) {
55 this.createDescription = createDescription;
56 this.isDebugContextEnabled = isDebugContextEnabled;
59 public boolean isDebugContextEnabled() {
60 return isDebugContextEnabled;
63 public Object getAnchor() {
67 public String getCreateDescription() {
68 return createDescription;
71 // package protected, not public; only CloseTrackedTrait invokes this
72 void add(CloseTracked<T> closeTracked) {
73 tracked.add(closeTracked);
76 // package protected, not public; only CloseTrackedTrait invokes this
77 void remove(CloseTracked<T> closeTracked) {
78 tracked.remove(closeTracked);
82 * Creates and returns a "report" of (currently) tracked but not (yet) closed
85 * @return Set of CloseTrackedRegistryReportEntry, of which each the stack trace
86 * element identifies a unique allocation context (or an empty List if
87 * debugContextEnabled is false), and value is the number of open
88 * instances created at that place in the code.
90 public Set<CloseTrackedRegistryReportEntry<T>> getAllUnique() {
91 Map<List<StackTraceElement>, Long> map = new HashMap<>();
92 Set<CloseTracked<T>> copyOfTracked = new HashSet<>(tracked);
93 for (CloseTracked<T> closeTracked : copyOfTracked) {
94 final StackTraceElement[] stackTraceArray = closeTracked.getAllocationContextStackTrace();
95 List<StackTraceElement> stackTraceElements =
96 stackTraceArray != null ? Arrays.asList(stackTraceArray) : Collections.emptyList();
97 map.merge(stackTraceElements, 1L, (oldValue, value) -> oldValue + 1);
100 Set<CloseTrackedRegistryReportEntry<T>> report = new HashSet<>();
101 map.forEach((stackTraceElements, number) -> {
102 copyOfTracked.stream().filter(closeTracked -> {
103 StackTraceElement[] closeTrackedStackTraceArray = closeTracked.getAllocationContextStackTrace();
104 List<StackTraceElement> closeTrackedStackTraceElements =
105 closeTrackedStackTraceArray != null ? asList(closeTrackedStackTraceArray) : emptyList();
106 return closeTrackedStackTraceElements.equals(stackTraceElements);
107 }).findAny().ifPresent(exampleCloseTracked -> {
108 report.add(new CloseTrackedRegistryReportEntry<>(exampleCloseTracked, number, stackTraceElements));