use of com.apple.foundationdb.record.IndexEntry in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexCursor method computeNextResultStates.
@Nonnull
@Override
protected CompletableFuture<List<MergeCursorState<IndexEntry>>> computeNextResultStates() {
final List<MergeCursorState<IndexEntry>> cursorStates = getCursorStates();
return whenAll(cursorStates).thenApply(vignore -> {
boolean anyHasNext = false;
for (MergeCursorState<IndexEntry> cursorState : cursorStates) {
if (cursorState.getResult().hasNext()) {
anyHasNext = true;
} else if (cursorState.getResult().getNoNextReason().isLimitReached()) {
// Stop if any has reached limit.
return Collections.emptyList();
}
}
if (anyHasNext) {
// Result states are all those that share the minimum next position,
// whose bitmaps need to be merged to produce the next stream element.
final List<MergeCursorState<IndexEntry>> resultStates = new ArrayList<>();
long nextPosition = Long.MAX_VALUE;
for (MergeCursorState<IndexEntry> cursorState : cursorStates) {
if (cursorState.getResult().hasNext()) {
final IndexEntry indexEntry = cursorState.getResult().get();
final Tuple indexKey = indexEntry.getKey();
final long position = indexKey.getLong(indexKey.size() - 1);
if (nextPosition > position) {
resultStates.clear();
nextPosition = position;
}
if (nextPosition == position) {
resultStates.add(cursorState);
}
}
}
return resultStates;
} else {
return Collections.emptyList();
}
});
}
use of com.apple.foundationdb.record.IndexEntry in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexCursor method getNextResult.
@Nonnull
@Override
protected IndexEntry getNextResult(@Nonnull List<MergeCursorState<IndexEntry>> resultStates) {
final List<MergeCursorState<IndexEntry>> cursorStates = getCursorStates();
final IndexEntry firstEntry = resultStates.get(0).getResult().get();
final int size = firstEntry.getValue().getBytes(0).length;
final List<byte[]> bitmaps = new ArrayList<>(cursorStates.size());
for (MergeCursorState<IndexEntry> cursorState : cursorStates) {
if (resultStates.contains(cursorState)) {
byte[] bitmap = cursorState.getResult().get().getValue().getBytes(0);
if (bitmap.length != size) {
throw new RecordCoreException("Index bitmaps are not all the same size");
}
bitmaps.add(bitmap);
} else {
bitmaps.add(null);
}
}
final byte[] composed = composer.compose(bitmaps, size);
return new IndexEntry(firstEntry.getIndex(), firstEntry.getKey(), Tuple.fromList(Collections.singletonList(composed)));
}
use of com.apple.foundationdb.record.IndexEntry in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexQueryPlan method executePlan.
@Nonnull
@Override
public <M extends Message> RecordCursor<QueryResult> executePlan(@Nonnull final FDBRecordStoreBase<M> store, @Nonnull final EvaluationContext context, @Nullable final byte[] continuation, @Nonnull final ExecuteProperties executeProperties) {
final ExecuteProperties scanExecuteProperties = executeProperties.getSkip() > 0 ? executeProperties.clearSkipAndAdjustLimit() : executeProperties;
final List<Function<byte[], RecordCursor<IndexEntry>>> cursorFunctions = indexPlans.stream().map(RecordQueryCoveringIndexPlan::getIndexPlan).map(scan -> (Function<byte[], RecordCursor<IndexEntry>>) childContinuation -> scan.executeEntries(store, context, childContinuation, scanExecuteProperties)).collect(Collectors.toList());
return ComposedBitmapIndexCursor.create(cursorFunctions, composer, continuation, store.getTimer()).filter(indexEntry -> indexEntry.getValue().get(0) != null).map(indexPlans.get(0).indexEntryToQueriedRecord(store)).map(QueryResult::of);
}
use of com.apple.foundationdb.record.IndexEntry in project fdb-record-layer by FoundationDB.
the class QueryPlanUtils method getCoveringIndexEntryToPartialRecordFunction.
/**
* The method to get a function from an {@link IndexEntry} to a {@link FDBQueriedRecord} representing a partial record.
*/
@SuppressWarnings("unchecked")
public static <M extends Message> Function<IndexEntry, FDBQueriedRecord<M>> getCoveringIndexEntryToPartialRecordFunction(@Nonnull final FDBRecordStoreBase<M> store, @Nonnull final String recordTypeName, @Nonnull final String indexName, @Nonnull final IndexKeyValueToPartialRecord toRecord, @Nonnull final IndexScanType scanType) {
final RecordMetaData metaData = store.getRecordMetaData();
final RecordType recordType = metaData.getRecordType(recordTypeName);
final Index index = metaData.getIndex(indexName);
final Descriptors.Descriptor recordDescriptor = recordType.getDescriptor();
boolean hasPrimaryKey = scanType != IndexScanType.BY_GROUP && scanType != IndexScanType.BY_LUCENE_AUTO_COMPLETE && scanType != IndexScanType.BY_LUCENE_SPELLCHECK;
return indexEntry -> store.coveredIndexQueriedRecord(index, indexEntry, recordType, (M) toRecord.toRecord(recordDescriptor, indexEntry), hasPrimaryKey);
}
use of com.apple.foundationdb.record.IndexEntry in project fdb-record-layer by FoundationDB.
the class StandardIndexMaintainer method validateMissingEntries.
/**
* Validate entries in the index. It scans the records and checks if the index entries associated with each record
* exist. Note that it may not work for indexes on synthetic record types (e.g., join indexes).
* @param continuation any continuation from a previous validation invocation
* @param scanProperties skip, limit and other properties of the validation
* @return a cursor over records that have no associated index entries including the reason
*/
@Nonnull
protected RecordCursor<InvalidIndexEntry> validateMissingEntries(@Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
final Collection<RecordType> recordTypes = state.store.getRecordMetaData().recordTypesForIndex(state.index);
final FDBRecordStoreBase.PipelineSizer pipelineSizer = state.store.getPipelineSizer();
return RecordCursor.flatMapPipelined(cont -> state.store.scanRecords(TupleRange.ALL, cont, scanProperties).filter(rec -> recordTypes.contains(rec.getRecordType())), (record, cont) -> {
List<IndexEntry> filteredIndexEntries = filteredIndexEntries(record);
return RecordCursor.fromList(filteredIndexEntries == null ? Collections.emptyList() : filteredIndexEntries.stream().map(indexEntryWithoutPrimaryKey -> new IndexEntry(indexEntryWithoutPrimaryKey.getIndex(), indexEntryKey(indexEntryWithoutPrimaryKey.getKey(), record.getPrimaryKey()), indexEntryWithoutPrimaryKey.getValue())).map(indexEntry -> Pair.of(indexEntry, record)).collect(Collectors.toList()), cont);
}, continuation, pipelineSizer.getPipelineSize(PipelineOperation.RECORD_FUNCTION)).filterAsync(indexEntryRecordPair -> {
final byte[] keyBytes = state.indexSubspace.pack(indexEntryRecordPair.getLeft().getKey());
return state.transaction.get(keyBytes).thenApply(Objects::isNull);
}, pipelineSizer.getPipelineSize(PipelineOperation.INDEX_ASYNC_FILTER)).map(indexEntryKeyRecordPair -> InvalidIndexEntry.newMissing(indexEntryKeyRecordPair.getLeft(), indexEntryKeyRecordPair.getRight()));
}
Aggregations