LockMode (Oracle - Berkeley DB Java Edition API)
Date: 2014-12-16

com.sleepycat.je

## Enum LockMode

- java.lang.Object
- - java.lang.Enum<LockMode>
  - - com.sleepycat.je.LockMode

- All Implemented Interfaces:
    Serializable, Comparable<LockMode>

      public enum LockMode
      extends Enum<LockMode>

  Record lock modes for read operations. Lock mode parameters may be specified for all operations that retrieve data.

  Locking Rules

  Together with `CursorConfig`, `TransactionConfig` and `EnvironmentConfig` settings, lock mode parameters determine how records are locked during read operations. Record locking is used to enforce the isolation modes that are configured. Record locking is summarized below for read and write operations. For more information on isolation levels and transactions, see Writing Transactional Applications.

  With one exception, a record lock is always acquired when a record is read or written, and a cursor will always hold the lock as long as it is positioned on the record. The exception is when `READ_UNCOMMITTED` is specified, which allows a record to be read without any locking.

  Both read (shared) and write (exclusive) locks are used. Read locks are normally acquired on read (`get` method) operations and write locks on write (`put` method) operations. The only exception is that a write lock will be acquired on a read operation if `RMW` is specified.

  Because read locks are shared, multiple accessors may read the same record. Because write locks are exclusive, if a record is written by one accessor it may not be read or written by another accessor. An accessor is either a transaction or a thread (for non-transactional operations).

  Whether additional locking is performed and how locks are released depend on whether the operation is transactional and other configuration settings.

  Transactional Locking

  Transactional operations include all write operations for a transactional database, and read operations when a non-null `Transaction` parameter is passed. When a null transaction parameter is passed for a write operation for a transactional database, an auto-commit transaction is automatically used.

  With transactions, read and write locks are normally held until the end of the transaction (commit or abort). Write locks are always held until the end of the transaction. However, if `READ_COMMITTED` is configured, then read locks for cursor operations are only held during the operation and while the cursor is positioned on the record. The read lock is released when the cursor is moved to a different record or closed. When `READ_COMMITTED` is used for a database (non-cursor) operation, the read lock is released before the method returns.

  When neither `READ_UNCOMMITTED` nor `READ_COMMITTED` is specified, read and write locking as described above provide Repeatable Read isolation, which is the default transactional isolation level. If Serializable isolation is configured, additional "next key" locking is performed to prevent "phantoms" -- records that are not visible at one point in a transaction but that become visible at a later point after being inserted by another transaction. Serializable isolation is configured via `TransactionConfig.setSerializableIsolation(boolean)` or `EnvironmentConfig.setTxnSerializableIsolation(boolean)`.

  Non-Transactional Locking

  Non-transactional operations include all operations for a non-transactional database (including a Deferred Write database), and read operations for a transactional database when a null `Transaction` parameter is passed.

  For non-transactional operations, both read and write locks are only held while a cursor is positioned on the record, and are released when the cursor is moved to a different record or closed. For database (non-cursor) operations, the read or write lock is released before the method returns.

  This behavior is similar to `READ_COMMITTED`, except that both read and write locks are released. Configuring `READ_COMMITTED` for a non-transactional database cursor has no effect.

  Because the current thread is the accessor (locker) for non-transactional operations, a single thread may have multiple cursors open without locking conflicts. Two non-transactional cursors in the same thread may access the same record via write or read operations without conflicts, and the changes make by one cursor will be visible to the other cursor.

  However, a non-transactional operation will conflict with a transactional operation for the same record even when performed in the same thread. When using a transaction in a particular thread for a particular database, to avoid conflicts you should use that transaction for all access to that database in that thread. In other words, to avoid conflicts always pass the transaction parameter, not null, for all operations. If you don't wish to hold the read lock for the duration of the transaction, specify `READ_COMMITTED`.

  Read Uncommitted (Dirty-Read)

  When `READ_UNCOMMITTED` is configured, no locking is performed by a read operation. `READ_UNCOMMITTED` does not apply to write operations.

  `READ_UNCOMMITTED` is sometimes called dirty-read because records are visible to the caller in their current state in the Btree at the time of the read, even when that state is due to operations performed using a transaction that has not yet committed. In addition, because no lock is acquired by the dirty read operation, the record's state may change at any time, even while a cursor used to do the dirty-read is still positioned on the record.

  To illustrate this, let's say a record is read with dirty-read (`READ_UNCOMMITTED`) by calling `Cursor.getNext` with a cursor C, and changes to the record are also being made in another thread using transaction T. When a locking (non-dirty-read) call to `Cursor.getCurrent` is subsequently made to read the same record again with C at the current position, a result may be returned that is different than the result returned by the earlier call to `getNext`. For example:

  - If the record is updated by T after the dirty-read `getNext` call, and T is committed, a subsequent call to `getCurrent` will return the data updated by T.
  - If the record is updated by T before the dirty-read `getNext` call, the `getNext` will returned the data updated by T. But if call, the `getNext` will return the data updated by T. But if T is then aborted, a subsequent call to `getCurrent` will return the version of the data before it was updated by T.
  - If the record was inserted by T before the dirty-read `getNext` call, the `getNext` call will return the inserted record. But if T is aborted, a subsequent call to `getCurrent` will return `OperationStatus.KEYEMPTY`.
  - If the record is deleted by T after the dirty-read `getNext` call, and T is committed, a subsequent call to `getCurrent` will return `OperationStatus.KEYEMPTY`.

  Note that deleted records are handled specially in JE. Deleted records remain in the Btree until after the deleting transaction is committed, and they are removed from the Btree asynchronously (not immediately at commit time). When using `#READ_UNCOMMITTED`, any record encountered in the Btree that was previously deleted, whether or not the deleting transaction has been committed, will be ignored (skipped over) by the read operation. Of course, if the deleting transaction is aborted, the record will no longer be deleted. If the application is scanning records, for example, this means that such records may be skipped by the scan. If this behavior is not desirable, `READ_UNCOMMITTED_ALL` may be used instead. This mode ensures that records deleted by a transaction that is later aborted will not be skipped by a read operation. This is accomplished in two different ways depending on the type of database and whether the record's data is requested by the operation.

  1. If the DB is configured for duplicates or the record's data is not requested, then a record that has been deleted by an open transaction is returned by the read operation.
  2. If the DB is not configured for duplicates and the record's data is requested, then the read operation must wait for the deleting transaction to close (commit or abort). After the transaction is closed, the record will be returned if it is actually deleted and otherwise will be skipped.

  By "record data" we mean both the `data` parameter for a regular or primary DB, and the `pKey` parameter for a secondary DB. By "record data requested" we mean that all or part of the `DatabaseEntry` will be returned by the read operation. Unless explicitly not requested, the complete `DatabaseEntry` is returned. See Using Partial DatabaseEntry Parameters for more information.

  Because of this difference in behavior, although `#READ_UNCOMMITTED` is fully non-blocking, `#READ_UNCOMMITTED_ALL` is not (under the conditions described). As a result, when using `#READ_UNCOMMITTED_ALL` under these conditions, a `LockConflictException` will be thrown when blocking results in a deadlock or lock timeout.

  To summarize, callers that use `READ_UNCOMMITTED` or `#READ_UNCOMMITTED_ALL` should be prepared for the following behaviors.

  - After a successful dirty-read operation, because no lock is acquired the record can be changed by another transaction, even when the cursor used to perform the dirty-read operation is still positioned on the record.
  - After a successful dirty-read operation using a cursor C, say that another transaction T deletes the record, and T is committed. In this case, `OperationStatus.KEYEMPTY` will be returned by the following methods if they are called while C is still positioned on the deleted record: `Cursor.getCurrent`, `Cursor.putCurrent` and `Cursor.delete`.
  - When using `READ_UNCOMMITTED`, deleted records will be skipped even when the deleting transaction is still open. No blocking will occur and `LockConflictException` is never thrown when using this mode.
  - When using `#READ_UNCOMMITTED_ALL`, deleted records will not be skipped even when the deleting transaction is open. If the DB is a duplicates DB or the record's data is not requested, the deleted record will be returned. If the DB is not a duplicates DB and the record's data is requested, blocking will occur until the deleting transaction is closed. In the latter case, `LockConflictException` will be thrown when this blocking results in a deadlock or a lock timeout.

- - ### Enum Constant Summary

    Enum Constants
    Enum Constant and Description
    `DEFAULT` Uses the default lock mode and is equivalent to passing `null` for the lock mode parameter.
    `READ_COMMITTED` Read committed isolation provides for cursor stability but not repeatable reads.
    `READ_UNCOMMITTED` Reads modified but not yet committed data.
    `READ_UNCOMMITTED_ALL` Reads modified but not yet committed data, ensuring that records are not skipped due to transaction aborts.
    `RMW` Acquire write locks instead of read locks when doing the retrieval.

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `String` | `toString()`
    `static LockMode` | `valueOf(String name)` Returns the enum constant of this type with the specified name.
    `static LockMode[]` | `values()` Returns an array containing the constants of this enum type, in the order they are declared.

    - ### Methods inherited from class java.lang.Enum

      `clone, compareTo, equals, finalize, getDeclaringClass, hashCode, name, ordinal, valueOf`

    - ### Methods inherited from class java.lang.Object

      `getClass, notify, notifyAll, wait, wait, wait`

- - ### Enum Constant Detail

    - #### DEFAULT

          public static final LockMode DEFAULT

      Uses the default lock mode and is equivalent to passing `null` for the lock mode parameter.

      The default lock mode is `READ_UNCOMMITTED` when this lock mode is configured via `CursorConfig.setReadUncommitted(boolean)` or `TransactionConfig.setReadUncommitted(boolean)`. The Read Uncommitted mode overrides any other configuration settings.

      Otherwise, the default lock mode is `READ_COMMITTED` when this lock mode is configured via `CursorConfig.setReadCommitted(boolean)` or `TransactionConfig.setReadCommitted(boolean)`. The Read Committed mode overrides other configuration settings except for `READ_UNCOMMITTED`.

      Otherwise, the default lock mode is to acquire read locks and release them according to the `default locking rules` for transactional and non-transactional operations.

    - #### READ_UNCOMMITTED

          public static final LockMode READ_UNCOMMITTED

      Reads modified but not yet committed data.

      The Read Uncommitted mode is used if this lock mode is explicitly passed for the lock mode parameter, or if null or `DEFAULT` is passed and Read Uncommitted is the default -- see `DEFAULT` for details.

      Unlike `READ_UNCOMMITTED_ALL`, deleted records will be skipped even when the deleting transaction is still open. No blocking will occur and `LockConflictException` is never thrown when using this mode.

      See the `locking rules` for information on how Read Uncommitted impacts transactional and non-transactional locking.

    - #### READ_UNCOMMITTED_ALL

          public static final LockMode READ_UNCOMMITTED_ALL

      Reads modified but not yet committed data, ensuring that records are not skipped due to transaction aborts.

      The Read Uncommitted mode is used only when this lock mode is explicitly passed for the lock mode parameter.

      Unlike `READ_UNCOMMITTED`, deleted records will not be skipped even when the deleting transaction is open. If the DB is a duplicates DB or the record's data is not requested, the deleted record will be returned. If the DB is not a duplicates DB and the record's data is requested, blocking will occur until the deleting transaction is closed. In the latter case, `LockConflictException` will be thrown when this blocking results in a deadlock or a lock timeout.

      See the `locking rules` for information on how Read Uncommitted impacts transactional and non-transactional locking.

    - #### READ_COMMITTED

          public static final LockMode READ_COMMITTED

      Read committed isolation provides for cursor stability but not repeatable reads. Data items which have been previously read by this transaction may be deleted or modified by other transactions before the cursor is closed or the transaction completes. Note that this LockMode may only be passed to `Database` get methods, not to `Cursor` methods. To configure a cursor for Read Committed isolation, use `CursorConfig.setReadCommitted(boolean)`.

      See the `locking rules` for information on how Read Committed impacts transactional and non-transactional locking.

    - #### RMW

          public static final LockMode RMW

      Acquire write locks instead of read locks when doing the retrieval.

      Because it causes a write lock to be acquired, specifying this lock mode as a `Cursor` or `Database` `get` (read) method parameter will override the Read Committed or Read Uncommitted isolation mode that is configured using `CursorConfig` or `TransactionConfig`. The write lock will acquired and held until the end of the transaction. For non-transactional use, the write lock will be released when the cursor is moved to a new position or closed.

      Setting this flag can eliminate deadlock during a read-modify-write cycle by acquiring the write lock during the read part of the cycle so that another thread of control acquiring a read lock for the same item, in its own read-modify-write cycle, will not result in deadlock.

  - ### Method Detail

    - #### values

          public static LockMode[] values()

      Returns an array containing the constants of this enum type, in the order they are declared. This method may be used to iterate over the constants as follows:

          for (LockMode c : LockMode.values())
              System.out.println(c);

      Returns:
        an array containing the constants of this enum type, in the order they are declared

    - #### valueOf

          public static LockMode valueOf(String name)

      Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
      Parameters:
        `name` - the name of the enum constant to be returned.
      Returns:
        the enum constant with the specified name
      Throws:
        `IllegalArgumentException` - if this enum type has no constant with the specified name
        `NullPointerException` - if the argument is null

    - #### toString

          public String toString()

      Overrides:
        `toString` in class `Enum<LockMode>`

Copyright (c) 2004, 2014 Oracle and/or its affiliates. All rights reserved.