~ubuntu-branches/ubuntu/maverick/hsqldb/maverick

« back to all changes in this revision

Viewing changes to src/org/hsqldb/persist/DataFileCache.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-09-26 11:47:49 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060926114749-3jd0utm7w21x1iqt
Tags: 1.8.0.5-2ubuntu1
* Synchronise with Debian unstable; remaining changes:
  - build using java-gcj-compat.
* libhsqldb-java: Add gij as alternative dependency.
* Build a libhsqldb-java-gcj package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
 
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
32
package org.hsqldb.persist;
33
33
 
34
34
import java.io.File;
39
39
import org.hsqldb.Trace;
40
40
import org.hsqldb.lib.FileAccess;
41
41
import org.hsqldb.lib.FileUtil;
 
42
import org.hsqldb.lib.SimpleLog;
42
43
import org.hsqldb.lib.StopWatch;
43
44
import org.hsqldb.lib.Storage;
44
45
import org.hsqldb.lib.ZipUnzipFile;
62
63
 */
63
64
public class DataFileCache {
64
65
 
65
 
    private FileAccess fa;
 
66
    protected FileAccess fa;
66
67
 
67
68
    // flags
68
69
    public static final int FLAG_ISSAVED = 2;
111
112
    protected long    maxCacheBytes;            // number of bytes
112
113
    protected Cache   cache;
113
114
 
114
 
    public DataFileCache(Database db, String fileName,
115
 
                         String backupName) throws HsqlException {
116
 
 
117
 
        this.fileName       = fileName;
118
 
        this.backupFileName = backupName;
119
 
        database            = db;
120
 
        fa                  = database.getFileAccess();
121
 
 
122
 
        initParams();
 
115
    public DataFileCache(Database db,
 
116
                         String baseFileName) throws HsqlException {
 
117
 
 
118
        initParams(db, baseFileName);
123
119
 
124
120
        cache = new Cache(this);
125
121
    }
127
123
    /**
128
124
     * initial external parameters are set here.
129
125
     */
130
 
    protected void initParams() throws HsqlException {
 
126
    protected void initParams(Database database,
 
127
                              String baseFileName) throws HsqlException {
 
128
 
 
129
        fileName       = baseFileName + ".data";
 
130
        backupFileName = baseFileName + ".backup";
 
131
        this.database  = database;
 
132
        fa             = database.getFileAccess();
131
133
 
132
134
        int cacheScale = database.getProperties().getIntegerProperty(
133
135
            HsqlDatabaseProperties.hsqldb_cache_scale, 14, 8, 18);
160
162
 
161
163
        fileFreePosition = 0;
162
164
 
 
165
        database.logger.appLog.logContext(SimpleLog.LOG_NORMAL, "start");
 
166
 
163
167
        try {
164
168
            boolean preexists = database.isFilesInJar();
165
169
            long    freesize  = 0;
208
212
            String skey =
209
213
                database.getURLProperties().getProperty("storage_key");
210
214
 
211
 
            dataFile = ScaledRAFile.newScaledRAFile(fileName, readonly,
212
 
                    fileType, cname, skey);
 
215
            dataFile = ScaledRAFile.newScaledRAFile(database, fileName,
 
216
                    readonly, fileType, cname, skey);
213
217
 
214
218
            if (preexists) {
215
219
                dataFile.seek(FLAGS_POS);
238
242
            fileModified = false;
239
243
            freeBlocks = new DataFileBlockManager(FREE_BLOCKS_COUNT,
240
244
                                                  cacheFileScale, freesize);
 
245
 
 
246
            database.logger.appLog.logContext(SimpleLog.LOG_NORMAL, "end");
241
247
        } catch (Throwable e) {
 
248
            database.logger.appLog.logContext(SimpleLog.LOG_ERROR, "failed");
242
249
            database.logger.appLog.logContext(e);
243
250
            close(false);
244
251
 
260
267
     */
261
268
    public void close(boolean write) throws HsqlException {
262
269
 
 
270
        SimpleLog appLog = database.logger.appLog;
 
271
 
263
272
        try {
264
273
            if (cacheReadonly) {
265
274
                if (dataFile != null) {
271
280
 
272
281
            StopWatch sw = new StopWatch();
273
282
 
 
283
            appLog.sendLine(SimpleLog.LOG_NORMAL,
 
284
                            "DataFileCache.close(" + write + ") : start");
 
285
 
274
286
            if (write) {
275
287
                cache.saveAll();
276
288
                Trace.printSystemOut("saveAll: " + sw.elapsedTime());
277
 
 
278
 
                // set empty
279
 
                dataFile.seek(LONG_EMPTY_SIZE);
280
 
                dataFile.writeLong(freeBlocks.getLostBlocksSize());
281
 
 
282
 
                // set end
283
 
                dataFile.seek(LONG_FREE_POS_POS);
284
 
                dataFile.writeLong(fileFreePosition);
285
 
 
286
 
                // set saved flag;
287
 
                dataFile.seek(FLAGS_POS);
288
 
 
289
 
                int flag = BitMap.set(0, FLAG_ISSAVED);
290
 
 
291
 
                if (hasRowInfo) {
292
 
                    flag = BitMap.set(flag, FLAG_ROWINFO);
 
289
                appLog.sendLine(SimpleLog.LOG_NORMAL,
 
290
                                "DataFileCache.close() : save data");
 
291
 
 
292
                if (fileModified || freeBlocks.isModified()) {
 
293
 
 
294
                    // set empty
 
295
                    dataFile.seek(LONG_EMPTY_SIZE);
 
296
                    dataFile.writeLong(freeBlocks.getLostBlocksSize());
 
297
 
 
298
                    // set end
 
299
                    dataFile.seek(LONG_FREE_POS_POS);
 
300
                    dataFile.writeLong(fileFreePosition);
 
301
 
 
302
                    // set saved flag;
 
303
                    dataFile.seek(FLAGS_POS);
 
304
 
 
305
                    int flag = BitMap.set(0, FLAG_ISSAVED);
 
306
 
 
307
                    if (hasRowInfo) {
 
308
                        flag = BitMap.set(flag, FLAG_ROWINFO);
 
309
                    }
 
310
 
 
311
                    dataFile.writeInt(flag);
 
312
                    appLog.sendLine(SimpleLog.LOG_NORMAL,
 
313
                                    "DataFileCache.close() : flags");
 
314
 
 
315
                    //
 
316
                    if (dataFile.length() != fileFreePosition) {
 
317
                        dataFile.seek(fileFreePosition);
 
318
                    }
 
319
 
 
320
                    appLog.sendLine(SimpleLog.LOG_NORMAL,
 
321
                                    "DataFileCache.close() : seek end");
 
322
                    Trace.printSystemOut("pos and flags: "
 
323
                                         + sw.elapsedTime());
293
324
                }
294
 
 
295
 
                dataFile.writeInt(flag);
296
 
 
297
 
                //
298
 
                dataFile.seek(fileFreePosition);
299
 
                Trace.printSystemOut("pos and flags: " + sw.elapsedTime());
300
325
            }
301
326
 
302
327
            if (dataFile != null) {
303
328
                dataFile.close();
 
329
                appLog.sendLine(SimpleLog.LOG_NORMAL,
 
330
                                "DataFileCache.close() : close");
304
331
 
305
332
                dataFile = null;
306
333
 
314
341
                fa.removeElement(backupFileName);
315
342
            }
316
343
        } catch (Throwable e) {
317
 
            database.logger.appLog.logContext(e);
 
344
            appLog.logContext(e);
318
345
 
319
346
            throw Trace.error(Trace.FILE_IO_ERROR, Trace.DataFileCache_close,
320
347
                              new Object[] {
325
352
 
326
353
    void postClose(boolean keep) throws HsqlException {
327
354
 
 
355
        SimpleLog appLog = database.logger.appLog;
 
356
 
328
357
        if (cacheReadonly) {
329
358
            return;
330
359
        }
331
360
 
332
361
        try {
 
362
            appLog.sendLine(SimpleLog.LOG_NORMAL,
 
363
                            "DataFileCache.postClose(" + keep + ") : start");
 
364
 
333
365
            if (keep) {
334
366
                database.getProperties().setProperty(
335
367
                    HsqlDatabaseProperties.hsqldb_cache_version,
336
368
                    HsqlDatabaseProperties.VERSION_STRING_1_7_0);
337
369
                database.getProperties().save();
 
370
                appLog.sendLine(SimpleLog.LOG_NORMAL,
 
371
                                "DataFileCache.postClose() : save props");
338
372
 
339
373
                if (fileModified) {
340
374
                    backup();
341
375
                }
342
376
            } else {
343
377
                fa.removeElement(backupFileName);
 
378
                appLog.sendLine(SimpleLog.LOG_NORMAL,
 
379
                                "DataFileCache.postClose() : delete backup");
344
380
                deleteOrResetFreePos(database, fileName);
 
381
                appLog.sendLine(SimpleLog.LOG_NORMAL,
 
382
                                "DataFileCache.postClose() : delete file");
345
383
            }
346
384
        } catch (IOException e) {
347
385
            throw new HsqlException(
377
415
        }
378
416
 
379
417
        try {
 
418
            cache.saveAll();
 
419
 
380
420
            boolean        wasNio = dataFile.wasNio();
381
421
            DataFileDefrag dfd = new DataFileDefrag(database, this, fileName);
382
422
 
403
443
                }
404
444
            }
405
445
 
406
 
// oj@openofice.org - change to file access api
 
446
            // oj@openofice.org - change to file access api
407
447
            fa.renameElement(fileName + ".new", fileName);
408
448
            backup();
409
449
            database.getProperties().setProperty(
410
450
                HsqlDatabaseProperties.hsqldb_cache_version,
411
451
                HsqlDatabaseProperties.VERSION_STRING_1_7_0);
412
452
            database.getProperties().save();
413
 
            initParams();
414
453
            cache.clear();
415
454
 
416
455
            cache = new Cache(this);
421
460
            Trace.printSystemOut("opened cache");
422
461
        } catch (Throwable e) {
423
462
            database.logger.appLog.logContext(e);
 
463
            e.printStackTrace();
424
464
 
425
465
            throw new HsqlException(
426
466
                e, Trace.getMessage(Trace.GENERAL_IO_ERROR),
433
473
     * Removes the row from the cache data structures.
434
474
     * Adds the file space for the row to the list of free positions.
435
475
     */
436
 
    public void remove(int i, PersistentStore store) throws HsqlException {
 
476
    public synchronized void remove(int i,
 
477
                                    PersistentStore store)
 
478
                                    throws IOException {
437
479
 
438
480
        CachedObject r    = release(i);
439
481
        int          size = r == null ? getStorageSize(i)
442
484
        freeBlocks.add(i, size);
443
485
    }
444
486
 
 
487
    public synchronized void removePersistence(int i,
 
488
            PersistentStore store) throws IOException {}
 
489
 
445
490
    /**
446
491
     * Allocates file space for the row. <p>
447
492
     *
472
517
        return i;
473
518
    }
474
519
 
475
 
    public void add(CachedObject object) throws IOException {
 
520
    public synchronized void add(CachedObject object) throws IOException {
476
521
 
477
522
        int size = object.getRealSize(rowOut);
478
523
 
495
540
     * For a CacheObject that had been previously released from the cache.
496
541
     * A new version is introduced, using the preallocated space for the object.
497
542
     */
498
 
    public void restore(CachedObject object) throws IOException {
 
543
    public synchronized void restore(CachedObject object) throws IOException {
499
544
 
500
545
        int i = object.getPos();
501
546
 
507
552
        }
508
553
    }
509
554
 
510
 
    public synchronized int getStorageSize(int i) throws HsqlException {
511
 
 
512
 
        try {
513
 
            CachedObject value = cache.get(i);
514
 
 
515
 
            if (value != null) {
516
 
                return value.getStorageSize();
517
 
            }
518
 
 
519
 
            return readSize(i);
520
 
        } catch (IOException e) {
521
 
            database.logger.appLog.logContext(e);
522
 
 
523
 
            throw Trace.error(Trace.DATA_FILE_ERROR,
524
 
                              Trace.DataFileCache_makeRow, new Object[] {
525
 
                e, fileName
526
 
            });
 
555
    public synchronized int getStorageSize(int i) throws IOException {
 
556
 
 
557
        CachedObject value = cache.get(i);
 
558
 
 
559
        if (value != null) {
 
560
            return value.getStorageSize();
527
561
        }
 
562
 
 
563
        return readSize(i);
528
564
    }
529
565
 
530
566
    public synchronized CachedObject get(int i, PersistentStore store,
559
595
 
560
596
            return object;
561
597
        } catch (IOException e) {
562
 
            database.logger.appLog.logContext("" + cache + " pos: " + i);
 
598
            database.logger.appLog.logContext(SimpleLog.LOG_ERROR,
 
599
                                              fileName + " get pos: " + i);
563
600
            database.logger.appLog.logContext(e);
564
601
 
565
602
            throw Trace.error(Trace.DATA_FILE_ERROR,
569
606
        }
570
607
    }
571
608
 
572
 
    RowInputInterface getRaw(int i) throws IOException {
 
609
    synchronized RowInputInterface getRaw(int i) throws IOException {
573
610
        return readObject(i);
574
611
    }
575
612
 
576
 
    protected int readSize(int pos) throws IOException {
 
613
    protected synchronized int readSize(int pos) throws IOException {
577
614
 
578
615
        dataFile.seek((long) pos * cacheFileScale);
579
616
 
580
617
        return dataFile.readInt();
581
618
    }
582
619
 
583
 
    protected RowInputInterface readObject(int pos) throws IOException {
 
620
    protected synchronized RowInputInterface readObject(int pos)
 
621
    throws IOException {
584
622
 
585
623
        dataFile.seek((long) pos * cacheFileScale);
586
624
 
592
630
        return rowIn;
593
631
    }
594
632
 
595
 
    public CachedObject release(int i) {
 
633
    public synchronized CachedObject release(int i) {
596
634
        return cache.release(i);
597
635
    }
598
636
 
600
638
     * This is called internally when old rows need to be removed from the
601
639
     * cache.
602
640
     */
603
 
    protected void saveRows(CachedObject[] rows, int offset,
604
 
                            int count) throws IOException {
 
641
    protected synchronized void saveRows(CachedObject[] rows, int offset,
 
642
                                         int count) throws IOException {
605
643
 
606
644
        for (int i = offset; i < offset + count; i++) {
607
645
            CachedObject r = rows[i];
618
656
     * Writes out the specified Row. Will write only the Nodes or both Nodes
619
657
     * and table row data depending on what is not already persisted to disk.
620
658
     */
621
 
    public void saveRow(CachedObject row) throws IOException {
 
659
    public synchronized void saveRow(CachedObject row) throws IOException {
622
660
 
623
661
        setFileModified();
624
662
        rowOut.reset();
670
708
        }
671
709
 
672
710
        try {
673
 
            raFile = new ScaledRAFile(filename, false);
 
711
            raFile = new ScaledRAFile(database, filename, false);
674
712
 
675
713
            raFile.seek(LONG_FREE_POS_POS);
676
714
            raFile.writeLong(INITIAL_FREE_POS);
687
725
        }
688
726
    }
689
727
 
690
 
    public static int getFlags(String filename) throws HsqlException {
691
 
 
692
 
        try {
693
 
            ScaledRAFile raFile =
694
 
                (ScaledRAFile) ScaledRAFile.newScaledRAFile(filename, true,
695
 
                    ScaledRAFile.DATA_FILE_RAF, null, null);
696
 
 
697
 
            raFile.seek(FLAGS_POS);
698
 
 
699
 
            int flags = raFile.readInt();
700
 
 
701
 
            raFile.close();
702
 
 
703
 
            return flags;
704
 
        } catch (IOException e) {
705
 
            throw Trace.error(Trace.DATA_FILE_ERROR);
706
 
        }
707
 
    }
708
 
 
709
728
    public int capacity() {
710
729
        return maxCacheSize;
711
730
    }
746
765
        return fileModified;
747
766
    }
748
767
 
749
 
    protected void setFileModified() throws IOException {
 
768
    protected synchronized void setFileModified() throws IOException {
750
769
 
751
770
        if (!fileModified) {
752
771