001: /**
002: * com.mckoi.database.V1FileStoreSystem 04 Feb 2003
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.database;
024:
025: import com.mckoi.store.*;
026: import com.mckoi.debug.Lvl;
027: import java.io.File;
028: import java.io.FileOutputStream;
029: import java.io.IOException;
030:
031: /**
032: * An implementation of StoreSystem that manages persistant data through the
033: * native file system. Each store is represented by a ScatteringFileStore
034: * object against the current path. This implementation is compatible with
035: * versions of the database from 0.94 onwards.
036: *
037: * @author Tobias Downer
038: */
039:
040: class V1FileStoreSystem implements StoreSystem {
041:
042: /**
043: * The name of the file extention of the file lock on this conglomerate.
044: */
045: private static final String FLOCK_EXT = ".lock";
046:
047: /**
048: * The TransactionSystem that contains the various configuration options for
049: * the database.
050: */
051: private TransactionSystem system;
052:
053: /**
054: * The path in the filesystem where the data files are located.
055: */
056: private File path;
057:
058: /**
059: * True if the stores are read-only.
060: */
061: private boolean read_only;
062:
063: /**
064: * The lock file.
065: */
066: private FileOutputStream lock_file;
067:
068: /**
069: * Constructor.
070: */
071: public V1FileStoreSystem(TransactionSystem system, File path,
072: boolean read_only) {
073: this .system = system;
074: this .path = path;
075: this .read_only = read_only;
076: // If the database path doesn't exist, create it now,
077: if (!read_only && !path.exists()) {
078: path.mkdirs();
079: }
080: }
081:
082: /**
083: * Creates the JournalledFileStore object for this table.
084: */
085: private JournalledFileStore createFileStore(String file_name)
086: throws IOException {
087: LoggingBufferManager buffer_manager = system.getBufferManager();
088: return new JournalledFileStore(file_name, buffer_manager,
089: read_only);
090: }
091:
092: // ---------- Implemented from StoreSystem ----------
093:
094: public boolean storeExists(String name) {
095: try {
096: JournalledFileStore store = createFileStore(name);
097: return store.exists();
098: } catch (IOException e) {
099: system.Debug().writeException(e);
100: throw new RuntimeException("IO Error: " + e.getMessage());
101: }
102: }
103:
104: public Store createStore(String name) {
105: LoggingBufferManager buffer_manager = system.getBufferManager();
106: if (read_only) {
107: throw new RuntimeException(
108: "Can not create store because system is read-only.");
109: }
110: try {
111: buffer_manager.lockForWrite();
112:
113: JournalledFileStore store = createFileStore(name);
114: if (!store.exists()) {
115: store.open();
116: return store;
117: } else {
118: throw new RuntimeException(
119: "Can not create - store with name " + name
120: + " already exists.");
121: }
122: } catch (IOException e) {
123: system.Debug().writeException(e);
124: throw new RuntimeException("IO Error: " + e.getMessage());
125: } catch (InterruptedException e) {
126: throw new Error("Interrupted: " + e.getMessage());
127: } finally {
128: buffer_manager.unlockForWrite();
129: }
130:
131: }
132:
133: public Store openStore(String name) {
134: LoggingBufferManager buffer_manager = system.getBufferManager();
135: try {
136: buffer_manager.lockForWrite();
137:
138: JournalledFileStore store = createFileStore(name);
139: if (store.exists()) {
140: store.open();
141: return store;
142: } else {
143: throw new RuntimeException(
144: "Can not open - store with name " + name
145: + " does not exist.");
146: }
147: } catch (IOException e) {
148: system.Debug().writeException(e);
149: throw new RuntimeException("IO Error: " + e.getMessage());
150: } catch (InterruptedException e) {
151: throw new Error("Interrupted: " + e.getMessage());
152: } finally {
153: buffer_manager.unlockForWrite();
154: }
155:
156: }
157:
158: public boolean closeStore(Store store) {
159: LoggingBufferManager buffer_manager = system.getBufferManager();
160: try {
161: buffer_manager.lockForWrite();
162:
163: ((JournalledFileStore) store).close();
164: return true;
165: } catch (IOException e) {
166: system.Debug().writeException(e);
167: throw new RuntimeException("IO Error: " + e.getMessage());
168: } catch (InterruptedException e) {
169: throw new Error("Interrupted: " + e.getMessage());
170: } finally {
171: buffer_manager.unlockForWrite();
172: }
173:
174: }
175:
176: public boolean deleteStore(Store store) {
177: LoggingBufferManager buffer_manager = system.getBufferManager();
178: try {
179: buffer_manager.lockForWrite();
180:
181: return ((JournalledFileStore) store).delete();
182: } catch (IOException e) {
183: system.Debug().writeException(e);
184: throw new RuntimeException("IO Error: " + e.getMessage());
185: } catch (InterruptedException e) {
186: throw new Error("Interrupted: " + e.getMessage());
187: } finally {
188: buffer_manager.unlockForWrite();
189: }
190:
191: }
192:
193: public void setCheckPoint() {
194: try {
195: LoggingBufferManager buffer_manager = system
196: .getBufferManager();
197: buffer_manager.setCheckPoint(false);
198: } catch (IOException e) {
199: system.Debug().writeException(e);
200: throw new RuntimeException("IO Error: " + e.getMessage());
201: } catch (InterruptedException e) {
202: system.Debug().writeException(e);
203: throw new RuntimeException("Interrupted Error: "
204: + e.getMessage());
205: }
206: }
207:
208: public void lock(String name) throws IOException {
209: File flock_fn = new File(path, name + FLOCK_EXT);
210: if (flock_fn.exists()) {
211: // Okay, the file lock exists. This means either an extremely bad
212: // crash or there is another database locked on the files. If we can
213: // delete the lock then we can go on.
214: system.Debug().write(Lvl.WARNING, this ,
215: "File lock file exists: " + flock_fn);
216: boolean deleted = false;
217: deleted = flock_fn.delete();
218: if (!deleted) {
219: // If we couldn't delete, then most likely database being used.
220: System.err
221: .println("\n"
222: + "I couldn't delete the file lock for Database '"
223: + name
224: + "'.\n"
225: + "This most likely means the database is open and being used by\n"
226: + "another process.\n"
227: + "The lock file is: " + flock_fn
228: + "\n\n");
229: throw new IOException(
230: "Couldn't delete conglomerate file lock.");
231: }
232: }
233: //#IFDEF(NO_1.1)
234: // Atomically create the file,
235: flock_fn.createNewFile();
236: // Set it to delete on normal exit of the JVM.
237: flock_fn.deleteOnExit();
238: //#ENDIF
239: // Open up a stream and lock it in the OS
240: lock_file = new FileOutputStream(flock_fn);
241: }
242:
243: public void unlock(String name) throws IOException {
244: // Close and delete the lock file.
245: if (lock_file != null) {
246: lock_file.close();
247: }
248: // Try and delete it
249: File flock_fn = new File(path, name + FLOCK_EXT);
250: flock_fn.delete();
251: }
252:
253: }
|