1 | package de.uka.ipd.sdq.probespec.framework.garbagecollection; |
2 | |
3 | import java.util.HashMap; |
4 | import java.util.Map; |
5 | |
6 | import org.apache.log4j.Logger; |
7 | |
8 | import de.uka.ipd.sdq.probespec.framework.ISampleBlackboard; |
9 | import de.uka.ipd.sdq.probespec.framework.ProbeSetAndRequestContext; |
10 | import de.uka.ipd.sdq.probespec.framework.calculator.Calculator; |
11 | |
12 | /** |
13 | * A garbage collector for the {@link ISampleBlackboard}. It cleans up obsolete |
14 | * samples stored at the blackboard. |
15 | * <p> |
16 | * Generally a sample is obsolete if there are no {@link Calculator}s interested |
17 | * in the sample anymore. Assuming that calculators are solely interested in |
18 | * samples from the same region, all samples belonging to a particular region |
19 | * can be cleaned up as soon as it is assured that there will be no new samples |
20 | * within that region. |
21 | * <p> |
22 | * A region can be represented by a thread, a process or something else like |
23 | * specified by the class parameter T. |
24 | * <p> |
25 | * The cleanup starts as soon as the population within a region turns to 0. Then |
26 | * it is assumed that there will be no new samples within that region. The |
27 | * population is increased by calling {@link #enterRegion(Object)} and decreased |
28 | * by calling {@link #leaveRegion(Object)}. |
29 | * |
30 | * @param <T> |
31 | * denotes the type representing regions. |
32 | * |
33 | * @author Philipp Merkle |
34 | * |
35 | */ |
36 | public abstract class RegionBasedGarbageCollector<T> implements |
37 | IRegionBasedGarbageCollector<T> { |
38 | |
39 | public static Logger logger = Logger |
40 | .getLogger(RegionBasedGarbageCollector.class); |
41 | |
42 | // Counts how often a regions has been entered but not left yet (the |
43 | // region's population) |
44 | // Maps regionId to process count within region. |
45 | private Map<T, Integer> regionCountMap; |
46 | |
47 | /** |
48 | * Default constructor. Constructs a garbage collector for the specified |
49 | * blackboard. |
50 | * |
51 | * @param blackboard |
52 | * the blackboard which is to keep clean by the garbage |
53 | * collector. |
54 | */ |
55 | public RegionBasedGarbageCollector() { |
56 | // initialise maps |
57 | regionCountMap = new HashMap<T, Integer>(); |
58 | } |
59 | |
60 | /** |
61 | * Extracts the region id for the specified |
62 | * {@link ProbeSetAndRequestContext}. |
63 | * |
64 | * @param c |
65 | * the {@link ProbeSetAndRequestContext} |
66 | * @return the extracted region representative |
67 | */ |
68 | public abstract T obtainRegionId(ProbeSetAndRequestContext c); |
69 | |
70 | /** |
71 | * Informs the garbage collector that the specified region has been entered. |
72 | * |
73 | * @param regionId |
74 | * the id representing the entered region |
75 | */ |
76 | @Override |
77 | public void enterRegion(T regionId) { |
78 | if (increasePopulation(regionId) == 1) { |
79 | logger.debug("Region " + regionId + " opened."); |
80 | } |
81 | } |
82 | |
83 | /** |
84 | * Informs the garbage collector that the specified region has been left. |
85 | * |
86 | * As soon as the population reaches 0, the cleanup starts. |
87 | * |
88 | * @param regionId |
89 | * the id representing the left region |
90 | */ |
91 | @Override |
92 | public void leaveRegion(T regionId) { |
93 | if (decreasePopulation(regionId) == 0) { |
94 | collectRegionSamples(regionId); |
95 | regionCountMap.remove(regionId); |
96 | logger.debug("Region " + regionId + " closed."); |
97 | } |
98 | } |
99 | |
100 | /** |
101 | * Informs the garbage collector that a new sample has been arrived that |
102 | * eventually needs to be collected. Only the observed blackboard should |
103 | * call this method. |
104 | */ |
105 | |
106 | /** |
107 | * Deletes all probe samples taken within the specified region from the |
108 | * blackboard. |
109 | * |
110 | * @param regionId |
111 | * the region id whose probe samples are to be deleted |
112 | */ |
113 | public abstract void collectRegionSamples(T regionId); |
114 | |
115 | /** |
116 | * Changes the population count of the specified region. |
117 | * |
118 | * @param regionId |
119 | * the id representing the region |
120 | * @param amount |
121 | * the amount to add (positive value) or subtract (negative |
122 | * value) |
123 | * @return the changed population count |
124 | */ |
125 | private int changePopulationCounter(T regionId, int amount) { |
126 | int counter = 0; |
127 | if (regionCountMap.containsKey(regionId)) { |
128 | counter = regionCountMap.get(regionId); |
129 | } |
130 | counter += amount; |
131 | regionCountMap.put(regionId, counter); |
132 | return counter; |
133 | } |
134 | |
135 | /** |
136 | * Increases the population count of the specified region by one. |
137 | * |
138 | * @param regionId |
139 | * the id representing the region |
140 | * @return the increased population count |
141 | */ |
142 | private int increasePopulation(T regionId) { |
143 | return changePopulationCounter(regionId, 1); |
144 | } |
145 | |
146 | /** |
147 | * Decreases the population count of the specified region by one. |
148 | * |
149 | * @param regionId |
150 | * the id representing the region |
151 | * @return the decreased population count |
152 | */ |
153 | private int decreasePopulation(T regionId) { |
154 | return changePopulationCounter(regionId, -1); |
155 | } |
156 | |
157 | } |