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

com.sleepycat.je.LockMode Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je;

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

Locking Rules

* *

Together with {@link CursorConfig}, {@link TransactionConfig} and {@link * 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 {@link #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 ({@code get} method) operations and write locks on * write ({@code put} method) operations. The only exception is that a write * lock will be acquired on a read operation if {@link #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 {@link 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 {@link #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 {@link * #READ_COMMITTED} is used for a database (non-cursor) operation, the read * lock is released before the method returns.

* *

When neither {@link #READ_UNCOMMITTED} nor {@link #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 * {@link TransactionConfig#setSerializableIsolation} or {@link * EnvironmentConfig#setTxnSerializableIsolation}.

* *

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 {@link 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 {@link #READ_COMMITTED}, except that both * read and write locks are released. Configuring {@link #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 {@link * #READ_COMMITTED}.

* *

Read Uncommitted (Dirty-Read)

* *

When {@link #READ_UNCOMMITTED} is configured, no locking is performed * by a read operation. {@code READ_UNCOMMITTED} does not apply to write * operations.

* *

{@code 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 * ({@code READ_UNCOMMITTED}) by calling {@link Cursor#getNext 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 {@link * Cursor#getCurrent 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 {@code * getNext}. For example: *

    *
  • If the record is updated by T after the dirty-read {@code getNext} * call, and T is committed, a subsequent call to {@code getCurrent} will * return the data updated by T.
  • * *
  • If the record is updated by T before the dirty-read {@code getNext} * call, the {@code getNext} will returned the data updated by T. But if * call, the {@code getNext} will return the data updated by T. But if * T is then aborted, a subsequent call to {@code 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 {@code * getNext} call, the {@code getNext} call will return the inserted record. * But if T is aborted, a subsequent call to {@code getCurrent} will return * {@link OperationStatus#KEYEMPTY}.
  • * *
  • If the record is deleted by T after the dirty-read {@code getNext} * call, and T is committed, a subsequent call to {@code getCurrent} will * return {@link 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 {@code #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, {@link #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. * *
  3. 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 not deleted and * otherwise will be skipped.
  4. *
* *

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

* *

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

* *

To summarize, callers that use {@code READ_UNCOMMITTED} or {@code * #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, {@link OperationStatus#KEYEMPTY} will be returned by the following * methods if they are called while C is still positioned on the deleted * record: {@link Cursor#getCurrent Cursor.getCurrent}, {@link * Cursor#putCurrent Cursor.putCurrent} and {@link Cursor#delete * Cursor.delete}.
  • * *
  • When using {@code READ_UNCOMMITTED}, deleted records will be skipped * even when the deleting transaction is still open. No blocking will occur * and {@link LockConflictException} is never thrown when using this * mode.
  • * *
  • When using {@code #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, {@link LockConflictException} will be thrown * when this blocking results in a deadlock or a lock timeout.
  • *
*/ public enum LockMode { /** * Uses the default lock mode and is equivalent to passing {@code null} for * the lock mode parameter. * *

The default lock mode is {@link #READ_UNCOMMITTED} when this lock * mode is configured via {@link CursorConfig#setReadUncommitted} or {@link * TransactionConfig#setReadUncommitted}, or when using a {@link * DiskOrderedCursor}. The Read Uncommitted mode overrides any other * configuration settings.

* *

Otherwise, the default lock mode is {@link #READ_COMMITTED} when this * lock mode is configured via {@link CursorConfig#setReadCommitted} or * {@link TransactionConfig#setReadCommitted}. The Read Committed mode * overrides other configuration settings except for {@link * #READ_UNCOMMITTED}.

* *

Otherwise, the default lock mode is to acquire read locks and release * them according to the {@link LockMode default locking rules} for * transactional and non-transactional operations.

*/ DEFAULT, /** * 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 {@link #DEFAULT} is * passed and Read Uncommitted is the default -- see {@link #DEFAULT} for * details.

* *

Unlike {@link #READ_UNCOMMITTED_ALL}, deleted records will be skipped * even when the deleting transaction is still open. No blocking will occur * and {@link LockConflictException} is never thrown when using this * mode.

* *

See the {@link LockMode locking rules} for information on how Read * Uncommitted impacts transactional and non-transactional locking.

*/ READ_UNCOMMITTED, /** * 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 {@link #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, {@link LockConflictException} will be thrown when * this blocking results in a deadlock or a lock timeout.

* *

See the {@link LockMode locking rules} for information on how Read * Uncommitted impacts transactional and non-transactional locking.

*/ READ_UNCOMMITTED_ALL, /** * 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 {@link Database} get * methods, not to {@link Cursor} methods. To configure a cursor for Read * Committed isolation, use {@link CursorConfig#setReadCommitted}.

* *

See the {@link LockMode locking rules} for information on how Read * Committed impacts transactional and non-transactional locking.

* * @see Cache * Statistics: Unexpected Sizes */ READ_COMMITTED, /** * 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 {@link Cursor} or {@link Database} {@code get} (read) method * parameter will override the Read Committed or Read Uncommitted isolation * mode that is configured using {@link CursorConfig} or {@link * 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.

*/ RMW; private final ReadOptions readOptions; LockMode() { readOptions = new ReadOptions().setLockMode(this); } /** * Returns a ReadOptions with this LockMode property, and default values * for all other properties. * *

WARNING: Do not modify the returned object, since it is a singleton. * * @since 7.0 */ public ReadOptions toReadOptions() { return readOptions; } public String toString() { return "LockMode." + name(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy