001: /*
002: * $Id: SnapshotIsolationTransaction.java,v 1.45 2005/12/20 18:32:45 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2002-2006 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040:
041: package org.axiondb.engine;
042:
043: import java.io.File;
044: import java.util.HashMap;
045: import java.util.HashSet;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Map;
049: import java.util.Set;
050:
051: import org.axiondb.AxionException;
052: import org.axiondb.DataType;
053: import org.axiondb.Database;
054: import org.axiondb.DatabaseLink;
055: import org.axiondb.Index;
056: import org.axiondb.IndexFactory;
057: import org.axiondb.Sequence;
058: import org.axiondb.Table;
059: import org.axiondb.TableFactory;
060: import org.axiondb.TableIdentifier;
061: import org.axiondb.TransactableTable;
062: import org.axiondb.Transaction;
063: import org.axiondb.TransactionManager;
064: import org.axiondb.VariableContext;
065: import org.axiondb.event.ColumnEvent;
066: import org.axiondb.event.ConstraintEvent;
067: import org.axiondb.event.DatabaseModificationListener;
068: import org.axiondb.event.RowEvent;
069: import org.axiondb.event.TableModificationListener;
070: import org.axiondb.functions.ConcreteFunction;
071:
072: /**
073: * A {@link Transaction}implementation that provides "snapshot isolation", which supports
074: * TRANSACTION_SERIALIZABLE isolation without locking.
075: *
076: * @version $Revision: 1.45 $ $Date: 2005/12/20 18:32:45 $
077: * @author Rodney Waldhoff
078: * @author Chuck Burdick
079: * @author Amrish Lal
080: * @author Dave Pekarek Krohn
081: * @author Ahimanikya Satapathy
082: */
083: public class SnapshotIsolationTransaction implements Transaction,
084: TableModificationListener, VariableContext {
085:
086: public SnapshotIsolationTransaction(Database db) {
087: _openOnTransaction = db;
088: }
089:
090: public void addDatabaseModificationListener(
091: DatabaseModificationListener l) {
092: }
093:
094: public void addIndex(Index index, Table table)
095: throws AxionException {
096: _openOnTransaction.addIndex(index, table);
097: }
098:
099: public void addIndex(Index index, Table table, boolean doPopulate)
100: throws AxionException {
101: _openOnTransaction.addIndex(index, table, doPopulate);
102: }
103:
104: public void addTable(Table table) throws AxionException {
105: _openOnTransaction.addTable(table);
106: }
107:
108: public void apply() throws AxionException {
109: if (STATE_COMMITTED != _state) {
110: throw new AxionException("Not committed, can't apply.");
111: }
112: for (Iterator iter = _wrappedTables.values().iterator(); iter
113: .hasNext();) {
114: TransactableTable ttable = (TransactableTable) (iter.next());
115: ttable.apply();
116: }
117: _state = STATE_APPLIED;
118: }
119:
120: public void checkpoint() throws AxionException {
121: _openOnTransaction.checkpoint();
122: }
123:
124: public void columnAdded(ColumnEvent event) throws AxionException {
125: }
126:
127: public void commit() throws AxionException {
128: assertOpen();
129: for (Iterator iter = _wrappedTables.values().iterator(); iter
130: .hasNext();) {
131: TransactableTable ttable = (TransactableTable) (iter.next());
132: ttable.commit();
133: }
134: _contextVariables.clear();
135: _state = STATE_COMMITTED;
136: }
137:
138: // FIXME: There must be a better way to handle long running transaction
139: public TransactableTable commit(TableIdentifier tid)
140: throws AxionException {
141: assertOpen();
142:
143: // remove the old transaction table
144: if (_wrappedTables.containsKey(tid.getTableName())) {
145: TransactableTable ttable = (TransactableTable) _wrappedTables
146: .remove(tid.getTableName());
147: ttable.commit();
148: ttable.apply();
149: _readTables.remove(tid.getTableName());
150: _modifiedTables.remove(tid.getTableName());
151: }
152:
153: return getWrappedTable(tid);
154: }
155:
156: public void constraintAdded(ConstraintEvent event)
157: throws AxionException {
158: }
159:
160: public void constraintRemoved(ConstraintEvent event)
161: throws AxionException {
162: }
163:
164: public boolean containsKey(Object key) {
165: return _contextVariables.containsKey(key);
166: }
167:
168: public void createDatabaseLink(DatabaseLink server)
169: throws AxionException {
170: _openOnTransaction.createDatabaseLink(server);
171: }
172:
173: public void createSequence(Sequence seq) throws AxionException {
174: _openOnTransaction.createSequence(seq);
175: }
176:
177: public void dropDatabaseLink(String server) throws AxionException {
178: _openOnTransaction.dropDatabaseLink(server);
179: }
180:
181: public void dropDependentExternalDBTable(List tables)
182: throws AxionException {
183: _openOnTransaction.dropDependentExternalDBTable(tables);
184: }
185:
186: public void dropDependentViews(List views) throws AxionException {
187: _openOnTransaction.dropDependentViews(views);
188: }
189:
190: public void dropIndex(String name) throws AxionException {
191: _openOnTransaction.dropIndex(name);
192: }
193:
194: public void dropSequence(String name) throws AxionException {
195: _openOnTransaction.dropSequence(name);
196: }
197:
198: public void dropTable(String name) throws AxionException {
199: _openOnTransaction.dropTable(name);
200: if (_wrappedTables.containsKey(name)) {
201: _wrappedTables.remove(name);
202: _readTables.remove(name);
203: }
204: }
205:
206: public Object get(Object key) {
207: return _contextVariables.get(key);
208: }
209:
210: public DatabaseLink getDatabaseLink(String name) {
211: return _openOnTransaction.getDatabaseLink(name);
212: }
213:
214: public List getDatabaseModificationListeners() {
215: return null;
216: }
217:
218: public DataType getDataType(String name) {
219: return _openOnTransaction.getDataType(name);
220: }
221:
222: public File getDBDirectory() {
223: return _openOnTransaction.getDBDirectory();
224: }
225:
226: public List getDependentExternalDBTable(String name) {
227: return _openOnTransaction.getDependentExternalDBTable(name);
228: }
229:
230: public List getDependentViews(String tableName) {
231: return _openOnTransaction.getDependentViews(tableName);
232: }
233:
234: public ConcreteFunction getFunction(String name) {
235: return _openOnTransaction.getFunction(name);
236: }
237:
238: public Object getGlobalVariable(String key) {
239: return _openOnTransaction.getGlobalVariable(key);
240: }
241:
242: public IndexFactory getIndexFactory(String name) {
243: return _openOnTransaction.getIndexFactory(name);
244: }
245:
246: public Set getModifiedTables() {
247: return _modifiedTables;
248: }
249:
250: public String getName() {
251: return _openOnTransaction.getName();
252: }
253:
254: public Database getOpenOnTransaction() {
255: return _openOnTransaction;
256: }
257:
258: public Set getReadTables() {
259: return _readTables;
260: }
261:
262: public Sequence getSequence(String name) {
263: return _openOnTransaction.getSequence(name);
264: }
265:
266: public int getState() {
267: return _state;
268: }
269:
270: public Table getTable(String name) throws AxionException {
271: return getWrappedTable(new TableIdentifier(name));
272: }
273:
274: public Table getTable(TableIdentifier table) throws AxionException {
275: return getWrappedTable(table);
276: }
277:
278: public TableFactory getTableFactory(String name) {
279: return _openOnTransaction.getTableFactory(name);
280: }
281:
282: public TransactionManager getTransactionManager() {
283: return _openOnTransaction.getTransactionManager();
284: }
285:
286: public boolean hasDatabaseLink(String name) throws AxionException {
287: return _openOnTransaction.hasDatabaseLink(name);
288: }
289:
290: public boolean hasIndex(String name) throws AxionException {
291: return _openOnTransaction.hasIndex(name);
292: }
293:
294: public boolean hasSequence(String name) throws AxionException {
295: return _openOnTransaction.hasSequence(name);
296: }
297:
298: public boolean hasTable(String name) throws AxionException {
299: return _openOnTransaction.hasTable(name);
300: }
301:
302: public boolean hasTable(TableIdentifier table)
303: throws AxionException {
304: return _openOnTransaction.hasTable(table);
305: }
306:
307: public boolean isReadOnly() {
308: return _openOnTransaction.isReadOnly();
309: }
310:
311: public void migrate(int version) throws AxionException {
312: _openOnTransaction.migrate(version);
313: }
314:
315: public void put(Object key, Object value) {
316: _contextVariables.put(key, value);
317: }
318:
319: public void remount(File newdir) throws AxionException {
320: _openOnTransaction.remount(newdir);
321: }
322:
323: public void remove(Object key) {
324: _contextVariables.remove(key);
325: }
326:
327: public void renameTable(String oldName, String newName)
328: throws AxionException {
329: if (_wrappedTables.containsKey(oldName)) {
330:
331: // Apply any pending transaction before renaming it.
332: TransactableTable ttable = (TransactableTable) _wrappedTables
333: .get(oldName);
334: ttable.commit();
335: ttable.apply();
336:
337: // remove the old table from this transaction
338: _wrappedTables.remove(oldName);
339: _readTables.remove(oldName);
340: }
341:
342: // rename the table to the newName
343: _openOnTransaction.renameTable(oldName, newName);
344: }
345:
346: public void rollback() throws AxionException {
347: assertOpen();
348: for (Iterator iter = _wrappedTables.values().iterator(); iter
349: .hasNext();) {
350: TransactableTable ttable = (TransactableTable) (iter.next());
351: ttable.rollback();
352: }
353: _contextVariables.clear();
354: _state = STATE_ABORTED;
355: }
356:
357: public void rowDeleted(RowEvent event) throws AxionException {
358: _modifiedTables.add(event.getTable().getName());
359: }
360:
361: public void rowInserted(RowEvent event) throws AxionException {
362: _modifiedTables.add(event.getTable().getName());
363: }
364:
365: public void rowUpdated(RowEvent event) throws AxionException {
366: _modifiedTables.add(event.getTable().getName());
367: }
368:
369: public void shutdown() throws AxionException {
370: _openOnTransaction.shutdown();
371: }
372:
373: public void tableAltered(Table table) throws AxionException {
374: _openOnTransaction.tableAltered(table);
375: }
376:
377: private void assertOpen() throws AxionException {
378: if (STATE_OPEN != _state) {
379: throw new AxionException(
380: "Already committed or rolled back.");
381: }
382: }
383:
384: private TransactableTable getWrappedTable(TableIdentifier id)
385: throws AxionException {
386: TransactableTable ttable = (TransactableTable) (_wrappedTables
387: .get(id.getTableName()));
388: if (null == ttable) {
389: Table table = _openOnTransaction.getTable(id);
390: if (null == table) {
391: return null;
392: }
393:
394: ttable = table.makeTransactableTable();
395: ttable.addTableModificationListener(this );
396: _wrappedTables.put(id.getTableName(), ttable);
397: _readTables.add(ttable.getName());
398: }
399: return ttable;
400: }
401:
402: private Map _contextVariables = new HashMap();
403: private Set _modifiedTables = new HashSet();
404: private Database _openOnTransaction;
405: private Set _readTables = new HashSet();
406: private int _state = STATE_OPEN;
407: private Map _wrappedTables = new HashMap();
408:
409: }
|