Interface Lock
-
- All Known Implementing Classes:
AbstractGammaObject
,BaseGammaTxnRef
,GammaTxnBoolean
,GammaTxnDouble
,GammaTxnInteger
,GammaTxnLong
,GammaTxnRef
public interface Lock
The Lock provides access to pessimistic behavior of aTxnObject
. 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:- LockMode.None: it doesn't do any locking
- LockMode.Read: it allows multiple transactions to acquire the read lock, but transaction acquiring the write-lock or exclusive lock (needed when a transaction wants to commit) is prohibited. If the read lock is acquired by a different transaction, a transaction still is able to read/write, but it isn't allowed to commit the changes (since and exclusive lock is required for that).
- LockMode.Write: it allows only one transaction to acquire the write lock, but unlike a traditional write-lock, reads still are allowed. Normally this would not be acceptable because once the write-lock is acquired, the internals could be modified. But in case of STM, the STM can still provide a consistent view even though the locking transaction has made changes. This essentially is the same behavior you get with the 'select for update' from Oracle. Once the write lock is acquired, other transactions can't acquire the Lock.
- LockMode.Exclusive: it allows only one transaction to acquire the commit lock, and readers are not
allowed to read anymore. From an isolation perspective, the exclusive lock looks a lot like the synchronized
statement (or a
ReentrantLock
} where only mutually exclusive access is possible. The exclusive lock normally is used by the STM when it commits.
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 retriesTxnFactoryBuilder.setMaxRetries(int)
in combination with a backoffTxnFactoryBuilder.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:
- LockMode.Read to LockMode.Write: as long as no other transaction has acquired the Lock in LockMode.Read
- LockMode.Read to LockMode.Exclusive: as long as no other transaction has acquired the Lock in LockMode.Read
- LockMode.Write to 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)
andTxnFactoryBuilder.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 theTxnObject.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:
- Transactions acquiring locks in a different order
- Transactions that do an unbound waiting for a lock to come available
-
-
Method Summary
All Methods Instance Methods Abstract Methods Modifier and Type Method Description 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 theTxnThreadLocal
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, thegetLockMode()
orgetLockMode(Txn)
need to be used.- Returns:
- the current LockMode.
-
getLockMode
LockMode getLockMode()
Gets the LockMode the transaction stored in the theTxnThreadLocal
has on this Lock. To retrieve the actual LockMode of the Lock, you need to use theatomicGetLockMode()
.- 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 theatomicGetLockMode()
- 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 aReadWriteConflict
. It could also be that the Lock is acquired, but the Txn sees that it isn't consistent anymore. In that case also aReadWriteConflict
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 aReadWriteConflict
. It could also be that the Lock is acquired, but the Txn sees that it isn't consistent anymore. In that case also aReadWriteConflict
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.
-
-