001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the Hypersonic SQL Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: *
030: * This software consists of voluntary contributions made by many individuals
031: * on behalf of the Hypersonic SQL Group.
032: *
033: *
034: * For work added by the HSQL Development Group:
035: *
036: * Copyright (c) 2001-2005, The HSQL Development Group
037: * All rights reserved.
038: *
039: * Redistribution and use in source and binary forms, with or without
040: * modification, are permitted provided that the following conditions are met:
041: *
042: * Redistributions of source code must retain the above copyright notice, this
043: * list of conditions and the following disclaimer.
044: *
045: * Redistributions in binary form must reproduce the above copyright notice,
046: * this list of conditions and the following disclaimer in the documentation
047: * and/or other materials provided with the distribution.
048: *
049: * Neither the name of the HSQL Development Group nor the names of its
050: * contributors may be used to endorse or promote products derived from this
051: * software without specific prior written permission.
052: *
053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
064: */
065:
066: package org.hsqldb.persist;
067:
068: import java.io.File;
069: import java.io.IOException;
070:
071: import org.hsqldb.Database;
072: import org.hsqldb.HsqlException;
073: import org.hsqldb.NumberSequence;
074: import org.hsqldb.Session;
075: import org.hsqldb.Table;
076: import org.hsqldb.Trace;
077: import org.hsqldb.lib.FileAccess;
078: import org.hsqldb.lib.HashMap;
079: import org.hsqldb.lib.Iterator;
080: import org.hsqldb.lib.SimpleLog;
081: import org.hsqldb.lib.ZipUnzipFile;
082: import org.hsqldb.scriptio.ScriptReaderBase;
083: import org.hsqldb.scriptio.ScriptWriterBase;
084:
085: // fredt@users 20020215 - patch 1.7.0 by fredt
086: // to move operations on the database.properties files to new
087: // class HsqlDatabaseProperties
088: // fredt@users 20020220 - patch 488200 by xclayl@users - throw exception
089: // throw addded to all methods relying on file io
090: // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
091: // fredt@users 20020405 - patch 1.7.0 by fredt - no change in db location
092: // because important information about the database is now stored in the
093: // *.properties file, all database files should be in the same folder as the
094: // *.properties file
095: // tony_lai@users 20020820 - export hsqldb.log_size to .properties file
096: // tony_lai@users 20020820 - changes to shutdown compact to save memory
097: // fredt@users 20020910 - patch 1.7.1 by Nitin Chauhan - code improvements
098: // fredt@users 20021208 - ongoing revamp
099: // fredt@users 20021212 - do not rewrite the *.backup file if the *.data
100: // file has not been updated in the current session.
101: // boucherb@users 20030510 - patch 1.7.2 consolidated all periodic database
102: // tasks in one timed task queue
103: // fredt@users - 20050102 patch 1.8.0 - refactoring and clearer separation of concerns
104:
105: /**
106: * This class is responsible for managing the database files. An HSQLDB database
107: * consists of a .properties file, a .script file (contains an SQL script),
108: * a .data file (contains data of cached tables) a .backup file
109: * and a .log file.<p>
110: * When using TEXT tables, a data source for each table is also present.<p>
111: *
112: * Notes on OpenOffice.org integration.
113: *
114: * A Storage API is used when HSQLDB is integrated into OpenOffice.org. All
115: * file operations on the 4 main files are performed by OOo, which integrates
116: * the contents of these files into its database file. The script format is
117: * always TEXT in this case.
118: *
119: * Extensively rewritten and extended in successive versions of HSQLDB.
120: *
121: * @author Thomas Mueller (Hypersonic SQL Group)
122: * @author fredt@users.
123: * @version 1.8.0
124: * @since Hypersonic SQL
125: */
126: public class Log {
127:
128: private HsqlDatabaseProperties properties;
129: private String fileName;
130: private Database database;
131: private FileAccess fa;
132: private ScriptWriterBase dbLogWriter;
133: private String scriptFileName;
134: private String logFileName;
135: private boolean filesReadOnly;
136: private long maxLogSize;
137: private int writeDelay;
138: private int scriptFormat;
139: private DataFileCache cache;
140:
141: Log(Database db) throws HsqlException {
142:
143: database = db;
144: fa = db.getFileAccess();
145: fileName = db.getPath();
146: properties = db.getProperties();
147: }
148:
149: void initParams() {
150:
151: // Allows the user to set log size in the properties file.
152: int logMegas = properties.getIntegerProperty(
153: HsqlDatabaseProperties.hsqldb_log_size, 0);
154:
155: maxLogSize = logMegas * 1024 * 1024;
156: scriptFormat = properties.getIntegerProperty(
157: HsqlDatabaseProperties.hsqldb_script_format,
158: ScriptWriterBase.SCRIPT_TEXT_170);
159: writeDelay = properties.getDefaultWriteDelay();
160: filesReadOnly = database.isFilesReadOnly();
161: scriptFileName = fileName + ".script";
162: logFileName = fileName + ".log";
163: }
164:
165: /**
166: * When opening a database, the hsqldb.compatible_version property is
167: * used to determine if this version of the engine is equal to or greater
168: * than the earliest version of the engine capable of opening that
169: * database.<p>
170: *
171: * @throws HsqlException
172: */
173: void open() throws HsqlException {
174:
175: initParams();
176:
177: int state = properties.getDBModified();
178:
179: switch (state) {
180:
181: case HsqlDatabaseProperties.FILES_MODIFIED:
182: deleteNewAndOldFiles();
183: restoreBackup();
184: processScript();
185: processDataFile();
186: processLog();
187: close(false);
188:
189: if (cache != null) {
190: cache.open(filesReadOnly);
191: }
192:
193: reopenAllTextCaches();
194: break;
195:
196: case HsqlDatabaseProperties.FILES_NEW:
197: try {
198: deleteBackup();
199: backupData();
200: renameNewBackup();
201: renameNewScript();
202: deleteLog();
203: properties
204: .setDBModified(HsqlDatabaseProperties.FILES_NOT_MODIFIED);
205: } catch (IOException e) {
206: database.logger.appLog.logContext(e, null);
207: }
208:
209: // continue as non-modified files
210: case HsqlDatabaseProperties.FILES_NOT_MODIFIED:
211:
212: /**
213: * if startup is after a SHUTDOWN SCRIPT and there are CACHED
214: * or TEXT tables, perform a checkpoint so that the .script
215: * file no longer contains CACHED or TEXT table rows.
216: */
217: processScript();
218:
219: if (isAnyCacheModified()) {
220: properties
221: .setDBModified(HsqlDatabaseProperties.FILES_MODIFIED);
222: close(false);
223:
224: if (cache != null) {
225: cache.open(filesReadOnly);
226: }
227:
228: reopenAllTextCaches();
229: }
230: break;
231: }
232:
233: openLog();
234:
235: if (!filesReadOnly) {
236: properties
237: .setDBModified(HsqlDatabaseProperties.FILES_MODIFIED);
238: }
239: }
240:
241: /**
242: * Close all the database files. If script argument is true, no .data
243: * or .backup file will remain and the .script file will contain all the
244: * data of the cached tables as well as memory tables.
245: *
246: * This is not used for filesReadOnly databases which use shutdown.
247: */
248: void close(boolean script) throws HsqlException {
249:
250: closeLog();
251: deleteNewAndOldFiles();
252: writeScript(script);
253: closeAllTextCaches(script);
254:
255: if (cache != null) {
256: cache.close(true);
257: }
258:
259: properties.setProperty(HsqlDatabaseProperties.db_version,
260: HsqlDatabaseProperties.THIS_VERSION);
261: properties.setProperty(
262: HsqlDatabaseProperties.hsqldb_compatible_version,
263: HsqlDatabaseProperties.FIRST_COMPATIBLE_VERSION);
264:
265: // set this one last to save the props
266: properties.setDBModified(HsqlDatabaseProperties.FILES_NEW);
267: deleteLog();
268:
269: if (script) {
270: deleteBackup();
271: deleteData();
272: } else {
273: try {
274: backupData();
275: renameNewBackup();
276: } catch (IOException e) {
277: }
278: }
279:
280: renameNewScript();
281: properties.setProperty(
282: HsqlDatabaseProperties.hsqldb_cache_version,
283: HsqlDatabaseProperties.THIS_CACHE_VERSION);
284: properties
285: .setDBModified(HsqlDatabaseProperties.FILES_NOT_MODIFIED);
286: }
287:
288: /**
289: * Fast counterpart to close(). Does not perform a checkpoint or a backup
290: * of the .data file.
291: */
292: void shutdown() throws HsqlException {
293:
294: synchLog();
295:
296: if (cache != null) {
297: cache.close(false);
298: }
299:
300: closeAllTextCaches(false);
301: closeLog();
302: }
303:
304: /**
305: * Deletes the leftovers from any previous unfinished operations.
306: */
307: void deleteNewAndOldFiles() {
308:
309: fa.removeElement(fileName + ".data" + ".old");
310: fa.removeElement(fileName + ".data" + ".new");
311: fa.removeElement(fileName + ".backup" + ".new");
312: fa.removeElement(scriptFileName + ".new");
313: }
314:
315: void deleteBackup() {
316: fa.removeElement(fileName + ".backup");
317: }
318:
319: void deleteData() {
320: fa.removeElement(fileName + ".data");
321: }
322:
323: void backupData() throws IOException {
324:
325: if (fa.isStreamElement(fileName + ".data")) {
326: ZipUnzipFile.compressFile(fileName + ".data", fileName
327: + ".backup.new", database.getFileAccess());
328: }
329: }
330:
331: void renameNewBackup() {
332:
333: if (fa.isStreamElement(fileName + ".backup.new")) {
334: fa.renameElement(fileName + ".backup.new", fileName
335: + ".backup");
336: }
337: }
338:
339: void renameNewScript() {
340:
341: if (fa.isStreamElement(scriptFileName + ".new")) {
342: fa.renameElement(scriptFileName + ".new", scriptFileName);
343: }
344: }
345:
346: void deleteNewScript() {
347: fa.removeElement(scriptFileName + ".new");
348: }
349:
350: void deleteNewBackup() {
351: fa.removeElement(scriptFileName + ".backup.new");
352: }
353:
354: void deleteLog() {
355: fa.removeElement(logFileName);
356: }
357:
358: /**
359: * Checks all the caches and returns true if the modified flag is set for any
360: */
361: boolean isAnyCacheModified() {
362:
363: if (cache != null && cache.isFileModified()) {
364: return true;
365: }
366:
367: return isAnyTextCacheModified();
368: }
369:
370: /**
371: * Performs checkpoint including pre and post operations. Returns to the
372: * same state as before the checkpoint.
373: */
374: void checkpoint(boolean defrag) throws HsqlException {
375:
376: if (filesReadOnly) {
377: return;
378: }
379:
380: database.logger.appLog
381: .logContext(SimpleLog.LOG_NORMAL, "start");
382: deleteNewAndOldFiles();
383:
384: if (cache != null) {
385: if (forceDefrag()) {
386: defrag = true;
387: }
388:
389: if (defrag) {
390: try {
391: cache.defrag();
392: } catch (Exception e) {
393: }
394: } else {
395: cache.close(true);
396:
397: try {
398: cache.backupFile();
399: } catch (IOException e1) {
400: deleteNewBackup();
401: cache.open(false);
402:
403: return;
404: }
405:
406: cache.open(false);
407: }
408: }
409:
410: writeScript(false);
411: properties.setDBModified(HsqlDatabaseProperties.FILES_NEW);
412: closeLog();
413: deleteLog();
414: renameNewScript();
415: renameNewBackup();
416: properties.setDBModified(HsqlDatabaseProperties.FILES_MODIFIED);
417:
418: if (dbLogWriter == null) {
419: return;
420: }
421:
422: openLog();
423:
424: Session[] sessions = database.sessionManager.getAllSessions();
425:
426: try {
427: for (int i = 0; i < sessions.length; i++) {
428: Session session = sessions[i];
429:
430: if (session.isAutoCommit() == false) {
431: dbLogWriter.writeLogStatement(session, session
432: .getAutoCommitStatement());
433: }
434: }
435: } catch (IOException e) {
436: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
437: }
438:
439: database.logger.appLog.logContext(SimpleLog.LOG_NORMAL, "end");
440: }
441:
442: /**
443: * Returns true if lost space is above the threshold
444: */
445: boolean forceDefrag() {
446:
447: long megas = properties.getIntegerProperty(
448: HsqlDatabaseProperties.hsqldb_defrag_limit, 200);
449: long defraglimit = megas * 1024 * 1024;
450: long lostSize = cache.freeBlocks.getLostBlocksSize();
451:
452: return lostSize > defraglimit;
453: }
454:
455: /**
456: *
457: */
458: boolean hasCache() {
459: return cache != null;
460: }
461:
462: /**
463: * Responsible for creating the cache instance.
464: */
465: DataFileCache getCache() throws HsqlException {
466:
467: /*
468: if (database.isFilesInJar()) {
469: return null;
470: }
471: */
472: if (cache == null) {
473: cache = new DataFileCache(database, fileName);
474:
475: cache.open(filesReadOnly);
476: }
477:
478: return cache;
479: }
480:
481: int getLogSize() {
482: return (int) (maxLogSize / (1024 * 11024));
483: }
484:
485: void setLogSize(int megas) {
486:
487: properties.setProperty(HsqlDatabaseProperties.hsqldb_log_size,
488: String.valueOf(megas));
489:
490: maxLogSize = megas * 1024 * 1024;
491: }
492:
493: int getScriptType() {
494: return scriptFormat;
495: }
496:
497: /**
498: * Changing the script format results in a checkpoint, with the .script
499: * file written in the new format.
500: */
501: void setScriptType(int type) throws HsqlException {
502:
503: if (database.isStoredFileAccess()) {
504: return;
505: }
506:
507: boolean needsCheckpoint = scriptFormat != type;
508:
509: scriptFormat = type;
510:
511: properties.setProperty(
512: HsqlDatabaseProperties.hsqldb_script_format, String
513: .valueOf(scriptFormat));
514:
515: if (needsCheckpoint) {
516: database.logger.needsCheckpoint = true;
517: }
518: }
519:
520: /**
521: * Write delay specifies the frequency of FileDescriptor.sync() calls.
522: */
523: int getWriteDelay() {
524: return writeDelay;
525: }
526:
527: void setWriteDelay(int delay) {
528:
529: writeDelay = delay;
530:
531: if (dbLogWriter != null) {
532: synchLog();
533: dbLogWriter.setWriteDelay(delay);
534: }
535: }
536:
537: /**
538: * Various writeXXX() methods are used for logging statements.
539: */
540: void writeStatement(Session session, String s) throws HsqlException {
541:
542: if (s == null || s.length() == 0) {
543: return;
544: }
545:
546: try {
547: dbLogWriter.writeLogStatement(session, s);
548: } catch (IOException e) {
549: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
550: }
551:
552: if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) {
553: database.logger.needsCheckpoint = true;
554: }
555: }
556:
557: void writeInsertStatement(Session session, Table t, Object[] row)
558: throws HsqlException {
559:
560: try {
561: dbLogWriter.writeInsertStatement(session, t, row);
562: } catch (IOException e) {
563: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
564: }
565:
566: if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) {
567: database.logger.needsCheckpoint = true;
568: }
569: }
570:
571: void writeDeleteStatement(Session session, Table t, Object[] row)
572: throws HsqlException {
573:
574: try {
575: dbLogWriter.writeDeleteStatement(session, t, row);
576: } catch (IOException e) {
577: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
578: }
579:
580: if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) {
581: database.logger.needsCheckpoint = true;
582: }
583: }
584:
585: void writeSequenceStatement(Session session, NumberSequence s)
586: throws HsqlException {
587:
588: try {
589: dbLogWriter.writeSequenceStatement(session, s);
590: } catch (IOException e) {
591: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
592: }
593:
594: if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) {
595: database.logger.needsCheckpoint = true;
596: }
597: }
598:
599: void writeCommitStatement(Session session) throws HsqlException {
600:
601: try {
602: dbLogWriter.writeCommitStatement(session);
603: } catch (IOException e) {
604: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
605: }
606:
607: if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) {
608: database.logger.needsCheckpoint = true;
609: }
610: }
611:
612: void synchLog() {
613:
614: if (dbLogWriter != null) {
615: dbLogWriter.sync();
616: }
617: }
618:
619: /**
620: * Wrappers for openning-starting / stoping-closing the log file and
621: * writer.
622: */
623: private void openLog() throws HsqlException {
624:
625: if (filesReadOnly) {
626: return;
627: }
628:
629: try {
630: dbLogWriter = ScriptWriterBase.newScriptWriter(database,
631: logFileName, false, false,
632: ScriptWriterBase.SCRIPT_TEXT_170);
633:
634: dbLogWriter.setWriteDelay(writeDelay);
635: dbLogWriter.start();
636: } catch (Exception e) {
637: throw Trace.error(Trace.FILE_IO_ERROR, logFileName);
638: }
639: }
640:
641: private synchronized void closeLog() throws HsqlException {
642:
643: if (dbLogWriter != null) {
644: dbLogWriter.close();
645: }
646: }
647:
648: /**
649: * Write the .script file as .script.new.
650: */
651: private void writeScript(boolean full) throws HsqlException {
652:
653: deleteNewScript();
654:
655: //fredt - to do - flag for chache set index
656: ScriptWriterBase scw = ScriptWriterBase.newScriptWriter(
657: database, scriptFileName + ".new", full, true,
658: scriptFormat);
659:
660: scw.writeAll();
661: scw.close();
662: }
663:
664: /**
665: * Performs all the commands in the .script file.
666: */
667: private void processScript() throws HsqlException {
668:
669: ScriptReaderBase scr = null;
670:
671: try {
672: if (database.isFilesInJar()
673: || fa.isStreamElement(scriptFileName)) {
674: scr = ScriptReaderBase.newScriptReader(database,
675: scriptFileName, scriptFormat);
676:
677: scr.readAll(database.sessionManager.getSysSession(null,
678: true));
679: scr.close();
680: }
681: } catch (Throwable e) {
682: if (scr != null) {
683: scr.close();
684:
685: if (cache != null) {
686: cache.close(false);
687: }
688:
689: closeAllTextCaches(false);
690: }
691:
692: database.logger.appLog.logContext(e, null);
693:
694: if (e instanceof HsqlException) {
695: throw (HsqlException) e;
696: } else if (e instanceof IOException) {
697: throw Trace.error(Trace.FILE_IO_ERROR, e.toString());
698: } else if (e instanceof OutOfMemoryError) {
699: throw Trace.error(Trace.OUT_OF_MEMORY);
700: } else {
701: throw Trace.error(Trace.GENERAL_ERROR, e.toString());
702: }
703: }
704: }
705:
706: /**
707: * Defrag large data files when the sum of .log and .data files is large.
708: */
709: private void processDataFile() throws HsqlException {
710:
711: if (cache == null || filesReadOnly
712: || database.isStoredFileAccess()
713: || !fa.isStreamElement(logFileName)) {
714: return;
715: }
716:
717: File file = new File(logFileName);
718: long logLength = file.length();
719: long dataLength = cache.getFileFreePos();
720:
721: if (logLength + dataLength > cache.maxDataFileSize) {
722: database.logger.needsCheckpoint = true;
723: }
724: }
725:
726: /**
727: * Performs all the commands in the .log file.
728: */
729: private void processLog() throws HsqlException {
730:
731: if (!database.isFilesInJar() && fa.isStreamElement(logFileName)) {
732: ScriptRunner.runScript(database, logFileName,
733: ScriptWriterBase.SCRIPT_TEXT_170);
734: }
735: }
736:
737: /**
738: * Restores a compressed backup or the .data file.
739: */
740: private void restoreBackup() throws HsqlException {
741:
742: // in case data file cannot be deleted, reset it
743: DataFileCache
744: .deleteOrResetFreePos(database, fileName + ".data");
745:
746: try {
747: ZipUnzipFile.decompressFile(fileName + ".backup", fileName
748: + ".data", database.getFileAccess());
749: } catch (Exception e) {
750: throw Trace
751: .error(Trace.FILE_IO_ERROR, Trace.Message_Pair,
752: new Object[] { fileName + ".backup",
753: e.toString() });
754: }
755: }
756:
757: // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP) - text tables
758: private HashMap textCacheList = new HashMap();
759:
760: DataFileCache openTextCache(Table table, String source,
761: boolean readOnlyData, boolean reversed)
762: throws HsqlException {
763:
764: closeTextCache(table);
765:
766: if (!properties.isPropertyTrue("textdb.allow_full_path")) {
767: if (source.indexOf("..") != -1) {
768: throw (Trace.error(Trace.ACCESS_IS_DENIED, source));
769: }
770:
771: String path = new File(new File(database.getPath()
772: + ".properties").getAbsolutePath()).getParent();
773:
774: if (path != null) {
775: source = path + File.separator + source;
776: }
777: }
778:
779: TextCache c;
780: int type;
781:
782: if (reversed) {
783: c = new TextCache(table, source);
784: } else {
785: c = new TextCache(table, source);
786: }
787:
788: c.open(readOnlyData || filesReadOnly);
789: textCacheList.put(table.getName(), c);
790:
791: return c;
792: }
793:
794: void closeTextCache(Table table) throws HsqlException {
795:
796: TextCache c = (TextCache) textCacheList.remove(table.getName());
797:
798: if (c != null) {
799: c.close(true);
800: }
801: }
802:
803: private void closeAllTextCaches(boolean compact)
804: throws HsqlException {
805:
806: Iterator it = textCacheList.values().iterator();
807:
808: while (it.hasNext()) {
809: if (compact) {
810: ((TextCache) it.next()).purge();
811: } else {
812: ((TextCache) it.next()).close(true);
813: }
814: }
815: }
816:
817: private void reopenAllTextCaches() throws HsqlException {
818:
819: Iterator it = textCacheList.values().iterator();
820:
821: while (it.hasNext()) {
822: ((TextCache) it.next()).reopen();
823: }
824: }
825:
826: private boolean isAnyTextCacheModified() {
827:
828: Iterator it = textCacheList.values().iterator();
829:
830: while (it.hasNext()) {
831: if (((TextCache) it.next()).isFileModified()) {
832: return true;
833: }
834: }
835:
836: return false;
837: }
838: }
|