T
- the type of elements of the cursor@API(value=STABLE) public interface RecordCursor<T> extends AutoCloseable, Iterator<T>
Iterator
, a RecordCursor
provides one-item-at-a-time access to an ordered collection.
It differs in three primary respects:
RecordCursor
is asynchronous. Instead of the synchronous Iterator.hasNext()
and
Iterator.next()
methods, RecordCursor
advances the iteration using the asynchronous onNext()
method, which returns a CompletableFuture
.
RecordCursor
supports continuations, which are opaque tokens that represent the position of the
cursor between records. Continuations can be used to restart the iteration at the same point later. Continuations
represent all of the state needed to do this restart, even if the original objects no longer exist.
RecordCursor
's API offers correctness by construction. In contrast to the hasNext()
/
next()
API used by Iterator
, RecordCursor
's primary API isonNext()
which
produces the next value if one is present, or an object indicating that there is no such record. The presence of a
next value is instead indicated by RecordCursorResult.hasNext()
. This API serves to bundle a continuation
(and possible a RecordCursor.NoNextReason
) with the result, ensuring that a continuation is obtained only when it is valid.
For compatibility with Iterator
, RecordCursor
also supports onHasNext()
and
next()
, but continuations must be used carefully with this API, as described below.
RecordCursor
supports getContinuation()
for use with the Iterator
-style API. A cursor is
between records and valid for getting its continuation after calling next()
or after hasNext()
returns
false
.
When a cursor stops producing values, it can report why using a RecordCursor.NoNextReason
. This can be returned as part of
a RecordCursorResult
if using the onNext()
API or using getNoNextReason()
if using the
Iterator
-style API. No-next-reasons are fundamentally distinguished between those that are due to the data
itself (in-band) and those that are due to the environment / context (out-of-band). For example, running out of data
or having returned the maximum number of records requested are in-band, while reaching a limit on the number of
key-value pairs scanned by the transaction or the time that a transaction has been open are out-of-band.
Modifier and Type | Interface and Description |
---|---|
static class |
RecordCursor.NoNextReason
The reason that
hasNext() returned false . |
Modifier and Type | Method and Description |
---|---|
boolean |
accept(RecordCursorVisitor visitor)
Accept a visit from hierarchical visitor, which implements
RecordCursorVisitor . |
default RecordCursorIterator<T> |
asIterator()
Return a view of this cursor as a
RecordCursorIterator . |
default CompletableFuture<List<T>> |
asList()
Return the entire stream of records as an asynchronous list.
|
void |
close() |
static <T> RecordCursor<T> |
empty()
Get a new cursor that does not return any records.
|
static <T> RecordCursor<T> |
empty(Executor executor) |
default RecordCursor<T> |
filter(Function<T,Boolean> pred)
Get a new cursor that skips records that do not satisfy the given predicate.
|
default RecordCursor<T> |
filterAsync(Function<T,CompletableFuture<Boolean>> pred,
int pipelineSize)
Get a new cursor that skips records that do not satisfy the given asynchronous predicate.
|
default RecordCursor<T> |
filterAsyncInstrumented(Function<T,CompletableFuture<Boolean>> pred,
int pipelineSize,
StoreTimer timer,
Set<StoreTimer.Count> inSet,
Set<StoreTimer.Event> duringSet,
Set<StoreTimer.Count> successSet,
Set<StoreTimer.Count> failureSet)
Get a new cursor that skips records that do not satisfy the given asynchronous predicate, while instrumenting the
number of records that the filter sees, the number that it passes, the number that it fails, and the amount of
time that it spends computing the predicate.
|
default RecordCursor<T> |
filterAsyncInstrumented(Function<T,CompletableFuture<Boolean>> pred,
int pipelineSize,
StoreTimer timer,
StoreTimer.Count in,
StoreTimer.Event during,
StoreTimer.Count success,
StoreTimer.Count failure) |
default RecordCursor<T> |
filterInstrumented(Function<T,Boolean> pred,
StoreTimer timer,
Set<StoreTimer.Count> inSet,
Set<StoreTimer.Event> duringSet,
Set<StoreTimer.Count> successSet,
Set<StoreTimer.Count> failureSet)
Get a new cursor that skips records that do not satisfy the given predicate, while instrumenting the number of
records that the filter sees, the number that it passes, the number that it fails, and the amount of time that it
spends computing the predicate.
|
default RecordCursor<T> |
filterInstrumented(Function<T,Boolean> pred,
StoreTimer timer,
StoreTimer.Count in,
StoreTimer.Event during,
StoreTimer.Count success,
StoreTimer.Count failure) |
default CompletableFuture<Optional<T>> |
first()
Fetches the first item returned by the cursor.
|
static <T,V> RecordCursor<V> |
flatMapPipelined(Function<byte[],? extends RecordCursor<T>> outerFunc,
BiFunction<T,byte[],? extends RecordCursor<V>> innerFunc,
byte[] continuation,
int pipelineSize) |
static <T,V> RecordCursor<V> |
flatMapPipelined(Function<byte[],? extends RecordCursor<T>> outerFunc,
BiFunction<T,byte[],? extends RecordCursor<V>> innerFunc,
Function<T,byte[]> checker,
byte[] continuation,
int pipelineSize)
Resume a nested cursor with the given continuation or start if
null . |
default <V> RecordCursor<V> |
flatMapPipelined(Function<T,? extends RecordCursor<V>> func,
int pipelineSize)
Deprecated.
because it does not support continuations and is easy to misuse.
Use
flatMapPipelined(Function, BiFunction, byte[], int) instead. |
default CompletableFuture<Void> |
forEach(Consumer<T> consumer)
Call the given consumer as each record becomes available.
|
default CompletableFuture<Void> |
forEachAsync(Function<T,CompletableFuture<Void>> func,
int pipelineSize)
Call the function as each record becomes available.
|
default CompletableFuture<RecordCursorResult<T>> |
forEachResult(Consumer<RecordCursorResult<T>> consumer)
Call the given consumer as each record result becomes available.
|
default CompletableFuture<RecordCursorResult<T>> |
forEachResultAsync(Function<RecordCursorResult<T>,CompletableFuture<Void>> func)
Call the function as each record result becomes available.
|
static <T> RecordCursor<T> |
fromFuture(CompletableFuture<T> future)
Get a new cursor that has the contents of the given future as its only record
The record will be available when the future is complete.
|
static <T> RecordCursor<T> |
fromFuture(Executor executor,
CompletableFuture<T> future) |
static <T> RecordCursor<T> |
fromIterator(Executor executor,
Iterator<T> iterator) |
static <T> RecordCursor<T> |
fromIterator(Iterator<T> iterator)
Get a new cursor from an ordinary
Iterator . |
static <T> RecordCursor<T> |
fromList(Executor executor,
List<T> list) |
static <T> RecordCursor<T> |
fromList(Executor executor,
List<T> list,
byte[] continuation) |
static <T> RecordCursor<T> |
fromList(List<T> list)
Get a new cursor from an ordinary
List . |
static <T> RecordCursor<T> |
fromList(List<T> list,
byte[] continuation)
Get a new cursor from an ordinary
List , skipping ahead according to the given continuation. |
byte[] |
getContinuation()
Deprecated.
in favor of the
onNext() method or advancing the cursor asIterator() |
default CompletableFuture<Integer> |
getCount()
Count the number of records remaining.
|
Executor |
getExecutor() |
default RecordCursorResult<T> |
getNext()
Get the next result from this cursor.
|
RecordCursor.NoNextReason |
getNoNextReason()
Deprecated.
in favor of the
onNext() method or advancing the cursor asIterator() |
default boolean |
hasNext()
Deprecated.
in favor of the
onNext() method or advancing the cursor asIterator() |
default RecordCursor<T> |
limitRowsTo(int limit)
Get a new cursor that will only return records up to the given limit.
|
default RecordCursor<T> |
limitTo(int limit)
Deprecated.
Use
limitRowsTo(int) instead. |
default <V> RecordCursor<V> |
map(Function<T,V> func)
Get a new cursor by applying the given function to the records in this cursor.
|
default RecordCursor<T> |
mapEffect(Consumer<T> consumer)
Get a new cursor that applies the given consumer to the records in this cursor, without modifying the cursor records.
|
default RecordCursor<T> |
mapEffect(Runnable runnable)
Get a new cursor that runs the given runnable every time a record arrives, without modifying the cursor records.
|
static <T,V> RecordCursor<T> |
mapFuture(Executor executor,
CompletableFuture<V> future,
byte[] continuation,
BiFunction<V,byte[],? extends RecordCursor<T>> function)
Get a new cursor by applying the contents of the given future
to the given function, with proper continuation handling.
|
default <V> RecordCursor<V> |
mapPipelined(Function<T,CompletableFuture<V>> func,
int pipelineSize)
Get a new cursor by applying the given asynchronous function to the records in this cursor.
|
T |
next()
Deprecated.
in favor of the
onNext() method or advancing the cursor asIterator() |
CompletableFuture<Boolean> |
onHasNext()
Deprecated.
in favor of the
onNext() method or advancing the cursor asIterator() |
CompletableFuture<RecordCursorResult<T>> |
onNext()
Asynchronously return the next result from this cursor.
|
default RecordCursor<T> |
orElse(Function<Executor,RecordCursor<T>> func)
Get a new cursor that substitutes another cursor if this cursor is empty.
|
default <U> CompletableFuture<U> |
reduce(U identity,
BiFunction<U,? super T,U> accumulator)
Reduce contents of cursor to single value.
|
default RecordCursor<T> |
skip(int skip)
Get a new cursor that skips the given number of records.
|
default RecordCursor<T> |
skipThenLimit(int skip,
int limit) |
forEachRemaining, remove
@API(value=DEPRECATED) @Deprecated @Nonnull CompletableFuture<Boolean> onHasNext()
onNext()
method or advancing the cursor asIterator()
true
if next()
would return a record.AsyncIterator.onHasNext()
@API(value=DEPRECATED) @Deprecated default boolean hasNext()
onNext()
method or advancing the cursor asIterator()
@API(value=DEPRECATED) @Deprecated @Nullable T next()
onNext()
method or advancing the cursor asIterator()
@API(value=DEPRECATED) @Deprecated @Nullable byte[] getContinuation()
onNext()
method or advancing the cursor asIterator()
null
if the underlying source is completely exhausted, independent of any limit
passed to the cursor creator. Since such creators generally accept null
to mean no continuation,
that is, start from the beginning, one must check for null
from getContinuation
to
keep from starting over.
Result is not always defined if called before onHasNext
or before next
after
onHasNext
has returned true
. That is, a continuation is only guaranteed when called
"between" records from a while (hasNext) next
loop or after its end.@API(value=DEPRECATED) @Nonnull @Deprecated RecordCursor.NoNextReason getNoNextReason()
onNext()
method or advancing the cursor asIterator()
false
for hasNext()
.
If hasNext
was not called or returned true
last time, the result is undefined and
may be an exception.@Nonnull CompletableFuture<RecordCursorResult<T>> onNext()
RecordCursorResult
, which represents exactly one of the following:
T
produced by the cursor. In addition to the next record, this result
includes a RecordCursorContinuation
that can be used to continue the cursor after the last record
returned. The returned continuation is guaranteed not to be an "end continuation" representing the end of
the cursor: specifically, RecordCursorContinuation.isEnd()
is always false
on the returned
continuation.
RecordCursor.NoNextReason
that
explains why no record could be produced. The result include a continuation that can be used to continue
the cursor after the last record returned.
If the result's NoNextReason
is anything other than RecordCursor.NoNextReason.SOURCE_EXHAUSTED
, the
returned continuation must not be an end continuation. Conversely, if the result's NoNextReason
is SOURCE_EXHAUSTED
, then the returned continuation must be an an "end continuation".
RecordCursorContinuation
can be serialized to an opaque byte array using
RecordCursorContinuation.toBytes()
. This can be passed back into a new cursor of the same type, with all
other parameters remaining the same.RecordCursorResult
,
RecordCursorContinuation
@Nonnull default RecordCursorResult<T> getNext()
onNext()
, should
be preferred in such circumstances.onNext()
,
RecordCursorResult
,
RecordCursorContinuation
@Nonnull @API(value=STABLE) default RecordCursorIterator<T> asIterator()
RecordCursorIterator
. This allows the cursor to be consumed by
methods that take Iterator
s or AsyncIterator
s.RecordCursorIterator
void close()
close
in interface AutoCloseable
boolean accept(@Nonnull RecordCursorVisitor visitor)
RecordCursorVisitor
.
By contract, implementations of this method must return the value of visitor.visitLeave(this)
,
which determines whether or not subsequent siblings of this cursor should be visited.visitor
- a hierarchical visitortrue
if the subsequent siblings of the cursor
should be visited, and false
otherwise@Nonnull default CompletableFuture<List<T>> asList()
@Nonnull default CompletableFuture<Integer> getCount()
@Nonnull default CompletableFuture<Optional<T>> first()
Optional.empty()
if the cursor had no results or if the first record was null,
otherwise returns an Optional
of the first item returned by the cursor.@Nonnull default <V> RecordCursor<V> map(@Nonnull Function<T,V> func)
V
- the type of the record elementsfunc
- the function to apply@Nonnull default RecordCursor<T> mapEffect(@Nonnull Consumer<T> consumer)
consumer
- the consumer to apply@Nonnull default RecordCursor<T> mapEffect(@Nonnull Runnable runnable)
runnable
- the runnable to call@Nonnull default RecordCursor<T> filter(@Nonnull Function<T,Boolean> pred)
pred
- the predicate to applypred
returns false
@Nonnull default RecordCursor<T> filterInstrumented(@Nonnull Function<T,Boolean> pred, @Nullable StoreTimer timer, @Nullable StoreTimer.Count in, @Nullable StoreTimer.Event during, @Nullable StoreTimer.Count success, @Nullable StoreTimer.Count failure)
@Nonnull default RecordCursor<T> filterInstrumented(@Nonnull Function<T,Boolean> pred, @Nullable StoreTimer timer, @Nonnull Set<StoreTimer.Count> inSet, @Nonnull Set<StoreTimer.Event> duringSet, @Nonnull Set<StoreTimer.Count> successSet, @Nonnull Set<StoreTimer.Count> failureSet)
pred
- a boolean predicate to filter ontimer
- a StoreTimer to log the counts and eventsinSet
- a set StoreTimer.Count that will be incremented for each record the filter seesduringSet
- a set of StoreTimer.Event that will log the time spent computing the predicatesuccessSet
- a set of StoreTimer.Count that will be increment for each record on which the predicate evaluates true
failureSet
- a set of StoreTimer.Count that will be increment for each record on which the predicate evaluates false
pred
returns false
default RecordCursor<T> skip(int skip)
skip
- number of records to skipskip
records@Deprecated default RecordCursor<T> limitTo(int limit)
limitRowsTo(int)
instead.limit
- the maximum number of records to returnlimit
records@Nonnull default RecordCursor<T> limitRowsTo(int limit)
limit
- the maximum number of records to returnlimit
records@Nonnull default RecordCursor<T> skipThenLimit(int skip, int limit)
@Nonnull default <V> RecordCursor<V> mapPipelined(@Nonnull Function<T,CompletableFuture<V>> func, int pipelineSize)
V
- the result type of the mapping functionfunc
- the function to apply to each recordpipelineSize
- the number of futures from applications of the mapping function to start ahead of time@Deprecated @API(value=DEPRECATED) @Nonnull default <V> RecordCursor<V> flatMapPipelined(@Nonnull Function<T,? extends RecordCursor<V>> func, int pipelineSize)
flatMapPipelined(Function, BiFunction, byte[], int)
instead.V
- the result type of the mapping functionfunc
- the function to apply to each recordpipelineSize
- the number of cursors from applications of the mapping function to open ahead of time@Nonnull static <T,V> RecordCursor<V> flatMapPipelined(@Nonnull Function<byte[],? extends RecordCursor<T>> outerFunc, @Nonnull BiFunction<T,byte[],? extends RecordCursor<V>> innerFunc, @Nullable byte[] continuation, int pipelineSize)
@Nonnull static <T,V> RecordCursor<V> flatMapPipelined(@Nonnull Function<byte[],? extends RecordCursor<T>> outerFunc, @Nonnull BiFunction<T,byte[],? extends RecordCursor<V>> innerFunc, @Nullable Function<T,byte[]> checker, @Nullable byte[] continuation, int pipelineSize)
null
.T
- the result type of the outer cursorV
- the result type of the inner cursor produced by the mapping functionouterFunc
- a function that takes the outer continuation and returns the outer cursor.innerFunc
- a function that takes an outer record and an inner continuation and returns the inner cursor.checker
- a function that takes an outer record and returns a way of recognizing it again or null
.
When computing the continuation, this is called on the current outer record and the result, if not null
,
becomes part of the continuation. When this continuation is used, the function (presumably the same one) is called
on the outer record again. If the results match, the inner cursor picks up where it left off. If not, the entire
inner cursor is run.
This handles common cases of the data changing between transactions, such as the outer record being deleted (skip rest of inner record)
or a new record being inserted right before it (do full inner cursor, not partial based on previous).continuation
- the continuation returned from a previous instance of this pipeline or null
at start.pipelineSize
- the number of outer items to work ahead; inner cursors for these will be started in parallel.FlatMapPipelinedCursor
that maps the inner function across the results of the outer function@Nonnull default RecordCursor<T> filterAsync(@Nonnull Function<T,CompletableFuture<Boolean>> pred, int pipelineSize)
pred
- a predicate to applypipelineSize
- the number of futures from applications of the predicate to start ahead of timepred
returned a future that completed to false
@Nonnull default RecordCursor<T> filterAsyncInstrumented(@Nonnull Function<T,CompletableFuture<Boolean>> pred, int pipelineSize, @Nullable StoreTimer timer, @Nullable StoreTimer.Count in, @Nullable StoreTimer.Event during, @Nullable StoreTimer.Count success, @Nullable StoreTimer.Count failure)
@Nonnull default RecordCursor<T> filterAsyncInstrumented(@Nonnull Function<T,CompletableFuture<Boolean>> pred, int pipelineSize, @Nullable StoreTimer timer, @Nonnull Set<StoreTimer.Count> inSet, @Nonnull Set<StoreTimer.Event> duringSet, @Nonnull Set<StoreTimer.Count> successSet, @Nonnull Set<StoreTimer.Count> failureSet)
pred
- a boolean predicate to filter onpipelineSize
- the number of futures from applications of the predicate to start ahead of timetimer
- a StoreTimer to log the counts and eventsinSet
- a set StoreTimer.Count that will be incremented for each record the filter seesduringSet
- a set of StoreTimer.Event that will log the time spent computing the predicatesuccessSet
- a set of StoreTimer.Count that will be increment for each record on which the predicate evaluates true
failureSet
- a set of StoreTimer.Count that will be increment for each record on which the predicate evaluates false
pred
returned a future that completed to false
@Nonnull default CompletableFuture<Void> forEach(Consumer<T> consumer)
consumer
- function to be applied to each record@Nonnull default CompletableFuture<RecordCursorResult<T>> forEachResult(@Nonnull Consumer<RecordCursorResult<T>> consumer)
hasNext()
on
the result will return true
. The returned future will then contain the first result that
does not have an associated value, i.e., hasNext()
on the result will return
false
. This allows the caller to get a continuation for this cursor and determine why this
cursor stopped producing values.consumer
- function to be applied to each result@Nonnull default CompletableFuture<Void> forEachAsync(@Nonnull Function<T,CompletableFuture<Void>> func, int pipelineSize)
func
- function to be applied to each recordpipelineSize
- the number of futures from applications of the function to start ahead of time@Nonnull default CompletableFuture<RecordCursorResult<T>> forEachResultAsync(@Nonnull Function<RecordCursorResult<T>,CompletableFuture<Void>> func)
hasNext()
on the result will
return true
. The return future will then contain the first result that does not
have an associated value, i.e., hasNext()
on the result will return false
. This
allows the caller to get a continuation and determine why this cursor stopped producing values.func
- function to be applied to each result@Nonnull default RecordCursor<T> orElse(@Nonnull Function<Executor,RecordCursor<T>> func)
func
- function to be called if the cursor is empty to give another source of recordsfunc
if this cursor does not produce any records@Nonnull static <T> RecordCursor<T> fromIterator(@Nonnull Iterator<T> iterator)
Iterator
.T
- the type of elements of iterator
iterator
- the iterator of records@Nonnull static <T> RecordCursor<T> fromIterator(@Nonnull Executor executor, @Nonnull Iterator<T> iterator)
@Nonnull static <T> RecordCursor<T> fromList(@Nonnull List<T> list)
List
.T
- the type of elements of list
list
- the list of recordslist
@Nonnull static <T> RecordCursor<T> fromList(@Nonnull Executor executor, @Nonnull List<T> list)
@Nonnull static <T> RecordCursor<T> fromList(@Nonnull List<T> list, @Nullable byte[] continuation)
List
, skipping ahead according to the given continuation.T
- the type of elements of list
list
- the list of recordscontinuation
- the result of getContinuation()
from an earlier list cursor.list
, resuming if continuation
is not null
@Nonnull static <T> RecordCursor<T> fromList(@Nonnull Executor executor, @Nonnull List<T> list, @Nullable byte[] continuation)
@Nonnull static <T> RecordCursor<T> fromFuture(@Nonnull CompletableFuture<T> future)
T
- the result type of the futurefuture
- a future that completes to the only element of the cursorfuture
@Nonnull static <T> RecordCursor<T> fromFuture(@Nonnull Executor executor, @Nonnull CompletableFuture<T> future)
static <T,V> RecordCursor<T> mapFuture(@Nonnull Executor executor, @Nonnull CompletableFuture<V> future, @Nullable byte[] continuation, @Nonnull BiFunction<V,byte[],? extends RecordCursor<T>> function)
T
- the type of elements of the cursorV
- the return type of the functionexecutor
- an executor in which to run asynchronous callsfuture
- a future that completes to the argument to the functioncontinuation
- any continuation from a previous invocation of this methodfunction
- a function that takes the contents of the future and a continuation and returns a cursorfunction
to future
and continuation
@Nonnull static <T> RecordCursor<T> empty()
T
- the type of elements of the cursor@Nonnull static <T> RecordCursor<T> empty(@Nonnull Executor executor)
@Nullable default <U> CompletableFuture<U> reduce(U identity, BiFunction<U,? super T,U> accumulator)
U
- the result type of the reductionidentity
- initial value for reductionaccumulator
- function that takes previous reduced value and computes new value by combining with each record