KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > prevayler > foundation > DurableOutputStream


1 //Prevayler(TM) - The Free-Software Prevalence Layer.
2
//Copyright (C) 2001-2005 Klaus Wuestefeld
3
//This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
4
//Contributions: Justin Sampson, Tobias Hill
5

6 package org.prevayler.foundation;
7
8 import java.io.*;
9
10
11 public class DurableOutputStream {
12     private static final int NOT_CLOSED = 0;
13     private static final int CLOSE_CALLED = 1;
14     private static final int REALLY_CLOSED = 2;
15
16     private final File _file;
17     private final ObjectOutputStream _objectOutputStream;
18     private final FileOutputStream _fileOutputStream;
19     private final FileDescriptor _fileDescriptor;
20
21     private IOException _exceptionWhileSynching;
22     private IOException _exceptionWhileClosing;
23
24     private int _objectsWritten = 0;
25     private int _objectsSynced = 0;
26     private int _fileSyncCount = 0;
27
28     private int _closingState = NOT_CLOSED;
29
30     public DurableOutputStream(File file) throws IOException {
31         _file = file;
32         _fileOutputStream = new FileOutputStream(file);
33         _fileDescriptor = _fileOutputStream.getFD();
34         _objectOutputStream = new ObjectOutputStream(new BufferedOutputStream(_fileOutputStream, 16 * 512)); //Arbitrarily large buffer. Should be a power of two multiplied by 512 bytes (disk sector size).
35

36         startSyncher();
37     }
38
39     private void startSyncher() {
40         Thread JavaDoc syncher = new Thread JavaDoc() {
41             public void run() {
42                 syncher();
43             }
44         };
45         syncher.setDaemon(true);
46         syncher.start();
47     }
48
49
50     public void sync(Object JavaDoc object, Turn myTurn) throws IOException {
51         int thisWrite;
52
53         try {
54             myTurn.start();
55             thisWrite = writeObject(object);
56         } finally {
57             myTurn.end();
58         }
59
60         waitUntilSynced(thisWrite);
61     }
62
63     private synchronized int writeObject(Object JavaDoc object) throws IOException {
64         if (_closingState != NOT_CLOSED) {
65             throw new IOException("stream is closing");
66         }
67
68         _objectOutputStream.writeObject(object);
69         _objectOutputStream.reset();
70         _objectsWritten++;
71         notifyAll();
72         return _objectsWritten;
73     }
74
75     private synchronized void waitUntilSynced(int thisWrite) throws IOException {
76         while (_objectsSynced < thisWrite && _exceptionWhileSynching == null) {
77             Cool.wait(this);
78         }
79         if (_objectsSynced < thisWrite) {
80             throw _exceptionWhileSynching;
81         }
82     }
83
84     public synchronized void close() throws IOException {
85         if (_closingState == NOT_CLOSED) {
86             _closingState = CLOSE_CALLED;
87             notifyAll();
88         }
89
90         while (_closingState != REALLY_CLOSED) {
91             Cool.wait(this);
92         }
93
94         if (_exceptionWhileClosing != null) {
95             throw _exceptionWhileClosing;
96         }
97     }
98
99     private synchronized void syncher() {
100         try {
101             while (true) {
102                 while (_objectsSynced == _objectsWritten && _closingState == NOT_CLOSED) {
103                     Cool.wait(this);
104                 }
105
106                 if (_objectsSynced == _objectsWritten) {
107                     break;
108                 }
109
110                 _objectOutputStream.flush();
111
112                 // ObjectOutputStream > BufferedOutputStream > FileOutputStream.
113
// The ObjectOutputStream will flush its underlying stream,
114
// but the BufferedOutputStream API documentation (JDK1.4.1_01)
115
// does not specify that it must flush its underlying stream too. :P
116
// This line is here in case some obscure implementation doesn't
117
// flush the underlying stream.
118
_fileOutputStream.flush();
119
120                 _fileDescriptor.sync();
121
122                 _objectsSynced = _objectsWritten;
123                 _fileSyncCount++;
124
125                 notifyAll();
126             }
127         } catch (IOException duringSync) {
128             _exceptionWhileSynching = duringSync;
129         } finally {
130             try {
131                 _objectOutputStream.close();
132             } catch (IOException duringClose) {
133                 _exceptionWhileClosing = duringClose;
134             }
135             _closingState = REALLY_CLOSED;
136             notifyAll();
137         }
138     }
139
140
141     public File file() {
142         return _file;
143     }
144
145     public synchronized int fileSyncCount() {
146         return _fileSyncCount;
147     }
148
149     public synchronized boolean reallyClosed() {
150         return _closingState == REALLY_CLOSED;
151     }
152
153 }
154
Popular Tags