View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
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   * Another tracker implementation for testing purposes only.
23   *
24   * @author Ceki Gülcü
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         // both list should be sorted before removal attempts
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 }