Search in sources :

Example 1 with RecordCursorContinuation

use of com.apple.foundationdb.record.RecordCursorContinuation in project fdb-record-layer by FoundationDB.

the class MapPipelinedCursor method tryToFillPipeline.

/**
 * Take items from inner cursor and put in pipeline until no more or a mapping result is available.
 * @return a future that will complete with {@code false} if an item is available or none will ever be, or with {@code true} if this method should be called to try again
 */
protected CompletableFuture<Boolean> tryToFillPipeline() {
    while (!innerExhausted && pipeline.size() < pipelineSize) {
        // try to add a future to the pipeline
        if (waitInnerFuture == null) {
            waitInnerFuture = inner.onNext();
        }
        if (!waitInnerFuture.isDone()) {
            // still waiting for inner future, check back once something has finished
            CompletableFuture<RecordCursorResult<V>> nextEntry = pipeline.peek();
            if (nextEntry == null) {
                // loop back to process inner result
                return waitInnerFuture.thenApply(vignore -> true);
            } else {
                // keep looping unless the next entry is done
                return CompletableFuture.anyOf(waitInnerFuture, nextEntry).thenApply(vignore -> !nextEntry.isDone());
            }
        }
        // future is ready, doesn't block
        final RecordCursorResult<T> innerResult = waitInnerFuture.join();
        pipeline.add(innerResult.mapAsync(func));
        if (innerResult.hasNext()) {
            // just added something to the pipeline, so pipeline will contain an entry
            // done with this future, should advanced cursor next time
            waitInnerFuture = null;
            if (pipeline.peek().isDone()) {
                // next entry ready, don't loop
                return AsyncUtil.READY_FALSE;
            }
        // otherwise, keep looping
        } else {
            // don't have next, and won't ever with this cursor
            innerExhausted = true;
            if (innerResult.getNoNextReason() == NoNextReason.TIME_LIMIT_REACHED && nextResult != null) {
                // Under time pressure, do not want to wait for any futures to complete.
                // For other out-of-band reasons, still return results from the futures that were
                // already started.
                // Cannot do this for the very first entry, because do not have a continuation before that.
                RecordCursorContinuation lastFinishedContinuation = cancelPendingFutures();
                pipeline.add(CompletableFuture.completedFuture(RecordCursorResult.withoutNextValue(lastFinishedContinuation, NoNextReason.TIME_LIMIT_REACHED)));
            }
            // Wait for next entry, as if pipeline were full
            break;
        }
    }
    // the next result is ready
    return pipeline.peek().thenApply(vignore -> false);
}
Also used : RecordCursorContinuation(com.apple.foundationdb.record.RecordCursorContinuation) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult)

Example 2 with RecordCursorContinuation

use of com.apple.foundationdb.record.RecordCursorContinuation in project fdb-record-layer by FoundationDB.

the class MapPipelinedCursor method cancelPendingFutures.

@Nonnull
private RecordCursorContinuation cancelPendingFutures() {
    Iterator<CompletableFuture<RecordCursorResult<V>>> iter = pipeline.iterator();
    // The earliest continuation we could need to start with is the one from the last returned result.
    // We may, however, return more results if they are already completed.
    RecordCursorContinuation continuation = nextResult.getContinuation();
    while (iter.hasNext()) {
        CompletableFuture<RecordCursorResult<V>> pendingEntry = iter.next();
        if (!pendingEntry.isDone()) {
            // futures, remove them from the pipeline, and do *not* update the continuation.
            while (true) {
                iter.remove();
                pendingEntry.cancel(false);
                if (!iter.hasNext()) {
                    return continuation;
                }
                pendingEntry = iter.next();
            }
        } else {
            // Entry is done, so this cursor will return this result. Keep the entry
            // in the pipeline, and update the continuation.
            continuation = pendingEntry.join().getContinuation();
        }
    }
    return continuation;
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) RecordCursorContinuation(com.apple.foundationdb.record.RecordCursorContinuation) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) Nonnull(javax.annotation.Nonnull)

Example 3 with RecordCursorContinuation

use of com.apple.foundationdb.record.RecordCursorContinuation in project fdb-record-layer by FoundationDB.

the class AggregateCursor method onNext.

@Nonnull
@Override
public CompletableFuture<RecordCursorResult<QueryResult>> onNext() {
    if (previousResult != null && !previousResult.hasNext()) {
        // post-done termination condition: Keep returning terminal element after inner is exhausted.
        return CompletableFuture.completedFuture(previousResult);
    }
    return AsyncUtil.whileTrue(() -> inner.onNext().thenApply(innerResult -> {
        previousResult = innerResult;
        if (!innerResult.hasNext()) {
            groupAggregator.finalizeGroup();
            return false;
        } else {
            previousValidResult = innerResult;
            FDBQueriedRecord<M> record = innerResult.get().getQueriedRecord(0);
            boolean groupBreak = groupAggregator.apply(record);
            return (!groupBreak);
        }
    }), getExecutor()).thenApply(vignore -> {
        if ((previousValidResult == null) && (!previousResult.hasNext())) {
            // Edge case where there are no records at all
            return previousResult;
        }
        List<Object> groupResult = groupAggregator.getCompletedGroupResult();
        QueryResult queryResult = QueryResult.of(groupResult);
        // Use the last valid result for the continuation as we need non-terminal one here.
        RecordCursorContinuation continuation = previousValidResult.getContinuation();
        return RecordCursorResult.withNextValue(queryResult, continuation);
    });
}
Also used : QueryResult(com.apple.foundationdb.record.query.plan.plans.QueryResult) RecordCursorContinuation(com.apple.foundationdb.record.RecordCursorContinuation) Nonnull(javax.annotation.Nonnull)

Example 4 with RecordCursorContinuation

use of com.apple.foundationdb.record.RecordCursorContinuation in project fdb-record-layer by FoundationDB.

the class FlatMapPipelinedCursor method tryToFillPipeline.

/**
 * Take items from inner cursor and put in pipeline until no more or a mapped cursor item is available.
 * @return a future that will complete with {@code false} if an item is available or none will ever be, or with {@code true} if this method should be called to try again
 */
protected CompletableFuture<Boolean> tryToFillPipeline() {
    // Clear pipeline entries left behind by exhausted inner cursors.
    while (!pipeline.isEmpty() && pipeline.peek().doesNotHaveReturnableResult()) {
        pipeline.remove().close();
    }
    while (!outerExhausted && pipeline.size() < pipelineSize) {
        if (outerNextFuture == null) {
            outerNextFuture = outerCursor.onNext();
        }
        if (!outerNextFuture.isDone()) {
            // Still waiting for outer future. Check back when it has finished.
            final PipelineQueueEntry nextEntry = pipeline.peek();
            if (nextEntry == null) {
                // loop back to process outer result
                return outerNextFuture.thenApply(vignore -> true);
            } else {
                // keep looping unless we get something from the next entry's inner cursor or the next cursor is ready
                final CompletableFuture<PipelineQueueEntry> innerPipelineFuture = nextEntry.getNextInnerPipelineFuture();
                return CompletableFuture.anyOf(outerNextFuture, innerPipelineFuture).thenApply(vignore -> !innerPipelineFuture.isDone() || innerPipelineFuture.join().doesNotHaveReturnableResult());
            }
        }
        final RecordCursorResult<T> outerResult = outerNextFuture.join();
        if (outerResult.hasNext()) {
            final RecordCursorContinuation priorOuterContinuation = outerContinuation;
            final T outerValue = outerResult.get();
            final byte[] outerCheckValue = checkValueFunction == null ? null : checkValueFunction.apply(outerValue);
            byte[] innerContinuation = null;
            if (initialInnerContinuation != null) {
                // so we should start the inner cursor from the beginning.
                if (initialCheckValue == null || outerCheckValue == null || Arrays.equals(initialCheckValue, outerCheckValue)) {
                    innerContinuation = initialInnerContinuation;
                    initialInnerContinuation = null;
                }
            }
            final RecordCursor<V> innerCursor = innerCursorFunction.apply(outerValue, innerContinuation);
            outerContinuation = outerResult.getContinuation();
            pipeline.add(new PipelineQueueEntry(innerCursor, priorOuterContinuation, outerResult, outerCheckValue));
            // done with this future, advance outer cursor next time
            outerNextFuture = null;
        // keep looping to fill pipeline
        } else {
            // don't have next, and won't ever with this cursor
            // Add sentinel to end of pipeline
            pipeline.add(new PipelineQueueEntry(null, outerContinuation, outerResult, null));
            outerExhausted = true;
            // Wait for next entry, as if pipeline were full
            break;
        }
    }
    // In any case, it contains an entry so pipeline.peek() will be non-null.
    return pipeline.peek().getNextInnerPipelineFuture().thenApply(PipelineQueueEntry::doesNotHaveReturnableResult);
}
Also used : RecordCursorContinuation(com.apple.foundationdb.record.RecordCursorContinuation)

Example 5 with RecordCursorContinuation

use of com.apple.foundationdb.record.RecordCursorContinuation in project fdb-record-layer by FoundationDB.

the class MapWhileCursor method onNext.

@Nonnull
@Override
public CompletableFuture<RecordCursorResult<V>> onNext() {
    if (!nextResult.hasNext()) {
        // that the cursor return more results if values later on in the child cursor match the predicate.
        return CompletableFuture.completedFuture(nextResult);
    } else {
        return inner.onNext().thenApply(innerResult -> {
            if (!innerResult.hasNext()) {
                nextResult = RecordCursorResult.withoutNextValue(innerResult);
                return nextResult;
            }
            final Optional<V> maybeRecord = func.apply(innerResult.get());
            if (maybeRecord.isPresent()) {
                nextResult = RecordCursorResult.withNextValue(maybeRecord.get(), innerResult.getContinuation());
                return nextResult;
            }
            // return no record, handle special cases for continuation
            switch(stopContinuation) {
                case NONE:
                    nextResult = RecordCursorResult.exhausted();
                    break;
                case BEFORE:
                    // previous saved result
                    final RecordCursorContinuation continuation = nextResult.getContinuation();
                    nextResult = RecordCursorResult.withoutNextValue(continuation, NoNextReason.SCAN_LIMIT_REACHED);
                    break;
                case AFTER:
                default:
                    nextResult = RecordCursorResult.withoutNextValue(innerResult.getContinuation(), NoNextReason.SCAN_LIMIT_REACHED);
                    break;
            }
            return nextResult;
        });
    }
}
Also used : RecordCursorContinuation(com.apple.foundationdb.record.RecordCursorContinuation) Nonnull(javax.annotation.Nonnull)

Aggregations

RecordCursorContinuation (com.apple.foundationdb.record.RecordCursorContinuation)5 Nonnull (javax.annotation.Nonnull)3 RecordCursorResult (com.apple.foundationdb.record.RecordCursorResult)2 QueryResult (com.apple.foundationdb.record.query.plan.plans.QueryResult)1 CompletableFuture (java.util.concurrent.CompletableFuture)1