[jboss-svn-commits] JBL Code SVN: r37856 - in labs/jbosstm/workspace/mlittle/STM-Arjuna/src: main/java/org/jboss/stm/optimistic and 2 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Jan 20 08:41:49 EST 2012


Author: mark.little at jboss.com
Date: 2012-01-20 08:41:49 -0500 (Fri, 20 Jan 2012)
New Revision: 37856

Added:
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockManager.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockRecord.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/ConflictType.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/LockConflictManager.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLock.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockManager.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockRecord.java
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/
   labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/OptimisticUnitTest.java
Log:
Initial optimistic concurrency control approach. Hacked. Shouldn't need to copy most of these classes.

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockManager.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockManager.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockManager.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,94 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.  
+ *
+ * $Id: CadaverLockManager.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.arjuna.state.*;
+
+import com.arjuna.ats.txoj.logging.txojLogger;
+import com.arjuna.ats.txoj.logging.FacilityCode;
+
+import com.arjuna.common.util.logging.*;
+
+/*
+ *
+ * Lock concurrency controller
+ *
+ * Lock-base concurrency control management system
+ * Instances of this class are created by CadaverLockRecord class
+ * instances for the sole purpose of lock cleanup due to a locked
+ * object going out of scope prior to action termination. 
+ * Serialisability prevents locks being released as scope is exited
+ * thus they must be cleaned up later.
+ *
+ */
+
+class CadaverLockManager extends OptimisticLockManager
+{
+
+    public CadaverLockManager(Uid objUid, String tName)
+    {
+        super(objUid);
+
+        objectTypeName = new String(tName);
+
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "CadaverLockManager::CadaverLockManager(" + objUid + ")");
+        }
+    }
+
+    /*
+     * Publically inherited functions
+     */
+
+    public boolean restore_state (InputObjectState os, int t)
+    {
+        return false;
+    }
+
+    public boolean save_state (OutputObjectState os, int t)
+    {
+        return false;
+    }
+
+    public String type ()
+    {
+        return objectTypeName;
+    }
+
+    private String objectTypeName;
+
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockRecord.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockRecord.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/CadaverLockRecord.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,283 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000, 2001,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.  
+ *
+ * $Id: CadaverLockRecord.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
+import com.arjuna.ats.arjuna.*;
+import com.arjuna.ats.arjuna.coordinator.*;
+import com.arjuna.ats.arjuna.common.Uid;
+
+import com.arjuna.ats.txoj.logging.txojLogger;
+import com.arjuna.ats.txoj.logging.FacilityCode;
+
+import com.arjuna.common.util.logging.*;
+
+import com.arjuna.ats.txoj.lockstore.*;
+import java.io.PrintWriter;
+
+import com.arjuna.ats.arjuna.exceptions.FatalError;
+
+/**
+ * @message com.arjuna.ats.txoj.CadaverLockRecord_1 [com.arjuna.ats.txoj.CadaverLockRecord_1] - CadaverLockRecord::nestedAbort - no Current!
+ * @message com.arjuna.ats.txoj.CadaverLockRecord_2 [com.arjuna.ats.txoj.CadaverLockRecord_2] - CadaverLockRecord::nestedCommit - no Current!
+ * @message com.arjuna.ats.txoj.CadaverLockRecord_3 [com.arjuna.ats.txoj.CadaverLockRecord_3] - CadaverLockRecord::topLevelAbort - no Current!
+ * @message com.arjuna.ats.txoj.CadaverLockRecord_4 [com.arjuna.ats.txoj.CadaverLockRecord_4] - CadaverLockRecord::topLevelCommit - no Current!
+ */
+
+/*
+ *
+ * Cadaver Lock Record Class Implementation
+ *
+ * Instances of this record class are created by LockManager if the
+ * object goes out of scope prior to the end of a manipulating action.
+ * The intention is that the operations of this class will clean up
+ * those locks that get left set as the object goes out of scope but
+ * which must remain held until the action ends otherwise serialisability
+ * is compromised
+ *
+ */ 
+
+class CadaverLockRecord extends OptimisticLockRecord
+{
+
+    public CadaverLockRecord (LockStore store, OptimisticLockManager lm, BasicAction currAct)
+    {
+	super(lm, currAct);
+	
+	cadaverLockStore = store;
+	objectTypeName = new String(lm.type());
+	
+	if (((StateManagerAttribute)lm.attributes()).objectModel == ObjectModel.SINGLE)
+	{
+	    doRelease = false;
+	}
+	else
+	    doRelease = true;
+
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				     "CadaverLockRecord::CadaverLockRecord("+store+
+				       ", "+((lm != null) ? lm.get_uid() : Uid.nullUid())+")");
+	}
+    }
+    
+    /*
+     * Public virtual functions. These are all re-implementations of inherited
+     * functions 
+     */
+    
+    public boolean propagateOnAbort ()
+    {
+	return true;
+    }
+    
+    /*
+     * Atomic action controlled functions. These functions create an instance
+     * of CadaverLockManager to handle the lock manipulation that is needed and
+     * then throw it away when done.
+     */
+
+    public int nestedAbort ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "CadaverLockRecord::nestedAbort() for "+order());
+	}
+	
+	if (doRelease)
+	{
+	    CadaverLockManager manager = new CadaverLockManager(order(), objectTypeName);
+
+	    if (super.actionHandle == null)
+	    {
+		if (txojLogger.aitLoggerI18N.isFatalEnabled())
+		{
+		    txojLogger.aitLoggerI18N.fatal("CadaverLockRecord_1");
+		}
+		
+		throw new FatalError(txojLogger.log_mesg.getString("com.arjuna.ats.txoj.CadaverLockRecord_1"));
+	    }
+	    
+	    return (manager.releaseAll(super.actionHandle.get_uid()) ? TwoPhaseOutcome.FINISH_OK : TwoPhaseOutcome.FINISH_ERROR);
+	}
+	else
+	    return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public int nestedCommit ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "CadaverLockRecord::nestedCommit() for "+order());
+	}
+	
+	if (doRelease)
+	{
+	    /*
+	     * Need to change the owner of the locks from the current
+	     * committing action to its parent. Since no genuine LockManager
+	     * exists at this time create one to take care of this.
+	     */
+    
+	    if (super.actionHandle == null)
+	    {
+		if (txojLogger.aitLoggerI18N.isFatalEnabled())
+		{
+		    txojLogger.aitLoggerI18N.fatal("com.arjuna.ats.txoj.CadaverLockRecord_2");
+		}
+		
+		throw new FatalError(txojLogger.log_mesg.getString("com.arjuna.ats.txoj.CadaverLockRecord_2"));
+	    }
+    
+	    CadaverLockManager manager = new CadaverLockManager(order(), objectTypeName);
+	    
+	    return (manager.propagate(super.actionHandle.get_uid(), super.actionHandle.parent().get_uid()) ? TwoPhaseOutcome.FINISH_OK : TwoPhaseOutcome.FINISH_ERROR);
+	}
+	else
+	    return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public int topLevelAbort ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "CadaverLockRecord::topLevelAbort() for "+order());
+	}
+	
+	if (doRelease)
+	{
+	    if (super.actionHandle == null)
+	    {
+		if (txojLogger.aitLoggerI18N.isFatalEnabled())
+		{
+		    txojLogger.aitLoggerI18N.fatal("com.arjuna.ats.txoj.CadaverLockRecord_3");
+		}
+		
+		throw new FatalError(txojLogger.log_mesg.getString("com.arjuna.ats.txoj.CadaverLockRecord_3"));
+	    }
+
+	    CadaverLockManager manager = new CadaverLockManager(order(), objectTypeName);
+
+	    return (manager.releaseAll(super.actionHandle.get_uid()) ? TwoPhaseOutcome.FINISH_OK : TwoPhaseOutcome.FINISH_ERROR);
+	}
+	else
+	    return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public int topLevelCommit ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "CadaverLockRecord::topLevelCommit() for "+order());
+	}
+	
+	if (doRelease)
+	{
+	    if (super.actionHandle == null)
+	    {
+		if (txojLogger.aitLoggerI18N.isFatalEnabled())
+		{
+		    txojLogger.aitLoggerI18N.fatal("com.arjuna.ats.txoj.CadaverLockRecord_4");
+		}
+		
+		throw new FatalError(txojLogger.log_mesg.getString("com.arjuna.ats.txoj.CadaverLockRecord_4"));
+	    }
+
+	    CadaverLockManager manager = new CadaverLockManager(order(), objectTypeName);
+
+	    return (manager.releaseAll(super.actionHandle.get_uid()) ? TwoPhaseOutcome.FINISH_OK : TwoPhaseOutcome.FINISH_ERROR);
+	}
+	else
+	    return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public void print (PrintWriter strm)
+    {
+	strm.println("CadaverLockRecord : ");
+	super.print(strm);
+    }
+
+    public String type ()
+    {
+	return "/StateManager/AbstractRecord/LockRecord/CadaverLockRecord";
+    }
+    
+    public boolean shouldReplace (AbstractRecord ar)
+    {
+	return (((order().equals(ar.order())) &&
+		 ar.typeIs() == RecordType.LOCK ) ? true : false);
+    }
+    
+    /*
+     * Already determined that ar is a LockRecord, otherwise replace would
+     * not have been called.
+     * So, get the type from it before it is deleted!
+     */
+    
+    public void replace (AbstractRecord ar)
+    {
+	OptimisticLockRecord lr = (OptimisticLockRecord) ar;
+
+	objectTypeName = lr.lockType();
+    }
+    
+    protected CadaverLockRecord ()
+    {
+	super();
+	
+	cadaverLockStore = null;
+	objectTypeName = null;
+	doRelease = false;
+	
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PROTECTED,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "CadaverLockRecord::CadaverLockRecord ()");
+	}
+    }
+
+    private LockStore   cadaverLockStore;
+    private String      objectTypeName;
+    private boolean     doRelease;
+
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/ConflictType.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/ConflictType.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/ConflictType.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.
+ *
+ * $Id: ConflictType.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import java.io.PrintWriter;
+
+/**
+ * The various types of lock conflict that can occur when
+ * trying to set a lock.
+ */
+
+class ConflictType
+{
+
+    public static final int CONFLICT = 0;
+    public static final int COMPATIBLE = 1;
+    public static final int PRESENT = 2;
+
+    public static String stringForm (int c)
+    {
+	switch (c)
+	{
+	case CONFLICT:
+	    return "ConflictType.CONFLICT";
+	case COMPATIBLE:
+	    return "ConflictType.COMPATIBLE";
+	case PRESENT:
+	    return "ConflictType.PRESENT";
+	default:
+	    return "Unknown";
+	}
+    }
+    
+    /**
+     * Print a human-readable form of the conflict type.
+     */
+
+    public static void print (PrintWriter strm, int c)
+    {
+	strm.print(c);
+    }
+    
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/LockConflictManager.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/LockConflictManager.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/LockConflictManager.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 2000, 2001,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.  
+ *
+ * $Id: LockConflictManager.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import java.lang.InterruptedException;
+
+/**
+ * An instance of this class is used to determine what to do in the event of a
+ * lock conflict for a given object. If the timeout and retry values are >=0
+ * then we use them to sleep the thread which tried to get the lock. If the
+ * retry value is -100 (LockManager.waitTotalTimeout) then the thread will block
+ * for up to the total timeout and be signalled either when the timeout occurs,
+ * or when the lock is actually released.
+ */
+
+class LockConflictManager
+{
+
+    LockConflictManager()
+    {
+        _lock = new Object();
+        _signals = 0;
+    }
+
+    /**
+     * Wait for the specified timeout and retry. We may either sleep the thread,
+     * or block it on a mutex. Returns the time taken to wait.
+     */
+
+    int wait (int retry, int waitTime)
+    {
+        /*
+         * If the retry is -1 then we wait on the object as if it were a lock.
+         * Otherwise we do the usual sleep call.
+         */
+
+        if (retry < 0)
+        {
+            /*
+             * Wait for the lock object to be signalled.
+             */
+
+            Date d1 = Calendar.getInstance().getTime();
+
+            synchronized (_lock)
+            {
+                try
+                {
+                    /*
+                     * Consume an old signal. May cause us to go round the loop
+                     * quicker than we should, but its better than synchronizing
+                     * signal and wait.
+                     */
+
+                    if (_signals == 0)
+                    {
+                        _lock.wait(waitTime);
+                    }
+                    else
+                    {
+                        _signals--;
+
+                        return waitTime;
+                    }
+                }
+                catch (InterruptedException e)
+                {
+                }
+            }
+
+            Date d2 = Calendar.getInstance().getTime();
+
+            return (int) (d2.getTime() - d1.getTime());
+        }
+        else
+        {
+            try
+            {
+                /* hope things happen in time */
+
+                Thread.sleep(waitTime);
+            }
+            catch (InterruptedException e)
+            {
+            }
+
+            return 0;
+        }
+    }
+
+    /**
+     * Signal that the lock has been released.
+     */
+
+    void signal ()
+    {
+        synchronized (_lock)
+        {
+            _lock.notifyAll();
+
+            _signals++;
+
+            if (_signals < 0) // check for overflow
+                _signals = 1;
+        }
+    }
+
+    private Object _lock;
+
+    private int _signals;
+
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLock.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLock.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLock.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.  
+ *
+ * $Id: Lock.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.txoj.Lock;
+
+/**
+ * Instances of this class (or derived user classes) are used when trying to set
+ * a lock. The default implementation provides a single-write/multiple-reader
+ * policy. However, by overridding the appropriate methods, other, type-specific
+ * concurrency control locks can be implemented.
+ * 
+ * @author Mark Little (mark at arjuna.com)
+ * @version $Id: Lock.java 2342 2006-03-30 13:06:17Z $
+ * @since JTS 1.0.
+ */
+
+public class OptimisticLock extends Lock
+{
+    public OptimisticLock ()
+    {
+        super();
+    }
+    
+    public OptimisticLock (int lm)
+    {
+        super(lm);
+    }
+    
+    public OptimisticLock (final Uid storeId)
+    {
+        super(storeId);
+    }
+    
+    /**
+     * Does this lock imply a modification of the object it is applied to? For
+     * example, a READ lock would return false, but a WRITE lock would return
+     * true.
+     * 
+     * @return <code>true</code> if this lock implies the object's state will be
+     *         modified, <code>false</code> otherwise.
+     */
+
+    public boolean modifiesObject ()
+    {
+        return true;
+    }
+
+    /**
+     * Implementation of Lock conflict check. Returns TRUE if there is conflict
+     * FALSE otherwise. Does not take account of relationship in the atomic
+     * action hierarchy since this is a function of LockManager.
+     * 
+     * @return <code>true</code> if this lock conflicts with the parameter,
+     *         <code>false</code> otherwise.
+     */
+
+    public boolean conflictsWith (Lock otherLock)
+    {
+        return false; /* no conflict between these locks */
+    }
+
+    /**
+     * Overrides StateManager.type()
+     */
+
+    public String type ()
+    {
+        return "/StateManager/Lock/OptimisticLock";
+    }
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockManager.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockManager.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockManager.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,1515 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000, 2001,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.
+ *
+ * $Id: LockManager.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import com.arjuna.ats.txoj.Lock;
+import com.arjuna.ats.txoj.LockList;
+import com.arjuna.ats.txoj.LockListIterator;
+import com.arjuna.ats.txoj.LockManagerAttribute;
+import com.arjuna.ats.txoj.LockResult;
+import com.arjuna.ats.txoj.lockstore.*;
+import com.arjuna.ats.txoj.semaphore.*;
+import com.arjuna.ats.txoj.common.Environment;
+import com.arjuna.ats.arjuna.*;
+import com.arjuna.ats.arjuna.common.*;
+import com.arjuna.ats.arjuna.StateManager;
+import com.arjuna.ats.arjuna.gandiva.*;
+
+import com.arjuna.ats.txoj.logging.txojLogger;
+import com.arjuna.ats.txoj.logging.FacilityCode;
+
+import com.arjuna.common.util.logging.*;
+
+import com.arjuna.ats.arjuna.coordinator.*;
+import com.arjuna.ats.arjuna.state.*;
+import com.arjuna.ats.txoj.common.txojPropertyManager;
+import java.io.PrintWriter;
+import java.util.*;
+
+import com.arjuna.ats.txoj.exceptions.LockStoreException;
+import java.lang.InterruptedException;
+import java.io.IOException;
+
+/**
+ * This class provides (transactional) concurrency control for application
+ * objects.
+ * 
+ * @author Mark Little (mark at arjuna.com)
+ * @version $Id: LockManager.java 2342 2006-03-30 13:06:17Z $
+ * @since JTS 1.0.
+ * @see com.arjuna.ats.arjuna.StateManager
+ * @message com.arjuna.ats.txoj.LockManager_1 [com.arjuna.ats.txoj.LockManager_1]
+ *          - LockManager: lock propagation failed
+ * @message com.arjuna.ats.txoj.LockManager_2
+ *          [com.arjuna.ats.txoj.LockManager_2] - LockManager::setlock() no
+ *          lock!
+ * @message com.arjuna.ats.txoj.LockManager_3
+ *          [com.arjuna.ats.txoj.LockManager_3] - LockManager::setlock() cannot
+ *          find action hierarchy
+ * @message com.arjuna.ats.txoj.LockManager_4
+ *          [com.arjuna.ats.txoj.LockManager_4] - LockManager::setlock() cannot
+ *          load existing lock states
+ * @message com.arjuna.ats.txoj.LockManager_5
+ *          [com.arjuna.ats.txoj.LockManager_5] - LockManager::setlock() cannot
+ *          activate object
+ * @message com.arjuna.ats.txoj.LockManager_6
+ *          [com.arjuna.ats.txoj.LockManager_6] - LockManager::setlock() cannot
+ *          save new lock states
+ * @message com.arjuna.ats.txoj.LockManager_7
+ *          [com.arjuna.ats.txoj.LockManager_7] - Lockmanager::releaselock()
+ *          could not load old lock states
+ * @message com.arjuna.ats.txoj.LockManager_8
+ *          [com.arjuna.ats.txoj.LockManager_8] - Lockmanager::releaselock()
+ *          could not unload new lock states
+ * @message com.arjuna.ats.txoj.LockManager_10
+ *          [com.arjuna.ats.txoj.LockManager_10] - LockManager::unloadState()
+ *          failed to remove empty lock state for object {0} of type {1}
+ * @message com.arjuna.ats.txoj.LockManager_11
+ *          [com.arjuna.ats.txoj.LockManager_11] - LockManager.unloadState -
+ *          could not save lock state: {0}
+ * @message com.arjuna.ats.txoj.LockManager_12
+ *          [com.arjuna.ats.txoj.LockManager_12] - LockManager::unloadState()
+ *          failed to write new state for object {0} of type {1}
+ * @message com.arjuna.ats.txoj.LockManager_13
+ *          [com.arjuna.ats.txoj.LockManager_13] - LockManager::unloadState()
+ *          failed to pack up new state for object {0} of type {1}
+ */
+
+public class OptimisticLockManager extends StateManager
+{
+
+    /**
+     * The default retry value which will be used by setlock if no other value
+     * is given.
+     * 
+     * @see #setlock
+     */
+
+    public static final int defaultRetry = 100;
+
+    /**
+     * The default timeout value which will be used by setlock if no other value
+     * is given.
+     * 
+     * @see #setlock
+     */
+
+    public static final int defaultSleepTime = 250;
+
+    /**
+     * By default, threads which call setlock with conflicting locks will spin
+     * for the specified (or default) number of timeout and retry attempts, and
+     * then return failure if the lock could not be acquired. If the *retry*
+     * period is set to this value, then such threads will sleep for their total
+     * wait period and be signalled if the lock is released within this period
+     * of time.
+     * 
+     * @see #setlock
+     * @since JTS 2.1.
+     */
+
+    public static final int waitTotalTimeout = -100;
+
+    /**
+     * Cleanup. Note we grab the semaphore before destroying the the lock store
+     * to ensure the store is deleted cleanly.
+     */
+
+    public void finalize () throws Throwable
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.DESTRUCTORS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager.finalize()");
+        }
+
+        boolean doSignal = false;
+
+        cleanUp();
+
+        if (mutex != null)
+        {
+            if (mutex.lock() == Semaphore.SM_LOCKED)
+                doSignal = true;
+        }
+
+        lmAttributes = null;
+        locksHeld = null;
+        lockStore = null;
+        conflictManager = null;
+
+        if (doSignal) // mutex must be set
+            mutex.unlock();
+
+        mutex = null;
+
+        super.finalize();
+    }
+
+    /**
+     * Change lock ownership as nested action commits. All locks owned by the
+     * committing action have their owners changed to be the parent of the
+     * committing action. BasicAction ensures this is only called at nested
+     * commit. This function works by copying the old LockList pointer and then
+     * creating a new held lock list. Locks are then moved from the old to the
+     * new, propagating en route.
+     */
+
+    public final boolean propagate (Uid from, Uid to)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::propagate(" + from + ", " + to + ")");
+        }
+
+        boolean result = false;
+        int retryCount = 10;
+
+        do
+        {
+            try
+            {
+                synchronized (locksHeldLockObject)
+                {
+                    if (loadState())
+                    {
+                        LockList oldlist = locksHeld;
+                        Lock current = null;
+
+                        locksHeld = new LockList(); /* create a new one */
+
+                        if (locksHeld != null)
+                        {
+                            /*
+                             * scan through old list of held locks and propagate
+                             * to parent.
+                             */
+
+                            while ((current = oldlist.pop()) != null)
+                            {
+                                if (current.getCurrentOwner().equals(from))
+                                {
+                                    current.propagate();
+                                }
+
+                                if (!locksHeld.insert(current))
+                                {
+                                    current = null;
+                                }
+                            }
+
+                            oldlist = null; /* get rid of old lock list */
+
+                            result = true;
+                        }
+                        else
+                        {
+                            /*
+                             * Cannot create new locklist - abort and try again.
+                             */
+
+                            freeState();
+
+                            throw new NullPointerException();
+                        }
+                    }
+
+                    if (result)
+                        result = unloadState();
+                }
+            }
+            catch (NullPointerException e)
+            {
+                result = false;
+            }
+
+            if (!result)
+            {
+                try
+                {
+                    Thread.sleep(OptimisticLockManager.DOZE_TIME);
+                }
+                catch (InterruptedException e)
+                {
+                }
+            }
+
+        }
+        while ((!result) && (--retryCount > 0));
+
+        if (!result)
+        {
+            if (txojLogger.aitLoggerI18N.isWarnEnabled())
+            {
+                txojLogger.aitLoggerI18N
+                        .warn("com.arjuna.ats.txoj.LockManager_1");
+            }
+
+            synchronized (locksHeldLockObject)
+            {
+                freeState();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Clear out all locks for a given action. Should be triggered automatically
+     * at top-level commit but is also user callable so is potentially
+     * dangerous.
+     */
+
+    public final boolean releaseAll (Uid actionUid)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::releaseAll(" + actionUid + ")");
+        }
+
+        return doRelease(actionUid, true);
+    }
+
+    /**
+     * Release a SINGLE LOCK lock that has the given uid. Breaks two-phase
+     * locking rules so watch out!
+     */
+
+    public final boolean releaselock (Uid lockUid)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::releaseLock(" + lockUid + ")");
+        }
+
+        return doRelease(lockUid, false);
+    }
+
+    /*
+     * This is the main user visible operation. Attempts to set the given lock
+     * on the current object. If lock cannot be set, then the lock attempt is
+     * retried retry times before giving up and returning an error. This gives a
+     * simple handle on deadlock. Use the default timeout and retry values.
+     * @return <code>LockResult</code> indicating outcome.
+     */
+
+    public final int setlock (Lock toSet)
+    {
+        return setlock(toSet, OptimisticLockManager.defaultRetry,
+                OptimisticLockManager.defaultSleepTime);
+    }
+
+    /*
+     * This is the main user visible operation. Attempts to set the given lock
+     * on the current object. If lock cannot be set, then the lock attempt is
+     * retried retry times before giving up and returning an error. This gives a
+     * simple handle on deadlock. Use the default timeout value.
+     * @return <code>LockResult</code> indicating outcome.
+     */
+
+    public final int setlock (Lock toSet, int retry)
+    {
+        return setlock(toSet, retry, OptimisticLockManager.defaultSleepTime);
+    }
+
+    /*
+     * This is the main user visible operation. Attempts to set the given lock
+     * on the current object. If lock cannot be set, then the lock attempt is
+     * retried retry times before giving up and returning an error. This gives a
+     * simple handle on deadlock.
+     * @return <code>LockResult</code> indicating outcome.
+     */
+
+    public final int setlock (Lock toSet, int retry, int sleepTime)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PUBLIC,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::setlock(" + toSet + ", " + retry + ", "
+                            + sleepTime + ")");
+        }
+
+        if (!(toSet instanceof OptimisticLock))
+            return LockResult.REFUSED;
+
+        int conflict = ConflictType.CONFLICT;
+        int returnStatus = LockResult.REFUSED;
+        OptimisticLockRecord newLockR = null;
+        boolean modifyRequired = false;
+        BasicAction currAct = null;
+
+        if (toSet == null)
+        {
+            if (txojLogger.aitLoggerI18N.isWarnEnabled())
+            {
+                txojLogger.aitLoggerI18N
+                        .warn("com.arjuna.ats.txoj.LockManager_2");
+            }
+
+            return LockResult.REFUSED;
+        }
+
+        currAct = BasicAction.Current();
+
+        if (currAct != null)
+        {
+            ActionHierarchy ah = currAct.getHierarchy();
+
+            if (ah != null)
+                toSet.changeHierarchy(ah);
+            else
+            {
+                if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                {
+                    txojLogger.aitLoggerI18N
+                            .warn("com.arjuna.ats.txoj.LockManager_3");
+                }
+
+                toSet = null;
+
+                return LockResult.REFUSED;
+            }
+        }
+
+        if (super.loadObjectState())
+            super.setupStore();
+
+        while ((conflict == ConflictType.CONFLICT)
+                && ((retry >= 0) || (retry == OptimisticLockManager.waitTotalTimeout)))
+        {
+            synchronized (locksHeldLockObject)
+            {
+                conflict = ConflictType.CONFLICT;
+
+                if (loadState())
+                {
+                    conflict = lockConflict(toSet);
+                }
+                else
+                {
+                    if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                    {
+                        txojLogger.aitLoggerI18N
+                                .warn("com.arjuna.ats.txoj.LockManager_4");
+                    }
+                }
+
+                if (conflict != ConflictType.CONFLICT)
+                {
+                    /*
+                     * When here the conflict was resolved or the retry limit
+                     * expired.
+                     */
+
+                    /* no conflict so set lock */
+
+                    modifyRequired = toSet.modifiesObject();
+
+                    /* trigger object load from store */
+
+                    if (super.activate())
+                    {
+                        returnStatus = LockResult.GRANTED;
+
+                        if ((conflict == ConflictType.COMPATIBLE) && (!modifyRequired))
+                        {
+                            int lrStatus = AddOutcome.AR_ADDED;
+
+                            if (currAct != null)
+                            {
+                                /* add new lock record to action list */
+
+                                newLockR = new OptimisticLockRecord(this,
+                                        (modifyRequired ? false : true),
+                                        currAct);
+
+                                if ((lrStatus = currAct.add(newLockR)) != AddOutcome.AR_ADDED)
+                                {
+                                    newLockR = null;
+
+                                    if (lrStatus == AddOutcome.AR_REJECTED)
+                                        returnStatus = LockResult.REFUSED;
+                                }
+                            }
+
+                            if (returnStatus == LockResult.GRANTED)
+                            {
+                                locksHeld.insert(toSet); /*
+                                                          * add to local lock
+                                                          * list
+                                                          */
+                            }
+                        }
+                        else
+                        {
+                            if (modifyRequired)
+                                returnStatus = LockResult.GRANTED;
+                        }
+                    }
+                    else
+                    {
+                        /* activate failed - refuse request */
+
+                        if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                        {
+                            txojLogger.aitLoggerI18N
+                                    .warn("com.arjuna.ats.txoj.LockManager_5");
+                        }
+
+                        returnStatus = LockResult.REFUSED;
+                    }
+                }
+
+                /*
+                 * Unload internal state into lock store only if lock list was
+                 * modified if this fails claim the setlock failed. If we are
+                 * using the lock daemon we can arbitrarily throw the lock away
+                 * as the daemon has it.
+                 */
+
+                if ((returnStatus == LockResult.GRANTED)
+                        && (conflict == ConflictType.COMPATIBLE))
+                {
+                    if (!unloadState())
+                    {
+                        if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                        {
+                            txojLogger.aitLoggerI18N
+                                    .warn("com.arjuna.ats.txoj.LockManager_6");
+                        }
+
+                        returnStatus = LockResult.REFUSED;
+                    }
+                }
+                else
+                    freeState();
+
+                /*
+                 * Postpone call on modified to here so that semaphore will have
+                 * been released. This means when modified invokes save_state
+                 * that routine may set another lock without blocking.
+                 */
+
+                if (returnStatus == LockResult.GRANTED)
+                {
+                    if (modifyRequired)
+                    {
+                        if (super.modified())
+                            hasBeenLocked = true;
+                        else
+                        {
+                            conflict = ConflictType.CONFLICT;
+
+                            returnStatus = LockResult.REFUSED;
+                        }
+                    }
+                }
+
+                /*
+                 * Make sure we free state while we still have the lock.
+                 */
+
+                if (conflict == ConflictType.CONFLICT)
+                    freeState();
+            }
+
+            if (conflict == ConflictType.CONFLICT)
+            {
+                if (retry != 0)
+                {
+                    if (sleepTime > 0)
+                    {
+                        sleepTime -= conflictManager.wait(retry, sleepTime);
+                    }
+                    else
+                        retry = 0;
+                }
+
+                if (retry != OptimisticLockManager.waitTotalTimeout)
+                    retry--;
+            }
+        }
+
+        return returnStatus;
+    }
+
+    protected synchronized boolean modified ()
+    {
+        BasicAction currAct = BasicAction.Current();
+        boolean modifyRequired = true;
+        int lrStatus;
+        boolean returnStatus = true;
+        
+        if (currAct != null)
+        {
+            /* add new lock record to action list */
+
+            OptimisticLockRecord newLockR = new OptimisticLockRecord(this,
+                    (modifyRequired ? false : true),
+                    currAct);
+
+            if ((lrStatus = currAct.add(newLockR)) != AddOutcome.AR_ADDED)
+            {
+                newLockR = null;
+
+                if (lrStatus == AddOutcome.AR_REJECTED)
+                    returnStatus = false;
+            }
+        }
+        
+        if (returnStatus)
+            return super.modified();
+        else
+            return false;
+    }
+    
+    /**
+     * Print information about this instance on the specified
+     * <code>PrintWriter</code>.
+     */
+
+    public void print (PrintWriter strm)
+    {
+        LockListIterator next = new LockListIterator(locksHeld);
+        Lock current;
+
+        strm.println("LocalLockManager for object " + get_uid());
+
+        if (!stateLoaded)
+            strm.println("No loaded state");
+        else if (locksHeld != null)
+        {
+            strm.println("\tCurrently holding : " + locksHeld.entryCount()
+                    + " locks");
+
+            while ((current = next.iterate()) != null)
+                current.print(strm);
+        }
+        else
+            strm.println("Currently holding : 0 locks");
+    }
+
+    /**
+     * Load state into object prior to doing the printing.
+     */
+
+    public synchronized void printState (PrintWriter strm)
+    {
+        synchronized (locksHeldLockObject)
+        {
+            boolean iDeleteState = false;
+
+            if (!stateLoaded)
+            {
+                loadState();
+                iDeleteState = true;
+            }
+
+            print(strm);
+
+            if (iDeleteState)
+                freeState();
+        }
+    }
+
+    /**
+     * Overload StateManager.type()
+     */
+
+    public String type ()
+    {
+        return "StateManager/LockManager";
+    }
+
+    /**
+     * @return the <code>LockManagerAttribute</code> object for this instance.
+     *         Must be returned as an <code>Object</code> because it overrides
+     *         StateManager.attributes.
+     * @see LockManagerAttribute
+     */
+
+    public Object attributes ()
+    {
+        return lmAttributes;
+    }
+
+    /*
+     * Pass on some args to StateManager and initialise internal state. The lock
+     * store and semaphore are set up lazily since they depend upon the result
+     * of the type() operation which if run in the constructor always give the
+     * same answer!
+     */
+
+    protected OptimisticLockManager(Uid storeUid)
+    {
+        this(storeUid, ObjectType.ANDPERSISTENT, null);
+    }
+
+    protected OptimisticLockManager(Uid storeUid, ObjectName attr)
+    {
+        this(storeUid, ObjectType.ANDPERSISTENT, attr);
+    }
+
+    protected OptimisticLockManager(Uid storeUid, int ot)
+    {
+        this(storeUid, ot, null);
+    }
+
+    protected OptimisticLockManager(Uid storeUid, int ot, ObjectName attr)
+    {
+        super(storeUid, ot, attr);
+
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS,
+                    VisibilityLevel.VIS_PROTECTED,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::LockManager(" + storeUid + ")");
+        }
+
+        parseObjectName();
+
+        systemKey = null;
+        locksHeld = new LockList();
+        lockStore = null;
+        mutex = null;
+        stateLoaded = false;
+        hasBeenLocked = false;
+        objectLocked = false;
+        conflictManager = new LockConflictManager();
+    }
+
+    /*
+     * Pass on some args to StateManager and initialise internal state. The lock
+     * store and semaphore are set up lazily since they depend upon the result
+     * of the type() operation which if run in the constructor always give the
+     * same answer!
+     */
+
+    protected OptimisticLockManager()
+    {
+        this(ObjectType.RECOVERABLE, null);
+    }
+
+    protected OptimisticLockManager(int ot)
+    {
+        this(ot, null);
+    }
+
+    protected OptimisticLockManager(int ot, ObjectName attr)
+    {
+        super(ot, attr);
+
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS,
+                    VisibilityLevel.VIS_PROTECTED,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::LockManager(" + ot + ")");
+        }
+
+        parseObjectName();
+
+        systemKey = null;
+        locksHeld = new LockList();
+        lockStore = null;
+        mutex = null;
+        stateLoaded = false;
+        hasBeenLocked = false;
+        objectLocked = false;
+        conflictManager = new LockConflictManager();
+    }
+
+    /**
+     * This method *must* be called in the finalizer of every object. It ensures
+     * that any necessary cleanup work is done in the event that the object goes
+     * out of scope within a transaction.
+     */
+
+    protected void terminate ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PROTECTED,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::terminate() for object-id " + get_uid());
+        }
+
+        cleanUp();
+        super.terminate();
+    }
+
+    private final synchronized void cleanUp ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::cleanUp() for object-id " + get_uid());
+        }
+
+        if (hasBeenLocked)
+        {
+            if ((super.smAttributes.objectModel == ObjectModel.MULTIPLE)
+                    && (systemKey == null))
+            {
+                initialise();
+            }
+
+            /*
+             * Unlike in the original version of Arjuna, we don't check to see
+             * if the invoking thread is within a transaction. We look at
+             * whether this object has been used within a transaction, and then
+             * act accordingly.
+             */
+
+            synchronized (super.usingActions)
+            {
+                if (super.usingActions != null)
+                {
+                    Enumeration e = super.usingActions.keys();
+
+                    while (e.hasMoreElements())
+                    {
+                        BasicAction action = (BasicAction) e.nextElement();
+
+                        while (action != null)
+                        {
+                            /*
+                             * Pop actions off using list. Don't check if action
+                             * is running below so that cadavers can be created
+                             * in commit protocol too.
+                             */
+
+                            /*
+                             * We need to create a cadaver lock record to
+                             * maintain the locks because this object is being
+                             * deleted.
+                             */
+
+                            AbstractRecord A = new CadaverLockRecord(lockStore,
+                                    this, action);
+
+                            if (action.add(A) != AddOutcome.AR_ADDED)
+                                A = null;
+                        }
+                    }
+                }
+            }
+
+            hasBeenLocked = false;
+        }
+    }
+
+    /*
+     * doRelease: Does all the hard work of lock release. Either releases all
+     * locks for a given tx uid, or simply one lock with a given uid as
+     * appropriate. Does not require 'synchronized' as it can only be called
+     * from other synchronized methods.
+     */
+
+    private final boolean doRelease (Uid u, boolean all)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::doRelease(" + u + ", " + all + ")");
+        }
+
+        Lock previous = null;
+        Lock current = null;
+        boolean deleted = false;
+        boolean result = false;
+        int retryCount = 10;
+        boolean loaded = false;
+
+        do
+        {
+            synchronized (locksHeldLockObject)
+            {
+                if (loadState())
+                {
+                    loaded = true;
+
+                    /*
+                     * Must declare iterator after loadstate or it sees an empty
+                     * list!
+                     */
+
+                    LockListIterator next = new LockListIterator(locksHeld);
+
+                    /*
+                     * Now scan through held lock list to find which locks to
+                     * release u is either the unique id of the lock owner
+                     * (oneOrAll = ALL_LOCKS) or the uid of the actual lock
+                     * itself (oneOrAll = SINGLE_LOCK).
+                     */
+
+                    previous = null;
+
+                    while ((current = next.iterate()) != null)
+                    {
+                        Uid checkUid = null;
+
+                        if (all)
+                            checkUid = current.getCurrentOwner();
+                        else
+                            checkUid = current.get_uid();
+
+                        /*
+                         * Is this the right lock?
+                         */
+
+                        if (u.equals(checkUid))
+                        {
+                            locksHeld.forgetNext(previous);
+                            current = null;
+                            deleted = true;
+
+                            if (!all)
+                            {
+                                break;
+                            }
+                        }
+                        else
+                            previous = current;
+                    }
+
+                    result = true;
+                }
+                else
+                {
+                    /*
+                     * Free state while we still have the lock.
+                     */
+
+                    freeState();
+
+                    result = false;
+                }
+            }
+
+            if (!result)
+            {
+                try
+                {
+                    Thread.sleep(OptimisticLockManager.DOZE_TIME);
+                }
+                catch (InterruptedException e)
+                {
+                }
+            }
+
+        }
+        while ((!result) && (--retryCount > 0));
+
+        boolean releasedOK = false;
+
+        // if (!stateLoaded)
+        if (!loaded)
+        {
+            if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                txojLogger.aitLoggerI18N
+                        .warn("com.arjuna.ats.txoj.LockManager_7");
+            /*
+             * No need to freeState since we will have done that by now.
+             */
+        }
+        else
+        {
+            if (!deleted)
+            {
+                if (txojLogger.aitLogger.isDebugEnabled())
+                {
+                    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                            VisibilityLevel.VIS_PRIVATE,
+                            FacilityCode.FAC_CONCURRENCY_CONTROL,
+                            " *** CANNOT locate locks  ***");
+                }
+            }
+
+            retryCount = 10;
+
+            synchronized (locksHeldLockObject)
+            {
+                do
+                {
+                    if (!unloadState())
+                    {
+                        if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                            txojLogger.aitLoggerI18N
+                                    .warn("com.arjuna.ats.txoj.LockManager_8");
+                    }
+                    else
+                        releasedOK = true;
+
+                }
+                while ((--retryCount > 0) && (!releasedOK));
+            }
+        }
+
+        /*
+         * Now signal to any waiting threads that they may try to acquire the
+         * lock.
+         */
+
+        conflictManager.signal();
+
+        return releasedOK;
+    }
+
+    /*
+     * Simply free up the semaphore. We do this if we detect conflict. Since the
+     * list has not been modified it can simply be discarded. Does not need
+     * 'synchronized' as can only be called from synchronized methods.
+     */
+
+    private final void freeState ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::freeState()");
+        }
+
+        if (mutex != null)
+        {
+            /*
+             * If we are working in a shared lock store mode, then clear the
+             * cached lock list. Otherwise, do nothing.
+             */
+
+            if (super.smAttributes.objectModel != ObjectModel.SINGLE)
+            {
+                /* clear out the existing list */
+
+                while (locksHeld.pop() != null)
+                    ;
+
+                stateLoaded = false;
+
+                if (objectLocked)
+                {
+                    objectLocked = false;
+
+                    mutex.unlock();
+                }
+            }
+            else
+                stateLoaded = false;
+        }
+        else
+        {
+            stateLoaded = false;
+            objectLocked = false;
+        }
+    }
+
+    /*
+     * Don't need to protect with a synchronization as this routine can only be
+     * called from within other protected methods. Only called if multiple
+     * object model is used.
+     */
+
+    private final boolean initialise ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::initialise()");
+        }
+
+        boolean result = false;
+
+        if (systemKey == null)
+        {
+            systemKey = type();
+
+            if (mutex == null)
+            {
+                mutex = new Semaphore(systemKey);
+            }
+
+            if (mutex != null)
+            {
+                if (mutex.lock() == Semaphore.SM_LOCKED)
+                {
+                    if (lockStore == null)
+                    {
+                        Object[] param = new Object[3];
+
+                        param[0] = lmAttributes.lockStoreType;
+                        param[1] = new Integer(ObjectModel.MULTIPLE);
+                        param[2] = systemKey;
+
+                        lockStore = new LockStore(param);
+
+                        param = null;
+                    }
+                }
+
+                mutex.unlock();
+            }
+        }
+
+        result = (lockStore != null);
+
+        return result;
+    }
+
+    private final boolean isAncestorOf (Lock heldLock)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::isAncestorOf(" + heldLock.getCurrentOwner()
+                            + ")");
+        }
+
+        BasicAction action = BasicAction.Current();
+
+        if (action == null)
+            return false; /* no action no ancestry! */
+
+        return action.isAncestor(heldLock.getCurrentOwner());
+    }
+
+    /*
+     * Lock and load the concurrency control state. First we grab the semaphore
+     * to ensure exclusive access and then we build the held lock list by
+     * retreiving the locks from the lock repository. If there is only one
+     * server we do not bother doing this since all the locks can stay in the
+     * server's memory. This is yet another consequence of not having
+     * multi-threaded servers. Does not require synchronized since it can only
+     * be called from other synchronized methods.
+     */
+
+    private final boolean loadState ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::loadState()");
+        }
+
+        if (super.smAttributes.objectModel == ObjectModel.SINGLE)
+        {
+            stateLoaded = true;
+
+            return true;
+        }
+        else
+        {
+            InputObjectState S = null;
+
+            if ((systemKey == null) && !initialise())
+            {
+                return false; /* init failed */
+            }
+
+            if ((mutex == null) || (mutex.lock() != Semaphore.SM_LOCKED))
+            {
+                return false;
+            }
+
+            stateLoaded = false;
+            objectLocked = true;
+
+            /*
+             * An exception indicates some form of error andNOT that the state
+             * cannot be found, which is indicated by S being null.
+             */
+
+            try
+            {
+                S = lockStore.read_state(get_uid(), type());
+
+                /* Pick returned state apart again */
+
+                if (S != null)
+                {
+                    Uid u = new Uid(Uid.nullUid()); /*
+                                                     * avoid system calls in Uid
+                                                     * creation
+                                                     */
+                    Lock current = null;
+                    int count = 0;
+
+                    try
+                    {
+                        count = S.unpackInt();
+
+                        boolean cleanLoad = true;
+
+                        if (txojLogger.aitLogger.isDebugEnabled())
+                        {
+                            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                                    VisibilityLevel.VIS_PRIVATE,
+                                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                                    "LockManager::loadState() loading " + count
+                                            + " lock(s)");
+                        }
+
+                        /*
+                         * Carefully rebuild the internal state - if we fail
+                         * throw it away and return.
+                         */
+
+                        for (int i = 0; (i < count) && cleanLoad; i++)
+                        {
+                            try
+                            {
+                                u.unpack(S);
+                                current = new Lock(u);
+
+                                if (current != null)
+                                {
+                                    if (current.restore_state(S,
+                                            ObjectType.ANDPERSISTENT))
+                                    {
+                                        locksHeld.push(current);
+                                    }
+                                    else
+                                    {
+                                        current = null;
+                                        cleanLoad = false;
+                                    }
+                                }
+                                else
+                                    cleanLoad = false;
+                            }
+                            catch (IOException e)
+                            {
+                                cleanLoad = false;
+                            }
+                        }
+
+                        if (cleanLoad)
+                            stateLoaded = true;
+                        else
+                        {
+                            while ((current = locksHeld.pop()) != null)
+                                current = null;
+                        }
+                    }
+                    catch (IOException e)
+                    {
+                    }
+
+                    S = null;
+                }
+                else
+                    stateLoaded = true;
+            }
+            catch (LockStoreException e)
+            {
+                if (txojLogger.aitLogger.isWarnEnabled())
+                    txojLogger.aitLogger.warn(e.getMessage());
+            }
+        }
+
+        return stateLoaded;
+    }
+
+    /*
+     * lockconflict: Here we attempt to determine if the provided lock is in
+     * conflict with any of the existing locks. If it is we use nested locking
+     * rules to allow children to lock objects already locked by their
+     * ancestors.
+     */
+
+    private final int lockConflict (Lock otherLock)
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::lockConflict(" + otherLock.get_uid() + ")");
+        }
+
+        boolean matching = false;
+        Lock heldLock = null;
+        LockListIterator next = new LockListIterator(locksHeld);
+
+        while ((heldLock = next.iterate()) != null)
+        {
+            if (heldLock.conflictsWith(otherLock))
+            {
+                if (OptimisticLockManager.nestedLocking)
+                {
+                    if (!isAncestorOf(heldLock)) /* not quite Moss's rules */
+                    {
+                        return ConflictType.CONFLICT;
+                    }
+                }
+                else
+                    return ConflictType.CONFLICT;
+            }
+            else
+            {
+                if (heldLock.equals(otherLock))
+                    matching = true;
+            }
+        }
+
+        return (matching ? ConflictType.PRESENT : ConflictType.COMPATIBLE);
+    }
+
+    /*
+     * Unload the state by writing all the locks to the repository and then
+     * freeing the semaphore.
+     */
+
+    private final boolean unloadState ()
+    {
+        if (txojLogger.aitLogger.isDebugEnabled())
+        {
+            txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CONCURRENCY_CONTROL,
+                    "LockManager::unloadState()");
+        }
+
+        /*
+         * Single object model means we don't need a lock store at all.
+         */
+
+        if (super.smAttributes.objectModel == ObjectModel.SINGLE)
+        {
+            stateLoaded = false;
+
+            return true;
+        }
+        else
+        {
+            boolean unloadOk = false;
+            Lock current = null;
+            String otype = type();
+            Uid u = get_uid();
+            OutputObjectState S = new OutputObjectState(u, otype);
+            int lockCount = locksHeld.entryCount();
+
+            /* destroy old state from lock store */
+
+            if (txojLogger.aitLogger.isDebugEnabled())
+            {
+                txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS,
+                        VisibilityLevel.VIS_PRIVATE,
+                        FacilityCode.FAC_CONCURRENCY_CONTROL,
+                        "LockManager::unloadState() unloading " + lockCount
+                                + " lock(s)");
+            }
+
+            if (lockCount == 0)
+            {
+                if (lockStore.remove_state(u, otype))
+                {
+                    unloadOk = true;
+                }
+                else
+                {
+                    if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                    {
+                        txojLogger.aitLoggerI18N.warn(
+                                "com.arjuna.ats.txoj.LockManager_10",
+                                new Object[]
+                                { u, otype });
+                    }
+                }
+            }
+            else
+            {
+                try
+                {
+                    /* generate new state */
+
+                    S.packInt(lockCount);
+
+                    while ((current = locksHeld.pop()) != null)
+                    {
+                        current.get_uid().pack(S);
+
+                        if (!current.save_state(S, ObjectType.ANDPERSISTENT))
+                        {
+                            if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                            {
+                                txojLogger.aitLoggerI18N.warn(
+                                        "com.arjuna.ats.txoj.LockManager_11",
+                                        new Object[]
+                                        { current });
+                            }
+                            unloadOk = false;
+                        }
+
+                        current = null;
+                    }
+
+                    if (unloadOk)
+                    {
+                        /* load image into store */
+
+                        if (S.valid() && lockStore.write_committed(u, otype, S))
+                        {
+                            unloadOk = true;
+                        }
+                        else
+                        {
+                            if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                            {
+                                txojLogger.aitLoggerI18N.warn(
+                                        "com.arjuna.ats.txoj.LockManager_12",
+                                        new Object[]
+                                        { u, otype });
+                            }
+                        }
+                    }
+                }
+                catch (IOException e)
+                {
+                    unloadOk = false;
+
+                    if (txojLogger.aitLoggerI18N.isWarnEnabled())
+                    {
+                        txojLogger.aitLoggerI18N.warn(
+                                "com.arjuna.ats.txoj.LockManager_13",
+                                new Object[]
+                                { u, otype });
+                    }
+                }
+            }
+
+            stateLoaded = false;
+
+            if (objectLocked)
+            {
+                objectLocked = false;
+
+                if (mutex != null) // means object model != SINGLE
+                    mutex.unlock(); // and exit mutual exclusion
+            }
+
+            return unloadOk;
+        }
+    }
+
+    private void parseObjectName ()
+    {
+        lmAttributes = new LockManagerAttribute();
+
+        if (super.objectName != null)
+        {
+            try
+            {
+                /*
+                 * Use same attribute name as environment.
+                 */
+
+                lmAttributes.lockStoreType = super.objectName
+                        .getClassNameAttribute(Environment.LOCKSTORE_TYPE);
+            }
+            catch (Exception e)
+            {
+                // assume not present.
+            }
+
+            // if present should now look for locations as with StateManager
+        }
+    }
+
+    protected LockManagerAttribute lmAttributes;
+
+    private String systemKey;/* used in accessing system resources */
+
+    private LockList locksHeld; /* the actual list of locks set */
+
+    private final Object locksHeldLockObject = new Object(); // mutex for sync
+                                                             // on locksHeld.
+                                                             // Can't use
+                                                             // locksHeld
+                                                             // itself, it's
+                                                             // mutable.
+
+    private LockStore lockStore; /* locks held in shared memory */
+
+    private boolean stateLoaded;
+
+    private boolean hasBeenLocked;/* Locked at least once */
+
+    private boolean objectLocked;/* Semaphore grabbed */
+
+    private Semaphore mutex; /* Controls access to the lock store */
+
+    private LockConflictManager conflictManager;
+
+    private static final int DOZE_TIME = 1000000;
+
+    private static boolean nestedLocking = true;
+
+    static
+    {
+        String nl = txojPropertyManager.propertyManager
+                .getProperty(Environment.ALLOW_NESTED_LOCKING);
+
+        if (nl != null)
+        {
+            if (nl.equals("NO"))
+                nestedLocking = false;
+        }
+    }
+
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockRecord.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockRecord.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/main/java/org/jboss/stm/optimistic/OptimisticLockRecord.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,454 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors 
+ * as indicated by the @author tags. 
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors. 
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A 
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ * 
+ * (C) 2005-2006,
+ * @author JBoss Inc.
+ */
+/*
+ * Copyright (C) 1998, 1999, 2000,
+ *
+ * Arjuna Solutions Limited,
+ * Newcastle upon Tyne,
+ * Tyne and Wear,
+ * UK.  
+ *
+ * $Id: LockRecord.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package org.jboss.stm.optimistic;
+
+import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
+import com.arjuna.ats.arjuna.ObjectType;
+import com.arjuna.ats.arjuna.state.*;
+import com.arjuna.ats.arjuna.common.Uid;
+
+import com.arjuna.ats.txoj.logging.txojLogger;
+import com.arjuna.ats.txoj.logging.FacilityCode;
+
+import com.arjuna.common.util.logging.*;
+
+import com.arjuna.ats.arjuna.coordinator.*;
+import java.io.*;
+
+/*
+ * Default visibility.
+ */
+
+/*
+ * Use mutex from StateManager?
+ */
+
+/*
+ * Optimistic cc in operation. Grab a copy of the current state so we can check against
+ * the state again when we commit.
+ */
+
+class OptimisticLockRecord extends AbstractRecord
+{
+
+    public OptimisticLockRecord (OptimisticLockManager lm, BasicAction currAct)
+    {
+	super(lm.get_uid(), lm.type(), ObjectType.ANDPERSISTENT);
+
+	actionHandle = currAct;
+
+	managerAddress = lm;
+	readOnly = false;
+	managerType = lm.type();
+	lm.save_state(state, lm.ObjectType());
+    }
+    
+    public OptimisticLockRecord (OptimisticLockManager lm, boolean rdOnly, BasicAction currAct)
+    {
+	super(lm.get_uid(), lm.type(), ObjectType.ANDPERSISTENT);
+
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				     "LockRecord::LockRecord("+lm.get_uid()+", "
+				       +(readOnly ? "PREPARE_READONLY" : "WRITEABLE")+")");
+	}
+	
+	actionHandle = currAct;
+
+	managerAddress = lm;
+	readOnly = rdOnly;
+	managerType = lm.type();
+	lm.save_state(state, lm.ObjectType());
+    }
+
+    public int typeIs ()
+    {
+	return RecordType.LOCK;
+    }
+
+    public Object value ()
+    {
+	return (Object) managerAddress;
+    }
+
+    public void setValue (Object o)
+    {
+	if (txojLogger.aitLoggerI18N.isWarnEnabled())
+	    txojLogger.aitLoggerI18N.warn("com.arjuna.ats.txoj.LockRecord_1");
+    }
+
+    public int nestedAbort ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				       (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::nestedAbort() for "+order());
+	}
+	
+	/*
+	 * Optimistic cc means we just throw away the state.
+	 */
+	
+	state = null;
+	
+	return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public int nestedCommit ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::nestedCommit() for "+order());
+	}
+	
+	/* default constructor problem. */
+
+	if (managerAddress == null)
+	    return TwoPhaseOutcome.FINISH_ERROR;
+
+	if (actionHandle != null)
+	{
+	    Uid toRelease = actionHandle.get_uid();
+	    
+	    actionHandle = actionHandle.parent();
+	    
+	    return (managerAddress.propagate(toRelease, actionHandle.get_uid()) ? TwoPhaseOutcome.FINISH_OK : TwoPhaseOutcome.FINISH_ERROR);
+	}
+	else
+	{
+	    if (txojLogger.aitLoggerI18N.isWarnEnabled())
+		txojLogger.aitLoggerI18N.warn("com.arjuna.ats.txoj.LockRecord_4");
+	}
+
+	return TwoPhaseOutcome.FINISH_ERROR;
+    }
+
+    public int nestedPrepare ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::nestedPrepare() for "+order());
+	}
+	
+	if (managerAddress == null)
+            return TwoPhaseOutcome.PREPARE_NOTOK;
+	
+	if (checkState())
+	    return TwoPhaseOutcome.PREPARE_OK;
+	else
+	    return TwoPhaseOutcome.PREPARE_NOTOK;
+    }
+
+    public int topLevelAbort ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::topLevelAbort() for "+order());
+	}
+	
+	return nestedAbort();
+    }
+
+    public int topLevelCommit ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::topLevelCommit() for "+order());
+	}
+	
+	/* default constructor problem. */
+
+	if (managerAddress == null)
+	    return TwoPhaseOutcome.FINISH_ERROR;
+
+	if (!checkState())
+	    return TwoPhaseOutcome.FINISH_ERROR;
+	
+	if (actionHandle != null)
+	{
+	    if (!managerAddress.releaseAll(actionHandle.get_uid()))
+	    {
+		if (txojLogger.aitLoggerI18N.isWarnEnabled())
+		{
+		    txojLogger.aitLoggerI18N.warn("com.arjuna.ats.txoj.LockRecord_5", 
+						new Object[]{actionHandle.get_uid()});
+		}
+
+		return TwoPhaseOutcome.FINISH_ERROR;
+	    }
+	}
+	else
+	{
+	    if (txojLogger.aitLoggerI18N.isWarnEnabled())
+		txojLogger.aitLoggerI18N.warn("com.arjuna.ats.txoj.LockRecord_6");
+
+	    return TwoPhaseOutcome.FINISH_ERROR;
+	}
+
+	return TwoPhaseOutcome.FINISH_OK;
+    }
+
+    public int topLevelPrepare ()
+    {
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PUBLIC,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::topLevelPrepare() for "+order());
+	}
+	
+	if (readOnly)
+	{
+	    if (topLevelCommit() == TwoPhaseOutcome.FINISH_OK)
+		return TwoPhaseOutcome.PREPARE_READONLY;
+	    else
+		return TwoPhaseOutcome.PREPARE_NOTOK;
+	}
+    
+	return TwoPhaseOutcome.PREPARE_OK;
+    }
+
+    public String toString ()
+    {
+	StringWriter strm = new StringWriter();
+
+	print(new PrintWriter(strm));
+	
+	return strm.toString();
+    }
+    
+    public void print (PrintWriter strm)
+    {
+	super.print(strm);
+	strm.println("OptimisticLockRecord");
+    }
+
+    /*
+     * restore_state and save_state for LockRecords doesn't generally
+     * apply due to object pointers.
+     */
+
+    public boolean restore_state (InputObjectState o, int t)
+    {
+	if (txojLogger.aitLoggerI18N.isWarnEnabled())
+	{
+	    txojLogger.aitLoggerI18N.warn("com.arjuna.ats.txoj.LockRecord_7",
+					new Object[]{type(), order()});
+	}
+
+	return false;
+    }
+
+    public boolean save_state (OutputObjectState o, int t)
+    {
+	return true;
+    }
+
+    public String type ()
+    {
+	return "/StateManager/AbstractRecord/OptimisticLockRecord";
+    }
+
+    public final boolean isReadOnly ()
+    {
+	return readOnly;
+    }
+
+    public final String lockType ()
+    {
+	return managerType;
+    }
+    
+    public void merge (AbstractRecord a)
+    {
+    }
+
+    public void alter (AbstractRecord a)
+    {
+    }
+
+    public boolean shouldAdd (AbstractRecord a)
+    {
+	return false;
+    }
+
+    public boolean shouldAlter (AbstractRecord a)
+    {
+	return false;
+    }
+
+    public boolean shouldMerge (AbstractRecord a)
+    {
+	return false;
+    }
+
+    public boolean shouldReplace (AbstractRecord ar)
+    {
+	if ((order().equals(ar.order())) && typeIs() == ar.typeIs())
+	{
+	    /*
+	     * The first test should ensure that ar is a LockRecord.
+	     */
+	    
+	    if (((OptimisticLockRecord) ar).isReadOnly() && !readOnly)
+		return true;
+	}
+	
+	return false;
+    }
+    
+    protected OptimisticLockRecord ()
+    {
+	super();
+
+	if (txojLogger.aitLogger.isDebugEnabled())
+	{
+	    txojLogger.aitLogger.debug(DebugLevel.CONSTRUCTORS, VisibilityLevel.VIS_PROTECTED,
+				     (FacilityCode.FAC_CONCURRENCY_CONTROL | com.arjuna.ats.arjuna.logging.FacilityCode.FAC_ABSTRACT_REC),
+				       "LockRecord::LockRecord()");
+	}
+	
+	actionHandle = null;
+
+	managerAddress = null;
+	readOnly = false;
+	managerType = null;
+    }
+
+    private boolean checkState ()
+    {
+        /*
+         * If the object is recoverable then we can just check the local state.
+         * If the object is persistent then we have to check the state on disk.
+         */
+        
+        OutputObjectState tempState = new OutputObjectState();
+        int objectType = managerAddress.ObjectType();
+        
+        /*
+         * If we check the state now, it's possible that some other transactions may be
+         * doing the same concurrently. We need to lock the object at this point. Or
+         * suffer heuristic by checking during commit - though this still leaves a window
+         * of vulnerability.
+         */
+        
+        /*
+         * Assume initially that this will only work if the objects are all in the same
+         * address space, since sharing across spaces will impose performance overhead
+         * anyway. In that case, we can maintain a list of all objects that are being
+         * managed optimistically and check them directly as well as lock them.
+         * 
+         * Problem is that it's the state that needs to be checked and there may be
+         * multiple instances of the state active in memory at the same time. So would
+         * need to keep each instance per Uid.
+         */
+        
+        /*
+         * Could even make this specific to STM and in which case we have even more control.
+         */
+        
+        if (objectType == ObjectType.RECOVERABLE)
+        {
+            if (managerAddress.save_state(tempState, objectType))
+            {
+                boolean identical = true;
+                
+                if (tempState.length() == state.length())
+                {
+                    for (int i = 0; (i < tempState.length()) && identical; i++)
+                    {
+                        if (tempState.buffer()[i] != state.buffer()[i])
+                            identical = false;
+                    }
+                    
+                    if (identical)
+                        return true;
+                }
+            }
+        }
+        
+        if (objectType == ObjectType.ANDPERSISTENT)
+        {
+            /*
+             * Don't need the state - could just check the time of the file update if we are using
+             * a file based object store.
+             */
+            
+            try
+            {
+                InputObjectState s = managerAddress.getStore().read_committed(managerAddress.get_uid(), managerAddress.type());
+                
+                if (s != null)
+                {
+                    boolean identical = true;
+                    
+                    if (s.length() == state.length())
+                    {
+                        for (int i = 0; (i < s.length()) && identical; i++)
+                        {
+                            if (s.buffer()[i] != state.buffer()[i])
+                                identical = false;
+                        }
+                        
+                        if (identical)
+                            return true;
+                    }
+                }
+                else
+                    return true;  // no state, so we are first! (check state type instead?)
+            }
+            catch (final Exception ex)
+            {
+            }
+        }
+        
+        return false;
+    }
+    
+    protected BasicAction actionHandle;  // must be changed if we propagate
+    
+    private OptimisticLockManager managerAddress;
+    private boolean     readOnly;
+    private String      managerType;
+    private OutputObjectState state = new OutputObjectState();
+}

Added: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/OptimisticUnitTest.java
===================================================================
--- labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/OptimisticUnitTest.java	                        (rev 0)
+++ labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/OptimisticUnitTest.java	2012-01-20 13:41:49 UTC (rev 37856)
@@ -0,0 +1,382 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.stm.optimistic;
+
+import java.io.IOException;
+import java.util.Random;
+
+import org.jboss.stm.annotations.State;
+import org.jboss.stm.annotations.Transactional;
+import org.jboss.stm.annotations.ReadLock;
+import org.jboss.stm.annotations.WriteLock;
+
+import com.arjuna.ats.arjuna.AtomicAction;
+import com.arjuna.ats.arjuna.ObjectType;
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.arjuna.coordinator.ActionStatus;
+import com.arjuna.ats.arjuna.coordinator.BasicAction;
+import com.arjuna.ats.arjuna.state.InputObjectState;
+import com.arjuna.ats.arjuna.state.OutputObjectState;
+import com.arjuna.ats.txoj.Lock;
+import com.arjuna.ats.txoj.LockManager;
+import com.arjuna.ats.txoj.LockMode;
+import com.arjuna.ats.txoj.LockResult;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for the Class class.
+ * 
+ * @author Mark Little
+ */
+
+public class OptimisticUnitTest extends TestCase
+{
+
+    public class AtomicObject extends OptimisticLockManager
+    {
+        public AtomicObject()
+        {
+            super();
+            
+            state = 0;
+
+            AtomicAction A = new AtomicAction();
+
+            A.begin();
+
+            if (setlock(new OptimisticLock(LockMode.WRITE), 0) == LockResult.GRANTED)
+            {
+                if (A.commit() == ActionStatus.COMMITTED)
+                    System.out.println("Created persistent object " + get_uid());
+                else
+                    System.out.println("Action.commit error.");
+            }
+            else
+            {
+                A.abort();
+
+                System.out.println("setlock error.");
+            }
+        }
+  
+        /*
+         * In the pessimistic locking case we use Locks to guard against concurrent
+         * access. In the optimistic case we don't. However, this means that multiple
+         * threads acting on the same instance can overwrite state and conflict. So we
+         * need to make these methods thread-safe. Use synchronized keyword for now, but
+         * obviously this could be finer grained. Since these are language constructs they
+         * are not maintained for the duration of the transaction.
+         */
+        
+        public synchronized void incr (int value) throws Exception
+        {
+            AtomicAction A = new AtomicAction();
+
+            A.begin();
+            
+            /*
+             * setlock will activate the state and create a checkpoint. It will also
+             * add a LockRecord, which takes a snapshot of the state for later comparison.
+             * That is wrong: the LockRecord needs to see the current state and the final
+             * state so that it can compare the current state with the state the object
+             * has at commit time. In fact it probably doesn't need to see the updated state
+             * at all. It could use the updated state as an optimisation: suppose the new
+             * state is different to that which existed at the time setlock was called but is
+             * identical to the state update that this method made, then we probably don't
+             * need to rollback! Someone else made the change for us!
+             */
+            
+            if (setlock(new OptimisticLock(LockMode.WRITE), 0) == LockResult.GRANTED)
+            {
+                state += value;
+
+                modified();
+                
+                if (A.commit() != ActionStatus.COMMITTED)
+                    throw new Exception("Action commit error.");
+                else
+                    return;
+            }
+
+            A.abort();
+
+            throw new Exception("Write lock error.");
+        }
+
+        public synchronized void set (int value) throws Exception
+        {
+            AtomicAction A = new AtomicAction();
+
+            A.begin();
+            
+            if (setlock(new OptimisticLock(LockMode.WRITE), 0) == LockResult.GRANTED)
+            {
+                state = value;
+
+                modified();
+                
+                if (A.commit() != ActionStatus.COMMITTED)
+                    throw new Exception("Action commit error.");
+                else
+                    return;
+            }
+
+            A.abort();
+
+            throw new Exception("Write lock error.");
+        }
+
+        public synchronized int get () throws Exception
+        {
+            AtomicAction A = new AtomicAction();
+            int value = -1;
+
+            A.begin();
+            
+            if (setlock(new OptimisticLock(LockMode.READ), 0) == LockResult.GRANTED)
+            {
+                value = state;
+
+                /*
+                 * We don't need to call modified for read locks, but we do need to
+                 * check that the state remains unmodified at commit time. This is the job
+                 * of the LockRecord. So setlock should add a LockRecord if the lock is read
+                 * but should ignore if it is write, because modified must be called later
+                 * instead which will do the registration.
+                 */
+                
+                if (A.commit() == ActionStatus.COMMITTED)
+                    return value;
+                else
+                    throw new Exception("Action commit error.");
+            }
+
+            A.abort();
+
+            throw new Exception("Read lock error.");
+        }
+
+        public boolean save_state (OutputObjectState os, int ot)
+        {
+            boolean result = super.save_state(os, ot);
+
+            if (!result)
+                return false;
+
+            try
+            {
+                os.packInt(state);
+            }
+            catch (IOException e)
+            {
+                result = false;
+            }
+
+            return result;
+        }
+
+        public boolean restore_state (InputObjectState os, int ot)
+        {
+            boolean result = super.restore_state(os, ot);
+
+            if (!result)
+                return false;
+
+            try
+            {
+                state = os.unpackInt();
+            }
+            catch (IOException e)
+            {
+                result = false;
+            }
+
+            return result;
+        }
+
+        public String type ()
+        {
+            return "/StateManager/LockManager/AtomicObject";
+        }
+
+        private int state;
+    }
+
+    public class Worker extends Thread
+    {
+        public Worker (AtomicObject obj)
+        {
+            _obj = obj;
+        }
+        
+        public void run ()
+        {
+            Random rand = new Random();
+            
+            for (int i = 0; i < 1000; i++)
+            {
+                boolean fault;
+                
+                do
+                {
+                    fault = false;
+                    
+                    AtomicAction A = new AtomicAction();
+                    boolean doCommit = true;
+                    
+                    A.begin();
+                    
+                    try
+                    {
+                        _obj.incr(i);
+                    }
+                    catch (final Throwable ex)
+                    {
+                        ex.printStackTrace();
+                        
+                        doCommit = false;
+                        fault = true;
+                    }
+                    
+                    if (doCommit)
+                    {
+                        if (A.commit() != ActionStatus.COMMITTED)
+                        {
+                            System.err.println("Failed to commit!");
+                            
+                            fault = true;
+                        }
+                    }
+                    else
+                        A.abort();
+                    
+                } while (fault);
+            }
+        }
+        
+        private AtomicObject _obj;
+    }
+    
+    public void testAtomicObject () throws Exception
+    {
+        AtomicObject obj = new AtomicObject();
+        AtomicAction a = new AtomicAction();
+        
+        a.begin();
+        
+        obj.set(1234);
+        
+        a.commit();
+        
+        assertEquals(obj.get(), 1234);
+        
+        a = new AtomicAction();
+        
+        a.begin();
+        
+        obj.incr(1);
+        
+        a.abort();
+        
+        assertEquals(obj.get(), 1234);
+    }
+    
+    public void testMultiSet () throws Exception
+    {
+        AtomicObject obj = new AtomicObject();
+        AtomicAction a = new AtomicAction();
+        
+        a.begin();
+        
+        obj.set(1234);
+        obj.set(345);
+        
+        a.commit();
+        
+        assertEquals(obj.get(), 345);
+    }
+    
+    public void testNestedAbort () throws Exception
+    {
+        AtomicObject obj = new AtomicObject();
+        AtomicAction a = new AtomicAction();
+        AtomicAction b = new AtomicAction();
+        
+        a.begin();
+        
+        obj.set(1234);
+        
+        b.begin();
+        
+        obj.set(345);
+        
+        b.abort();
+        
+        a.commit();
+        
+        assertEquals(obj.get(), 1234);
+    }
+    
+    public void testNestedCommit () throws Exception
+    {
+        AtomicObject obj = new AtomicObject();
+        AtomicAction a = new AtomicAction();
+        AtomicAction b = new AtomicAction();
+        
+        a.begin();
+        
+        obj.set(1234);
+        
+        b.begin();
+        
+        obj.set(345);
+        
+        b.commit();
+        
+        a.commit();
+        
+        assertEquals(obj.get(), 345);
+    }
+    
+    public void testRecoverableHammer () throws Exception
+    {
+        AtomicObject obj = new AtomicObject();
+        Worker worker1 = new Worker(obj);
+        Worker worker2 = new Worker(obj);
+        
+        worker1.start();
+        worker2.start();
+        
+        try
+        {
+            worker1.join();
+            worker2.join();
+        }
+        catch (final Throwable ex)
+        {
+        }
+        
+        assertEquals(obj.get(), 999000);  // 2* sum of series 0..1000
+    }
+}


Property changes on: labs/jbosstm/workspace/mlittle/STM-Arjuna/src/test/java/org/jboss/stm/optimistic/OptimisticUnitTest.java
___________________________________________________________________
Added: svn:executable
   + *



More information about the jboss-svn-commits mailing list