final class ProgressiveResults extends java.lang.Object implements Results
Results interface which is backed by
Results sets of progressively increasing size.
This results object is best used in queries which start at the beginning
of a result set and scroll forward sequentially. While non-linear access
to records is possible, it is not the best choice for random access to
results. In fact certain operations currently are disallowed, such as
testing whether the current position is the last available. Thus, the
associated methods throw UnsupportedOperationException in the
current implementation.
This implementation is designed to balance the need for an immediate initial result with the need for fast access to a large number of results.
To accomplish this, results are retrieved in brackets. The initial fetch retrieves a bracket containing a single record. Each subsequent bracket fetch retrieves a maximum size which is calculated by raising a base number to a power one higher than that applied to the previous bracket. So, for a base number of 10, the first bracket would have maximum 10^0 (or 1) record. The second bracket (if any) would have maximum 10^1 (or 10) records. The third, 10^2 (or 100), and so on. The default base value is 10.
The exponential progression of bracket sizes ensures that the first result is retrieved as quickly as possible, and subsequent brackets are retrieved with reasonable efficiency. Thus, queries which fall to the smaller end of the spectrum will benefit from the quick retrieval of the first few brackets, while the up front expense of retrieving larger brackets will be amortized more evenly for those queries which process larger data sets.
Note that currently, this progression is (effectively) not capped, which presumes a reasonable JDBC fetch size to prevent a JDBC driver from caching too many records and overrunning memory.
When considered end-to-end, in order of increasing size, all brackets together form the virtualized set of results to a database query. This object keeps track of the virtual index position as it moves through the various brackets. Methods which accept an absolute row index expect this value to represent the absolute offset of the target row in this overall, virtualized result set, such that the bracketing implementation is an implementation detail which is transparent to users of this class.
Only the most recently created result set bracket is retained. Once all records in a bracket have been retrieved and the walk proceeds to the next record, the current bracket is discarded and a new one is retrieved. Users of this class which require the ability to perform non-linear, non first-to-last access must instantiate this class in scrolling mode. In this mode, a cache of visited records is maintained. If a previously accessed record must be re-retrieved, it is pulled from the cache. Accordingly, scrolling instances may have a higher memory requirement.
| Modifier and Type | Class and Description |
|---|---|
private static class |
ProgressiveResults.Locator
A descriptor object used to locate results brackets and store
information used to access them.
|
| Modifier and Type | Field and Description |
|---|---|
private java.lang.Integer |
actualMaxExponent
Actual maximum exponent in use
|
private static int |
ANALYZE_EXPONENT
The exponent used to get the average size of records
|
private java.lang.Object[] |
args
Substitution parameters, if any, to be applied to the query
|
private static int |
BASE
Base value used for exponential bracket size progression
|
private int |
bracket
Index of the active delegate
|
private java.util.List<java.lang.Object[]> |
cache
Cached results (scrolling mode only); arrays of DMOs or IDs
|
private int |
checkedCount
Numbers of records used to compute the size
|
private boolean |
closed
Flag indicates results are closed
|
private Results |
delegate
Result set to which record retrieval work is delegated
|
private java.lang.String[] |
entities
Names of entities involved in the query associated with these results
|
private static int |
FALLBACK_MAX_EXPONENT
Maximum exponent to which BASE can be raised in case we didn`t manage to analyze the optimal max
exponent based on row size.
|
private java.lang.String |
hql
HQL query string used to select records
|
private int |
lastValidBracket
Index of the most recent valid bracket
|
private int |
lastValidPosition
Most recent valid "real" position in the virtualized result set
|
private static CentralLogger |
LOG
Logger
|
private static long |
MAX_RESULTS_SIZE
Maximum memory allocated for a bracket
|
private static int |
MIN_CHECKED_THRESHOLD
Minimum number of records that needs to be computed in order to set the maximum exponent.
|
private Persistence |
persistence
Object which provides persistence services
|
private Persistence.Context |
persistenceContext
The persistence context.
|
private int |
position
Current "real" position in the overall, virtualized result set
|
private boolean |
projection
Flag indicating whether these results are for a projection query
|
private DataRelation |
relation
The recursive DATA-RELATION the query is to FILL for
|
private java.util.ArrayList<VirtualResultsListener> |
resultsChangeListeners
List of results change listeners
|
private long |
totalCheckedSize
The sum of some records used to compute the size of the brackets
|
| Constructor and Description |
|---|
ProgressiveResults(Persistence persistence,
java.lang.String hql,
java.lang.Object[] args,
boolean scrolling,
java.lang.String[] entities,
boolean projection,
DataRelation relation)
Convenience constructor which sets all variables required for record retrieval.
|
| Modifier and Type | Method and Description |
|---|---|
void |
addResultsChangeListener(VirtualResultsListener listener)
Register results change listener.
|
private boolean |
advanceCache(Results results,
int row)
Sequentially retrieve records and store them in the cache until either
there are no more records, or until the current position has reached
row. |
private void |
analyzeRow(java.lang.Object[] result)
Calculates the size of a row in bytes.
|
void |
cleanup()
Close an open result set, if any, and clear the cache, if any.
|
private void |
closeDelegate()
Close the delegate result set, if any.
|
private void |
fireResultsChanged()
Notify all listeners about changes in obtained results.
|
boolean |
first()
Move to the first result row.
|
java.lang.Object[] |
get()
Get the array of objects at the current result row.
|
java.lang.Object |
get(int column)
Get the object at the current result row, at the specified column.
|
java.lang.Long |
getID(int column)
Get the primary key ID at the current result row, at the specified
column.
|
private int |
getMaxExponent()
Calculate the largest exponent in regard to the row size analysis we done to determine the
optimal size for the brackets.
|
private Results |
getResults(int bracket)
Access the delegate result set object for the given bracket index.
|
private Results |
getResults(ProgressiveResults.Locator locator)
Access the delegate result set object defined by the given locator.
|
int |
getRowNumber()
Get the row number currently under the cursor.
|
boolean |
isFirst()
Is the cursor on the first row in the result set?
|
boolean |
isLast()
Indicate whether the current record is the last row in the overall,
virtualized result set.
|
boolean |
isResultSetCached()
Indicate whether the full result set is cached in this object.
|
boolean |
last()
Move to the last result row.
|
private ProgressiveResults.Locator |
locateBracket(int bracket)
Generate a descriptor object which is used to locate the bracket
at the given index among all results brackets.
|
private ProgressiveResults.Locator |
locateRow(int row)
Generate a descriptor object which is used to locate the bracket
containing the specified row and the row's location within the bracket.
|
private boolean |
moveTo(int row)
Attempt to move to a specific row offset within the virtualized result
set, and report whether a record exists at that row.
|
private boolean |
moveTo(int row,
boolean force)
Attempt to move to a specific row offset within the virtualized result
set, and report whether a record exists at that row.
|
boolean |
next()
Move cursor to the next result row.
|
boolean |
previous()
Move cursor to the previous result row.
|
void |
reset()
Reset the cursor to its natural starting position, before the first
result row.
|
boolean |
scroll(int rows)
Scroll the cursor ahead by the specified number of rows.
|
void |
sessionClosing()
Respond to a session closing event by caching a batch of this results
object's records.
|
boolean |
setRowNumber(int row)
Set the row number currently under the cursor.
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitaddRow, deleteRow, get, getNumberOfLoadedRows, isAutoFetchprivate static final CentralLogger LOG
private static final int BASE
private static final int FALLBACK_MAX_EXPONENT
private static final long MAX_RESULTS_SIZE
private static final int ANALYZE_EXPONENT
private static final int MIN_CHECKED_THRESHOLD
private final Persistence persistence
private final java.lang.String hql
private final java.lang.Object[] args
private final java.util.List<java.lang.Object[]> cache
private final java.lang.String[] entities
private final boolean projection
private final DataRelation relation
private Results delegate
private int position
private int lastValidPosition
private int bracket
private int lastValidBracket
private java.util.ArrayList<VirtualResultsListener> resultsChangeListeners
private boolean closed
private long totalCheckedSize
private int checkedCount
private java.lang.Integer actualMaxExponent
private final Persistence.Context persistenceContext
ProgressiveResults(Persistence persistence, java.lang.String hql, java.lang.Object[] args, boolean scrolling, java.lang.String[] entities, boolean projection, DataRelation relation)
persistence - Object which provides persistence services.hql - HQL query string used to select records.args - Substitution parameters, if any, to be applied to the query.scrolling - true to allow results to be scrollable. If false, it will only
be possible to move forward through results, beginning at the first result;
random access will be disallowed.entities - Names of entities associated with these results.projection - Flag indicating whether these results are for a projection query.relation - The recursive DATA-RELATION the query is to FILL for.public boolean first()
public boolean last()
public boolean next()
public boolean previous()
public boolean isFirst()
public boolean isLast()
This method is not supported by this implementation.
public java.lang.Object[] get()
public java.lang.Object get(int column)
public boolean isResultSetCached()
isResultSetCached in interface Resultstrue if all results are contained this object; false if not or
if unknown (such as for a scrolling or cursored result set. Default return value
is false.public java.lang.Long getID(int column)
public int getRowNumber()
getRowNumber in interface Results-1
if the cursor is not currently on a result.public boolean setRowNumber(int row)
setRowNumber in interface Resultsrow - Zero-based index of the row to be set as the current row.true if there is a row at the specified row
number; else false.public boolean scroll(int rows)
public void reset()
public void sessionClosing()
sessionClosing in interface Resultspublic void cleanup()
public void addResultsChangeListener(VirtualResultsListener listener)
listener - Listener to add.private ProgressiveResults.Locator locateRow(int row)
The object returned does not reflect the state of records or whether the target record actually exists in the result set. Rather, this method calculates where the record should be located based upon the bracketing algorithm in use.
row - 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).private ProgressiveResults.Locator locateBracket(int bracket)
The object returned does not reflect the state of records or whether the target bracket actually exists. Rather, this method calculates the parameters required to request the records which would comprise the bracket, according to the bracketing algorithm in use.
The Locator object returned will contain the specified
bracket, an offset of 0, the size of the bracket, and its row will
reflect the zero-based offset (in the virtualized result set) of the
row which starts the target bracket.
bracket - 0-based index of the target bracket in the virtualized result
set.private boolean moveTo(int row)
This method updates the internal state variables which track the current virtualized row index and bracket index. Both are set to their default values if the target row does not exist.
row - 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).true if there is a row at the specified row
number; else false.java.lang.UnsupportedOperationException - if a backwards move is requested for a non-scrolling results
object.private boolean moveTo(int row,
boolean force)
This method updates the internal state variables which track the current virtualized row index and bracket index. Both are set to their default values if the target row does not exist.
row - 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).force - Force move even if the target row matches the current row.
Allows to initialize delegate in some cases.true if there is a row at the specified row
number; else false.java.lang.UnsupportedOperationException - if a backwards move is requested for a non-scrolling results
object.private boolean advanceCache(Results results, int row)
row.results - Delegate results object from which to retrieve records.row - Target row index. Retrieval halts when the current record
position reaches this row.true if the last attempt to retrieve a record was
successful; false if we reached the end of the
delegate result set bracket before reaching our target row.java.lang.IllegalStateException - if the current position is not at the last record in the
cache.private Results getResults(int bracket) throws PersistenceException
bracket - 0-based index of the target bracket.Results for the given bracket,
or null if no such bracket exists.PersistenceExceptionprivate Results getResults(ProgressiveResults.Locator locator) throws PersistenceException
locator - Descriptor of the target bracket.Results for the given bracket,
or null if no such bracket exists.PersistenceException - if there is an error retrieving a result set.private void closeDelegate()
private void fireResultsChanged()
private int getMaxExponent()
MAX_RESULTS_SIZE. However, this is an effort to avoid retrieving a lot of records
at once to trigger OOM.private void analyzeRow(java.lang.Object[] result)
result - The row that should be analyzed.