package org.exist.fluent;
import org.exist.dom.DocumentImpl;
import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock;
import org.exist.storage.txn.*;
import org.exist.util.LockException;
/**
* A transaction on the database. This can be either a top-level transaction, or a "nested"
* transaction. Nested transactions do nothing on commit and abort. All transactions will
* only execute a commit or abort once, all further invocations do nothing. This makes it
* convenient to put abort in a finally clause -- it will only have an effect if no commit was
* reached beforehand.
*
* @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
*/
class Transaction {
private final TransactionManager txManager;
final Txn tx;
final DBBroker broker;
private final Database db;
private boolean complete;
/**
* Begin a new transaction.
*
* @param txManager the manager to use
*/
Transaction(TransactionManager txManager, Database db) {
this.txManager = txManager;
this.tx = txManager.beginTransaction();
this.db = db;
this.broker = db == null ? null : db.acquireBroker();
complete = false;
}
/**
* Join an existing transaction, do nothing on commit or abort.
*
* @param tx the transaction to join
*/
Transaction(Transaction tx, Database db) {
this.txManager = null;
this.tx = tx.tx;
this.db = db;
this.broker = db == null ? null : db.acquireBroker();
complete = true;
}
void commit() {
if (complete) return;
try {
if (tx != null && txManager != null) try {
txManager.commit(tx);
complete = true;
} catch (TransactionException e) {
throw new DatabaseException(e);
}
} finally {
if (broker != null) db.releaseBroker(broker);
}
}
void abortIfIncomplete() {
if (complete) return;
if (tx != null && txManager != null) txManager.abort(tx);
if (broker != null) db.releaseBroker(broker);
complete = true;
}
void lockWrite(DocumentImpl doc) {
try {
tx.acquireLock(doc.getUpdateLock(), Lock.WRITE_LOCK);
} catch (LockException e) {
throw new DatabaseException(e);
}
}
void lockRead(DocumentImpl doc) {
try {
tx.acquireLock(doc.getUpdateLock(), Lock.READ_LOCK);
} catch (LockException e) {
throw new DatabaseException(e);
}
}
}