KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > persist > ScaledRAFile


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb.persist;
33
34 import java.io.EOFException JavaDoc;
35 import java.io.FileNotFoundException JavaDoc;
36 import java.io.IOException JavaDoc;
37 import java.io.RandomAccessFile JavaDoc;
38 import java.lang.reflect.Constructor JavaDoc;
39
40 import org.hsqldb.Database;
41 import org.hsqldb.Trace;
42 import org.hsqldb.lib.HsqlByteArrayInputStream;
43 import org.hsqldb.lib.SimpleLog;
44 import org.hsqldb.lib.Storage;
45
46 // fredt@users 20030111 - patch 1.7.2 by bohgammer@users - pad file before seek() beyond end
47
// some incompatible JVM implementations do not allow seek beyond the existing end of file
48

49 /**
50  * This class is a wapper for a random access file such as that used for
51  * CACHED table storage.
52  *
53  * @author fredt@users
54  * @version 1.8.0
55  * @since 1.7.2
56  */

57 class ScaledRAFile implements ScaledRAInterface {
58
59     static final int DATA_FILE_RAF = 0;
60     static final int DATA_FILE_NIO = 1;
61     static final int DATA_FILE_JAR = 2;
62     static final long MAX_NIO_LENGTH = (1L << 28);
63
64     //
65
final SimpleLog appLog;
66     final RandomAccessFile JavaDoc file;
67     private final boolean readOnly;
68     final String JavaDoc fileName;
69     boolean isNio;
70     boolean bufferDirty = true;
71     final byte[] buffer;
72     final HsqlByteArrayInputStream ba;
73     long bufferOffset;
74
75     //
76
long seekPosition;
77     long realPosition;
78     static int cacheHit;
79
80     /**
81      * seekPosition is the position in seek() calls or after reading or writing
82      * realPosition is the file position
83      */

84     static Storage newScaledRAFile(Database database, String JavaDoc name,
85                                    boolean readonly, int type,
86                                    String JavaDoc classname,
87                                    String JavaDoc key)
88                                    throws FileNotFoundException JavaDoc, IOException JavaDoc {
89
90         if (classname != null) {
91             try {
92                 Class JavaDoc zclass = Class.forName(classname);
93                 Constructor JavaDoc constructor = zclass.getConstructor(new Class JavaDoc[] {
94                     String JavaDoc.class, Boolean JavaDoc.class, Object JavaDoc.class
95                 });
96
97                 return (Storage) constructor.newInstance(new Object JavaDoc[] {
98                     name, new Boolean JavaDoc(readonly), key
99                 });
100             } catch (ClassNotFoundException JavaDoc e) {
101                 throw new IOException JavaDoc();
102             } catch (NoSuchMethodException JavaDoc e) {
103                 throw new IOException JavaDoc();
104             } catch (InstantiationException JavaDoc e) {
105                 throw new IOException JavaDoc();
106             } catch (IllegalAccessException JavaDoc e) {
107                 throw new IOException JavaDoc();
108             } catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
109                 throw new IOException JavaDoc();
110             }
111         }
112
113         if (type == DATA_FILE_JAR) {
114             return new ScaledRAFileInJar(name);
115         } else if (type == DATA_FILE_RAF) {
116             return new ScaledRAFile(database, name, readonly);
117         } else {
118             RandomAccessFile JavaDoc file = new RandomAccessFile JavaDoc(name, readonly ? "r"
119                                                                         : "rw");
120
121             if (file.length() > MAX_NIO_LENGTH) {
122                 return new ScaledRAFile(database, name, file, readonly);
123             } else {
124                 file.close();
125             }
126
127             try {
128                 Class.forName("java.nio.MappedByteBuffer");
129
130                 Class JavaDoc c =
131                     Class.forName("org.hsqldb.persist.ScaledRAFileHybrid");
132                 Constructor JavaDoc constructor = c.getConstructor(new Class JavaDoc[] {
133                     Database.class, String JavaDoc.class, boolean.class
134                 });
135
136                 return (ScaledRAInterface) constructor.newInstance(
137                     new Object JavaDoc[] {
138                     database, name, new Boolean JavaDoc(readonly)
139                 });
140             } catch (Exception JavaDoc e) {
141                 return new ScaledRAFile(database, name, readonly);
142             }
143         }
144     }
145
146     ScaledRAFile(Database database, String JavaDoc name, RandomAccessFile JavaDoc file,
147                  boolean readonly) throws FileNotFoundException JavaDoc, IOException JavaDoc {
148
149         this.appLog = database.logger.appLog;
150         this.readOnly = readonly;
151         this.fileName = name;
152         this.file = file;
153
154         int bufferScale = database.getProperties().getIntegerProperty(
155             HsqlDatabaseProperties.hsqldb_raf_buffer_scale, 12, 8, 13);
156         int bufferSize = 1 << bufferScale;
157
158         buffer = new byte[bufferSize];
159         ba = new HsqlByteArrayInputStream(buffer);
160     }
161
162     ScaledRAFile(Database database, String JavaDoc name,
163                  boolean readonly) throws FileNotFoundException JavaDoc, IOException JavaDoc {
164
165         this.appLog = database.logger.appLog;
166         this.readOnly = readonly;
167         this.fileName = name;
168         this.file = new RandomAccessFile JavaDoc(name, readonly ? "r"
169                                                             : "rw");
170
171         int bufferScale = database.getProperties().getIntegerProperty(
172             HsqlDatabaseProperties.hsqldb_raf_buffer_scale, 12);
173         int bufferSize = 1 << bufferScale;
174
175         buffer = new byte[bufferSize];
176         ba = new HsqlByteArrayInputStream(buffer);
177     }
178
179     public long length() throws IOException JavaDoc {
180         return file.length();
181     }
182
183     /**
184      * Some JVM's do not allow seek beyond end of file, so zeros are written
185      * first in that case. Reported by bohgammer@users in Open Disucssion
186      * Forum.
187      */

188     public void seek(long position) throws IOException JavaDoc {
189
190         if (!readOnly && file.length() < position) {
191             long tempSize = position - file.length();
192
193             if (tempSize > 1 << 18) {
194                 tempSize = 1 << 18;
195             }
196
197             byte[] temp = new byte[(int) tempSize];
198
199             try {
200                 long pos = file.length();
201
202                 for (; pos < position - tempSize; pos += tempSize) {
203                     file.seek(pos);
204                     file.write(temp, 0, (int) tempSize);
205                 }
206
207                 file.seek(pos);
208                 file.write(temp, 0, (int) (position - pos));
209
210                 realPosition = position;
211             } catch (IOException JavaDoc e) {
212                 appLog.logContext(e, null);
213
214                 throw e;
215             }
216         }
217
218         seekPosition = position;
219     }
220
221     public long getFilePointer() throws IOException JavaDoc {
222         return seekPosition;
223     }
224
225     private void readIntoBuffer() throws IOException JavaDoc {
226
227         long filePos = seekPosition;
228         long subOffset = filePos % buffer.length;
229         long fileLength = file.length();
230         long readLength = fileLength - (filePos - subOffset);
231
232         try {
233             if (readLength <= 0) {
234                 throw new IOException JavaDoc("read beyond end of file");
235             }
236
237             if (readLength > buffer.length) {
238                 readLength = buffer.length;
239             }
240
241             file.seek(filePos - subOffset);
242             file.readFully(buffer, 0, (int) readLength);
243
244             bufferOffset = filePos - subOffset;
245             realPosition = bufferOffset + readLength;
246             bufferDirty = false;
247         } catch (IOException JavaDoc e) {
248             resetPointer();
249             appLog.logContext(e, "" + realPosition + " " + readLength);
250
251             throw e;
252         }
253     }
254
255     public int read() throws IOException JavaDoc {
256
257         try {
258             long fileLength = file.length();
259
260             if (seekPosition >= fileLength) {
261                 return -1;
262             }
263
264             if (bufferDirty || seekPosition < bufferOffset
265                     || seekPosition >= bufferOffset + buffer.length) {
266                 readIntoBuffer();
267             } else {
268                 cacheHit++;
269             }
270
271             ba.reset();
272             ba.skip(seekPosition - bufferOffset);
273
274             int val = ba.read();
275
276             seekPosition++;
277
278             return val;
279         } catch (IOException JavaDoc e) {
280             resetPointer();
281             appLog.logContext(e, null);
282
283             throw e;
284         }
285     }
286
287     public long readLong() throws IOException JavaDoc {
288
289         try {
290             if (bufferDirty || seekPosition < bufferOffset
291                     || seekPosition >= bufferOffset + buffer.length) {
292                 readIntoBuffer();
293             } else {
294                 cacheHit++;
295             }
296
297             ba.reset();
298
299             if (seekPosition - bufferOffset
300                     != ba.skip(seekPosition - bufferOffset)) {
301                 throw new EOFException JavaDoc();
302             }
303
304             long val;
305
306             try {
307                 val = ba.readLong();
308             } catch (EOFException JavaDoc e) {
309                 file.seek(seekPosition);
310
311                 val = file.readLong();
312                 realPosition = file.getFilePointer();
313             }
314
315             seekPosition += 8;
316
317             return val;
318         } catch (IOException JavaDoc e) {
319             resetPointer();
320             appLog.logContext(e, null);
321
322             throw e;
323         }
324     }
325
326     public int readInt() throws IOException JavaDoc {
327
328         try {
329             if (bufferDirty || seekPosition < bufferOffset
330                     || seekPosition >= bufferOffset + buffer.length) {
331                 readIntoBuffer();
332             } else {
333                 cacheHit++;
334             }
335
336             ba.reset();
337
338             if (seekPosition - bufferOffset
339                     != ba.skip(seekPosition - bufferOffset)) {
340                 throw new EOFException JavaDoc();
341             }
342
343             int val;
344
345             try {
346                 val = ba.readInt();
347             } catch (EOFException JavaDoc e) {
348                 file.seek(seekPosition);
349
350                 val = file.readInt();
351                 realPosition = file.getFilePointer();
352             }
353
354             seekPosition += 4;
355
356             return val;
357         } catch (IOException JavaDoc e) {
358             resetPointer();
359             appLog.logContext(e, null);
360
361             throw e;
362         }
363     }
364
365     public void read(byte[] b, int offset, int length) throws IOException JavaDoc {
366
367         try {
368             if (bufferDirty || seekPosition < bufferOffset
369                     || seekPosition >= bufferOffset + buffer.length) {
370                 readIntoBuffer();
371             } else {
372                 cacheHit++;
373             }
374
375             ba.reset();
376
377             if (seekPosition - bufferOffset
378                     != ba.skip(seekPosition - bufferOffset)) {
379                 throw new EOFException JavaDoc();
380             }
381
382             int bytesRead = ba.read(b, offset, length);
383
384             seekPosition += bytesRead;
385
386             if (bytesRead < length) {
387                 if (seekPosition != realPosition) {
388                     file.seek(seekPosition);
389                 }
390
391                 file.readFully(b, offset + bytesRead, length - bytesRead);
392
393                 seekPosition += (length - bytesRead);
394                 realPosition = seekPosition;
395             }
396         } catch (IOException JavaDoc e) {
397             resetPointer();
398             appLog.logContext(e, null);
399
400             throw e;
401         }
402     }
403
404     public void write(byte[] b, int off, int len) throws IOException JavaDoc {
405
406         try {
407             if (realPosition != seekPosition) {
408                 file.seek(seekPosition);
409
410                 realPosition = seekPosition;
411             }
412
413             if (seekPosition >= bufferOffset
414                     && seekPosition < bufferOffset + buffer.length) {
415                 bufferDirty = true;
416             }
417
418             file.write(b, off, len);
419
420             seekPosition += len;
421             realPosition = seekPosition;
422         } catch (IOException JavaDoc e) {
423             resetPointer();
424             appLog.logContext(e, null);
425
426             throw e;
427         }
428     }
429
430     public void writeInt(int i) throws IOException JavaDoc {
431
432         try {
433             if (realPosition != seekPosition) {
434                 file.seek(seekPosition);
435
436                 realPosition = seekPosition;
437             }
438
439             if (seekPosition >= bufferOffset
440                     && seekPosition < bufferOffset + buffer.length) {
441                 bufferDirty = true;
442             }
443
444             file.writeInt(i);
445
446             seekPosition += 4;
447             realPosition = seekPosition;
448         } catch (IOException JavaDoc e) {
449             resetPointer();
450             appLog.logContext(e, null);
451
452             throw e;
453         }
454     }
455
456     public void writeLong(long i) throws IOException JavaDoc {
457
458         try {
459             if (realPosition != seekPosition) {
460                 file.seek(seekPosition);
461
462                 realPosition = seekPosition;
463             }
464
465             if (seekPosition >= bufferOffset
466                     && seekPosition < bufferOffset + buffer.length) {
467                 bufferDirty = true;
468             }
469
470             file.writeLong(i);
471
472             seekPosition += 8;
473             realPosition = seekPosition;
474         } catch (IOException JavaDoc e) {
475             resetPointer();
476             appLog.logContext(e, null);
477
478             throw e;
479         }
480     }
481
482     public void close() throws IOException JavaDoc {
483         Trace.printSystemOut("cache hit " + cacheHit);
484         file.close();
485     }
486
487     public boolean isReadOnly() {
488         return readOnly;
489     }
490
491     public boolean wasNio() {
492         return false;
493     }
494
495     public boolean canAccess(int length) {
496         return true;
497     }
498
499     public boolean canSeek(long position) {
500         return true;
501     }
502
503     public Database getDatabase() {
504         return null;
505     }
506
507     private void resetPointer() {
508
509         try {
510             bufferDirty = true;
511
512             file.seek(seekPosition);
513
514             realPosition = seekPosition;
515         } catch (Throwable JavaDoc e) {}
516     }
517 }
518
Popular Tags