org.multiverse.api
Interface Lock

All Known Implementing Classes:
AbstractGammaObject, BaseGammaTxnRef, GammaTxnBoolean, GammaTxnDouble, GammaTxnInteger, GammaTxnLong, GammaTxnRef

public interface Lock

The Lock provides access to pessimistic behavior of a TxnObject. STM normally is very optimistic, but in some cases a more pessimistic approach (one with less retries) could be a better fitting solution.

There are 4 different types of lockmodes:

Lock duration and release

Locks atm are acquired for the remaining duration of the transaction and only will always be automatically released once the transaction commits/aborts. This is essentially the same behavior you get with Oracle once a update/delete/insert is done, or when the record is locked manually by executing the 'select for update'. For this to work it is very important that the ControlFlowError is not caught by the logic executed in an transactional closure, but is caught by the TxnExecutor itself.

Blocking

Atm it isn't possible to block on a lock. What happens is that some spinning is done TxnFactoryBuilder.setSpinCount(int) and then some retries TxnFactoryBuilder.setMaxRetries(int) in combination with a backoff TxnFactoryBuilder.setBackoffPolicy(BackoffPolicy). In the 0.8 release blocking will probably be added.

Fairness

Atm there is no support for fairness. The big problem with fairness and STM is that the locks are released and the transaction needs to begin again. It could be that a lower priority transaction is faster and acquires the lock again. This is a topic that needs more research and probably will be integrated in the contention management.

Lock upgrade

It is possible to upgrade a lock to more strict version, e.g. to upgrade a read-lock to a write-lock. The following upgrades are possible:

  1. LockMode.Read->LockMode.Write: as long as no other transaction has acquired the Lock in LockMode.Read
  2. LockMode.Read->LockMode.Exclusive: as long as no other transaction has acquired the Lock in LockMode.Read
  3. LockMode.Write->LockMode.Exclusive: will always succeed

The Txn is allowed to apply a more strict LockMode than the one specified.

Lock downgrade

Downgrading locks currently is not possible and downgrade calls are ignored.

Locking scope

Locking can be done on the Txn level (see the TxnFactoryBuilder.setReadLockMode(LockMode) and TxnFactoryBuilder.setWriteLockMode(LockMode) where all reads or all writes (to do a write also a read is needed) are locked automatically. It can also be done on the reference level using getAndLock/setAndLock/getAndSetAndLock methods or by accessing the TxnObject.getLock().

Lock escalation

In traditional lock based databases, managing locks in memory can be quite expensive. That is one of the reason why different Lock granularities are used (record level, page level, table level for example). To prevent managing too many locks, some databases apply lock escalation so that multiple low granularity locks are upgraded to a single higher granular lock. The problem with lock escalations is that the system could be subject to lock contention and to deadlocks.

The GammaStm (the main STM implementation) doesn't use lock escalation, but keeps on managing locks on the transactional object (ref) level.

Deadlocks

2 Ingredients are needed for a deadlock:

  1. Transactions acquiring locks in a different order
  2. Transactions that do an unbound waiting for a lock to come available
The problem with applying locks in the same order is that it places an extra borden on the developer. That is why atm the second ingredient is always missing if the GammaStm (the default STM implementation) is used. Therefor a developer doesn't need to worry about deadlocks (although it shifts the problem to an increased chance of starvation and livelocks).

Author:
Peter Veentjer.
See Also:
TxnFactoryBuilder.setReadLockMode(LockMode), TxnFactoryBuilder.setWriteLockMode(LockMode)

Method Summary
 void acquire(LockMode desiredLockMode)
          Acquires a Lock with the provided LockMode.
 void acquire(Txn txn, LockMode desiredLockMode)
          Acquires a Lock with the provided LockMode using the provided transaction.
 LockMode atomicGetLockMode()
          Returns the current LockMode.
 LockMode getLockMode()
          Gets the LockMode the transaction stored in the the TxnThreadLocal has on this Lock.
 LockMode getLockMode(Txn txn)
          Gets the LockMode the transaction has on the Lock.
 

Method Detail

atomicGetLockMode

LockMode atomicGetLockMode()
Returns the current LockMode. This call doesn't look at any running transaction, it shows the actual state of the Lock. The value could be stale as soon as it is received. To retrieve the LockMode a a Txn has on a Lock, the getLockMode() or getLockMode(Txn) need to be used.

Returns:
the current LockMode.

getLockMode

LockMode getLockMode()
Gets the LockMode the transaction stored in the the TxnThreadLocal has on this Lock. To retrieve the actual LockMode of the Lock, you need to use the atomicGetLockMode().

Returns:
the LockMode.
Throws:
TxnExecutionException - if something failed while using the transaction. The transaction is guaranteed to have been aborted.
ControlFlowError - if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction is guaranteed to have been aborted.
See Also:
atomicGetLockMode(), getLockMode(Txn)

getLockMode

LockMode getLockMode(Txn txn)
Gets the LockMode the transaction has on the Lock. This call makes use of the tx. To retrieve the actual LockMode of the Lock, you need to use the atomicGetLockMode()

Parameters:
txn - the Lock
Returns:
the LockMode the transaction has on the Lock.
Throws:
TxnExecutionException - if something failed while using the transaction. The transaction is guaranteed to have been aborted.
ControlFlowError - if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction is guaranteed to have been aborted.
See Also:
atomicGetLockMode(), getLockMode(Txn)

acquire

void acquire(LockMode desiredLockMode)
Acquires a Lock with the provided LockMode. This call doesn't block if the Lock can't be upgraded, but throws a ReadWriteConflict. It could also be that the Lock is acquired, but the Txn sees that it isn't consistent anymore. In that case also a ReadWriteConflict is thrown.

This call makes use of the Txn stored in the TxnThreadLocal.

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored.

Parameters:
desiredLockMode - the desired lockMode.
Throws:
TxnExecutionException - if something failed while using the transaction. The transaction is guaranteed to have been aborted.
ControlFlowError - if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction is guaranteed to have been aborted.
NullPointerException - if desiredLockMode is null. If an alive transaction is available, it will be aborted.

acquire

void acquire(Txn txn,
             LockMode desiredLockMode)
Acquires a Lock with the provided LockMode using the provided transaction. This call doesn't block if the Lock can't be upgraded but throws a ReadWriteConflict. It could also be that the Lock is acquired, but the Txn sees that it isn't consistent anymore. In that case also a ReadWriteConflict is thrown.

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored.

Parameters:
txn - the Txn used for this operation.
desiredLockMode - the desired lockMode.
Throws:
TxnExecutionException - if something failed while using the transaction. The transaction is guaranteed to have been aborted.
ControlFlowError - if the Stm needs to control the flow in a different way than normal returns of exceptions. The transaction is guaranteed to have been aborted.
NullPointerException - if tx or desiredLockMode is null. If an alive transaction is available, it will be aborted.


Copyright © 2012. All Rights Reserved.