KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > file > Logger1


1 package com.quadcap.sql.file;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.BufferedInputStream JavaDoc;
42 import java.io.EOFException JavaDoc;
43 import java.io.File JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.io.InputStream JavaDoc;
46 import java.io.RandomAccessFile JavaDoc;
47
48 import java.util.Properties JavaDoc;
49
50 import com.quadcap.sql.io.ObjectOutputStream;
51 import com.quadcap.sql.io.ObjectInputStream;
52
53 import com.quadcap.util.collections.LongMap;
54
55 import com.quadcap.util.Debug;
56 import com.quadcap.util.Util;
57
58 /**
59  * A Logger implmeentation using a fixed size circular buffer.
60  *
61  * @author Stan Bailes
62  */

63 public class Logger1 implements Logger {
64     LogBuffer cb;
65     InputStream JavaDoc cbIn = null;
66     ObjectOutputStream oos = null;
67     ByteArrayRandomAccess bra = new ByteArrayRandomAccess();
68     RandomAccessInputStream ris = new RandomAccessInputStream(bra);
69     ObjectInputStream ois = new ObjectInputStream(ris);
70     byte[] tmp = new byte[8];
71
72     /**
73      * Transaction map:
74      * - ordered by transactionStart
75      * - first transaction is the oldest transaction still running
76      * so when committing the oldest transaction, move the begin
77      * - last transaction is the newest transaction still running
78      * transactions!
79      */

80     TransMap[] trans = new TransMap[16];
81
82     /**
83      * Keeps track of the number of TransMap entries allocated. Some entries
84      * will correspond to completed but not yet checkpointed transactions,
85      * so this number may be larger than the number of actual live transactions.
86      */

87     int numTrans;
88
89     /**
90      * Keep the actual count of live transactions as determined by calls
91      * to beginTransaction, endTransaction.
92      */

93     int liveTrans = 0;
94
95     /**
96      * The starting position of the most recent op we wrote to the file
97      */

98     long prevOp;
99
100     int maxSize = 128 * 1024 * 1024;
101     int minSize = 128 * 1024;
102
103     Log myLog;
104     Datafile db;
105
106     Logger1() {}
107
108     public void init(Log log, boolean create, Properties JavaDoc props)
109         throws IOException JavaDoc
110     {
111         this.myLog = log;
112         this.db = log.getDatafile();
113         this.cb = new LogBuffer();
114         // XXX better would be a call to Datafile.getProperty("logfile")
115
/*{com.quadcap.sql.Datafile-conn.xml-29}
116          * <config-var>
117          * <config-name>maxLogSize</config-name>
118          * <config-dflt>128 M bytes</config-dflt>
119          * <config-desc>For loggers which support rollback, the maximum
120          * size of the rollback log. Once this maximum is reached, it
121          * may be necessary to abort the oldest transaction and checkpoint
122          * in an attempt to regain log space.</config-desc>
123          * </config-var>
124          */

125         maxSize = Integer.parseInt(props.getProperty("maxLogSize", "" + maxSize));
126
127         /*{com.quadcap.sql.Datafile-conn.xml-29}
128          * <config-var>
129          * <config-name>minLogSize</config-name>
130          * <config-dflt>128 K bytes</config-dflt>
131          * <config-desc>For loggers which support rollback, the minimum size
132          * at which a logging checkpoint operation will occur. The logging
133          * checkpoint cleans the log of entries which correspond to completed
134          * transactions.</config-desc>
135          * </config-var>
136          */

137         minSize = Integer.parseInt(props.getProperty("minLogSize", "" + minSize));
138
139         File JavaDoc logfile = new File JavaDoc(db.getDbRootDir(), "logfile");
140         RandomAccessFile JavaDoc raf = new RandomAccessFile JavaDoc(logfile, "rw");
141         FileRandomAccess fra = new FileRandomAccess(raf, maxSize);
142         RandomAccess ra = fra;
143         if (create) {
144             cb.init(ra, maxSize);
145         } else {
146             lastSize = ra.size();
147             cb.init(ra, props);
148         }
149     }
150
151     public void init(File JavaDoc file) throws IOException JavaDoc {
152         RandomAccessFile JavaDoc raf = new RandomAccessFile JavaDoc(file, "rw");
153         FileRandomAccess fra = new FileRandomAccess(raf, raf.length());
154         RandomAccess ra = fra;
155         this.cb = new LogBuffer();
156         lastSize = ra.size();
157         cb.init(ra, new Properties JavaDoc());
158      }
159
160
161     /**
162      * Inner class used to to track active transactions.
163      */

164     class TransMap {
165         long transId;
166         /**
167          * If >0, the position of the first op in the transaction.
168          * This will generally be the BEGIN_TRANSACTION op.
169          */

170         int bufStart;
171         /**
172          * If >0, the position of the most recently written op in the
173          * transaction.
174          */

175         int bufEnd;
176         boolean complete;
177         
178         public void init(long t, int p) {
179             this.transId = t;
180             this.bufStart = p;
181             this.bufEnd = p;
182             this.complete = false;
183         }
184
185         public void init(TransMap t) {
186             this.transId = t.transId;
187             this.bufStart = -1;
188             this.bufEnd = -1;
189             this.complete = t.complete;
190         }
191
192         public void copy(TransMap t) {
193             this.transId = t.transId;
194             this.bufStart = t.bufStart;
195             this.bufEnd = t.bufEnd;
196             this.complete = t.complete;
197         }
198
199         public String JavaDoc toString() {
200             return "TransMap[" + transId + ": " + bufStart + "-" + bufEnd +
201                 (complete ? " (COMPLETE)" : "") + "]";
202         }
203     }
204
205     public String JavaDoc toString() {
206         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Logger1 {" + cb.getCheckpoint() +
207                                            ", " + cb.getEnd() + "} ");
208         for (int i = 0; i < trans.length; i++) {
209             TransMap tm = trans[i];
210             if (tm != null && !tm.complete) {
211                 sb.append(tm.toString());
212             }
213         }
214         return sb.toString();
215     }
216
217     public int getCheckpoint() {
218         return cb.getCheckpoint();
219     }
220
221     public int getEnd() {
222         return cb.getEnd();
223     }
224     
225     public int rput(LogEntry op) throws IOException JavaDoc {
226         int pos = cb.getEnd();
227         op.setPosition(pos);
228
229         long id = op.getTransactionId();
230         int tx = findTransaction(id);
231         if (tx >= 0) {
232             TransMap tm = trans[tx];
233             op.setPrev(tm.bufEnd);
234             tm.bufEnd = pos;
235         }
236
237         try {
238             if (oos == null) {
239                 oos = new ObjectOutputStream(cb.getOutputStream());
240             }
241             oos.writeObject(op);
242             oos.flush();
243         } catch (IOException JavaDoc ex) {
244             if (tx >= 0) {
245                 trans[tx].bufEnd = op.getPrev();
246             }
247             throw ex;
248         }
249         return pos;
250     }
251     
252     public void put(LogEntry op) throws IOException JavaDoc {
253         int pos = rput(op);
254         switch (op.getCode()) {
255         case LogEntry.BEGIN_TRANSACTION:
256             beginTransaction(op.getTransactionId(), pos);
257             break;
258         case LogEntry.COMMIT:
259             endTransaction(op.getTransactionId());
260             break;
261         }
262         //Debug.println("Logger1.put(" + op + ") [" + pos +
263
// "] ----------------------");
264
}
265     
266     public void setRedoState(LogEntry op, int state) throws IOException JavaDoc {
267         int pos = op.getPosition();
268         //Debug.println("setRedoState(" + op + ", " + state + ")");
269
cb.writeByte(pos+1, (byte)state);
270         op.redoState = state;
271     }
272     
273     public LogEntry getLastOp(long transId) throws IOException JavaDoc {
274         LogEntry ret = null;
275         int tx = findTransaction(transId);
276         if (tx >= 0) {
277             TransMap tm = trans[tx];
278             ret = readEntry(tm.bufEnd);
279         }
280         //#ifdef DEBUG
281
if (ret == null) {
282             Debug.println(Util.stackTrace());
283             Debug.println("getLastOp(" + transId + ") = null, trans:");
284             for (int i = 0; i < numTrans; i++) {
285                 Debug.println("trans[" + i + "] = " + trans[i]);
286             }
287         }
288         //#endif
289
return ret;
290     }
291
292     public LogEntry getPrevOp(LogEntry op) throws IOException JavaDoc {
293         int pos = op.getPrev();
294         int len = op.getPosition() - pos;
295         LogEntry ret = readEntry(pos, len);
296         return ret;
297     }
298
299     public LogEntry getFirstOp() throws IOException JavaDoc {
300         LogEntry ret = readEntry(cb.getBegin());
301         return ret;
302     }
303
304     public LogEntry getNextOp() throws IOException JavaDoc {
305         return readEntry();
306     }
307
308     public void sync() throws IOException JavaDoc {
309         cb.sync();
310     }
311
312     // close all the files
313
public void close() throws IOException JavaDoc {
314         cb.close();
315     }
316
317     long lastSize = 0;
318     public void reset() throws IOException JavaDoc {
319         cb.reset();
320         if (lastSize - cb.size() > 100 * 1000) {
321             cb.truncate();
322         }
323         lastSize = cb.size();
324     }
325
326     public long getOldestTransaction() {
327         if (numTrans > 0) {
328             return trans[0].transId;
329         } else {
330             return -1;
331         }
332     }
333
334     public int getActiveTransactionCount() {
335         return liveTrans;
336     }
337
338     public LongMap getActiveTransactions() {
339         LongMap map = new LongMap(16);
340         for (int i = 0; i < numTrans; i++) {
341             TransMap t = trans[i];
342             if (!t.complete) {
343                 map.put(t.transId, "");
344             }
345         }
346         return map;
347     }
348
349     public void checkpoint() throws IOException JavaDoc {
350         int offset = 0;
351         for (int i = 0; i < numTrans; i++) {
352             TransMap t = trans[i];
353             if (t.complete) {
354                 offset++;
355             } else if (offset > 0) {
356                 trans[i-offset].init(t);
357             }
358         }
359         //#ifdef DEBUG
360
if (Trace.bit(22)) {
361             Debug.println("BEGIN checkpoint [" + cb.getBegin() + "-" +
362                           cb.getEnd() + " (" + numTrans + " transactions)]");
363         }
364         //#endif
365
numTrans -= offset;
366         //Debug.println("Checkpoint: -" + offset + " = " + numTrans);
367
LogEntry entry = readEntry(0);
368         cb.reset();
369         if (numTrans > 0) {
370             while (entry != null) {
371                 boolean keep = false;
372                 long id = entry.getTransactionId();
373                 int tx = findTransaction(id);
374                 if (tx >= 0) {
375                     TransMap tm = trans[tx];
376                     keep = !tm.complete;
377                     if (keep) {
378                         if (tm.bufStart < 0) tm.bufStart = cb.getEnd();
379                     }
380                 }
381                 if (keep) {
382                     //#ifdef DEBUG
383
if (Trace.bit(23)) {
384                         Debug.println(" [" + cb.getEnd() + "] -> " + entry);
385                     }
386                     //#endif
387
rput(entry);
388                 } else {
389                     //#ifdef DEBUG
390
if (Trace.bit(23)) {
391                         Debug.println(" [" + cb.getEnd() + "] -> DISCARD: " + entry);
392                     }
393                     //#endif
394
entry.discard(db);
395                 }
396                 entry = readEntry();
397             }
398         }
399         cb.checkpoint();
400         //#ifdef DEBUG
401
if (Trace.bit(22)) {
402             Debug.println("END checkpoint [" + cb.getBegin() + "-" + cb.getEnd() +
403                           " (" + numTrans + " transactions)]");
404         }
405         //#endif
406
}
407
408     //--------------------------------- private stuff
409

410     private final void beginTransaction(long transId, int pos) {
411         if (numTrans >= trans.length) {
412             int newcap = numTrans + (numTrans/2) + 2;
413             trans = (TransMap[])Util.checkCapacity(trans, newcap);
414         }
415         TransMap t = trans[numTrans];
416         if (t == null) {
417             t = new TransMap();
418             trans[numTrans] = t;
419         }
420
421         // A race condition exists -- this might *not* be the newest trans,
422
// and we want to keep the 'trans' array ordered properly, so search
423
// backwards from the end to make sure we put this fellow in the
424
// right place.
425
for (int i = numTrans-1; i >= 0; i--) {
426             if (trans[i].transId > transId) {
427                 trans[i+1].copy(trans[i]);
428                 t = trans[i];
429             } else {
430                 break;
431             }
432         }
433         numTrans++;
434         //Debug.println("Begin T:" + transId + " = " + numTrans);
435
liveTrans++;
436         t.init(transId, pos);
437         //Debug.println("beginTransaction(" + transId + "): " + numTrans);
438
}
439
440     private final void endTransaction(final long transId) throws IOException JavaDoc {
441         //Debug.println("endTransaction(" + transId + "): " + numTrans);
442
int pos = findTransaction(transId);
443         if (pos >= 0) {
444             // Mark the transaction as complete. We don't decrement
445
// numTrans here; we wait until the next checkpoint, where
446
// all of the completed transactions can be reclaimed at
447
// once.
448
trans[pos].complete = true;
449             liveTrans--;
450             if (pos == 0 && cb.size() > minSize) {
451                 checkpoint();
452             }
453         }
454     }
455
456     /**
457      * Find the TransMap entry for the given transaction id
458      */

459     int findTransaction(long transId) {
460         int lo = 0;
461         int hi = numTrans-1;
462         while (hi >= lo) {
463             int mid = (hi+lo) / 2;
464             TransMap t = trans[mid];
465             if (t.transId == transId) {
466                 return mid;
467             }
468             if (t.transId < transId) {
469                 lo = mid+1;
470             } else {
471                 hi = mid-1;
472             }
473         }
474         return -1;
475     }
476
477     private final LogEntry readEntry(int pos, int len) throws IOException JavaDoc {
478         if (pos < 0) return null;
479         bra.resize(len);
480         byte[] buf = bra.getBytes();
481         cb.read(pos, buf, 0, len);
482         ris.setPosition(0);
483         ois.setInputStream(ris);
484         ois.setPosition(pos);
485         
486         LogEntry ret = readEntry();
487         return ret;
488     }
489
490     private final LogEntry readEntry(int pos) throws IOException JavaDoc {
491         if (pos < 0) return null;
492         cbIn = new BufferedInputStream JavaDoc(cb.getInputStream(pos));
493         ois.setInputStream(cbIn);
494         ois.setPosition(pos);
495
496         LogEntry ret = readEntry();
497         return ret;
498     }
499
500     private final LogEntry readEntry() throws IOException JavaDoc {
501         Object JavaDoc obj = null;
502         try {
503             int pos = (int)ois.getPosition();
504             LogEntry ret = (LogEntry)(obj = ois.readObject());
505             if (ret != null) {
506                 ret.setPosition(pos);
507             }
508             return ret;
509         } catch (EOFException JavaDoc ex) {
510             return null;
511         } catch (ClassCastException JavaDoc ez) {
512             throw new DatafileException(ez);
513         } catch (ClassNotFoundException JavaDoc ex) {
514             throw new DatafileException(ex);
515         }
516     }
517 }
518     
519
Popular Tags