All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.multiverse.api.Lock Maven / Gradle / Ivy

Go to download

Contains the core interfaces/classes of the Multiverse project. So no STM implementations

The newest version!
package org.multiverse.api;

/**
 * The Lock provides access to pessimistic behavior of a {@link 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 {@link java.util.concurrent.locks.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 {@link org.multiverse.api.exceptions.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 * {@link TxnFactoryBuilder#setSpinCount(int)} and then some retries * {@link TxnFactoryBuilder#setMaxRetries(int)} in combination with a backoff * {@link 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. *
  3. LockMode.Read->LockMode.Exclusive: as long as no other transaction has acquired the Lock in LockMode.Read
  4. *
  5. LockMode.Write->LockMode.Exclusive: will always succeed
  6. *
*

* 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 {@link TxnFactoryBuilder#setReadLockMode(LockMode)} and * {@link 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 {@link 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. *
  3. Transactions that do an unbound waiting for a lock to come available
  4. *
* 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 TxnFactoryBuilder#setReadLockMode(LockMode) * @see TxnFactoryBuilder#setWriteLockMode(LockMode) */ public interface Lock { /** * 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 {@link #getLockMode()} or {@link #getLockMode(Txn)} need * to be used. * * @return the current LockMode. */ LockMode atomicGetLockMode(); /** * Gets the LockMode the transaction stored in the the {@link TxnThreadLocal} has on this Lock. * To retrieve the actual LockMode of the Lock, you need to use the {@link #atomicGetLockMode()}. * * @return the LockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.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 #atomicGetLockMode() * @see #getLockMode(Txn) */ LockMode 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 the {@link #atomicGetLockMode()} * * @param txn the Lock * @return the LockMode the transaction has on the Lock. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.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 #atomicGetLockMode() * @see #getLockMode(Txn) */ LockMode getLockMode(Txn txn); /** * Acquires a Lock with the provided LockMode. This call doesn't block if the Lock can't be upgraded, but throws * a {@link org.multiverse.api.exceptions.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 * {@link org.multiverse.api.exceptions.ReadWriteConflict} is thrown. * *

This call makes use of the Txn stored in the {@link TxnThreadLocal}. * *

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored. * * @param desiredLockMode the desired lockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.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. * @throws NullPointerException if desiredLockMode is null. If an alive transaction is available, it will * be aborted. */ void acquire(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 {@link org.multiverse.api.exceptions.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 * {@link org.multiverse.api.exceptions.ReadWriteConflict} is thrown. * *

If the lockMode is lower than the LockMode the transaction already has on this Lock, the call is ignored. * * @param txn the Txn used for this operation. * @param desiredLockMode the desired lockMode. * @throws org.multiverse.api.exceptions.TxnExecutionException * if something failed while using the transaction. The transaction is guaranteed to have been aborted. * @throws org.multiverse.api.exceptions.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. * @throws NullPointerException if tx or desiredLockMode is null. If an alive transaction is available, it will * be aborted. */ void acquire(Txn txn, LockMode desiredLockMode); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy