1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.spi;
15
16 import ch.qos.logback.core.CoreConstants;
17 import ch.qos.logback.core.helpers.CyclicBuffer;
18
19 import java.util.*;
20
21
22
23
24
25
26 public class CyclicBufferTrackerT<E> implements ComponentTracker<CyclicBuffer<E>> {
27
28 int bufferSize = CyclicBufferTracker.DEFAULT_BUFFER_SIZE;
29 int maxComponents = CyclicBufferTracker.DEFAULT_NUMBER_OF_BUFFERS;
30
31 List<TEntry<E>> liveList = new LinkedList<TEntry<E>>();
32 List<TEntry<E>> lingererList = new LinkedList<TEntry<E>>();
33
34 long lastCheck = 0;
35
36 private TEntry<E> getEntry(List<TEntry<E>> list, String k) {
37 for (int i = 0; i < list.size(); i++) {
38 TEntry<E> te = list.get(i);
39 if (te.key.equals(k)) {
40 return te;
41 }
42 }
43 return null;
44 }
45
46 private TEntry<E> getFromEitherList(String key) {
47 TEntry<E> entry = getEntry(liveList, key);
48 if (entry != null)
49 return entry;
50 else {
51 return getEntry(lingererList, key);
52 }
53 }
54
55 private List<String> keysAsOrderedList(List<TEntry<E>> list) {
56 Collections.sort(list);
57 List<String> result = new LinkedList<String>();
58 for (int i = 0; i < list.size(); i++) {
59 TEntry<E> te = list.get(i);
60 result.add(te.key);
61 }
62 return result;
63 }
64
65 List<String> liveKeysAsOrderedList() {
66 return keysAsOrderedList(liveList);
67 }
68
69 List<String> lingererKeysAsOrderedList() {
70 return keysAsOrderedList(lingererList);
71 }
72
73 public Set<String> allKeys() {
74 HashSet<String> allKeys = new HashSet<String>();
75 for (TEntry<E> e : liveList)
76 allKeys.add(e.key);
77 for (TEntry<E> e : lingererList)
78 allKeys.add(e.key);
79 return allKeys;
80 }
81
82 public Collection<CyclicBuffer<E>> allComponents() {
83 List<CyclicBuffer<E>> allComponents = new ArrayList<CyclicBuffer<E>>();
84 for (TEntry<E> e : liveList)
85 allComponents.add(e.value);
86 for (TEntry<E> e : lingererList)
87 allComponents.add(e.value);
88
89 return allComponents;
90 }
91
92 public CyclicBuffer<E> find(String key) {
93 TEntry<E> te = getFromEitherList(key);
94 if (te == null)
95 return null;
96 else
97 return te.value;
98 }
99
100 public CyclicBuffer<E> getOrCreate(String key, long timestamp) {
101 TEntry<E> te = getFromEitherList(key);
102 if (te == null) {
103 CyclicBuffer<E> cb = new CyclicBuffer<E>(bufferSize);
104 te = new TEntry<E>(key, cb, timestamp);
105 liveList.add(te);
106 if (liveList.size() > maxComponents) {
107 Collections.sort(liveList);
108 liveList.remove(0);
109 }
110 } else {
111 te.timestamp = timestamp;
112 Collections.sort(liveList);
113 }
114 return te.value;
115 }
116
117 public void endOfLife(String k) {
118 TEntry<E> te = null;
119 boolean found = false;
120 for (int i = 0; i < liveList.size(); i++) {
121 te = liveList.get(i);
122 if (te.key.equals(k)) {
123 liveList.remove(i);
124 found = true;
125 break;
126 }
127 }
128 if (found) {
129 lingererList.add(te);
130 }
131 }
132
133 private boolean isEntryStale(TEntry<E> entry, long now) {
134 return ((entry.timestamp + DEFAULT_TIMEOUT) < now);
135 }
136
137 private boolean isEntryDoneLingering(TEntry<E> tEntry, long now) {
138 return ((tEntry.timestamp + AbstractComponentTracker.LINGERING_TIMEOUT) < now);
139 }
140
141 public void removeStaleComponents(long now) {
142 if (isTooSoonForRemovalIteration(now))
143 return;
144
145 Collections.sort(liveList);
146 Collections.sort(lingererList);
147 removeComponentsInExcessFromMainList();
148 removeStaleComponentsFromMainList(now);
149 removeStaleComponentsFromLingerersList(now);
150 }
151
152 private void removeComponentsInExcessFromMainList() {
153 while (liveList.size() > maxComponents) {
154 liveList.remove(0);
155 }
156 }
157
158 private void removeStaleComponentsFromMainList(long now) {
159 while (liveList.size() != 0 && isEntryStale(liveList.get(0), now)) {
160 liveList.remove(0);
161 }
162 }
163
164 private void removeStaleComponentsFromLingerersList(long now) {
165 while (lingererList.size() != 0 && isEntryDoneLingering(lingererList.get(0), now)) {
166 lingererList.remove(0);
167 }
168 }
169
170 private boolean isTooSoonForRemovalIteration(long now) {
171 if (lastCheck + CoreConstants.MILLIS_IN_ONE_SECOND > now) {
172 return true;
173 }
174 lastCheck = now;
175 return false;
176 }
177
178 public int getComponentCount() {
179 return liveList.size() + lingererList.size();
180 }
181
182
183
184 private class TEntry<X> implements Comparable<TEntry<?>> {
185
186 String key;
187 CyclicBuffer<E> value;
188 long timestamp;
189
190 TEntry(String k, CyclicBuffer<E> v, long timestamp) {
191 this.key = k;
192 this.value = v;
193 this.timestamp = timestamp;
194 }
195
196 @Override
197 public int hashCode() {
198 final int prime = 31;
199 int result = 1;
200 result = prime * result + ((key == null) ? 0 : key.hashCode());
201 return result;
202 }
203
204 public int compareTo(TEntry<?> o) {
205 if (!(o instanceof TEntry)) {
206 throw new IllegalArgumentException("arguments must be of type " + TEntry.class);
207 }
208
209 TEntry<?> other = (TEntry<?>) o;
210 if (timestamp > other.timestamp) {
211 return 1;
212 }
213 if (timestamp == other.timestamp) {
214 return 0;
215 }
216 return -1;
217 }
218
219 @Override
220 public boolean equals(Object obj) {
221 if (this == obj)
222 return true;
223 if (obj == null)
224 return false;
225 if (getClass() != obj.getClass())
226 return false;
227 @SuppressWarnings("unchecked")
228 final TEntry<?> other = (TEntry<?>) obj;
229 if (key == null) {
230 if (other.key != null)
231 return false;
232 } else if (!key.equals(other.key))
233 return false;
234 if (value == null) {
235 if (other.value != null)
236 return false;
237 } else if (!value.equals(other.value))
238 return false;
239 return true;
240 }
241
242 @Override
243 public String toString() {
244 return "(" + key + ", " + value + ")";
245 }
246 }
247 }