commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ozeigerm...@apache.org
Subject cvs commit: jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/memory OptimisticMapWrapperTest.java
Date Thu, 03 Jun 2004 21:07:54 GMT
ozeigermann    2004/06/03 14:07:54

  Modified:    transaction/src/java/org/apache/commons/transaction/memory
                        OptimisticMapWrapper.java
               transaction/src/test/org/apache/commons/transaction/memory
                        OptimisticMapWrapperTest.java
  Added:       transaction/src/java/org/apache/commons/transaction/memory
                        ConflictException.java
  Log:
  Finished initial version of optimistic map wrapper; tests run fine
  
  Revision  Changes    Path
  1.4       +55 -10    jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java
  
  Index: OptimisticMapWrapper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/OptimisticMapWrapper.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- OptimisticMapWrapper.java	3 Jun 2004 14:15:31 -0000	1.3
  +++ OptimisticMapWrapper.java	3 Jun 2004 21:07:53 -0000	1.4
  @@ -86,7 +86,17 @@
           setActiveTx(context);
       }
   
  -    public synchronized void commitTransaction() {
  +    public synchronized void rollbackTransaction() {
  +        TxContext txContext = getActiveTx();
  +        super.rollbackTransaction();
  +        activeTransactions.remove(txContext);
  +    }
  +
  +    public synchronized void commitTransaction() throws ConflictException {
  +        commitTransaction(false);
  +    }
  +
  +    public synchronized void commitTransaction(boolean force) throws ConflictException
{
           TxContext txContext = getActiveTx();
   
           if (txContext == null) {
  @@ -98,17 +108,33 @@
               throw new IllegalStateException("Active thread " + Thread.currentThread() +
" is marked for rollback!");
           }
   
  -        checkForConflicts();
  +        if (!force) {
  +            Object conflictKey = checkForConflicts();
  +            if (conflictKey != null) {
  +                throw new ConflictException(conflictKey);
  +            }
  +        }
   
           copyChangesToConcurrentTransactions();
   
           super.commitTransaction();
  -        activeTransactions.remove(Thread.currentThread());
  -
  +        activeTransactions.remove(txContext);
       }
   
  -    protected void checkForConflicts() {
  -        // TODO
  +    // TODO: Shouldn't we return a collection rather than a single key here?
  +    public Object checkForConflicts() {
  +        CopyingTxContext txContext = (CopyingTxContext) getActiveTx();
  +
  +        Set keys = txContext.changedKeys();
  +        Set externalKeys = txContext.externalChangedKeys();
  +
  +        for (Iterator it2 = keys.iterator(); it2.hasNext();) {
  +            Object key = it2.next();
  +            if (externalKeys.contains(key)) {
  +                return key;
  +            }
  +        }
  +        return null;
       }
   
       protected void copyChangesToConcurrentTransactions() {
  @@ -117,6 +143,9 @@
           for (Iterator it = activeTransactions.iterator(); it.hasNext();) {
               CopyingTxContext otherTxContext = (CopyingTxContext) it.next();
   
  +            if (otherTxContext == thisTxContext)
  +                continue;
  +
               // no need to copy data if the other transaction does not access global map
anyway
               if (otherTxContext.cleared)
                   continue;
  @@ -160,6 +189,22 @@
               externalChanges = mapFactory.createMap();
               externalDeletes = setFactory.createSet();
               externalAdds = mapFactory.createMap();
  +        }
  +
  +        protected Set externalChangedKeys() {
  +            Set keySet = new HashSet();
  +            keySet.addAll(externalDeletes);
  +            keySet.addAll(externalChanges.keySet());
  +            keySet.addAll(externalAdds.keySet());
  +            return keySet;
  +        }
  +
  +        protected Set changedKeys() {
  +            Set keySet = new HashSet();
  +            keySet.addAll(deletes);
  +            keySet.addAll(changes.keySet());
  +            keySet.addAll(adds.keySet());
  +            return keySet;
           }
   
           protected Set keys() {
  
  
  
  1.1                  jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/ConflictException.java
  
  Index: ConflictException.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/transaction/src/java/org/apache/commons/transaction/memory/ConflictException.java,v
1.1 2004/06/03 21:07:53 ozeigermann Exp $
   * $Revision: 1.1 $
   * $Date: 2004/06/03 21:07:53 $
   *
   * ====================================================================
   *
   * Copyright 1999-2002 The Apache Software Foundation 
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  
  package org.apache.commons.transaction.memory;
  
  
  /**
   * Exception displaying a conflict between two optimistic transactions.
   * 
   * @author <a href="mailto:ozeigermann@apache.org">Oliver Zeigermann</a>
   * @version $Revision: 1.1 $
   * @see OptimisticMapWrapper
   */
  public class ConflictException extends RuntimeException /* FIXME Exception*/ {
  	protected Object key;
  	
  	public ConflictException(Object key) {
  		this.key = key;
  	}
  }
  
  
  
  1.3       +65 -4     jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/memory/OptimisticMapWrapperTest.java
  
  Index: OptimisticMapWrapperTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/src/test/org/apache/commons/transaction/memory/OptimisticMapWrapperTest.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- OptimisticMapWrapperTest.java	3 Jun 2004 14:15:31 -0000	1.2
  +++ OptimisticMapWrapperTest.java	3 Jun 2004 21:07:54 -0000	1.3
  @@ -43,7 +43,7 @@
       private static final Logger logger = Logger.getLogger(OptimisticMapWrapperTest.class.getName());
       private static final LoggerFacade sLogger = new Jdk14Logger(logger);
   
  -    private static final long BARRIER_TIMEOUT = 2000;
  +    private static final long BARRIER_TIMEOUT = 20000;
   
       // XXX need this, as JUnit seems to print only part of these strings
       private static void report(String should, String is) {
  @@ -141,6 +141,67 @@
           txMap1.rollbackTransaction();
           report("value2", (String) txMap1.get("key1"));
       }
  +
  +	public void testConflict() throws Throwable {
  +		logger.info("Checking concurrent transaction features");
  +
  +		final Map map1 = new HashMap();
  +
  +		final OptimisticMapWrapper txMap1 = new OptimisticMapWrapper(map1);
  +
  +		final RendezvousBarrier beforeCommitBarrier =
  +			new RendezvousBarrier("Before Commit", 2, BARRIER_TIMEOUT, sLogger);
  +
  +		final RendezvousBarrier afterCommitBarrier = new RendezvousBarrier("After Commit", 2,
BARRIER_TIMEOUT, sLogger);
  +
  +		Thread thread1 = new Thread(new Runnable() {
  +			public void run() {
  +				txMap1.startTransaction();
  +				try {
  +					beforeCommitBarrier.meet();
  +					txMap1.put("key1", "value2");
  +					txMap1.commitTransaction();
  +					afterCommitBarrier.call();
  +				} catch (InterruptedException e) {
  +					logger.log(Level.WARNING, "Thread interrupted", e);
  +					afterCommitBarrier.reset();
  +					beforeCommitBarrier.reset();
  +				}
  +			}
  +		}, "Thread1");
  +
  +		txMap1.put("key1", "value1");
  +
  +		txMap1.startTransaction();
  +		thread1.start();
  +
  +		report("value1", (String) txMap1.get("key1"));
  +		beforeCommitBarrier.call();
  +		afterCommitBarrier.meet();
  +		// we have serializable as isolation level, that's why I will still see the old value
  +		report("value1", (String) txMap1.get("key1"));
  +
  +		// now when I override it it should of course be my value
  +		txMap1.put("key1", "value3");
  +		report("value3", (String) txMap1.get("key1"));
  +		
  +		boolean conflict = false;
  +		
  +		try {
  +			txMap1.commitTransaction();
  +		} catch (ConflictException ce) {
  +			conflict = true;
  +		}
  +		assertTrue(conflict);
  +		// after failed commit it must be the value written by the other thread
  +		report("value2", (String) map1.get("key1"));
  +
  +		// force commit anyhow...
  +		txMap1.commitTransaction(true);
  +		// after successful commit it must be the value written by this thread
  +		report("value3", (String) txMap1.get("key1"));
  +		report("value3", (String) map1.get("key1"));
  +	}
   
       public void testTxControl() throws Throwable {
           logger.info("Checking advanced transaction control (heavily used in JCA implementation)");
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message