+++ Introduction

[**Note**: The term 'Transaction' doesnt refer to database transactions here but to the general meaning of this term]

[**Note**: This component is in **Alpha State**]

Locking is a mechanism to control concurrency. The two most well known locking strategies are optimistic and pessimistic locking. The following is a short description of these two strategies from which only pessimistic locking is currently supported by Doctrine.

**Optimistic Locking:**

The state/version of the object(s) is noted when the transaction begins. When the transaction finishes the noted state/version of the participating objects is compared to the current state/version. When the states/versions differ the objects have been modified by another transaction and the current transaction should fail. This approach is called 'optimistic' because it is assumed that it is unlikely that several users will participate in transactions on the same objects at the same time.

**Pessimistic Locking:**

The objects that need to participate in the transaction are locked at the moment the user starts the transaction. No other user can start a transaction that operates on these objects while the locks are active. This ensures that the user who starts the transaction can be sure that noone else modifies the same objects until he has finished his work.

Doctrine's pessimistic offline locking capabilities can be used to control concurrency during actions or procedures that take several HTTP request and response cycles and/or a lot of time to complete.


+++ Examples

The following code snippet demonstrates the use of Doctrine's pessimistic offline locking capabilities.

At the page where the lock is requested...

<code type="php">

// Get a locking manager instance
$lockingMngr = new Doctrine_Locking_Manager_Pessimistic();

try
{
    // Ensure that old locks which timed out are released 
    // before we try to acquire our lock
    // 300 seconds = 5 minutes timeout
    $lockingMngr->releaseAgedLocks(300);

    // Try to get the lock on a record
    $gotLock = $lockingMngr->getLock(
     // The record to lock. This can be any Doctrine_Record
                        $myRecordToLock,
    // The unique identifier of the user who is trying to get the lock
                       'Bart Simpson'
               );

    if($gotLock)
    {
        echo "Got lock!";
        // ... proceed
    }
    else
    {
        echo "Sorry, someone else is currently working on this record";
    }
}
catch(Doctrine_Locking_Exception $dle)
{
    echo $dle->getMessage();
    // handle the error
}

</code>

At the page where the transaction finishes...

<code type="php">
// Get a locking manager instance
$lockingMngr = new Doctrine_Locking_Manager_Pessimistic();

try
{
    if($lockingMngr->releaseLock($myRecordToUnlock, 'Bart Simpson'))
    {
        echo "Lock released";
    }
    else
    {
        echo "Record was not locked. No locks released.";
    }
}
catch(Doctrine_Locking_Exception $dle)
{
    echo $dle->getMessage();
    // handle the error
}
</code>


+++ Planned

* Possibility to release locks of a specific Record type (i.e. releasing all locks on 'User' objects).

+++ Technical Details

The pessimistic offline locking manager stores the locks in the database (therefore 'offline'). The required locking table is automatically created when you try to instantiate an instance of the manager and the ATTR_CREATE_TABLES is set to TRUE. This behaviour may change in the future to provide a centralised and consistent table creation procedure for installation purposes.


+++ Maintainer

Roman Borschel - romanb at #doctrine (freenode)

Don't hesitate to contact me if you have questions, ideas, ect.

