public interface Lock
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:
ReentrantLock
} where only mutually exclusive access is
possible. The exclusive lock normally is used by the STM when it commits.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.
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.
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.
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:
The Txn is allowed to apply a more strict LockMode than the one specified.
Downgrading locks currently is not possible and downgrade calls are ignored.
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()
.
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.
2 Ingredients are needed for a deadlock:
TxnFactoryBuilder.setReadLockMode(LockMode)
,
TxnFactoryBuilder.setWriteLockMode(LockMode)
Modifier and Type | Method and 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 the
TxnThreadLocal has on this Lock. |
LockMode |
getLockMode(Txn txn)
Gets the LockMode the transaction has on the Lock.
|
LockMode atomicGetLockMode()
getLockMode()
or getLockMode(Txn)
need
to be used.LockMode getLockMode()
TxnThreadLocal
has on this Lock.
To retrieve the actual LockMode of the Lock, you need to use the atomicGetLockMode()
.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.atomicGetLockMode()
,
getLockMode(Txn)
LockMode getLockMode(Txn txn)
atomicGetLockMode()
txn
- the LockTxnExecutionException
- 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.atomicGetLockMode()
,
getLockMode(Txn)
void acquire(LockMode desiredLockMode)
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.
desiredLockMode
- the desired lockMode.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.void acquire(Txn txn, LockMode desiredLockMode)
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.
txn
- the Txn used for this operation.desiredLockMode
- the desired lockMode.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 © 2020. All rights reserved.