You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oz...@apache.org on 2005/01/31 01:12:32 UTC
svn commit: r149190 - in jakarta/commons/proper/transaction/trunk:
RELEASE-NOTES.txt
src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java
Author: ozeigermann
Date: Sun Jan 30 16:12:31 2005
New Revision: 149190
URL: http://svn.apache.org/viewcvs?view=rev&rev=149190
Log:
OptimisticMapWrapper now uses a read/write lock to guarantee
no other operations are being executed while
commiting.
Before this it was possible that conflicts that arose during the process of
committing remained undetected
Modified:
jakarta/commons/proper/transaction/trunk/RELEASE-NOTES.txt
jakarta/commons/proper/transaction/trunk/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java
Modified: jakarta/commons/proper/transaction/trunk/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/transaction/trunk/RELEASE-NOTES.txt?view=diff&r1=149189&r2=149190
==============================================================================
--- jakarta/commons/proper/transaction/trunk/RELEASE-NOTES.txt (original)
+++ jakarta/commons/proper/transaction/trunk/RELEASE-NOTES.txt Sun Jan 30 16:12:31 2005
@@ -65,6 +65,9 @@
- Fixed deadlock hazard in deadlock detection caused by interleaving access to locks set of an owner
- Fixed timeout that in certain scenarios did not work
- GenericLock test method released all locks held by the testing owner - fixed
+- OptimisticMapWrapper now uses a read/write lock to guarantee no other operations are being executed while
+ commiting; before it was possible that conflicts that arose during the process of
+ committing remained undetected
ENHANCEMENTS FROM 1.0 beta1
-----------------------
Modified: jakarta/commons/proper/transaction/trunk/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/transaction/trunk/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java?view=diff&r1=149189&r2=149190
==============================================================================
--- jakarta/commons/proper/transaction/trunk/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java (original)
+++ jakarta/commons/proper/transaction/trunk/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java Sun Jan 30 16:12:31 2005
@@ -1,7 +1,7 @@
/*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//transaction/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java,v 1.1 2004/11/18 23:27:18 ozeigermann Exp $
* $Revision: 1.1 $
- * $Date: 2004/11/18 23:27:18 $
+ * $Date$
*
* ====================================================================
*
@@ -23,12 +23,17 @@
package org.apache.commons.transaction.memory;
+import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
+import org.apache.commons.transaction.locking.ReadWriteLock;
+import org.apache.commons.transaction.util.LoggerFacade;
+import org.apache.commons.transaction.util.PrintWriterLogger;
+
/**
* Wrapper that adds transactional control to all kinds of maps that implement the {@link Map} interface. By using
* a naive optimistic transaction control this wrapper has better isolation than {@link TransactionalMapWrapper}, but
@@ -52,8 +57,15 @@
*/
public class OptimisticMapWrapper extends TransactionalMapWrapper {
+ protected static final int COMMIT_TIMEOUT = 1000 * 60; // 1 minute
+ protected static final int ACCESS_TIMEOUT = 1000 * 30; // 30 seconds
+
protected Set activeTransactions;
+ protected LoggerFacade logger;
+
+ protected ReadWriteLock commitLock;
+
/**
* Creates a new optimistic transactional map wrapper. Temporary maps and sets to store transactional
* data will be instances of {@link java.util.HashMap} and {@link java.util.HashSet}.
@@ -73,10 +85,28 @@
* @param setFactory factory for temporary sets
*/
public OptimisticMapWrapper(Map wrapped, MapFactory mapFactory, SetFactory setFactory) {
+ this(wrapped, mapFactory, setFactory, new PrintWriterLogger(new PrintWriter(System.out),
+ OptimisticMapWrapper.class.getName(), false));
+ }
+
+ /**
+ * Creates a new optimistic transactional map wrapper. Temporary maps and sets to store transactional
+ * data will be created and disposed using {@link MapFactory} and {@link SetFactory}.
+ *
+ * @param wrapped map to be wrapped
+ * @param mapFactory factory for temporary maps
+ * @param setFactory factory for temporary sets
+ * @param logger
+ * generic logger used for all kinds of logging
+ */
+ public OptimisticMapWrapper(Map wrapped, MapFactory mapFactory, SetFactory setFactory, LoggerFacade logger) {
super(wrapped, mapFactory, setFactory);
activeTransactions = Collections.synchronizedSet(new HashSet());
+ this.logger = logger;
+ commitLock = new ReadWriteLock("COMMIT", logger);
}
-
+
+
public void startTransaction() {
if (getActiveTx() != null) {
throw new IllegalStateException(
@@ -99,7 +129,7 @@
public void commitTransaction(boolean force) throws ConflictException {
TxContext txContext = getActiveTx();
-
+
if (txContext == null) {
throw new IllegalStateException(
"Active thread " + Thread.currentThread() + " not associated with a transaction!");
@@ -108,19 +138,28 @@
if (txContext.status == STATUS_MARKED_ROLLBACK) {
throw new IllegalStateException("Active thread " + Thread.currentThread() + " is marked for rollback!");
}
-
- if (!force) {
- Object conflictKey = checkForConflicts();
- if (conflictKey != null) {
- throw new ConflictException(conflictKey);
+
+ try {
+ // in this final commit phase we need to be the only one access the map
+ // to make sure no one adds an entry after we checked for conflicts
+ commitLock.acquireWrite(txContext, COMMIT_TIMEOUT);
+
+ if (!force) {
+ Object conflictKey = checkForConflicts();
+ if (conflictKey != null) {
+ throw new ConflictException(conflictKey);
+ }
}
- }
-
- // be sure commit is atomic
- synchronized (this) {
+
activeTransactions.remove(txContext);
copyChangesToConcurrentTransactions();
super.commitTransaction();
+
+ } catch (InterruptedException e) {
+ // XXX a bit dirty ;)
+ throw new ConflictException(e);
+ } finally {
+ commitLock.release(txContext);
}
}
@@ -208,76 +247,139 @@
}
protected Set keys() {
- Set keySet = super.keys();
- keySet.removeAll(externalDeletes);
- keySet.addAll(externalAdds.keySet());
- return keySet;
- }
-
- protected Object get(Object key) {
-
- if (deletes.contains(key)) {
- // reflects that entry has been deleted in this tx
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ Set keySet = super.keys();
+ keySet.removeAll(externalDeletes);
+ keySet.addAll(externalAdds.keySet());
+ return keySet;
+ } catch (InterruptedException e) {
return null;
+ } finally {
+ commitLock.release(this);
}
+ }
- Object changed = changes.get(key);
- if (changed != null) {
- return changed;
- }
-
- Object added = adds.get(key);
- if (added != null) {
- return added;
- }
+ protected Object get(Object key) {
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
- if (cleared) {
- return null;
- } else {
- if (externalDeletes.contains(key)) {
+ if (deletes.contains(key)) {
// reflects that entry has been deleted in this tx
return null;
}
-
- changed = externalChanges.get(key);
+
+ Object changed = changes.get(key);
if (changed != null) {
return changed;
}
-
- added = externalAdds.get(key);
+
+ Object added = adds.get(key);
if (added != null) {
return added;
}
+
+ if (cleared) {
+ return null;
+ } else {
+ if (externalDeletes.contains(key)) {
+ // reflects that entry has been deleted in this tx
+ return null;
+ }
+
+ changed = externalChanges.get(key);
+ if (changed != null) {
+ return changed;
+ }
+
+ added = externalAdds.get(key);
+ if (added != null) {
+ return added;
+ }
+
+ // not modified in this tx
+ return wrapped.get(key);
+ }
+ } catch (InterruptedException e) {
+ return null;
+ } finally {
+ commitLock.release(this);
+ }
+ }
- // not modified in this tx
- return wrapped.get(key);
+ protected void put(Object key, Object value) {
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ super.put(key, value);
+ } catch (InterruptedException e) {
+ } finally {
+ commitLock.release(this);
+ }
+ }
+
+ protected void remove(Object key) {
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ super.remove(key);
+ } catch (InterruptedException e) {
+ } finally {
+ commitLock.release(this);
}
}
protected int size() {
- int size = super.size();
-
- size -= externalDeletes.size();
- size += externalAdds.size();
-
- return size;
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ int size = super.size();
+
+ size -= externalDeletes.size();
+ size += externalAdds.size();
+
+ return size;
+ } catch (InterruptedException e) {
+ return -1;
+ } finally {
+ commitLock.release(this);
+ }
}
protected void clear() {
- super.clear();
- externalDeletes.clear();
- externalChanges.clear();
- externalAdds.clear();
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ super.clear();
+ externalDeletes.clear();
+ externalChanges.clear();
+ externalAdds.clear();
+ } catch (InterruptedException e) {
+ } finally {
+ commitLock.release(this);
+ }
}
+ protected void merge() {
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ super.merge();
+ } catch (InterruptedException e) {
+ } finally {
+ commitLock.release(this);
+ }
+ }
+
protected void dispose() {
- super.dispose();
- setFactory.disposeSet(externalDeletes);
- externalDeletes = null;
- mapFactory.disposeMap(externalChanges);
- externalChanges = null;
- mapFactory.disposeMap(externalAdds);
- externalAdds = null;
+ try {
+ commitLock.acquireRead(this, ACCESS_TIMEOUT);
+ super.dispose();
+ setFactory.disposeSet(externalDeletes);
+ externalDeletes = null;
+ mapFactory.disposeMap(externalChanges);
+ externalChanges = null;
+ mapFactory.disposeMap(externalAdds);
+ externalAdds = null;
+ } catch (InterruptedException e) {
+ } finally {
+ commitLock.release(this);
+ }
}
protected void finalize() throws Throwable {
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org