Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * 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 com.arjuna.ats.txoj;
  
  
This class provides (transactional) concurrency control for application objects.

Author(s):
Mark Little (mark@arjuna.com)
Version:
$Id: LockManager.java 2342 2006-03-30 13:06:17Z $
Since:
JTS 1.0.
See also:
com.arjuna.ats.arjuna.StateManager
  
  
  public class LockManager extends StateManager
  {

    
The default retry value which will be used by setlock if no other value is given.

  
  
      public static final int defaultRetry = 100;

    
The default timeout value which will be used by setlock if no other value is given.

  
  
      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.

Since:
JTS 2.1.
See also:
setlock(com.arjuna.ats.txoj.Lock)
 
 
     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 (..isTraceEnabled()) {
             ..trace("LockManager.finalize() for object-id " + get_uid()
                     + " type " + type());
         }
 
         /*
          * terminate should have been called. Check and warn/do something about it if this
          * is not the case!
          */
         
         if (status() == .)
         {
             BasicAction action = BasicAction.Current();
 
             if ((action != null) && (action.status() == .)) {
                 ..warn_StateManager_1();
                 cleanup(false);
             }
         }
         
         boolean doSignal = false;
 
         cleanUp();
 
         if ( != null)
         {
             if (.lock() == .)
                 doSignal = true;
         }
 
          = null;
          = null;
          = null;
 
         if (doSignal// mutex must be set
             .unlock();
 
          = 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 boolean propagate (Uid fromUid to)
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::propagate(" + from + ", " + to + ")");
         }
 
         boolean result = false;
         int retryCount = 10;
 
         do
         {
             try
             {
                 Object syncObject = ((BasicAction.Current() == null) ? getMutex() : BasicAction.Current());
                 
                 synchronized (syncObject)
                 {
                     synchronized ()
                     {
                         if (loadState())
                         {
                             LockList oldlist = ;
                             Lock current = null;
     
                              = new LockList(); /* create a new one */
     
                             if ( != 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 (!.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(.);
                 }
                 catch (InterruptedException e)
                 {
                 }
             }
 
         }
         while ((!result) && (--retryCount > 0));
 
         if (!result)
         {
             ..warn_LockManager_1();
 
             synchronized ()
             {
                 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 (..isTraceEnabled()) {
             ..trace("LockManager::releaseAll(" + actionUid + ")");
         }
         
         return doRelease(actionUidtrue);
     }

    
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 (..isTraceEnabled()) {
             ..trace("LockManager::releaseLock(" + lockUid + ")");
         }
 
         return doRelease(lockUidfalse);
     }
 
     /*
      * 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.,
                 .);
     }
 
     /*
      * 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 toSetint retry)
     {
         return setlock(toSetretry.);
     }
 
     /*
      * 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 int setlock (Lock toSetint retryint sleepTime)
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::setlock(" + toSet + ", " + retry + ", "
                     + sleepTime + ")");
         }
 
         int conflict = .;
         int returnStatus = .;
         LockRecord newLockR = null;
         boolean modifyRequired = false;
         BasicAction currAct = null;
 
         if (toSet == null)
         {
             ..warn_LockManager_2();
 
             return .;
         }
 
         currAct = BasicAction.Current();
 
         if (currAct != null)
         {
             ActionHierarchy ah = currAct.getHierarchy();
 
             if (ah != null)
                 toSet.changeHierarchy(ah);
             else
             {
                 ..warn_LockManager_3();
 
                 toSet = null;
 
                 return .;
             }
         }
 
         if (super.loadObjectState())
             super.setupStore();
         
         while ((conflict == .)
                 && ((retry >= 0) || ((retry == .) && (sleepTime > 0))))
         {
             Object syncObject = ((currAct == null) ? getMutex() : currAct);
             
             synchronized (syncObject)
             {
                 synchronized ()
                 {
                     conflict = .;
     
                     if (loadState())
                     {
                         conflict = lockConflict(toSet);
                     }
                     else
                     {
                         ..warn_LockManager_4();
                     }
                     
                     if (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 = .;
     
                             if (conflict == .)
                             {
                                 int lrStatus = .;
     
                                 if (currAct != null)
                                 {
                                     /* add new lock record to action list */
     
                                     newLockR = new LockRecord(this, (modifyRequired ? false : true), currAct);
 
                                     if ((lrStatus = currAct.add(newLockR)) != .)
                                     {
                                         newLockR = null;
 
                                         if (lrStatus == .)
                                             returnStatus = .;
                                     }
                                 }
     
                                 if (returnStatus == .)
                                 {
                                     .insert(toSet); /*
                                                               * add to local lock
                                                               * list
                                                               */
                                 }
                             }
                         }
                         else
                         {
                             /* activate failed - refuse request */
                             ..warn_LockManager_5();
 
                             returnStatus = .;
                         }
                     }
                     
                     /*
                      * 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 == .)
                             && (conflict == .))
                     {
                         if (!unloadState())
                         {
                             ..warn_LockManager_6();
 
                             returnStatus = .;
                         }
                     }
                     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 == .)
                     {
                         if (modifyRequired)
                         {
                             if (super.modified())
                                  = true;
                             else
                             {
                                 conflict = .;
     
                                 returnStatus = .;
                             }
                         }
                     }
     
                     /*
                      * Make sure we free state while we still have the lock.
                      */
     
                     if (conflict == .)
                         freeState();
                 }
             }
             
             if (conflict == .)
             {
                 if (retry != 0)
                 {
                     if (sleepTime > 0)
                     {
                         sleepTime -= .wait(retrysleepTime);
                     }
                     else
                         retry = 0;
                 }
 
                 if (retry != .)
                     retry--;
             }
         }
         
         return returnStatus;
     }

    
Print information about this instance on the specified PrintWriter.
 
 
     public void print (PrintWriter strm)
     {
         LockListIterator next = new LockListIterator();
         Lock current;
 
         strm.println("LocalLockManager for object " + get_uid());
 
         if (!)
             strm.println("No loaded state");
         else if ( != null)
         {
             strm.println("\tCurrently holding : " + .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 void printState (PrintWriter strm)
     {
         synchronized ()
         {
             boolean iDeleteState = false;
 
             if (!)
             {
                 loadState();
                 iDeleteState = true;
             }
 
             print(strm);
 
             if (iDeleteState)
                 freeState();
         }
     }

    
Overload StateManager.type()
 
 
     public String type ()
     {
         return "StateManager/LockManager";
     }
 
     /*
      * 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 LockManager(Uid storeUid)
     {
         this(storeUid..);
     }
 
     protected LockManager(Uid storeUidint ot)
     {
         this(storeUidot.);
     }
     
     // make default SINGLE
 
     protected LockManager (Uid storeUidint otint om)
     {
         super(storeUidotom);
         
         if (..isTraceEnabled()) {
             ..trace("LockManager::LockManager(" + storeUid + ")");
         }
 
          = null;
          = new LockList();
          = null;
          = null;
          = false;
          = false;
          = false;
          = 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 LockManager()
     {
         this(.);
     }
 
     protected LockManager(int ot)
     {
         this(ot.);
     }
 
     protected LockManager (int otint om)
     {
         super(otom);
         
         if (..isTraceEnabled()) {
             ..trace("LockManager::LockManager(" + ot + ")");
         }
 
          = null;
          = new LockList();
          = null;
          = null;
          = false;
          = false;
          = false;
          = 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 (..isTraceEnabled()) {
             ..trace("LockManager::terminate() for object-id " + get_uid());
         }
 
         cleanUp();
 
         super.terminate();
     }
 
     protected final void cleanUp ()
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::cleanUp() for object-id " + get_uid());
         }
 
         if ()
         {
             if ((super. == .)
                     && ( == 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.
              */
 
             BasicAction current = BasicAction.Current();
 
             synchronized (super.)
             {
                 if (super. != null)
                 {
                     Enumeration e = super..elements();
 
                     while (e.hasMoreElements())
                     {
                         BasicAction action = (BasicActione.nextElement();
 
                         if (action != null)  // shouldn't be 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(,
                                     thisaction);
 
                             if (action.add(A) != .)
                             {
                                 A = null;
                             }
                         }
                     }
                 }
             }
 
              = 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.
      */
 
     protected boolean doRelease (Uid uboolean all)
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::doRelease(" + u + ", " + all + ")");
         }
         
         Lock previous = null;
         Lock current = null;
         boolean deleted = false;
         boolean result = false;
         int retryCount = 10;
         boolean loaded = false;
         boolean releasedOK = false;
         BasicAction currAct = BasicAction.Current();
         Object syncObject = ((currAct == null) ? getMutex() : currAct);
         
         synchronized (syncObject)
         {
             synchronized ()
             {
                 do
                 {
                     if (loadState())
                     {
                         loaded = true;
     
                         /*
                          * Must declare iterator after loadstate or it sees an empty
                          * list!
                          */
     
                         LockListIterator next = new LockListIterator();
                         
                         /*
                          * 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))
                             {
                                 .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(.);
                         }
                         catch (InterruptedException e)
                         {
                         }
                     }
                     else
                     {
                         // if (!stateLoaded)
                         if (!loaded)
                         {
                             ..warn_LockManager_7();
                             /*
                              * No need to freeState since we will have done that by now.
                              */
                         }
                         else
                         {
                             if (!deleted)
                             {
                                 if (..isTraceEnabled()) {
                                     ..trace(" *** CANNOT locate locks  ***");
                                 }
                             }
     
                             int unloadRetryCount = 10;
 
                             do
                             {
                                 if (!unloadState())
                                 {
                                     ..warn_LockManager_8();
                                 }
                                 else
                                     releasedOK = true;
     
                             }
                             while ((--unloadRetryCount > 0) && (!releasedOK));
                         }
                     }
                 }
                 while ((!result) && (--retryCount > 0));
             }
         }
 
         /*
          * Now signal to any waiting threads that they may try to acquire the
          * lock.
          */
 
         .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.
      */
 
     protected final void freeState ()
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::freeState()");
         }
 
         if ( != null)
         {
             /*
              * If we are working in a shared lock store mode, then clear the
              * cached lock list. Otherwise, do nothing.
              */
 
             if (super. != .)
             {
                 /* clear out the existing list */
 
                 while (.pop() != null)
                     ;
 
                  = false;
 
                 if ()
                 {
                      = false;
 
                     .unlock();
                 }
             }
             else
                  = false;
         }
         else
         {
              = false;
              = 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.
      */
 
     protected final boolean initialise ()
     {
         if (..isTraceEnabled()) {
             ..trace("LockManager::initialise()");
         }
 
         boolean result = false;
 
         if ( == null)
         {
              = type();
 
             if ( == null)
             {
                 // TODO add a factory if we ever have more than one implementation
                 
                  = new com.arjuna.ats.internal.arjuna.common.BasicMutex();
             }
 
             if ( != null)
             {
                 if (.lock() == .)
                 {
                     /*
                      * At some point we may want to add a factory to hide this, but
                      * since we only have two implementations at the moment it is perhaps
                      * overkill.
                      * 
                      * TODO add factory.
                      */
                     
                     if ( == null)
                     {
                         try
                         {
                             if (.equals(BasicLockStore.class.getName())) {
                                  = new BasicLockStore();
                             } else {
                                 ObjectStoreEnvironmentBean objectStoreEnvironmentBean = new ObjectStoreEnvironmentBean();
                                 objectStoreEnvironmentBean.setLocalOSRoot();
                                  = new BasicPersistentLockStore(objectStoreEnvironmentBean);
                             }
                         }
                         catch (final Exception ex)
                         {
                              = null;
                         }
                     }
                 }
 
                 .unlock();
             }
         }
 
         result = ( != null);
 
         return result;
     }
 
     protected final boolean isAncestorOf (Lock heldLock)
     {
         if (..isTraceEnabled()) {
             ..trace("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.
     */
    protected final boolean loadState ()
    {
        if (..isTraceEnabled()) {
            ..trace("LockManager::loadState()");
        }
        if (super. == .)
        {
             = true;
            return true;
        }
        else
        {
            InputObjectState S = null;
            if (( == null) && !initialise())
            {
                return false/* init failed */
            }
            if (( == null) || (.tryLock() == .))
            {
                return false;
            }
             = false;
             = true;
            /*
             * An exception indicates some form of error and NOT that the state
             * cannot be found, which is indicated by S being null.
             */
            try
            {
                S = .read_state(get_uid(), type());
                /* Pick returned state apart again */
                if (S != null)
                {
                    Uid u = null/*
                                                     * avoid system calls in Uid
                                                     * creation
                                                     */
                    Lock current = null;
                    int count = 0;
                    try
                    {
                        count = S.unpackInt();
                        boolean cleanLoad = true;
                        if (..isTraceEnabled()) {
                            ..trace("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) && cleanLoadi++)
                        {
                            try
                            {
                                u = UidHelper.unpackFrom(S);
                                current = new Lock(u);
                                if (current != null)
                                {
                                    if (current.restore_state(S,
                                            .))
                                    {
                                        .push(current);
                                    }
                                    else
                                    {
                                        current = null;
                                        cleanLoad = false;
                                    }
                                }
                                else
                                    cleanLoad = false;
                            }
                            catch (IOException e)
                            {
                                cleanLoad = false;
                            }
                        }
                        if (cleanLoad)
                             = true;
                        else
                        {
                            while ((current = .pop()) != null)
                                current = null;
                        }
                    }
                    catch (IOException e)
                    {
                    }
                    S = null;
                }
                else
                     = true;
            }
            catch (LockStoreException e)
            {
                ..warn(e);
            }
        }
        return ;
    }
    /*
     * 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.
     */
    protected final int lockConflict (Lock otherLock)
    {
        if (..isTraceEnabled()) {
            ..trace("LockManager::lockConflict(" + otherLock.get_uid() + ")");
        }
        boolean matching = false;
        Lock heldLock = null;
        LockListIterator next = new LockListIterator();
        while ((heldLock = next.iterate()) != null)
        {
            if (heldLock.conflictsWith(otherLock))
            {
                if (.)
                {
                    if (!isAncestorOf(heldLock)) /* not quite Moss's rules */
                        return .;
                }
                else
                    return .;
            }
            else
            {
                if (heldLock.equals(otherLock))
                    matching = true;
            }
        }
        return (matching ? . : .);
    }
    /*
     * Unload the state by writing all the locks to the repository and then
     * freeing the semaphore.
     */
    protected final boolean unloadState ()
    {
        if (..isTraceEnabled()) {
            ..trace("LockManager::unloadState()");
        }
        /*
         * Single object model means we don't need a lock store at all.
         */
        if (super. == .)
        {
             = false;
            return true;
        }
        else
        {
            boolean unloadOk = false;
            Lock current = null;
            String otype = type();
            Uid u = get_uid();
            OutputObjectState S = new OutputObjectState(uotype);
            int lockCount = .entryCount();
            /* destroy old state from lock store */
            if (..isTraceEnabled()) {
                ..trace("LockManager::unloadState() unloading " + lockCount
                        + " lock(s)");
            }
            if (lockCount == 0)
            {
                if (.remove_state(uotype))
                {
                    unloadOk = true;
                }
                else
                {
                    ..warn_LockManager_10(uotype);
                }
            }
            else
            {
                try
                {
                    /* generate new state */
                    S.packInt(lockCount);
                    unloadOk = true;
                    
                    while ((current = .pop()) != null)
                    {
                        UidHelper.