KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > objectserver > core > impl > MarkAndSweepGarbageCollector


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.objectserver.core.impl;
5
6 import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
7
8 import com.tc.logging.TCLogger;
9 import com.tc.logging.TCLogging;
10 import com.tc.object.ObjectID;
11 import com.tc.objectserver.api.GCStats;
12 import com.tc.objectserver.api.ObjectManager;
13 import com.tc.objectserver.api.ObjectManagerEventListener;
14 import com.tc.objectserver.core.api.Filter;
15 import com.tc.objectserver.core.api.GarbageCollector;
16 import com.tc.objectserver.core.api.ManagedObject;
17 import com.tc.objectserver.impl.GCLogger;
18 import com.tc.objectserver.impl.GCStatsImpl;
19 import com.tc.objectserver.l1.api.ClientStateManager;
20 import com.tc.objectserver.managedobject.ManagedObjectChangeListener;
21 import com.tc.text.PrettyPrintable;
22 import com.tc.text.PrettyPrinter;
23 import com.tc.util.ObjectIDSet2;
24 import com.tc.util.SyncObjectIdSet;
25 import com.tc.util.concurrent.LifeCycleState;
26 import com.tc.util.concurrent.NullLifeCycleState;
27 import com.tc.util.concurrent.StoppableThread;
28
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Set JavaDoc;
35
36 /**
37  */

38 public class MarkAndSweepGarbageCollector implements GarbageCollector {
39
40   private static final TCLogger logger = TCLogging.getLogger(MarkAndSweepGarbageCollector.class);
41   private final GCLogger gcLogger;
42
43   private final List eventListeners = new CopyOnWriteArrayList();
44   private static final ChangeCollector NULL_CHANGE_COLLECTOR = new ChangeCollector() {
45                                                                public void changed(ObjectID changedObject,
46                                                                                    ObjectID oldReference,
47                                                                                    ObjectID newReference) {
48                                                                  return;
49                                                                }
50
51                                                                public void addNewReferencesTo(Set set) {
52                                                                  return;
53                                                                }
54
55                                                                public PrettyPrinter prettyPrint(PrettyPrinter out) {
56                                                                  return out.println("NULL CHANGE COLLECTOR");
57                                                                }
58                                                              };
59   private static final Filter NULL_FILTER = new Filter() {
60                                                                public boolean shouldVisit(ObjectID referencedObject) {
61                                                                  return true;
62                                                                }
63                                                              };
64   private final static LifeCycleState NULL_LIFECYCLE_STATE = new NullLifeCycleState();
65   private static final int GC_SLEEP = 1;
66   private static final int GC_PAUSING = 2;
67   private static final int GC_PAUSED = 3;
68
69   private int state = GC_SLEEP;
70   private LifeCycleState lifeCycleState;
71   private int gcIteration = 0;
72   private volatile ChangeCollector referenceCollector = NULL_CHANGE_COLLECTOR;
73   private final ObjectManager objectManager;
74   private final ClientStateManager stateManager;
75   private LifeCycleState gcState = new NullLifeCycleState();
76
77   public MarkAndSweepGarbageCollector(ObjectManager objectManager, ClientStateManager stateManager, boolean verboseGC) {
78     this.gcLogger = new GCLogger(logger, verboseGC);
79     this.objectManager = objectManager;
80     this.stateManager = stateManager;
81   }
82
83   private Set rescue(final Set gcResults, final List rescueTimes) {
84     long start = System.currentTimeMillis();
85     Set rescueIds = new ObjectIDSet2();
86     stateManager.addAllReferencedIdsTo(rescueIds);
87     int stateManagerIds = rescueIds.size();
88
89     addNewReferencesTo(rescueIds);
90     int referenceCollectorIds = rescueIds.size() - stateManagerIds;
91
92     logger.debug("rescueIds: " + rescueIds.size() + ", stateManagerIds: " + stateManagerIds
93                  + ", additional referenceCollectorIds: " + referenceCollectorIds);
94
95     rescueIds.retainAll(gcResults);
96
97     Filter rescueFilter = new Filter() {
98       public boolean shouldVisit(ObjectID referencedObject) {
99         return gcResults.contains(referencedObject);
100       }
101     };
102
103     Set rv = collect(rescueFilter, rescueIds, gcResults, gcState);
104     rescueTimes.add(new Long JavaDoc(System.currentTimeMillis() - start));
105     return rv;
106   }
107
108   public void gc() {
109     GCStatsImpl gcStats = new GCStatsImpl(gcIteration);
110
111     gcLogger.log_GCStart(gcIteration);
112     long startMillis = System.currentTimeMillis();
113     gcStats.setStartTime(startMillis);
114
115     Set rootIDs = null;
116     SyncObjectIdSet managedIDs = null;
117
118     this.referenceCollector = new NewReferenceCollector();
119     
120     rootIDs = objectManager.getRootIDs();
121     managedIDs = objectManager.getAllObjectIDs();
122     
123     gcStats.setBeginObjectCount(managedIDs.size());
124
125     if (gcState.isStopRequested()) { return; }
126
127     gcLogger.log_markStart(managedIDs);
128     Set gcResults = collect(NULL_FILTER, rootIDs, managedIDs, gcState);
129     gcLogger.log_markResults(gcResults);
130
131     if (gcState.isStopRequested()) { return; }
132
133     List rescueTimes = new ArrayList();
134
135     gcLogger.log_rescue(1, gcResults);
136     gcResults = rescue(gcResults, rescueTimes);
137
138     requestGCPause();
139
140     gcLogger.log_quiescing();
141
142     if (gcState.isStopRequested()) { return; }
143
144     objectManager.waitUntilReadyToGC();
145
146     if (gcState.isStopRequested()) { return; }
147
148     long pauseStartMillis = System.currentTimeMillis();
149     gcLogger.log_paused();
150
151     // Assert.eval("No pending lookups allowed during GC pause.", pending.size() == 0);
152

153     gcLogger.log_rescue(2, gcResults);
154
155     gcStats.setCandidateGarbageCount(gcResults.size());
156     Set toDelete = rescue(new ObjectIDSet2(gcResults), rescueTimes);
157
158     if (gcState.isStopRequested()) { return; }
159     gcLogger.log_sweep(toDelete);
160
161     gcLogger.log_notifyGCComplete();
162     
163     this.referenceCollector = NULL_CHANGE_COLLECTOR;
164     
165     // Delete Garbage
166
objectManager.notifyGCComplete(toDelete);
167     
168     gcStats.setActualGarbageCount(toDelete.size());
169     long endMillis = System.currentTimeMillis();
170     gcStats.setElapsedTime(endMillis - startMillis);
171     gcLogger.log_GCComplete(startMillis, pauseStartMillis, rescueTimes, endMillis, gcIteration);
172
173     gcLogger.push(gcStats);
174     fireGCCompleteEvent(gcStats);
175     gcIteration++;
176   }
177
178   public void changed(ObjectID changedObject, ObjectID oldReference, ObjectID newReference) {
179     referenceCollector.changed(changedObject, oldReference, newReference);
180   }
181
182   public Set collect(Filter filter, Collection JavaDoc rootIds, Set managedObjectIds) {
183     return collect(filter, rootIds, managedObjectIds, NULL_LIFECYCLE_STATE);
184   }
185
186   public Set collect(Filter filter, Collection JavaDoc rootIds, Set managedObjectIds, LifeCycleState aLifeCycleState) {
187     this.lifeCycleState = aLifeCycleState;
188
189     long start = System.currentTimeMillis();
190     logstart_collect(rootIds, managedObjectIds);
191
192     for (Iterator JavaDoc i = rootIds.iterator(); i.hasNext();) {
193       ObjectID rootId = (ObjectID) i.next();
194       managedObjectIds.remove(rootId);
195       if (lifeCycleState.isStopRequested()) return Collections.EMPTY_SET;
196       collectRoot(filter, rootId, managedObjectIds);
197     }
198
199     profile_collect(start);
200
201     return managedObjectIds;
202   }
203
204   private void collectRoot(Filter filter, ObjectID rootId, Set managedObjectIds) {
205     Set toBeVisited = new ObjectIDSet2();
206     toBeVisited.add(rootId);
207
208     while (!toBeVisited.isEmpty()) {
209
210       for (Iterator JavaDoc i = new ObjectIDSet2(toBeVisited).iterator(); i.hasNext();) {
211         ObjectID id = (ObjectID) i.next();
212         if (lifeCycleState.isStopRequested()) return;
213         ManagedObject obj = objectManager.getObjectByID(id);
214         toBeVisited.remove(id);
215
216         for (Iterator JavaDoc r = obj.getObjectReferences().iterator(); r.hasNext();) {
217           ObjectID mid = (ObjectID) r.next();
218           if (mid.isNull() || !managedObjectIds.contains(mid)) continue;
219           if (filter.shouldVisit(mid)) toBeVisited.add(mid);
220           managedObjectIds.remove(mid);
221         }
222         objectManager.releaseReadOnly(obj);
223       }
224     }
225   }
226
227   public synchronized boolean isPausingOrPaused() {
228     return GC_SLEEP != state;
229   }
230
231   public synchronized boolean isPaused() {
232     return state == GC_PAUSED;
233   }
234
235   public synchronized void requestGCPause() {
236     state = GC_PAUSING;
237   }
238
239   public synchronized void notifyReadyToGC() {
240     if (state == GC_PAUSING) {
241       state = GC_PAUSED;
242     }
243   }
244
245   public synchronized void notifyGCComplete() {
246     state = GC_SLEEP;
247   }
248
249   public synchronized PrettyPrinter prettyPrint(PrettyPrinter out) {
250     return out.print(getClass().getName()).print("[state: ").print(stateToString()).print("]");
251   }
252
253   private String JavaDoc stateToString() {
254     switch (state) {
255       case GC_SLEEP:
256         return "GC_SLEEP";
257       case GC_PAUSING:
258         return "GC_PAUSING";
259       case GC_PAUSED:
260         return "GC_PAUSED";
261       default:
262         return "UNKNOWN";
263     }
264   }
265
266   private void logstart_collect(Collection JavaDoc rootIds, Set managedObjectIds) {
267     if (logger.isDebugEnabled()) logger.debug("collect(): rootIds=" + rootIds.size() + ", managedObjectIds="
268                                               + managedObjectIds.size());
269   }
270
271   private void profile_collect(long start) {
272     if (logger.isDebugEnabled()) logger.debug("collect: " + (System.currentTimeMillis() - start) + " ms.");
273   }
274
275   private static class NewReferenceCollector implements ChangeCollector {
276
277     Set newReferences = new ObjectIDSet2();
278
279     public void changed(ObjectID changedObject, ObjectID oldReference, ObjectID newReference) {
280       synchronized (newReferences) {
281         newReferences.add(newReference);
282       }
283     }
284
285     public void addNewReferencesTo(Set set) {
286       long start = System.currentTimeMillis();
287       synchronized (newReferences) {
288         set.addAll(newReferences);
289       }
290       profile_addNewReferencesTo(start);
291     }
292
293     private void profile_addNewReferencesTo(long start) {
294       if (logger.isDebugEnabled()) {
295         logger.debug("addNewReferencesTo: " + (System.currentTimeMillis() - start) + " ms.");
296       }
297     }
298
299     public PrettyPrinter prettyPrint(PrettyPrinter out) {
300       synchronized (newReferences) {
301         return out.println("newReferences: ").println(newReferences);
302       }
303     }
304   }
305
306   private interface ChangeCollector extends ManagedObjectChangeListener, PrettyPrintable {
307     public void addNewReferencesTo(Set set);
308   }
309
310   public void addNewReferencesTo(Set rescueIds) {
311     referenceCollector.addNewReferencesTo(rescueIds);
312   }
313
314   public void start() {
315     gcState.start();
316   }
317
318   public void stop() {
319     int count = 0;
320     while (!this.gcState.stopAndWait(5000) && (count < 6)) {
321       count++;
322       logger.warn("GC Thread did not stop");
323     }
324   }
325
326   public void setState(StoppableThread st) {
327     this.gcState = st;
328   }
329
330   private void fireGCCompleteEvent(GCStats gcStats) {
331     for (Iterator JavaDoc iter = eventListeners.iterator(); iter.hasNext();) {
332       try {
333         ObjectManagerEventListener listener = (ObjectManagerEventListener) iter.next();
334         listener.garbageCollectionComplete(gcStats);
335       } catch (Exception JavaDoc e) {
336         if (logger.isDebugEnabled()) {
337           logger.debug(e);
338         } else {
339           logger.warn("Exception in GCComplete event callback: " + e.getMessage());
340         }
341       }
342     }
343   }
344
345   public void addListener(ObjectManagerEventListener listener) {
346     eventListeners.add(listener);
347   }
348
349   public GCStats[] getGarbageCollectorStats() {
350     return gcLogger.getGarbageCollectorStats();
351   }
352 }
Popular Tags