public enum LockMode extends java.lang.Enum<LockMode>
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:
getNext
call, and T is committed, a subsequent call to getCurrent
will
return the data updated by T.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.getNext
call, the getNext
call will return the inserted record.
But if T is aborted, a subsequent call to getCurrent
will return
OperationStatus.KEYEMPTY
.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.
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.
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
.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.#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 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.
|
Modifier and Type | Method and Description |
---|---|
ReadOptions |
toReadOptions()
Returns a ReadOptions with this LockMode property, and default values
for all other properties.
|
java.lang.String |
toString() |
static LockMode |
valueOf(java.lang.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.
|
public static final LockMode DEFAULT
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)
, or when using a DiskOrderedCursor
. 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.
public static final LockMode READ_UNCOMMITTED
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.
public static final LockMode READ_UNCOMMITTED_ALL
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.
public static final LockMode READ_COMMITTED
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.
public static final LockMode RMW
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.
public static LockMode[] values()
for (LockMode c : LockMode.values()) System.out.println(c);
public static LockMode valueOf(java.lang.String name)
name
- the name of the enum constant to be returned.java.lang.IllegalArgumentException
- if this enum type has no constant with the specified namejava.lang.NullPointerException
- if the argument is nullpublic ReadOptions toReadOptions()
WARNING: Do not modify the returned object, since it is a singleton.
public java.lang.String toString()
toString
in class java.lang.Enum<LockMode>
Copyright (c) 2002, 2017 Oracle and/or its affiliates. All rights reserved.