com.sleepycat.persist.EntityIndex Maven / Gradle / Ivy
/*-
* 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.persist;
import java.util.Map;
import java.util.SortedMap;
import com.sleepycat.collections.StoredMap;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
/* */
import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.Get;
/* */
import com.sleepycat.je.LockMode;
/* */
import com.sleepycat.je.OperationFailureException;
import com.sleepycat.je.OperationResult;
import com.sleepycat.je.ReadOptions;
/* */
import com.sleepycat.je.SecondaryDatabase;
import com.sleepycat.je.Transaction;
/* */
import com.sleepycat.je.WriteOptions;
/* */
/**
* The interface for accessing keys and entities via a primary or secondary
* index.
*
* {@code EntityIndex} objects are thread-safe. Multiple threads may safely
* call the methods of a shared {@code EntityIndex} object.
*
* An index is conceptually a map. {key:value} mappings are
* stored in the index and accessed by key. In fact, for interoperability with
* other libraries that use the standard Java {@link Map} or {@link SortedMap}
* interfaces, an {@code EntityIndex} may be accessed via these standard
* interfaces by calling the {@link #map} or {@link #sortedMap} methods.
*
* {@code EntityIndex} is an interface that is implemented by several
* classes in this package for different purposes. Depending on the context,
* the key type (K) and value type (V) of the index take on different meanings.
* The different classes that implement {@code EntityIndex} are:
*
* - {@link PrimaryIndex} maps primary keys to entities.
* - {@link SecondaryIndex} maps secondary keys to entities.
* - {@link SecondaryIndex#keysIndex} maps secondary keys to primary
* keys.
* - {@link SecondaryIndex#subIndex} maps primary keys to entities, for the
* subset of entities having a specified secondary key.
*
*
* In all cases, the index key type (K) is a primary or secondary key class.
* The index value type (V) is an entity class in all cases except for a {@link
* SecondaryIndex#keysIndex}, when it is a primary key class.
*
* In the following example, a {@code Employee} entity with a {@code
* MANY_TO_ONE} secondary key is defined.
*
*
* {@literal @Entity}
* class Employee {
*
* {@literal @PrimaryKey}
* long id;
*
* {@literal @SecondaryKey(relate=MANY_TO_ONE)}
* String department;
*
* String name;
*
* private Employee() {}
* }
*
* Consider that we have stored the entities below:
*
*
* Entities
* ID Department Name
* 1 Engineering Jane Smith
* 2 Sales Joan Smith
* 3 Engineering John Smith
* 4 Sales Jim Smith
*
*
* {@link PrimaryIndex} maps primary keys to entities:
*
*
* {@code PrimaryIndex} primaryIndex =
* store.getPrimaryIndex(Long.class, Employee.class);
*
*
* primaryIndex
* Primary Key Entity
* 1 1 Engineering Jane Smith
* 2 2 Sales Joan Smith
* 3 3 Engineering John Smith
* 4 4 Sales Jim Smith
*
*
* {@link SecondaryIndex} maps secondary keys to entities:
*
*
* {@code SecondaryIndex} secondaryIndex =
* store.getSecondaryIndex(primaryIndex, String.class, "department");
*
*
* secondaryIndex
* Secondary Key Entity
* Engineering 1 Engineering Jane Smith
* Engineering 3 Engineering John Smith
* Sales 2 Sales Joan Smith
* Sales 4 Sales Jim Smith
*
*
* {@link SecondaryIndex#keysIndex} maps secondary keys to primary
* keys:
*
*
* {@code EntityIndex} keysIndex = secondaryIndex.keysIndex();
*
*
* keysIndex
* Secondary Key Primary Key
* Engineering 1
* Engineering 3
* Sales 2
* Sales 4
*
*
* {@link SecondaryIndex#subIndex} maps primary keys to entities, for the
* subset of entities having a specified secondary key:
*
*
* {@code EntityIndex} subIndex = secondaryIndex.subIndex("Engineering");
*
*
* subIndex
* Primary Key Entity
* 1 1 Engineering Jane Smith
* 3 3 Engineering John Smith
*
*
* Accessing the Index
*
* An {@code EntityIndex} provides a variety of methods for retrieving
* entities from an index. It also provides methods for deleting entities.
* However, it does not provide methods for inserting and updating. To insert
* and update entities, use the {@link PrimaryIndex#put} family of methods in
* the {@link PrimaryIndex} class.
*
* An {@code EntityIndex} supports two mechanisms for retrieving
* entities:
*
* - The {@link #get} method returns a single value for a given key. If there
* are multiple values with the same secondary key (duplicates), it returns the
* first entity in the duplicate set.
* - An {@link EntityCursor} can be obtained using the {@link #keys} and
* {@link #entities} family of methods. A cursor can be used to return all
* values in the index, including duplicates. A cursor can also be used to
* return values within a specified range of keys.
*
*
* Using the example entities above, calling {@link #get} on the primary
* index will always return the employee with the given ID, or null if no such
* ID exists. But calling {@link #get} on the secondary index will retrieve
* the first employee in the given department, which may not be very
* useful:
*
*
* Employee emp = primaryIndex.get(1); // Returns by unique ID
* emp = secondaryIndex.get("Engineering"); // Returns first in department
*
* Using a cursor, you can iterate through all duplicates in the secondary
* index:
*
*
* {@code EntityCursor} cursor = secondaryIndex.entities();
* try {
* for (Employee entity : cursor) {
* if (entity.department.equals("Engineering")) {
* // Do something with the entity...
* }
* }
* } finally {
* cursor.close();
* }
*
* But for a large database it is much more efficient to iterate over only
* those entities with the secondary key you're searching for. This could be
* done by restricting a cursor to a range of keys:
*
*
* {@code EntityCursor} cursor =
* secondaryIndex.entities("Engineering", true, "Engineering", true);
* try {
* for (Employee entity : cursor) {
* // Do something with the entity...
* }
* } finally {
* cursor.close();
* }
*
* However, when you are interested only in the entities with a particular
* secondary key value, it is more convenient to use a sub-index:
*
*
* {@code EntityIndex} subIndex = secondaryIndex.subIndex("Engineering");
* {@code EntityCursor} cursor = subIndex.entities();
* try {
* for (Employee entity : cursor) {
* // Do something with the entity...
* }
* } finally {
* cursor.close();
* }
*
* In addition to being more convenient than a cursor range, a sub-index
* allows retrieving by primary key:
*
*
* Employee emp = subIndex.get(1);
*
* When using a sub-index, all operations performed on the sub-index are
* restricted to the single key that was specified when the sub-index was
* created. For example, the following returns null because employee 2 is not
* in the Engineering department and therefore is not part of the
* sub-index:
*
*
* Employee emp = subIndex.get(2);
*
* For more information on using cursors and cursor ranges, see {@link
* EntityCursor}.
*
* Note that when using an index, keys and values are stored and retrieved
* by value not by reference. In other words, if an entity object is stored
* and then retrieved, or retrieved twice, each object will be a separate
* instance. For example, in the code below the assertion will always
* fail.
*
* MyKey key = ...;
* MyEntity entity1 = index.get(key);
* MyEntity entity2 = index.get(key);
* assert entity1 == entity2; // always fails!
*
*
* Deleting from the Index
*
* Any type of index may be used to delete entities with a specified key by
* calling {@link #delete}. The important thing to keep in mind is that
* all entities with the specified key are deleted. In a primary index,
* at most a single entity is deleted:
*
*
* primaryIndex.delete(1); // Deletes a single employee by unique ID
*
* But in a secondary index, multiple entities may be deleted:
*
*
* secondaryIndex.delete("Engineering"); // Deletes all Engineering employees
*
* This begs this question: How can a single entity be deleted without
* knowing its primary key? The answer is to use cursors. After locating an
* entity using a cursor, the entity can be deleted by calling {@link
* EntityCursor#delete}.
*
* Transactions
*
* Transactions can be used to provide standard ACID (Atomicity,
* Consistency, Integrity and Durability) guarantees when retrieving, storing
* and deleting entities. This section provides a brief overview of how to use
* transactions with the Direct Persistence Layer. For more information on
* using transactions, see Writing
* Transactional Applications.
*
* Transactions may be used only with a transactional {@link EntityStore},
* which is one for which {@link StoreConfig#setTransactional
* StoreConfig.setTransactional(true)} has been called. Likewise, a
* transactional store may only be used with a transactional {@link
* Environment}, which is one for which {@link
* EnvironmentConfig#setTransactional EnvironmentConfig.setTransactional(true)}
* has been called. For example:
*
*
* EnvironmentConfig envConfig = new EnvironmentConfig();
* envConfig.setTransactional(true);
* envConfig.setAllowCreate(true);
* Environment env = new Environment(new File("/my/data"), envConfig);
*
* StoreConfig storeConfig = new StoreConfig();
* storeConfig.setTransactional(true);
* storeConfig.setAllowCreate(true);
* EntityStore store = new EntityStore(env, "myStore", storeConfig);
*
* Transactions are represented by {@link Transaction} objects, which are
* part of the {@link com.sleepycat.je Base API}. Transactions are created
* using the {@link Environment#beginTransaction Environment.beginTransaction}
* method.
*
* A transaction will include all operations for which the transaction
* object is passed as a method argument. All retrieval, storage and deletion
* methods have an optional {@link Transaction} parameter for this purpose.
* When a transaction is passed to a method that opens a cursor, all retrieval,
* storage and deletion operations performed using that cursor will be included
* in the transaction.
*
* A transaction may be committed by calling {@link Transaction#commit} or
* aborted by calling {@link Transaction#abort}. For example, two employees
* may be deleted atomically with a transaction; other words, either both are
* deleted or neither is deleted:
*
*
* Transaction txn = env.beginTransaction(null, null);
* try {
* primaryIndex.delete(txn, 1);
* primaryIndex.delete(txn, 2);
* txn.commit();
* txn = null;
* } finally {
* if (txn != null) {
* txn.abort();
* }
* }
*
* WARNING: Transactions must always be committed or aborted to
* prevent resource leaks which could lead to the index becoming unusable or
* cause an OutOfMemoryError
. To ensure that a transaction is
* aborted in the face of exceptions, call {@link Transaction#abort} in a
* finally block.
*
* For a transactional store, storage and deletion operations are always
* transaction protected, whether or not a transaction is explicitly used. A
* null transaction argument means to perform the operation using auto-commit,
* or the implied thread transaction if an XAEnvironment is being used. A
* transaction is automatically started as part of the operation and is
* automatically committed if the operation completes successfully. The
* transaction is automatically aborted if an exception occurs during the
* operation, and the exception is re-thrown to the caller. For example, each
* employee is deleted using a an auto-commit transaction below, but it is
* possible that employee 1 will be deleted and employee 2 will not be deleted,
* if an error or crash occurs while deleting employee 2:
*
*
* primaryIndex.delete(null, 1);
* primaryIndex.delete(null, 2);
*
* When retrieving entities, a null transaction argument means to perform
* the operation non-transactionally. The operation is performed outside the
* scope of any transaction, without providing transactional ACID guarantees.
* If an implied thread transaction is present (i.e. if an XAEnvironment is
* being used), that transaction is used. When a non-transactional store is
* used, transactional ACID guarantees are also not provided.
*
* For non-transactional and auto-commit usage, overloaded signatures for
* retrieval, storage and deletion methods are provided to avoid having to pass
* a null transaction argument. For example, {@link #delete} may be called
* instead of {@link #delete(Transaction,Object)}. For example, the following
* code is equivalent to the code above where null was passed for the
* transaction:
*
*
* primaryIndex.delete(1);
* primaryIndex.delete(2);
*
* For retrieval methods the overloaded signatures also include an optional
* {@link LockMode} parameter, and overloaded signatures for opening cursors
* include an optional {@link CursorConfig} parameter. These parameters are
* described further below in the Locking and Lock Modes section.
*
* Transactions and Cursors
*
* There are two special consideration when using cursors with transactions.
* First, for a transactional store, a non-null transaction must be passed to
* methods that open a cursor if that cursor will be used to delete or update
* entities. Cursors do not perform auto-commit when a null transaction is
* explicitly passed or implied by the method signature. For example, the
* following code will throw {@link DatabaseException} when the {@link
* EntityCursor#delete} method is called:
*
*
* // Does not work with a transactional store!
* {@code EntityCursor} cursor = primaryIndex.entities();
* try {
* for (Employee entity : cursor) {
* cursor.delete(); // Will throw DatabaseException.
* }
* } finally {
* cursor.close();
* }
*
* Instead, the {@link #entities(Transaction,CursorConfig)} signature must
* be used and a non-null transaction must be passed:
*
*
* {@code EntityCursor} cursor = primaryIndex.entities(txn, null);
* try {
* for (Employee entity : cursor) {
* cursor.delete();
* }
* } finally {
* cursor.close();
* }
*
* The second consideration is that error handling is more complex when
* using both transactions and cursors, for the following reasons:
*
* - When an exception occurs, the transaction should be aborted.
* - Cursors must be closed whether or not an exception occurs.
* - Cursors must be closed before committing or aborting the
* transaction.
*
*
* For example:
*
*
* Transaction txn = env.beginTransaction(null, null);
* {@code EntityCursor} cursor = null;
* try {
* cursor = primaryIndex.entities(txn, null);
* for (Employee entity : cursor) {
* cursor.delete();
* }
* cursor.close();
* cursor = null;
* txn.commit();
* txn = null;
* } finally {
* if (cursor != null) {
* cursor.close();
* }
* if (txn != null) {
* txn.abort();
* }
* }
*
* Locking and Lock Modes
*
* This section provides a brief overview of locking and describes how lock
* modes are used with the Direct Persistence Layer. For more information on
* locking, see Writing
* Transactional Applications.
*
* When using transactions, locks are normally acquired on each entity that
* is retrieved or stored. The locks are used to isolate one transaction from
* another. Locks are normally released only when the transaction is committed
* or aborted.
*
* When not using transactions, locks are also normally acquired on each
* entity that is retrieved or stored. However, these locks are released when
* the operation is complete. When using cursors, in order to provide
* cursor stability locks are held until the cursor is moved to a
* different entity or closed.
*
* This default locking behavior provides full transactional ACID guarantees
* and cursor stability. However, application performance can sometimes be
* improved by compromising these guarantees. As described in Writing
* Transactional Applications, the {@link LockMode} and {@link
* CursorConfig} parameters are two of the mechanisms that can be used to make
* compromises.
*
* For example, imagine that you need an approximate count of all entities
* matching certain criterion, and it is acceptable for entities to be changed
* by other threads or other transactions while performing this query. {@link
* LockMode#READ_UNCOMMITTED} can be used to perform the retrievals without
* acquiring any locks. This reduces memory consumption, does less processing,
* and improves concurrency.
*
*
* {@code EntityCursor} cursor = primaryIndex.entities(txn, null);
* try {
* Employee entity;
* while ((entity = cursor.next(LockMode.READ_UNCOMMITTED)) != null) {
* // Examine the entity and accumulate totals...
* }
* } finally {
* cursor.close();
* }
*
* The {@link LockMode} parameter specifies locking behavior on a
* per-operation basis. If null or {@link LockMode#DEFAULT} is specified, the
* default lock mode is used.
*
* It is also possible to specify the default locking behavior for a cursor
* using {@link CursorConfig}. The example below is equivalent to the example
* above:
*
*
* CursorConfig config = new CursorConfig();
* config.setReadUncommitted(true);
* {@code EntityCursor} cursor = primaryIndex.entities(txn, config);
* try {
* Employee entity;
* while ((entity = cursor.next()) != null) {
* // Examine the entity and accumulate totals...
* }
* } finally {
* cursor.close();
* }
*
*
* Note that {@code READ_UNCOMMITTED} can be used with a key cursor to
* reduce I/O, potentially providing significant performance benefits. See Key Cursor Optimization with
* READ_UNCOMMITTED
*
*
* The use of other lock modes, cursor configuration, and transaction
* configuration are discussed in Writing
* Transactional Applications.
*
* Performing Transaction Retries
*
* Lock conflict handling is another important topic discussed in Writing
* Transactional Applications. To go along with that material, here we
* show a lock conflict handling loop in the context of the Direct Persistence
* Layer. The example below shows deleting all entities in a primary index in
* a single transaction. If a lock conflict occurs, the transaction is aborted
* and the operation is retried.
*
*
* This is a DPL version of the equivalent example code
* for the base API.
*
* The following example code illustrates the recommended approach. Note
* that the {@code Environment.beginTransaction} and {@code Transaction.commit}
* calls are intentially inside the {@code try} block. When using JE-HA, this
* will make it easy to add a {@code catch} for other exceptions that can be
* resolved by retrying the transaction, such as consistency exceptions.
*
*
*
* void doTransaction(final Environment env,
* final {@code PrimaryIndex} primaryIndex,
* final int maxTries)
* throws DatabaseException {
*
* boolean success = false;
* long sleepMillis = 0;
* for (int i = 0; i < maxTries; i++) {
* // Sleep before retrying.
* if (sleepMillis != 0) {
* Thread.sleep(sleepMillis);
* sleepMillis = 0;
* }
* Transaction txn = null;
* try {
* txn = env.beginTransaction(null, null);
* final {@code EntityCursor} cursor =
* primaryIndex.entities(txn, null);
* try {
* // INSERT APP-SPECIFIC CODE HERE:
* // Perform read and write operations, for example:
* for (Employee entity : cursor) {
* cursor.delete();
* }
* } finally {
* cursor.close();
* }
* txn.commit();
* success = true;
* return;
* } catch (LockConflictException e) {
* sleepMillis = LOCK_CONFLICT_RETRY_SEC * 1000;
* continue;
* } finally {
* if (!success) {
* if (txn != null) {
* txn.abort();
* }
* }
* }
* }
* // INSERT APP-SPECIFIC CODE HERE:
* // Transaction failed, despite retries.
* // Take some app-specific course of action.
* }
*
* Low Level Access
*
* Each Direct Persistence Layer index is associated with an underlying
* {@link Database} or {@link SecondaryDatabase} defined in the {@link
* com.sleepycat.je Base API}. At this level, an index is a Btree managed by
* the Berkeley DB Java Edition transactional storage engine. Although you may
* never need to work at the {@code Base API} level, keep in mind that some
* types of performance tuning can be done by configuring the underlying
* databases. See the {@link EntityStore} class for more information on
* database and sequence configuration.
*
* If you wish to access an index using the {@code Base API}, you may call
* the {@link PrimaryIndex#getDatabase} or {@link SecondaryIndex#getDatabase}
* method to get the underlying database. To translate between entity or key
* objects and {@link DatabaseEntry} objects at this level, use the bindings
* returned by {@link PrimaryIndex#getEntityBinding}, {@link
* PrimaryIndex#getKeyBinding}, and {@link SecondaryIndex#getKeyBinding}.
*
* @author Mark Hayes
*/
public interface EntityIndex {
/**
* Returns the underlying database for this index.
*
* @return the database.
*/
Database getDatabase();
/**
* Checks for existence of a key in this index.
*
* The operation will not be transaction protected, and {@link
* LockMode#DEFAULT} is used implicitly.
*
*
* {@code READ_UNCOMMITTED} can be used with this method to reduce I/O,
* since the record data item will not be read. This is the same benefit
* as described in Key Cursor
* Optimization with READ_UNCOMMITTED
*
*
* @param key the key to search for.
*
* @return whether the key exists in the index.
*
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
boolean contains(K key)
throws DatabaseException;
/**
* Checks for existence of a key in this index.
*
*
* {@code READ_UNCOMMITTED} can be used with this method to reduce I/O,
* since the record data item will not be read. This is the same benefit
* as described in Key Cursor
* Optimization with READ_UNCOMMITTED
*
*
* @param txn the transaction used to protect this operation, or null
* if the operation should not be transaction protected.
*
* @param key the key to search for.
*
* @param lockMode the lock mode to use for this operation, or null to
* use {@link LockMode#DEFAULT}.
*
* @return whether the key exists in the index.
*
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
boolean contains(Transaction txn, K key, LockMode lockMode)
throws DatabaseException;
/**
* Gets an entity via a key of this index.
*
* The operation will not be transaction protected, and {@link
* LockMode#DEFAULT} is used implicitly.
*
* @param key the key to search for.
*
* @return the value mapped to the given key, or null if the key is not
* present in the index.
*
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
V get(K key)
throws DatabaseException;
/**
* Gets an entity via a key of this index.
*
* @param txn the transaction used to protect this operation, or null
* if the operation should not be transaction protected.
*
* @param key the key to search for.
*
* @param lockMode the lock mode to use for this operation, or null to
* use {@link LockMode#DEFAULT}.
*
* @return the value mapped to the given key, or null if the key is not
* present in the index.
*
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
V get(Transaction txn, K key, LockMode lockMode)
throws DatabaseException;
/* */
/**
* Gets an entity via a key of this index, using Get type and ReadOptions
* parameters, and returning an EntityResult.
*
* @param txn the transaction used to protect this operation, or null
* if the operation should not be transaction protected.
*
* @param key the key to search for.
*
* @param getType must be {@link Get#SEARCH}.
*
* @param options the ReadOptions, or null to use default options.
*
* @return the EntityResult, including the value mapped to the given key,
* or null if the key is not present in the index.
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
* @throws DatabaseException the base class for all BDB exceptions.
*
* @since 7.0
*/
EntityResult get(Transaction txn,
K key,
Get getType,
ReadOptions options)
throws DatabaseException;
/* */
/**
* Returns a non-transactional count of the entities in this index.
*
*
*
* This operation is faster than obtaining a count by scanning the index
* manually, and will not perturb the current contents of the cache.
* However, the count is not guaranteed to be accurate if there are
* concurrent updates. Note that this method does scan a significant
* portion of the index and should be considered a fairly expensive
* operation.
*
* This operation will disable deletion of log files by the JE log
* cleaner during its execution and will consume a certain amount of
* memory (but without affecting the memory that is available for the
* JE cache). To avoid excessive memory consumption (and a potential
* {@code OutOfMemoryError}) this method places an internal limit on
* its memory consumption. If this limit is reached, the method will
* still work properly, but its performance will degrade. To specify
* a different memory limit than the one used by this method, use the
* {@link EntityIndex#count(long memoryLimit)} method.
*
*
*
* @return the number of entities in this index.
*
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
long count()
throws DatabaseException;
/* */
/**
* Returns a non-transactional count of the entities in this index.
*
* This operation is faster than obtaining a count by scanning the index
* manually, and will not perturb the current contents of the cache.
* However, the count is not guaranteed to be accurate if there are
* concurrent updates. Note that this method does scan a significant
* portion of the index and should be considered a fairly expensive
* operation.
*
* This operation will disable deletion of log files by the JE log
* cleaner during its execution and will consume a certain amount of
* memory (but without affecting the memory that is available for the
* JE cache). To avoid excessive memory consumption (and a potential
* {@code OutOfMemoryError}) this method takes as input an upper bound
* on the memory it may consume. If this limit is reached, the method
* will still work properly, but its performance will degrade.
*
* @return the number of entities in this index.
*
* @throws OperationFailureException if one of the Read Operation
* Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
long count(long memoryLimit)
throws DatabaseException;
/* */
/**
* Deletes all entities with a given index key.
*
* Auto-commit is used implicitly if the store is transactional.
*
* @param key the key to search for.
*
* @return whether any entities were deleted.
*
*
* @throws OperationFailureException if one of the Write
* Operation Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
boolean delete(K key)
throws DatabaseException;
/**
* Deletes all entities with a given index key.
*
* @param txn the transaction used to protect this operation, null to use
* auto-commit, or null if the store is non-transactional.
*
* @param key the key to search for.
*
* @return whether any entities were deleted.
*
*
* @throws OperationFailureException if one of the Write
* Operation Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
boolean delete(Transaction txn, K key)
throws DatabaseException;
/* */
/**
* Deletes all entities with a given index key, using a WriteOptions
* parameter and returning an OperationResult.
*
* @param txn the transaction used to protect this operation, null to use
* auto-commit, or null if the store is non-transactional.
*
* @param key the key to search for.
*
* @param options the WriteOptions, or null to use default options.
*
* @return the OperationResult if any entities were deleted, else null. If
*
* @throws OperationFailureException if one of the Write
* Operation Failures occurs.
*
* @throws EnvironmentFailureException if an unexpected, internal or
* environment-wide failure occurs.
*
* @throws DatabaseException the base class for all BDB exceptions.
*
* @since 7.0
*/
OperationResult delete(Transaction txn, K key, WriteOptions options)
throws DatabaseException;
/* */
/**
* Opens a cursor for traversing all keys in this index.
*
* The operations performed with the cursor will not be transaction
* protected, and {@link CursorConfig#DEFAULT} is used implicitly. If the
* store is transactional, the cursor may not be used to update or delete
* entities.
*
*
* Note that {@code READ_UNCOMMITTED} can be used with a key cursor to
* reduce I/O, potentially providing significant performance benefits. See
* Key Cursor Optimization with
* READ_UNCOMMITTED
*
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor keys()
throws DatabaseException;
/**
* Opens a cursor for traversing all keys in this index.
*
*
* Note that {@code READ_UNCOMMITTED} can be used with a key cursor to
* reduce I/O, potentially providing significant performance benefits. See
* Key Cursor Optimization with
* READ_UNCOMMITTED
*
*
* @param txn the transaction used to protect all operations performed with
* the cursor, or null if the operations should not be transaction
* protected. If the store is non-transactional, null must be specified.
* For a transactional store the transaction is optional for read-only
* access and required for read-write access.
*
* @param config the cursor configuration that determines the default lock
* mode used for all cursor operations, or null to implicitly use {@link
* CursorConfig#DEFAULT}.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor keys(Transaction txn, CursorConfig config)
throws DatabaseException;
/**
* Opens a cursor for traversing all entities in this index.
*
* The operations performed with the cursor will not be transaction
* protected, and {@link CursorConfig#DEFAULT} is used implicitly. If the
* store is transactional, the cursor may not be used to update or delete
* entities.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor entities()
throws DatabaseException;
/**
* Opens a cursor for traversing all entities in this index.
*
* @param txn the transaction used to protect all operations performed with
* the cursor, or null if the operations should not be transaction
* protected. If the store is non-transactional, null must be specified.
* For a transactional store the transaction is optional for read-only
* access and required for read-write access.
*
* @param config the cursor configuration that determines the default lock
* mode used for all cursor operations, or null to implicitly use {@link
* CursorConfig#DEFAULT}.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor entities(Transaction txn,
CursorConfig config)
throws DatabaseException;
/**
* Opens a cursor for traversing keys in a key range.
*
* The operations performed with the cursor will not be transaction
* protected, and {@link CursorConfig#DEFAULT} is used implicitly. If the
* store is transactional, the cursor may not be used to update or delete
* entities.
*
*
* Note that {@code READ_UNCOMMITTED} can be used with a key cursor to
* reduce I/O, potentially providing significant performance benefits. See
* Key Cursor Optimization with
* READ_UNCOMMITTED
*
*
* @param fromKey is the lower bound of the key range, or null if the range
* has no lower bound.
*
* @param fromInclusive is true if keys greater than or equal to fromKey
* should be included in the key range, or false if only keys greater than
* fromKey should be included.
*
* @param toKey is the upper bound of the key range, or null if the range
* has no upper bound.
*
* @param toInclusive is true if keys less than or equal to toKey should be
* included in the key range, or false if only keys less than toKey should
* be included.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor keys(K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive)
throws DatabaseException;
/**
* Opens a cursor for traversing keys in a key range.
*
*
* Key Cursor Optimization with
* READ_UNCOMMITTED
*
* Using a key cursor potentially has a large performance benefit when
* the {@code READ_UNCOMMITTED} isolation mode is used. In this case, if
* the record data is not in the JE cache, it will not be read from disk.
* The performance benefit is potentially large because random access disk
* reads may be reduced. Examples are:
*
* - Scanning all records in key order, when the entity is not needed and
* {@code READ_UNCOMMITTED} isolation is acceptable.
* - Skipping over records quickly to perform approximate pagination with
* {@code READ_UNCOMMITTED} isolation.
*
*
* For other isolation modes ({@code READ_COMMITTED}, {@code
* REPEATABLE_READ} and {@code SERIALIZABLE}), the performance benefit of a
* key cursor is not as significant. In this case, the data item must be
* read into the JE cache if it is not already present, in order to lock
* the record. The only performance benefit is that the data will not be
* copied from the JE cache to the application's entry parameter, and will
* not be unmarshalled into an entity object.
*
* For information on specifying isolation modes, see {@link LockMode},
* {@link CursorConfig} and {@link com.sleepycat.je.TransactionConfig}.
*
*
* @param txn the transaction used to protect all operations performed with
* the cursor, or null if the operations should not be transaction
* protected. If the store is non-transactional, null must be specified.
* For a transactional store the transaction is optional for read-only
* access and required for read-write access.
*
* @param fromKey is the lower bound of the key range, or null if the range
* has no lower bound.
*
* @param fromInclusive is true if keys greater than or equal to fromKey
* should be included in the key range, or false if only keys greater than
* fromKey should be included.
*
* @param toKey is the upper bound of the key range, or null if the range
* has no upper bound.
*
* @param toInclusive is true if keys less than or equal to toKey should be
* included in the key range, or false if only keys less than toKey should
* be included.
*
* @param config the cursor configuration that determines the default lock
* mode used for all cursor operations, or null to implicitly use {@link
* CursorConfig#DEFAULT}.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor keys(Transaction txn,
K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive,
CursorConfig config)
throws DatabaseException;
/**
* Opens a cursor for traversing entities in a key range.
*
* The operations performed with the cursor will not be transaction
* protected, and {@link CursorConfig#DEFAULT} is used implicitly. If the
* store is transactional, the cursor may not be used to update or delete
* entities.
*
* @param fromKey is the lower bound of the key range, or null if the range
* has no lower bound.
*
* @param fromInclusive is true if keys greater than or equal to fromKey
* should be included in the key range, or false if only keys greater than
* fromKey should be included.
*
* @param toKey is the upper bound of the key range, or null if the range
* has no upper bound.
*
* @param toInclusive is true if keys less than or equal to toKey should be
* included in the key range, or false if only keys less than toKey should
* be included.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor entities(K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive)
throws DatabaseException;
/**
* Opens a cursor for traversing entities in a key range.
*
* @param txn the transaction used to protect all operations performed with
* the cursor, or null if the operations should not be transaction
* protected. If the store is non-transactional, null must be specified.
* For a transactional store the transaction is optional for read-only
* access and required for read-write access.
*
* @param fromKey is the lower bound of the key range, or null if the range
* has no lower bound.
*
* @param fromInclusive is true if keys greater than or equal to fromKey
* should be included in the key range, or false if only keys greater than
* fromKey should be included.
*
* @param toKey is the upper bound of the key range, or null if the range
* has no upper bound.
*
* @param toInclusive is true if keys less than or equal to toKey should be
* included in the key range, or false if only keys less than toKey should
* be included.
*
* @param config the cursor configuration that determines the default lock
* mode used for all cursor operations, or null to implicitly use {@link
* CursorConfig#DEFAULT}.
*
* @return the cursor.
*
* @throws DatabaseException the base class for all BDB exceptions.
*/
EntityCursor entities(Transaction txn,
K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive,
CursorConfig config)
throws DatabaseException;
/**
* Returns a standard Java map based on this entity index. The {@link
* StoredMap} returned is defined by the {@linkplain
* com.sleepycat.collections Collections API}. Stored collections conform
* to the standard Java collections framework interface.
*
* @return the map.
*/
Map map();
/**
* Returns a standard Java sorted map based on this entity index. The
* {@link StoredSortedMap} returned is defined by the {@linkplain
* com.sleepycat.collections Collections API}. Stored collections conform
* to the standard Java collections framework interface.
*
* @return the map.
*/
SortedMap sortedMap();
}