KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > YapConfigBlock


1 /* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com
2
3 This file is part of the db4o open source object database.
4
5 db4o is free software; you can redistribute it and/or modify it under
6 the terms of version 2 of the GNU General Public License as published
7 by the Free Software Foundation and as clarified by db4objects' GPL
8 interpretation policy, available at
9 http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
10 Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
11 Suite 350, San Mateo, CA 94403, USA.
12
13 db4o is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

21 package com.db4o;
22
23 import java.io.*;
24
25 import com.db4o.ext.*;
26 import com.db4o.foundation.*;
27 import com.db4o.header.*;
28 import com.db4o.inside.*;
29
30 /**
31  * configuration and agent to write the configuration block
32  * The configuration block also contains the timer lock and
33  * a pointer to the running transaction.
34  * @exclude
35  */

36 public final class YapConfigBlock {
37     
38     // ConfigBlock Format
39

40     // int length of the config block
41
// long last access time for timer lock
42
// long last access time for timer lock (duplicate for atomicity)
43
// byte unicode or not
44
// int transaction-in-process address
45
// int transaction-in-process address (duplicate for atomicity)
46
// int id of PBootRecord
47
// int unused (and lost)
48
// 5 bytes of the encryption password
49
// byte freespace system used
50
// int freespace address
51
// int converter versions
52

53     private final YapFile _stream;
54     private final TimerFileLock _timerFileLock;
55     
56     private int _address;
57     private Transaction _transactionToCommit;
58     public int _bootRecordID;
59     
60     private static final int MINIMUM_LENGTH =
61         YapConst.INT_LENGTH // own length
62
+ (YapConst.LONG_LENGTH * 2) // candidate ID and last access time
63
+ 1; // Unicode byte
64

65     static final int OPEN_TIME_OFFSET = YapConst.INT_LENGTH;
66     public static final int ACCESS_TIME_OFFSET = OPEN_TIME_OFFSET + YapConst.LONG_LENGTH;
67         
68     public static final int TRANSACTION_OFFSET = MINIMUM_LENGTH;
69     private static final int BOOTRECORD_OFFSET = TRANSACTION_OFFSET + YapConst.INT_LENGTH * 2;
70     private static final int INT_FORMERLY_KNOWN_AS_BLOCK_OFFSET = BOOTRECORD_OFFSET + YapConst.INT_LENGTH;
71     private static final int ENCRYPTION_PASSWORD_LENGTH = 5;
72     private static final int PASSWORD_OFFSET = INT_FORMERLY_KNOWN_AS_BLOCK_OFFSET+ENCRYPTION_PASSWORD_LENGTH;
73     private static final int FREESPACE_SYSTEM_OFFSET = PASSWORD_OFFSET + 1;
74     private static final int FREESPACE_ADDRESS_OFFSET = FREESPACE_SYSTEM_OFFSET + YapConst.INT_LENGTH;
75     private static final int CONVERTER_VERSION_OFFSET = FREESPACE_ADDRESS_OFFSET + YapConst.INT_LENGTH;
76     private static final int UUID_INDEX_ID_OFFSET = CONVERTER_VERSION_OFFSET + YapConst.INT_LENGTH;
77     
78     
79     // complete possible data in config block
80
private static final int LENGTH =
81         MINIMUM_LENGTH
82         + (YapConst.INT_LENGTH * 7) // (two transaction pointers, PDB ID, lost int, freespace address, converter_version, index id)
83
+ ENCRYPTION_PASSWORD_LENGTH
84         + 1;
85     
86     
87     public static YapConfigBlock forNewFile(YapFile file) throws IOException{
88         return new YapConfigBlock(file, true, 0);
89     }
90     
91     public static YapConfigBlock forExistingFile(YapFile file, int address) throws IOException{
92         return new YapConfigBlock(file, false, address);
93     }
94     
95     private YapConfigBlock(YapFile stream, boolean isNew, int address) throws IOException{
96         _stream = stream;
97         _timerFileLock = TimerFileLock.forFile(stream);
98         timerFileLock().writeHeaderLock();
99         if(! isNew){
100             read(address);
101         }
102         timerFileLock().start();
103     }
104     
105     private TimerFileLock timerFileLock(){
106         return _timerFileLock;
107     }
108     
109     public long openTime(){
110         return timerFileLock().openTime();
111     }
112     
113     public Transaction getTransactionToCommit(){
114         return _transactionToCommit;
115     }
116     
117     private boolean lockFile(){
118         if(! Debug.lockFile){
119             return false;
120         }
121         return _stream.needsLockFileThread();
122     }
123     
124     private byte[] passwordToken() {
125         byte[] pwdtoken=new byte[ENCRYPTION_PASSWORD_LENGTH];
126         String JavaDoc fullpwd=_stream.configImpl().password();
127         if(_stream.configImpl().encrypt() && fullpwd!=null) {
128             try {
129                 byte[] pwdbytes=new YapStringIO().write(fullpwd);
130                 YapReader encwriter=new YapWriter(_stream.getTransaction(),pwdbytes.length+ENCRYPTION_PASSWORD_LENGTH);
131                 encwriter.append(pwdbytes);
132                 encwriter.append(new byte[ENCRYPTION_PASSWORD_LENGTH]);
133                 _stream.i_handlers.decrypt(encwriter);
134                 System.arraycopy(encwriter._buffer, 0, pwdtoken, 0, ENCRYPTION_PASSWORD_LENGTH);
135             }
136             catch(Exception JavaDoc exc) {
137                 // should never happen
138
//if(Debug.atHome) {
139
exc.printStackTrace();
140                 //}
141
}
142         }
143         return pwdtoken;
144     }
145     
146     private SystemData systemData(){
147         return _stream.systemData();
148     }
149     
150     private void read(int address) {
151         addressChanged(address);
152         timerFileLock().writeOpenTime();
153         YapWriter reader = _stream.getWriter(_stream.getSystemTransaction(), _address, LENGTH);
154         try{
155             _stream.readBytes(reader._buffer, _address, LENGTH);
156         }catch(Exception JavaDoc e){
157             // TODO: Exception handling
158
}
159         int oldLength = reader.readInt();
160         if(oldLength > LENGTH || oldLength < MINIMUM_LENGTH){
161             Exceptions4.throwRuntimeException(17);
162         }
163         if(oldLength != LENGTH){
164             // TODO: instead of bailing out, somehow trigger wrapping the stream's io adapter in
165
// a readonly decorator, issue a notification and continue?
166
if(! _stream.configImpl().isReadOnly() && ! _stream.configImpl().allowVersionUpdates()){
167                 if(_stream.configImpl().automaticShutDown()) {
168                     Platform4.removeShutDownHook(_stream, _stream.i_lock);
169                 }
170                 Exceptions4.throwRuntimeException(65);
171             }
172         }
173         
174         reader.readLong(); // open time
175
long lastAccessTime = reader.readLong();
176         
177         systemData().stringEncoding(reader.readByte());
178         
179         if(oldLength > TRANSACTION_OFFSET){
180             _transactionToCommit = Transaction.readInterruptedTransaction(_stream, reader);
181         }
182         
183         if(oldLength > BOOTRECORD_OFFSET) {
184             _bootRecordID = reader.readInt();
185         }
186         
187         if(oldLength > INT_FORMERLY_KNOWN_AS_BLOCK_OFFSET) {
188             // this one is dead.
189
// Blocksize is in the very first bytes
190
reader.readInt();
191         }
192         
193         if(oldLength > PASSWORD_OFFSET) {
194             byte[] encpassword=reader.readBytes(ENCRYPTION_PASSWORD_LENGTH);
195             boolean nonZeroByte = false;
196             for (int i = 0; i < encpassword.length; i++) {
197                 if(encpassword[i] != 0){
198                     nonZeroByte = true;
199                     break;
200                 }
201             }
202             if(! nonZeroByte){
203                 // no password in the databasefile, work without encryption
204
_stream.i_handlers.oldEncryptionOff();
205             }else{
206                 byte[] storedpwd=passwordToken();
207                 for (int idx = 0; idx < storedpwd.length; idx++) {
208                     if(storedpwd[idx]!=encpassword[idx]) {
209                         _stream.fatalException(54);
210                     }
211                 }
212             }
213         }
214         
215         if(oldLength > FREESPACE_SYSTEM_OFFSET){
216             systemData().freespaceSystem(reader.readByte());
217         }
218         
219         if(oldLength > FREESPACE_ADDRESS_OFFSET){
220             systemData().freespaceAddress(reader.readInt());
221         }
222         
223         if(oldLength > CONVERTER_VERSION_OFFSET){
224             systemData().converterVersion(reader.readInt());
225         }
226         if(oldLength > UUID_INDEX_ID_OFFSET){
227             final int uuidIndexId = reader.readInt();
228             if (0 != uuidIndexId) {
229                 systemData().uuidIndexId(uuidIndexId);
230             }
231         }
232         
233         _stream.ensureFreespaceSlot();
234         
235         if(lockFile() && ( lastAccessTime != 0)){
236             _stream.logMsg(28, null);
237             long waitTime = YapConst.LOCK_TIME_INTERVAL * 5;
238             long currentTime = System.currentTimeMillis();
239
240             // If someone changes the system clock here,
241
// he is out of luck.
242
while(System.currentTimeMillis() < currentTime + waitTime){
243                 Cool.sleepIgnoringInterruption(waitTime);
244             }
245             reader = _stream.getWriter(_stream.getSystemTransaction(), _address, YapConst.LONG_LENGTH * 2);
246             reader.moveForward(OPEN_TIME_OFFSET);
247             reader.read();
248             
249             reader.readLong(); // open time
250

251             long currentAccessTime = reader.readLong();
252             if((currentAccessTime > lastAccessTime) ){
253                 throw new DatabaseFileLockedException();
254             }
255         }
256         if(lockFile()){
257             // We give the other process a chance to
258
// write its lock.
259
Cool.sleepIgnoringInterruption(100);
260             _stream.syncFiles();
261             timerFileLock().checkOpenTime();
262         }
263         if(oldLength < LENGTH){
264             write();
265         }
266     }
267     
268     public void write() {
269         
270         timerFileLock().checkHeaderLock();
271         addressChanged(_stream.getSlot(LENGTH));
272         
273         YapWriter writer = _stream.getWriter(_stream.getTransaction(), _address,LENGTH);
274         YInt.writeInt(LENGTH, writer);
275         for (int i = 0; i < 2; i++) {
276             writer.writeLong(timerFileLock().openTime());
277         }
278         writer.append(systemData().stringEncoding());
279         YInt.writeInt(0, writer);
280         YInt.writeInt(0, writer);
281         YInt.writeInt(_bootRecordID, writer);
282         YInt.writeInt(0, writer); // dead byte from wrong attempt for blocksize
283
writer.append(passwordToken());
284         writer.append(systemData().freespaceSystem());
285         _stream.ensureFreespaceSlot();
286         YInt.writeInt(systemData().freespaceAddress(), writer);
287         YInt.writeInt(systemData().converterVersion(), writer);
288         YInt.writeInt(systemData().uuidIndexId(), writer);
289         writer.write();
290         writePointer();
291     }
292     
293     private void addressChanged(int address){
294         _address = address;
295         timerFileLock().setAddresses(_address, OPEN_TIME_OFFSET, ACCESS_TIME_OFFSET);
296     }
297     
298     private void writePointer() {
299         timerFileLock().checkHeaderLock();
300         YapWriter writer = _stream.getWriter(_stream.getTransaction(), 0, YapConst.ID_LENGTH);
301         writer.moveForward(2);
302         YInt.writeInt(_address, writer);
303         writer.noXByteCheck();
304         writer.write();
305         timerFileLock().writeHeaderLock();
306     }
307     
308     public int address(){
309         return _address;
310     }
311
312     public void close() throws IOException {
313         timerFileLock().close();
314     }
315     
316 }
317
318
Popular Tags