001: /*
002: This source file is part of Smyle, a database library.
003: For up-to-date information, see http://www.drjava.de/smyle
004: Copyright (C) 2001 Stefan Reich (doc@drjava.de)
005:
006: This library is free software; you can redistribute it and/or
007: modify it under the terms of the GNU Lesser General Public
008: License as published by the Free Software Foundation; either
009: version 2.1 of the License, or (at your option) any later version.
010:
011: This library 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 GNU
014: Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public
017: License along with this library; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019:
020: For full license text, see doc/license/lgpl.txt in this distribution
021: */
022:
023: package drjava.smyle.core;
024:
025: import java.io.*;
026: import java.util.*;
027: import java.lang.Object;
028: import java.lang.ref.*;
029: import org.artsProject.mcop.*;
030: import org.artsProject.mcop.core.*;
031: import org.artsProject.util.*;
032: import drjava.smyle.*;
033: import drjava.smyle.meta.*;
034:
035: public final class SnapshotImpl implements Snapshot {
036: DiskStore store;
037:
038: // while converting legacy stores, this is different from chunkManager
039: ChunkManager newChunkManager;
040:
041: ChunkRef master = ChunkManager.NULLCHUNK;
042: Buffer masterBuffer;
043: ArrayList<String> tableNames = new ArrayList<String>();
044: ArrayList<ChunkRef> tableChunks = new ArrayList<ChunkRef>();
045: ArrayList<TableImpl> tables = new ArrayList<TableImpl>();
046: //int references = 0;
047: boolean closed;
048: boolean mutable;
049: boolean unwritten;
050:
051: // debugging
052: public int recCount;
053: public Thread currentThread;
054: public long workingSince;
055: public String currentFunctions[];
056:
057: SnapshotImpl(DiskStore store, ChunkManager newChunkManager,
058: boolean mutable) {
059: this .store = store;
060: this .newChunkManager = newChunkManager;
061: this .mutable = mutable;
062: master = store.chunkManager.getMasterChunk();
063: //if (debug) System.out.println("Master="+master);
064: loadMaster();
065: }
066:
067: synchronized void assertSnapshotOpen()
068: throws ClosedSnapshotException {
069: if (closed)
070: throw new ClosedSnapshotException("");
071: }
072:
073: public synchronized <T extends Struct<T>> Table<T> getTable(
074: String name, StructInfo<T> typeInfo) {
075: assertSnapshotOpen();
076: store.assertOpen();
077:
078: int i = tableNames.indexOf(name);
079: if (i < 0) {
080: i = tableNames.size();
081: //if (debug) System.out.println("New table "+name+" ("+i+" tables exist)");
082: tableNames.add(name);
083: tableChunks.add(ChunkManager.NULLCHUNK);
084: tables.add(null);
085: }
086: TableImpl table = tables.get(i);
087: if (table == null || !table.typed())
088: tables.set(i, table = new TableImpl<T>(this , typeInfo, i,
089: tableChunks.get(i), name));
090: return table; // compiler warning ok
091: }
092:
093: public synchronized void commitAndContinue()
094: throws SmyleIOException, ConcurrentWriteException {
095: assertSnapshotOpen();
096: store.assertOpen();
097:
098: if (store.deferThisCommit()) {
099: unwritten = true;
100: store.scheduleFlush();
101: } else {
102: save();
103: }
104: }
105:
106: synchronized void save() {
107: for (int i = 0; i < tables.size(); i++) {
108: TableImpl table = tables.get(i);
109: if (table != null) {
110: table.buildIndexIfAdvised();
111: table.flush();
112: }
113: }
114:
115: //System.out.println("commitAndContinue: tables: "+tables.size()+", changed="+(masterBuffer != null));
116: if (masterBuffer != null) {
117: synchronized (store) {
118: // The situation has changed since our snapshot was taken
119: // Just fail, even though there might be no conflict
120: if (!store.chunkManager.getMasterChunk().equals(master)) {
121: if (store.logger != null
122: && store.masterWriteSite != null)
123: store.masterWriteSite
124: .printStackTrace(store.logger);
125: throw new ConcurrentWriteException("");
126: }
127:
128: master = store.saveMaster(masterBuffer);
129: if (DiskStore.debug)
130: new Throwable("Writing " + masterBuffer.remaining()
131: + " bytes to master " + master.index)
132: .printStackTrace();
133: masterBuffer = null;
134:
135: /*if (tables.size() != 0)
136: if (debug) System.out.println("Saving master "+master+", table 0 elementsChunk: "+tableChunks.get(0));*/
137:
138: }
139: store.maybeGC();
140: }
141: }
142:
143: public synchronized void commit() throws SmyleIOException,
144: ConcurrentWriteException {
145: commitAndContinue();
146: forget();
147: }
148:
149: synchronized void collectChunks(BitSet whiteList) {
150: //if (debug) System.out.println("Adding master "+master+" to whitelist");
151:
152: // exit if snapshot has already been processed
153: if (whiteList.get(master.index))
154: return;
155:
156: whiteList.set(master.index);
157: for (int i = 0; i < tableChunks.size(); i++)
158: whiteList.set(tableChunks.get(i).index);
159: for (int i = 0; i < tables.size(); i++)
160: getOrCreateTable(i).collectChunks(whiteList);
161: }
162:
163: synchronized void saveMaster() {
164: Buffer b = new Buffer();
165: b.writeLong(store.VERSION);
166: MCOP.writeSeq(b, tableChunks);
167: MCOP.writeSeq(b, tableNames);
168: masterBuffer = b;
169: }
170:
171: private void loadMaster() {
172: try {
173: if (master.index != 0) {
174: if (DiskStore.debug)
175: new Throwable("Loading master chunk "
176: + master.index).printStackTrace();
177: Buffer b = store.chunkManager.readChunk(master);
178:
179: // read and check version
180:
181: store.version = b.readLong();
182: if (store.version > store.VERSION)
183: throw new BadUseException(
184: "This version of Smyle is too old to operate this store, please upgrade (this is revision "
185: + store.VERSION
186: + ", you need at least "
187: + store.version + ")");
188:
189: //if (debug) System.out.println("Master id: "+master+", bytes: "+b.remaining());
190: MCOP.readSeq(b, tableChunks, ChunkRef.DEMARSHALLER);
191: MCOP.readSeq(b, tableNames);
192: if (tableChunks.size() != tableNames.size())
193: throw new InternalSmyleError("Database is corrupt");
194: for (int i = 0; i < tableChunks.size(); i++)
195: tables.add(null);
196:
197: if (store.version < store.VERSION) {
198: // load all tables with store version
199: for (int i = 0; i < tableNames.size(); i++) {
200: tables.set(i, new TableImpl(this , i,
201: tableChunks.get(i), tableNames.get(i)));
202: }
203:
204: // bump version and store tables
205: store.version = store.VERSION;
206: for (int i = 0; i < tables.size(); i++) {
207: TableImpl t = tables.get(i);
208: t.saveSchema();
209: t.dirty = true;
210: t.flush();
211: if (DiskStore.debug)
212: System.out.println("Table chunk: "
213: + tableChunks.get(i));
214: }
215: //commitAndContinue();
216: }
217: }
218: } catch (MCOPException e) {
219: throw new InternalSmyleError(e);
220: }
221: }
222:
223: synchronized void setTableChunk(int tableId, ChunkRef file) {
224: //if (debug) System.out.println("setTableChunk "+tableId+" "+file.id);
225: tableChunks.set(tableId, file);
226: saveMaster();
227: }
228:
229: public synchronized void forget() {
230: if (mutable && !closed) {
231: closed = true;
232: synchronized (store) {
233: //if (store.writeSnapshot == this)
234: store.releaseWriteLock();
235:
236: store.forgetSnapshot(this );
237: }
238: }
239: }
240:
241: /** re-store a chunk in newChunkManager */
242: synchronized ChunkRef reStoreChunk(ChunkRef chunk) {
243: if (chunk.index == 0)
244: return chunk;
245: return newChunkManager.createChunk(store.chunkManager
246: .readChunk(chunk));
247: }
248:
249: synchronized void assertMutable() {
250: if (!mutable)
251: throw new ImmutableSnapshotException("");
252: }
253:
254: public synchronized SortedSet<String> getTableNames() {
255: return new TreeSet<String>(tableNames);
256: }
257:
258: public synchronized UntypedTable getUntypedTable(String name) {
259: assertSnapshotOpen();
260: store.assertOpen();
261:
262: int i = tableNames.indexOf(name);
263: if (i < 0)
264: return null;
265: return getOrCreateTable(i);
266: }
267:
268: private TableImpl getOrCreateTable(int i) {
269: TableImpl table = tables.get(i);
270: if (table == null)
271: tables.set(i, table = new TableImpl(this , i, tableChunks
272: .get(i), tableNames.get(i)));
273: return table;
274: }
275:
276: public synchronized boolean equals(Object o) {
277: return o instanceof SnapshotImpl
278: && master.equals(((SnapshotImpl) o).master);
279: }
280:
281: /*synchronized void ref() {
282: ++references;
283: }*/
284: }
|