public class DiskOrderedCursor extends java.lang.Object implements ForwardCursor
Database.openCursor(DiskOrderedCursorConfig)
method or the Environment.openDiskOrderedCursor(Database[], DiskOrderedCursorConfig)
method.
WARNING: After opening a DiskOrderedCursor, deletion of log files
by the JE log cleaner will be disabled until close()
is called. To
prevent unbounded growth of disk usage, be sure to call close()
to
re-enable log file deletion.
Optional configurations: the following options are available to tune the DiskOrderedCursor.
The DiskOrderedCursor creates a background producer thread which prefetches
some target records and inserts them in a queue for use by the cursor. The
parameter EnvironmentConfig.DOS_PRODUCER_QUEUE_TIMEOUT
applies to
this background thread, and controls the timeout which governs the blocking
queue.
See DiskOrderedCursorConfig
for additional options.
The consistency guarantees provided by a DiskOrderedCursor are, at best, the
same as those provided by READ_UNCOMMITTED (see LockMode
). With
READ_UNCOMMITTED, changes made by all transactions, including uncommitted
transactions, may be returned by the scan. Also, a record returned by the
scan is not locked, and may be modified or deleted by the application after
it is returned, including modification or deletion of the record at the
cursor position.
In other words, the records returned by the scan correspond to the state of the database (as if READ_UNCOMMITTED were used) at the beginning of the scan plus some, but not all, changes made by the application after the start of the scan. The user should not rely on the scan returning any changes made after the start of the scan. For example, if the record referred to by the DiskOrderedCursor is deleted after the DiskOrderedCursor is positioned at that record, getCurrent() will still return the key and value of that record and OperationStatus.SUCCESS. If a transactionally correct data set is required (as defined by READ_COMMITTED), the application must ensure that all transactions that write to the database are committed before the beginning of the scan. During the scan, no records in the database of the scan may be inserted, deleted, or modified. While this is possible, it is not the expected use case for a DiskOrderedCursor.
The internal algorithm used to approximate disk ordered reads is as follows.
For simplicity, the algorithm description assumes that a single database is
being scanned, but the algorithm is almost the same when multiple databases
are involved.
An internal producer thread is used to scan the database. This thread is
created and started when the DiskOrderedCursor
is created, and is
destroyed by close()
. Scanning consists of two
phases. In phase I the in-cache Btree of the scanned database is traversed
in key order. The LSNs (physical record addresses) of the data to be
fetched are accumulated in a memory buffer. Btree latches are held during
the traversal, but only for short durations. In phase II the accumulated
LSNs are sorted into disk order, fetched one at a time in that order, and
the fetched data is added to a blocking queue. The getNext
method
in this class removes the next entry from the queue. This approach allows
concurrent access to the Database during both phases of the scan, including
access by the application's consumer thread (the thread calling getNext
).
Phase I does not always process the entire Btree. During phase I if the
accumulation of LSNs causes the internal memory limit
or
LSN batch size
to be
exceeded, phase I is ended and phase II begins. In this case, after phase
II finishes, phase I resumes where it left off in the Btree traversal.
Phase I and II are repeated until the entire database is scanned.
By default, the internal memory limit and LSN batch size are unbounded (see
DiskOrderedCursorConfig
). For a database with a large number of
records, this could cause an OutOfMemoryError
. Therefore, it is
strongly recommended that either the internal memory limit or LSN batch size
is configured to limit the use of memory during the scan. On the other
hand, the efficiency of the scan is proportional to the amount of memory
used. If enough memory is available, the ideal case would be that the
database is scanned in in a single iteration of phase I and II. The more
iterations, the more random IO will occur.
Another factor is the queue
size
. During the phase I Btree traversal, data that is resident in the JE
cache will be added to the queue immediately, rather than waiting until
phase II and fetching it, but only if the queue is not full. Therefore,
increasing the size of the queue can avoid fetching data that is resident in
the JE cache. Also, increasing the queue size can improve parallelism of
the work done by the producer and consumer threads.
Also note that a keys-only
scan
is much more efficient than the default keys-and-data scan. With a
keys-only scan, only the BINs (bottom internal nodes) of the Btree need to
be fetched; the LNs (leaf nodes) do not. This is also true of databases
configured for duplicates
, even
for a keys-and-data scan, since internally the key and data are both
contained in the BIN.
Modifier and Type | Method and Description |
---|---|
void |
close()
Discards the cursor.
|
OperationResult |
get(DatabaseEntry key,
DatabaseEntry data,
Get getType,
ReadOptions options)
Moves the cursor to a record according to the specified
Get
type. |
DiskOrderedCursorConfig |
getConfig()
Returns this cursor's configuration.
|
OperationStatus |
getCurrent(DatabaseEntry key,
DatabaseEntry data,
LockMode lockMode)
Returns the key/data pair to which the cursor refers.
|
Database |
getDatabase()
Returns the Database handle for the database that contains the
latest record returned by getNext().
|
OperationStatus |
getNext(DatabaseEntry key,
DatabaseEntry data,
LockMode lockMode)
Moves the cursor to the next key/data pair and returns that pair.
|
public Database getDatabase()
getDatabase
in interface ForwardCursor
public void close() throws DatabaseException
The cursor handle may not be used again after this method has been called, regardless of the method's success or failure.
WARNING: To guard against memory leaks, the application should discard all references to the closed handle. While BDB makes an effort to discard references from closed objects to the allocated memory for an environment, this behavior is not guaranteed. The safe course of action for an application is to discard all references to closed BDB objects.
close
in interface ForwardCursor
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
EnvironmentFailureException
- if an unexpected, internal or
environment-wide failure occurs.DatabaseException
public OperationResult get(DatabaseEntry key, DatabaseEntry data, Get getType, ReadOptions options)
ForwardCursor
Get
type.get
in interface ForwardCursor
options
- the ReadOptions, or null to use default options.
For DiskOrderedCursors, ReadOptions.getLockMode()
must return
null, LockMode.DEFAULT
or
LockMode.READ_UNCOMMITTED
, and no locking
is performed.key
- the key returned as
output.data
- the data returned as
output.getType
- is Get.NEXT
or Get.CURRENT
.
interface. Get.CURRENT
is permitted only if the cursor is
initialized (positioned on a record).public OperationStatus getCurrent(DatabaseEntry key, DatabaseEntry data, LockMode lockMode)
ForwardCursor
Calling this method is equivalent to calling ForwardCursor.get(DatabaseEntry, DatabaseEntry, Get, ReadOptions)
with
Get.CURRENT
.
getCurrent
in interface ForwardCursor
lockMode
- the locking attributes. For DiskOrderedCursors this
parameter must be either null, LockMode.DEFAULT
or LockMode.READ_UNCOMMITTED
, and no locking
is performed.key
- the key returned as
output.data
- the data returned as
output.OperationStatus.KEYEMPTY
if there are no more records in the
DiskOrderedCursor set, otherwise, OperationStatus.SUCCESS
. If
the record referred to by a DiskOrderedCursor is deleted after the
ForwardCursor is positioned at that record, getCurrent() will still
return the key and value of that record and OperationStatus.SUCCESS.public OperationStatus getNext(DatabaseEntry key, DatabaseEntry data, LockMode lockMode)
ForwardCursor
Calling this method is equivalent to calling ForwardCursor.get(DatabaseEntry, DatabaseEntry, Get, ReadOptions)
with
Get.NEXT
.
getNext
in interface ForwardCursor
lockMode
- the locking attributes. For DiskOrderedCursors this
parameter must be either null, LockMode.DEFAULT
or LockMode.READ_UNCOMMITTED
, and no locking
is performed.key
- the key returned as
output.data
- the data returned as
output.OperationStatus.NOTFOUND
if no matching key/data pair is found;
otherwise, OperationStatus.SUCCESS
.public DiskOrderedCursorConfig getConfig()
This may differ from the configuration used to open this object if the cursor existed previously.
Copyright (c) 2002, 2017 Oracle and/or its affiliates. All rights reserved.