KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > MasterTableGarbageCollector


1 /**
2  * com.mckoi.database.MasterTableGarbageCollector 28 Nov 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import com.mckoi.util.BlockIntegerList;
28 import com.mckoi.debug.*;
29 import java.io.IOException JavaDoc;
30
31 /**
32  * A row garbage collector for a master table data source that manages
33  * garbage collection over a MasterTableDataSource object. Each time a row
34  * is committed deleted from a master table, this object is notified. When
35  * the master table has no root locks on it, then the garbage collector
36  * can kick in and mark all deleted rows as reclaimable.
37  *
38  * @author Tobias Downer
39  */

40
41 final class MasterTableGarbageCollector {
42
43   /**
44    * The MasterTableDataSource that this collector is managing.
45    */

46   private MasterTableDataSource data_source;
47
48   /**
49    * If this is true, then a full sweep of the table is due to reclaim all
50    * deleted rows from the table.
51    */

52   private boolean full_sweep_due;
53
54   /**
55    * The list of all rows from the master table that we have been notified
56    * of being deleted.
57    * <p>
58    * NOTE: This list shouldn't get too large. If it does, we should clear it
59    * and toggle the 'full_sweep_due' variable to true.
60    */

61   private BlockIntegerList deleted_rows;
62
63   /**
64    * The time when the last garbage collection event occurred.
65    */

66   private long last_garbage_success_event;
67   private long last_garbage_try_event;
68   
69   /**
70    * Constructs the garbage collector.
71    */

72   MasterTableGarbageCollector(MasterTableDataSource data_source) {
73     this.data_source = data_source;
74     full_sweep_due = false;
75     deleted_rows = new BlockIntegerList();
76     last_garbage_success_event = System.currentTimeMillis();
77     last_garbage_try_event = -1;
78   }
79
80   /**
81    * Returns the DebugLogger object that we can use to log debug messages.
82    */

83   public final DebugLogger Debug() {
84     return data_source.Debug();
85   }
86
87   /**
88    * Called by the MasterTableDataSoruce to notify the collector that a row
89    * has been marked as committed deleted.
90    * <p>
91    * SYNCHRONIZATION: We must be synchronized over 'data_source' when this
92    * is called. (This is guarenteed if called from MasterTableDataSource).
93    */

94   void markRowAsDeleted(int row_index) {
95     if (full_sweep_due == false) {
96       boolean b = deleted_rows.uniqueInsertSort(row_index);
97       if (b == false) {
98         throw new Error JavaDoc("Row marked twice for deletion.");
99       }
100     }
101   }
102
103   /**
104    * Called by the MasterTableDataSoruce to notify the collector to do a full
105    * sweep and remove of records in the table at the next scheduled collection.
106    * <p>
107    * SYNCHRONIZATION: We must be synchronized over 'data_source' when this
108    * is called. (This is guarenteed if called from MasterTableDataSource).
109    */

110   void markFullSweep() {
111     full_sweep_due = true;
112     if (deleted_rows.size() > 0) {
113       deleted_rows = new BlockIntegerList();
114     }
115   }
116
117   /**
118    * Performs the actual garbage collection event. This is called by the
119    * CollectionEvent object. Note that it synchronizes over the master table
120    * data source object.
121    * <p>
122    * If 'force' is true, then the collection event is forced even if there are
123    * root locks or transaction changes pending. It is only recommended that
124    * force is true when the table is shut down.
125    */

126   void performCollectionEvent(boolean force) {
127
128     try {
129       int check_count = 0;
130       int delete_count = 0;
131
132       // Synchronize over the master data table source so no other threads
133
// can interfere when we collect this information.
134
synchronized (data_source) {
135
136         if (data_source.isClosed()) {
137           return;
138         }
139
140         // If root is locked, or has transaction changes pending, then we
141
// can't delete any rows marked as deleted because they could be
142
// referenced by transactions or result sets.
143
if (force ||
144             (!data_source.isRootLocked() &&
145              !data_source.hasTransactionChangesPending())) {
146
147           last_garbage_success_event = System.currentTimeMillis();
148           last_garbage_try_event = -1;
149
150           // Are we due a full sweep?
151
if (full_sweep_due) {
152             int raw_row_count = data_source.rawRowCount();
153             for (int i = 0; i < raw_row_count; ++i) {
154               // Synchronized in data_source.
155
boolean b = data_source.hardCheckAndReclaimRow(i);
156               if (b) {
157                 ++delete_count;
158               }
159               ++check_count;
160             }
161             full_sweep_due = false;
162           }
163           else {
164             // Are there any rows marked as deleted?
165
int size = deleted_rows.size();
166             if (size > 0) {
167               // Go remove all rows marked as deleted.
168
for (int i = 0; i < size; ++i) {
169                 int row_index = deleted_rows.get(i);
170                 // Synchronized in data_source.
171
data_source.hardRemoveRow(row_index);
172                 ++delete_count;
173                 ++check_count;
174               }
175             }
176             deleted_rows = new BlockIntegerList();
177           }
178
179           if (check_count > 0) {
180             if (Debug().isInterestedIn(Lvl.INFORMATION)) {
181               Debug().write(Lvl.INFORMATION, this,
182                         "Row GC: [" + data_source.getName() +
183                         "] check_count=" + check_count +
184                         " delete count=" + delete_count);
185               Debug().write(Lvl.INFORMATION, this,
186                         "GC row sweep deleted " + delete_count + " rows.");
187             }
188           }
189
190         } // if not roots locked and not transactions pending
191

192       } // synchronized
193
}
194     catch (IOException JavaDoc e) {
195       Debug().writeException(e);
196     }
197
198   }
199   
200
201   // ---------- Inner classes ----------
202

203   /**
204    * The garbage collection event. This is an event run from the database
205    * dispatcher thread that performs the garbage collection of committed
206    * deleted rows on the data source. This can not delete rows from a table
207    * that has its roots locked.
208    */

209   private class CollectionEvent implements Runnable JavaDoc {
210
211     public void run() {
212       performCollectionEvent(false);
213     }
214
215   }
216
217 }
218
Popular Tags