use of com.apple.foundationdb.record.RecordCursorResult in project fdb-record-layer by FoundationDB.
the class SortCursorTests method memorySortContinuations.
@Test
public void memorySortContinuations() throws Exception {
final Function<byte[], RecordCursor<FDBQueriedRecord<Message>>> scanRecords = continuation -> {
final ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setScannedRecordsLimit(20).build();
return recordStore.scanRecords(null, null, EndpointType.TREE_START, EndpointType.TREE_END, continuation, new ScanProperties(executeProperties)).map(FDBQueriedRecord::stored);
};
final MemoryAdapterBase adapter = new MemoryAdapterBase() {
@Override
public int getMaxRecordCountInMemory() {
return 10;
}
};
List<Integer> resultNums = new ArrayList<>();
byte[] continuation = null;
int transactionCount = 0;
do {
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context);
try (RecordCursor<FDBQueriedRecord<Message>> cursor = MemorySortCursor.create(adapter, scanRecords, timer, continuation)) {
while (true) {
RecordCursorResult<FDBQueriedRecord<Message>> result = cursor.getNext();
if (result.hasNext()) {
int num2 = TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(result.get().getRecord()).getNumValue2();
resultNums.add(num2);
} else {
continuation = result.getContinuation().toBytes();
break;
}
}
}
transactionCount++;
}
} while (continuation != null);
assertEquals(110, transactionCount);
assertEquals(sortedNums, resultNums);
}
use of com.apple.foundationdb.record.RecordCursorResult in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreQueryTestBase method querySimpleRecordStoreWithContinuation.
/**
* A query execution utility that can handle continuations. This is very similar to the above {@link #querySimpleRecordStore}
* with the additional support for {@link ExecuteProperties} and continuation.
* This method returns the last result encountered. In the case where the row limit was encountered, this would be the one
* result that contains the continuation that should be used on the next call.
* @param recordMetaDataHook Metadata hook to invoke while opening store
* @param plan the plan to execute
* @param contextSupplier provider method to get execution context
* @param continuation execution continuation
* @param executeProperties execution properties to pass into the execute method
* @param checkNumRecords Consumer that verifies correct number of records returned
* @param checkRecord Consumer that asserts every record retrieved
* @param checkDiscarded Consumer that asserts the number of discarded records
* @return the last result from the cursor
* @throws Throwable any thrown exception, or its cause if the exception is a {@link ExecutionException}
*/
protected RecordCursorResult<FDBQueriedRecord<Message>> querySimpleRecordStoreWithContinuation(@Nonnull RecordMetaDataHook recordMetaDataHook, @Nonnull RecordQueryPlan plan, @Nonnull Supplier<EvaluationContext> contextSupplier, @Nullable byte[] continuation, @Nonnull ExecuteProperties executeProperties, @Nonnull Consumer<Integer> checkNumRecords, @Nonnull Consumer<TestRecords1Proto.MySimpleRecord.Builder> checkRecord, @Nonnull Consumer<FDBRecordContext> checkDiscarded) throws Throwable {
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, recordMetaDataHook);
AtomicInteger i = new AtomicInteger(0);
CompletableFuture<RecordCursorResult<FDBQueriedRecord<Message>>> lastResult;
RecordCursor<FDBQueriedRecord<Message>> cursor = plan.execute(recordStore, contextSupplier.get(), continuation, executeProperties);
lastResult = cursor.forEachResult(result -> {
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(result.get().getRecord());
checkRecord.accept(myrec);
i.incrementAndGet();
});
lastResult.get();
checkNumRecords.accept(i.get());
checkDiscarded.accept(context);
// TODO a hack until this gets refactored properly
clearStoreCounter(context);
return lastResult.get();
} catch (ExecutionException ex) {
throw ex.getCause();
}
}
use of com.apple.foundationdb.record.RecordCursorResult in project fdb-record-layer by FoundationDB.
the class FDBStoreTimerTest method timeoutCounterDifferenceTest.
@Test
public void timeoutCounterDifferenceTest() {
RecordCursor<KeyValue> kvc = KeyValueCursor.Builder.withSubspace(subspace).setContext(context).setScanProperties(ScanProperties.FORWARD_SCAN).setRange(TupleRange.ALL).build();
FDBStoreTimer latestTimer = context.getTimer();
CompletableFuture<RecordCursorResult<KeyValue>> fkvr;
RecordCursorResult<KeyValue> kvr;
// record timeout
latestTimer.recordTimeout(FDBStoreTimer.Waits.WAIT_ADVANCE_CURSOR, System.nanoTime() - 5000);
// the latest timer should have recorded the one timeout event
Map<String, Number> diffKVs;
diffKVs = latestTimer.getKeysAndValues();
assertEquals(1, diffKVs.get("wait_advance_cursor_timeout_count").intValue());
assertTrue(diffKVs.get("wait_advance_cursor_timeout_micros").intValue() > 0);
assertThat(diffKVs.get("wait_advance_cursor_timeout_micros").intValue(), greaterThan(0));
// advance the cursor without timing out
latestTimer.record(FDBStoreTimer.Waits.WAIT_ADVANCE_CURSOR, System.nanoTime());
latestTimer.record(FDBStoreTimer.Waits.WAIT_ADVANCE_CURSOR, System.nanoTime());
// record the state after the first timeout event and generate some more timeout events
StoreTimerSnapshot savedTimer;
savedTimer = StoreTimerSnapshot.from(latestTimer);
final int numTimeouts = 3;
for (int i = 0; i < numTimeouts; i++) {
latestTimer.recordTimeout(FDBStoreTimer.Waits.WAIT_ADVANCE_CURSOR, System.nanoTime() - 5000);
}
// should have the additional timeout events in latestTimer
diffKVs = latestTimer.getKeysAndValues();
assertEquals(numTimeouts + 1, diffKVs.get("wait_advance_cursor_timeout_count").intValue());
assertThat(diffKVs.get("wait_advance_cursor_timeout_micros").intValue(), greaterThan(0));
// the savedTimer should only have recorded the first timeout event and hence the difference is the numTimeout events that occurred after that
StoreTimer diffTimer;
diffTimer = StoreTimer.getDifference(latestTimer, savedTimer);
diffKVs = diffTimer.getKeysAndValues();
assertEquals(numTimeouts, diffKVs.get("wait_advance_cursor_timeout_count").intValue());
assertThat(diffKVs.get("wait_advance_cursor_timeout_micros").intValue(), greaterThan(0));
}
use of com.apple.foundationdb.record.RecordCursorResult in project fdb-record-layer by FoundationDB.
the class ProbableIntersectionCursorTest method basicIntersection.
/**
* Show that a basic intersection succeeds.
*/
@Test
public void basicIntersection() {
final FDBStoreTimer timer = new FDBStoreTimer();
final Iterator<Integer> iterator1 = IntStream.iterate(0, x -> x + 2).limit(150).iterator();
final Iterator<Integer> iterator2 = IntStream.iterate(0, x -> x + 3).limit(100).iterator();
final FirableCursor<Integer> cursor1 = new FirableCursor<>(RecordCursor.fromIterator(iterator1));
final FirableCursor<Integer> cursor2 = new FirableCursor<>(RecordCursor.fromIterator(iterator2));
final RecordCursor<Integer> intersectionCursor = ProbableIntersectionCursor.create(Collections::singletonList, Arrays.asList(bignore -> cursor1, bignore -> cursor2), null, timer);
// Intersection consumes first cursor
cursor1.fireAll();
CompletableFuture<RecordCursorResult<Integer>> firstFuture = intersectionCursor.onNext();
cursor2.fire();
RecordCursorResult<Integer> firstResult = firstFuture.join();
assertEquals(0, (int) firstResult.get());
assertThat(firstResult.hasNext(), is(true));
assertEquals(cursor1.getNext().getNoNextReason(), RecordCursor.NoNextReason.SOURCE_EXHAUSTED);
// Intersection consumes second cursor as they come
cursor2.fireAll();
AtomicInteger falsePositives = new AtomicInteger();
AsyncUtil.whileTrue(() -> intersectionCursor.onNext().thenApply(result -> {
if (result.hasNext()) {
int value = result.get();
// every result *must* be divisible by 3
assertEquals(0, value % 3);
if (value % 2 != 0) {
// most results should be divisible by 2
falsePositives.incrementAndGet();
}
assertThat(result.getContinuation().isEnd(), is(false));
assertNotNull(result.getContinuation().toBytes());
try {
RecordCursorProto.ProbableIntersectionContinuation protoContinuation = RecordCursorProto.ProbableIntersectionContinuation.parseFrom(result.getContinuation().toBytes());
assertEquals(2, protoContinuation.getChildStateCount());
assertThat(protoContinuation.getChildState(0).getExhausted(), is(true));
assertThat(protoContinuation.getChildState(0).hasContinuation(), is(false));
assertThat(protoContinuation.getChildState(1).getExhausted(), is(false));
assertThat(protoContinuation.getChildState(1).hasContinuation(), is(true));
} catch (InvalidProtocolBufferException e) {
throw new RecordCoreException("error parsing proto continuation", e);
}
} else {
assertThat(result.getNoNextReason().isSourceExhausted(), is(true));
assertThat(result.getContinuation().isEnd(), is(true));
assertNull(result.getContinuation().toBytes());
}
return result.hasNext();
}), intersectionCursor.getExecutor()).join();
assertThat(falsePositives.get(), lessThan(5));
assertEquals(50 + falsePositives.get(), timer.getCount(FDBStoreTimer.Counts.QUERY_INTERSECTION_PLAN_MATCHES));
assertEquals(200 - falsePositives.get(), timer.getCount(FDBStoreTimer.Counts.QUERY_INTERSECTION_PLAN_NONMATCHES));
}
use of com.apple.foundationdb.record.RecordCursorResult in project fdb-record-layer by FoundationDB.
the class ProbableIntersectionCursorTest method errorAndLimitInChild.
@Test
public void errorAndLimitInChild() {
CompletableFuture<Integer> future = new CompletableFuture<>();
RecordCursor<Integer> cursor = ProbableIntersectionCursor.create(Collections::singletonList, Arrays.asList(continuation -> RecordCursor.fromList(Arrays.asList(1, 2), continuation).limitRowsTo(1), continuation -> RecordCursor.fromFuture(future)), null, null);
CompletableFuture<RecordCursorResult<Integer>> cursorResultFuture = cursor.onNext();
final RecordCoreException ex = new RecordCoreException("something bad happened!");
future.completeExceptionally(ex);
ExecutionException executionException = assertThrows(ExecutionException.class, cursorResultFuture::get);
assertNotNull(executionException.getCause());
assertSame(ex, executionException.getCause());
}
Aggregations