[Mulgara-svn] r464 - trunk/src/jar/resolver/java/org/mulgara/resolver
andrae at mulgara.org
andrae at mulgara.org
Wed Oct 10 06:01:20 UTC 2007
Author: andrae
Date: 2007-10-10 01:01:19 -0500 (Wed, 10 Oct 2007)
New Revision: 464
Modified:
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
Log:
svn merge -r 426:430 ../branches/mgr-70
Resolves mgr-70 - Using a database-session in multiple threads can deadlock the
server.
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2007-10-05 19:02:51 UTC (rev 463)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransaction.java 2007-10-10 06:01:19 UTC (rev 464)
@@ -19,6 +19,7 @@
// Java 2 enterprise packages
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
@@ -88,6 +89,8 @@
private Transaction transaction;
private Thread currentThread;
+ private ReentrantLock activationMutex;
+
private State state;
private int inuse;
private int using;
@@ -107,6 +110,8 @@
this.manager = manager;
this.context = context;
this.enlisted = new HashSet<EnlistableResource>();
+ this.activationMutex = new ReentrantLock();
+ this.currentThread = null;
inuse = 0;
using = 0;
@@ -118,49 +123,55 @@
}
- synchronized void activate() throws MulgaraTransactionException {
+ void activate() throws MulgaraTransactionException {
// report("Activating Transaction");
-
try {
- if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
-
- switch (state) {
- case CONSTRUCTEDUNREF:
- startTransaction();
- inuse = 1;
- state = State.ACTUNREF;
- try {
- context.initiate(this);
- } catch (Throwable th) {
- throw implicitRollback(th);
- }
- break;
- case CONSTRUCTEDREF:
- startTransaction();
- inuse = 1;
- using = 1;
- state = State.ACTREF;
- try {
- context.initiate(this);
- } catch (Throwable th) {
- throw implicitRollback(th);
- }
- break;
- case DEACTREF:
- resumeTransaction();
- inuse = 1;
- state = State.ACTREF;
- break;
- case ACTREF:
- case ACTUNREF:
- inuse++;
- break;
- case FINISHED:
- throw new MulgaraTransactionException("Attempt to activate terminated transaction");
- case FAILED:
- throw new MulgaraTransactionException("Attempt to activate failed transaction", rollbackCause);
+
+ acquireActivationMutex();
+ try {
+ switch (state) {
+ case CONSTRUCTEDUNREF:
+ startTransaction();
+ inuse = 1;
+ state = State.ACTUNREF;
+ try {
+ context.initiate(this);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
+ break;
+ case CONSTRUCTEDREF:
+ startTransaction();
+ inuse = 1;
+ using = 1;
+ state = State.ACTREF;
+ try {
+ context.initiate(this);
+ } catch (Throwable th) {
+ throw implicitRollback(th);
+ }
+ break;
+ case DEACTREF:
+ resumeTransaction();
+ inuse = 1;
+ state = State.ACTREF;
+ break;
+ case ACTREF:
+ case ACTUNREF:
+ inuse++;
+ break;
+ case FINISHED:
+ throw new MulgaraTransactionException("Attempt to activate terminated transaction");
+ case FAILED:
+ throw new MulgaraTransactionException("Attempt to activate failed transaction", rollbackCause);
+ }
+ } finally {
+ releaseActivationMutex();
}
try {
@@ -178,45 +189,52 @@
}
- private synchronized void deactivate() throws MulgaraTransactionException {
+ private void deactivate() throws MulgaraTransactionException {
// report("Deactivating transaction");
try {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
-
- switch (state) {
- case ACTUNREF:
- if (inuse == 1) {
- commitTransaction();
- }
- inuse--;
- break;
- case ACTREF:
- if (inuse == 1) {
- suspendTransaction();
- }
- inuse--;
- break;
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Attempt to deactivate uninitiated refed transaction");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Attempt to deactivate uninitiated transaction");
- case DEACTREF:
- throw new IllegalStateException("Attempt to deactivate unactivated transaction");
- case FINISHED:
- if (inuse < 0) {
- errorReport("Activation count failure - too many deacts - in finished transaction", null);
- } else {
+
+ acquireActivationMutex();
+ try {
+ switch (state) {
+ case ACTUNREF:
+ if (inuse == 1) {
+ commitTransaction();
+ }
inuse--;
- }
- break;
- case FAILED:
- // Nothing to do here.
- break;
+ break;
+ case ACTREF:
+ if (inuse == 1) {
+ suspendTransaction();
+ }
+ inuse--;
+ break;
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Attempt to deactivate uninitiated refed transaction");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Attempt to deactivate uninitiated transaction");
+ case DEACTREF:
+ throw new IllegalStateException("Attempt to deactivate unactivated transaction");
+ case FINISHED:
+ if (inuse < 0) {
+ errorReport("Activation count failure - too many deacts - in finished transaction", null);
+ } else {
+ inuse--;
+ }
+ break;
+ case FAILED:
+ // Nothing to do here.
+ break;
+ }
+ } finally {
+ releaseActivationMutex();
}
} catch (MulgaraTransactionException em) {
throw em;
@@ -235,9 +253,12 @@
try {
report("Referencing Transaction");
- if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
+
switch (state) {
case CONSTRUCTEDUNREF:
state = State.CONSTRUCTEDREF;
@@ -270,9 +291,12 @@
void dereference() throws MulgaraTransactionException {
report("Dereferencing Transaction");
try {
- if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread != null && !currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
+
switch (state) {
case ACTREF:
if (using == 1) {
@@ -311,7 +335,9 @@
report("Initiating transaction");
try {
transaction = manager.transactionStart(this);
- currentThread = Thread.currentThread();
+ synchronized (this) {
+ currentThread = Thread.currentThread();
+ }
} catch (Throwable th) {
throw abortTransaction("Failed to start transaction", th);
}
@@ -321,7 +347,9 @@
// report("Resuming transaction");
try {
manager.transactionResumed(this, transaction);
- currentThread = Thread.currentThread();
+ synchronized (this) {
+ currentThread = Thread.currentThread();
+ }
} catch (Throwable th) {
abortTransaction("Failed to resume transaction", th);
}
@@ -335,7 +363,9 @@
new MulgaraTransactionException("Attempt to suspend unreferenced transaction"));
}
transaction = manager.transactionSuspended(this);
- currentThread = null;
+ synchronized (this) {
+ currentThread = null;
+ }
state = State.DEACTREF;
} catch (Throwable th) {
throw implicitRollback(th);
@@ -379,10 +409,12 @@
* after all we requested it.
*/
public void explicitRollback() throws MulgaraTransactionException {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction failed activation check");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction failed activation check");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
try {
@@ -426,10 +458,12 @@
try {
report("Implicit Rollback triggered");
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
if (rollbackCause != null) {
@@ -593,10 +627,12 @@
public void enlist(EnlistableResource enlistable) throws MulgaraTransactionException {
try {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ synchronized (this) {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
+ }
}
if (enlisted.contains(enlistable)) {
@@ -630,32 +666,42 @@
//
private void checkActivated() throws MulgaraTransactionException {
- if (currentThread == null) {
- throw new MulgaraTransactionException("Transaction not associated with thread");
- } else if (!currentThread.equals(Thread.currentThread())) {
- throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
- } else {
- switch (state) {
- case ACTUNREF:
- case ACTREF:
- if (inuse < 0 || using < 0) {
- throw new MulgaraTransactionException("Reference Failure, using: " + using + ", inuse: " + inuse);
- }
- return;
- case CONSTRUCTEDREF:
- throw new MulgaraTransactionException("Transaction (ref) uninitiated");
- case CONSTRUCTEDUNREF:
- throw new MulgaraTransactionException("Transaction (unref) uninitiated");
- case DEACTREF:
- throw new MulgaraTransactionException("Transaction deactivated");
- case FINISHED:
- throw new MulgaraTransactionException("Transaction is terminated");
- case FAILED:
- throw new MulgaraTransactionException("Transaction is failed", rollbackCause);
+ synchronized (this) {
+ if (currentThread == null) {
+ throw new MulgaraTransactionException("Transaction not associated with thread");
+ } else if (!currentThread.equals(Thread.currentThread())) {
+ throw new MulgaraTransactionException("Concurrent access attempted to transaction: Transaction has NOT been rolledback.");
}
}
+
+ switch (state) {
+ case ACTUNREF:
+ case ACTREF:
+ if (inuse < 0 || using < 0) {
+ throw new MulgaraTransactionException("Reference Failure, using: " + using + ", inuse: " + inuse);
+ }
+ return;
+ case CONSTRUCTEDREF:
+ throw new MulgaraTransactionException("Transaction (ref) uninitiated");
+ case CONSTRUCTEDUNREF:
+ throw new MulgaraTransactionException("Transaction (unref) uninitiated");
+ case DEACTREF:
+ throw new MulgaraTransactionException("Transaction deactivated");
+ case FINISHED:
+ throw new MulgaraTransactionException("Transaction is terminated");
+ case FAILED:
+ throw new MulgaraTransactionException("Transaction is failed", rollbackCause);
+ }
}
+ private void acquireActivationMutex() {
+ activationMutex.lock();
+ }
+
+ private void releaseActivationMutex() {
+ activationMutex.unlock();
+ }
+
protected void finalize() {
report("GC-finalize");
if (state != State.FINISHED && state != State.FAILED) {
@@ -668,7 +714,7 @@
}
if (state != State.FAILED && (inuse != 0 || using != 0)) {
- errorReport("Referernce counting error in transaction", null);
+ errorReport("Reference counting error in transaction", null);
}
if (manager != null || transaction != null) {
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2007-10-05 19:02:51 UTC (rev 463)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2007-10-10 06:01:19 UTC (rev 464)
@@ -528,10 +528,18 @@
}
}
+ /**
+ * Used to replace the built in monitor to allow it to be properly released
+ * during potentially blocking operations. All potentially blocking
+ * operations involve writes, so in these cases the write-lock is reserved
+ * allowing the mutex to be safely released and then reobtained after the
+ * blocking operation concludes.
+ */
private void acquireMutex() {
mutex.lock();
}
+
/**
* Used to reserve the write lock during a commit or rollback.
*/
@@ -584,11 +592,12 @@
for (int i = 0; i < holdCount; i++) {
mutex.unlock();
}
-
- proc.execute();
-
- for (int i = 0; i < holdCount; i++) {
- mutex.lock();
+ try {
+ proc.execute();
+ } finally {
+ for (int i = 0; i < holdCount; i++) {
+ mutex.lock();
+ }
}
}
}
More information about the Mulgara-svn
mailing list