Interface Lock
- All Known Implementing Classes:
AbstractGammaObject
,BaseGammaTxnRef
,GammaTxnBoolean
,GammaTxnDouble
,GammaTxnInteger
,GammaTxnLong
,GammaTxnRef
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:
- 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 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:
- LockMode.Read->LockMode.Write: as long as no other transaction has acquired the Lock in LockMode.Read
- LockMode.Read->LockMode.Exclusive: as long as no other transaction has acquired the Lock in LockMode.Read
- 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:
- Transactions acquiring locks in a different order
- Transactions that do an unbound waiting for a lock to come available
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionvoid
Acquires a Lock with the provided LockMode.void
Acquires a Lock with the provided LockMode using the provided transaction.Returns the current LockMode.Gets the LockMode the transaction stored in the theTxnThreadLocal
has on this Lock.getLockMode
(Txn txn) Gets the LockMode the transaction has on the Lock.
-
Method Details
-
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:
-
getLockMode
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:
-
acquire
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
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.
-