Search in sources :

Example 6 with ScanProperties

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

the class FDBRecordStore method loadIndexStatesAsync.

@Nonnull
private CompletableFuture<Map<String, IndexState>> loadIndexStatesAsync(@Nonnull IsolationLevel isolationLevel) {
    Subspace isSubspace = getSubspace().subspace(Tuple.from(INDEX_STATE_SPACE_KEY));
    KeyValueCursor cursor = KeyValueCursor.Builder.withSubspace(isSubspace).setContext(getContext()).setRange(TupleRange.ALL).setContinuation(null).setScanProperties(new ScanProperties(ExecuteProperties.newBuilder().setIsolationLevel(isolationLevel).setDefaultCursorStreamingMode(CursorStreamingMode.WANT_ALL).build())).build();
    FDBStoreTimer timer = getTimer();
    CompletableFuture<Map<String, IndexState>> result = cursor.asList().thenApply(list -> {
        Map<String, IndexState> indexStateMap;
        if (list.isEmpty()) {
            indexStateMap = Collections.emptyMap();
        } else {
            ImmutableMap.Builder<String, IndexState> indexStateMapBuilder = ImmutableMap.builder();
            for (KeyValue kv : list) {
                String indexName = isSubspace.unpack(kv.getKey()).getString(0);
                Object code = Tuple.fromBytes(kv.getValue()).get(0);
                indexStateMapBuilder.put(indexName, IndexState.fromCode(code));
                if (timer != null) {
                    timer.increment(FDBStoreTimer.Counts.LOAD_STORE_STATE_KEY);
                    timer.increment(FDBStoreTimer.Counts.LOAD_STORE_STATE_KEY_BYTES, kv.getKey().length);
                    timer.increment(FDBStoreTimer.Counts.LOAD_STORE_STATE_VALUE_BYTES, kv.getValue().length);
                }
            }
            indexStateMap = indexStateMapBuilder.build();
        }
        return indexStateMap;
    });
    if (timer != null) {
        result = timer.instrument(FDBStoreTimer.Events.LOAD_RECORD_STORE_INDEX_META_DATA, result, context.getExecutor());
    }
    return result;
}
Also used : KeyValue(com.apple.foundationdb.KeyValue) ByteString(com.google.protobuf.ByteString) IndexState(com.apple.foundationdb.record.IndexState) ImmutableMap(com.google.common.collect.ImmutableMap) ScanProperties(com.apple.foundationdb.record.ScanProperties) Subspace(com.apple.foundationdb.subspace.Subspace) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Nonnull(javax.annotation.Nonnull)

Example 7 with ScanProperties

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

the class IndexingByRecords method buildRangeOnly.

@Nonnull
private CompletableFuture<Tuple> buildRangeOnly(@Nonnull FDBRecordStore store, @Nonnull TupleRange range, boolean respectLimit, @Nullable AtomicLong recordsScanned) {
    validateSameMetadataOrThrow(store);
    Index index = common.getIndex();
    int limit = getLimit();
    final IndexMaintainer maintainer = store.getIndexMaintainer(index);
    final boolean isIdempotent = maintainer.isIdempotent();
    final ExecuteProperties.Builder executeProperties = ExecuteProperties.newBuilder().setIsolationLevel(isIdempotent ? IsolationLevel.SNAPSHOT : IsolationLevel.SERIALIZABLE);
    if (respectLimit) {
        // +1 allows continuation item
        executeProperties.setReturnedRowLimit(limit + 1);
    }
    final ScanProperties scanProperties = new ScanProperties(executeProperties.build());
    final RecordCursor<FDBStoredRecord<Message>> cursor = store.scanRecords(range, null, scanProperties);
    final AtomicBoolean hasMore = new AtomicBoolean(true);
    // Note: This runs all of the updates serially in order to avoid invoking a race condition
    // in the rank code that was causing incorrect results. If everything were thread safe,
    // a larger pipeline size would be possible.
    final AtomicReference<RecordCursorResult<FDBStoredRecord<Message>>> lastResult = new AtomicReference<>(RecordCursorResult.exhausted());
    return iterateRangeOnly(store, cursor, this::getRecordIfTypeMatch, lastResult, hasMore, recordsScanned, isIdempotent).thenApply(vignore -> hasMore.get() ? lastResult.get().get().getPrimaryKey() : range.getHigh());
}
Also used : KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Message(com.google.protobuf.Message) Index(com.apple.foundationdb.record.metadata.Index) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) AtomicReference(java.util.concurrent.atomic.AtomicReference) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ScanProperties(com.apple.foundationdb.record.ScanProperties) Nonnull(javax.annotation.Nonnull)

Example 8 with ScanProperties

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

the class IndexingByRecords method buildEndpoints.

@Nonnull
private CompletableFuture<TupleRange> buildEndpoints(@Nonnull FDBRecordStore store, @Nonnull RangeSet rangeSet, @Nullable AtomicLong recordsScanned) {
    boolean isIdempotent = store.getIndexMaintainer(common.getIndex()).isIdempotent();
    final IsolationLevel isolationLevel = isIdempotent ? // before this method's query) will be re-indexed.
    IsolationLevel.SNAPSHOT : IsolationLevel.SERIALIZABLE;
    final ExecuteProperties limit1 = ExecuteProperties.newBuilder().setReturnedRowLimit(1).setIsolationLevel(isolationLevel).build();
    final ScanProperties forward = new ScanProperties(limit1);
    RecordCursor<FDBStoredRecord<Message>> beginCursor = store.scanRecords(recordsRange, null, forward);
    CompletableFuture<Tuple> begin = beginCursor.onNext().thenCompose(result -> {
        if (result.hasNext()) {
            Tuple firstTuple = result.get().getPrimaryKey();
            return buildRange(store, null, firstTuple, recordsScanned).thenApply(vignore -> firstTuple);
        } else {
            // Empty range -- add the whole thing.
            return rangeSet.insertRange(store.ensureContextActive(), null, null).thenApply(bignore -> null);
        }
    });
    final ScanProperties backward = new ScanProperties(limit1, true);
    RecordCursor<FDBStoredRecord<Message>> endCursor = store.scanRecords(recordsRange, null, backward);
    CompletableFuture<Tuple> end = endCursor.onNext().thenCompose(result -> {
        if (result.hasNext()) {
            Tuple lastTuple = result.get().getPrimaryKey();
            return buildRange(store, lastTuple, null, recordsScanned).thenApply(vignore -> lastTuple);
        } else {
            // by the above future, so this has nothing to do.
            return CompletableFuture.completedFuture(null);
        }
    });
    return begin.thenCombine(end, (firstTuple, lastTuple) -> {
        if (firstTuple == null || firstTuple.equals(lastTuple)) {
            return null;
        } else {
            return new TupleRange(firstTuple, lastTuple, EndpointType.RANGE_INCLUSIVE, EndpointType.RANGE_EXCLUSIVE);
        }
    });
}
Also used : ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) ScanProperties(com.apple.foundationdb.record.ScanProperties) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 9 with ScanProperties

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

the class TimeWindowLeaderboardIndexMaintainer method scan.

@Nonnull
@Override
public RecordCursor<IndexEntry> scan(@Nonnull IndexScanBounds scanBounds, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    final IndexScanType scanType = scanBounds.getScanType();
    if (scanType != IndexScanType.BY_VALUE && scanType != IndexScanType.BY_RANK && scanType != IndexScanType.BY_TIME_WINDOW) {
        throw new RecordCoreException("Can only scan leaderboard index by time window, rank or value.");
    }
    // Decode range arguments.
    final int type;
    final long timestamp;
    final TupleRange leaderboardRange;
    if (scanType == IndexScanType.BY_TIME_WINDOW) {
        // Get oldest leaderboard of type containing timestamp.
        if (scanBounds instanceof TimeWindowScanRange) {
            TimeWindowScanRange scanRange = (TimeWindowScanRange) scanBounds;
            type = scanRange.getLeaderboardType();
            timestamp = scanRange.getLeaderboardTimestamp();
            leaderboardRange = scanRange.getScanRange();
        } else {
            // TODO: For compatibility, accept scan with BY_TIME_WINDOW and TupleRange for a while.
            // This code can be removed when we are confident all callers have been converted.
            IndexScanRange scanRange = (IndexScanRange) scanBounds;
            TupleRange rankRange = scanRange.getScanRange();
            final Tuple lowRank = rankRange.getLow();
            final Tuple highRank = rankRange.getHigh();
            type = (int) lowRank.getLong(0);
            timestamp = lowRank.getLong(1);
            leaderboardRange = new TupleRange(Tuple.fromList(lowRank.getItems().subList(2, lowRank.size())), Tuple.fromList(highRank.getItems().subList(2, highRank.size())), rankRange.getLowEndpoint(), rankRange.getHighEndpoint());
        }
    } else {
        // Get the all-time leaderboard for unqualified rank or value.
        IndexScanRange scanRange = (IndexScanRange) scanBounds;
        type = TimeWindowLeaderboard.ALL_TIME_LEADERBOARD_TYPE;
        // Any value would do.
        timestamp = 0;
        leaderboardRange = scanRange.getScanRange();
    }
    final int groupPrefixSize = getGroupingCount();
    final CompletableFuture<TimeWindowLeaderboard> leaderboardFuture = oldestLeaderboardMatching(type, timestamp);
    final CompletableFuture<TupleRange> scoreRangeFuture;
    if (scanType == IndexScanType.BY_VALUE) {
        scoreRangeFuture = leaderboardFuture.thenApply(leaderboard -> leaderboard == null ? null : leaderboardRange);
    } else {
        scoreRangeFuture = leaderboardFuture.thenCompose(leaderboard -> {
            if (leaderboard == null) {
                return CompletableFuture.completedFuture(null);
            }
            final Subspace extraSubspace = getSecondarySubspace();
            final Subspace leaderboardSubspace = extraSubspace.subspace(leaderboard.getSubspaceKey());
            final RankedSet.Config leaderboardConfig = config.toBuilder().setNLevels(leaderboard.getNLevels()).build();
            return RankedSetIndexHelper.rankRangeToScoreRange(state, groupPrefixSize, leaderboardSubspace, leaderboardConfig, leaderboardRange);
        });
    }
    // Add leaderboard's key to the front and take it off of the results.
    return RecordCursor.flatMapPipelined(ignore -> RecordCursor.fromFuture(getExecutor(), scoreRangeFuture), (scoreRange, ignore) -> {
        if (scoreRange == null) {
            return RecordCursor.empty(getExecutor());
        }
        // Already waited in scoreRangeFuture.
        final TimeWindowLeaderboard leaderboard = state.context.joinNow(leaderboardFuture);
        final CompletableFuture<Boolean> highStoreFirstFuture;
        if (scanType == IndexScanType.BY_VALUE) {
            final Tuple lowGroup = scoreRange.getLow() != null && scoreRange.getLow().size() > groupPrefixSize ? TupleHelpers.subTuple(scoreRange.getLow(), 0, groupPrefixSize) : null;
            final Tuple highGroup = scoreRange.getHigh() != null && scoreRange.getHigh().size() > groupPrefixSize ? TupleHelpers.subTuple(scoreRange.getHigh(), 0, groupPrefixSize) : null;
            if (lowGroup != null && lowGroup.equals(highGroup)) {
                highStoreFirstFuture = isHighScoreFirst(leaderboard.getDirectory(), lowGroup);
            } else {
                highStoreFirstFuture = CompletableFuture.completedFuture(leaderboard.getDirectory().isHighScoreFirst());
            }
        } else {
            highStoreFirstFuture = AsyncUtil.READY_FALSE;
        }
        if (highStoreFirstFuture.isDone()) {
            return scanLeaderboard(leaderboard, state.context.joinNow(highStoreFirstFuture), scoreRange, continuation, scanProperties);
        } else {
            return RecordCursor.flatMapPipelined(ignore2 -> RecordCursor.fromFuture(getExecutor(), highStoreFirstFuture), (highScoreFirst, ignore2) -> scanLeaderboard(leaderboard, highScoreFirst, scoreRange, continuation, scanProperties), null, 1);
        }
    }, null, 1).mapPipelined(kv -> getIndexEntry(kv, groupPrefixSize, state.context.joinNow(leaderboardFuture).getDirectory()), 1);
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) StoreTimer(com.apple.foundationdb.record.provider.common.StoreTimer) IndexMaintainerState(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) LoggerFactory(org.slf4j.LoggerFactory) RecordCoreStorageException(com.apple.foundationdb.record.RecordCoreStorageException) MapUtils(com.apple.foundationdb.record.util.MapUtils) Subspace(com.apple.foundationdb.subspace.Subspace) MutationType(com.apple.foundationdb.MutationType) Transaction(com.apple.foundationdb.Transaction) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Map(java.util.Map) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) FDBIndexableRecord(com.apple.foundationdb.record.provider.foundationdb.FDBIndexableRecord) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) Collection(java.util.Collection) Set(java.util.Set) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) List(java.util.List) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Optional(java.util.Optional) AtomicMutation(com.apple.foundationdb.record.provider.foundationdb.indexes.AtomicMutation) API(com.apple.foundationdb.annotation.API) FunctionNames(com.apple.foundationdb.record.FunctionNames) SpotBugsSuppressWarnings(com.apple.foundationdb.annotation.SpotBugsSuppressWarnings) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) IndexOperation(com.apple.foundationdb.record.provider.foundationdb.IndexOperation) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) TimeWindowLeaderboardProto(com.apple.foundationdb.record.TimeWindowLeaderboardProto) EndpointType(com.apple.foundationdb.record.EndpointType) ScanProperties(com.apple.foundationdb.record.ScanProperties) IndexScanBounds(com.apple.foundationdb.record.provider.foundationdb.IndexScanBounds) IndexScanRange(com.apple.foundationdb.record.provider.foundationdb.IndexScanRange) IndexRecordFunction(com.apple.foundationdb.record.metadata.IndexRecordFunction) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) ByteArrayUtil2(com.apple.foundationdb.tuple.ByteArrayUtil2) IndexOperationResult(com.apple.foundationdb.record.provider.foundationdb.IndexOperationResult) StandardIndexMaintainer(com.apple.foundationdb.record.provider.foundationdb.indexes.StandardIndexMaintainer) MoreAsyncUtil(com.apple.foundationdb.async.MoreAsyncUtil) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) RankedSetIndexHelper(com.apple.foundationdb.record.provider.foundationdb.indexes.RankedSetIndexHelper) RankedSet(com.apple.foundationdb.async.RankedSet) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) Collections(java.util.Collections) IndexScanRange(com.apple.foundationdb.record.provider.foundationdb.IndexScanRange) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) CompletableFuture(java.util.concurrent.CompletableFuture) IndexScanType(com.apple.foundationdb.record.IndexScanType) Subspace(com.apple.foundationdb.subspace.Subspace) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 10 with ScanProperties

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

the class KeySpaceDirectory method listSubdirectoryAsync.

@Nonnull
// SonarQube doesn't realize that the cursor is wrapped and returned
@SuppressWarnings("squid:S2095")
protected RecordCursor<ResolvedKeySpacePath> listSubdirectoryAsync(@Nullable KeySpacePath listFrom, @Nonnull FDBRecordContext context, @Nonnull String subdirName, @Nullable ValueRange<?> valueRange, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    if (listFrom != null && listFrom.getDirectory() != this) {
        throw new RecordCoreException("Provided path does not belong to this directory").addLogInfo("path", listFrom, "directory", this.getName());
    }
    final KeySpaceDirectory subdir = getSubdirectory(subdirName);
    final CompletableFuture<ResolvedKeySpacePath> resolvedFromFuture = listFrom == null ? CompletableFuture.completedFuture(null) : listFrom.toResolvedPathAsync(context);
    // The chained cursor cannot implement reverse scan, so we implement it by having the
    // inner key value cursor do the reversing but telling the chained cursor we are moving
    // forward.
    final ScanProperties chainedCursorScanProperties;
    if (scanProperties.isReverse()) {
        chainedCursorScanProperties = scanProperties.setReverse(false);
    } else {
        chainedCursorScanProperties = scanProperties;
    }
    // For the read of the individual row keys, we only want to read a single key. In addition,
    // the ChainedCursor is going to do counting of our reads to apply any limits that were specified
    // on the ScanProperties.  We don't want the inner KeyValueCursor in nextTuple() to ALSO count those
    // same reads so we clear out its limits.
    final ScanProperties keyReadScanProperties = scanProperties.with(props -> props.clearState().setReturnedRowLimit(1));
    return new LazyCursor<>(resolvedFromFuture.thenCompose(resolvedFrom -> {
        final Subspace subspace = resolvedFrom == null ? new Subspace() : resolvedFrom.toSubspace();
        return subdir.getValueRange(context, valueRange, subspace).thenApply(range -> {
            final RecordCursor<Tuple> cursor = new ChainedCursor<>(context, lastKey -> nextTuple(context, subspace, range, lastKey, keyReadScanProperties), Tuple::pack, Tuple::fromBytes, continuation, chainedCursorScanProperties);
            return cursor.mapPipelined(tuple -> {
                final Tuple key = Tuple.fromList(tuple.getItems());
                return findChildForKey(context, resolvedFrom, key, 1, 0);
            }, 1);
        });
    }), context.getExecutor());
}
Also used : Arrays(java.util.Arrays) KeyRange(com.apple.foundationdb.record.KeyRange) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) LazyCursor(com.apple.foundationdb.record.cursors.LazyCursor) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) Function(java.util.function.Function) Subspace(com.apple.foundationdb.subspace.Subspace) ArrayList(java.util.ArrayList) Tuple(com.apple.foundationdb.tuple.Tuple) EndpointType(com.apple.foundationdb.record.EndpointType) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) ScanProperties(com.apple.foundationdb.record.ScanProperties) Map(java.util.Map) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) KeyValue(com.apple.foundationdb.KeyValue) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) ChainedCursor(com.apple.foundationdb.record.cursors.ChainedCursor) StringWriter(java.io.StringWriter) IOException(java.io.IOException) UUID(java.util.UUID) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Objects(java.util.Objects) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Writer(java.io.Writer) RecordCursor(com.apple.foundationdb.record.RecordCursor) ValueRange(com.apple.foundationdb.record.ValueRange) Optional(java.util.Optional) API(com.apple.foundationdb.annotation.API) BitSet(java.util.BitSet) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) LazyCursor(com.apple.foundationdb.record.cursors.LazyCursor) RecordCursor(com.apple.foundationdb.record.RecordCursor) ScanProperties(com.apple.foundationdb.record.ScanProperties) Subspace(com.apple.foundationdb.subspace.Subspace) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Aggregations

ScanProperties (com.apple.foundationdb.record.ScanProperties)54 ExecuteProperties (com.apple.foundationdb.record.ExecuteProperties)29 Nonnull (javax.annotation.Nonnull)29 Tuple (com.apple.foundationdb.tuple.Tuple)26 Message (com.google.protobuf.Message)24 Test (org.junit.jupiter.api.Test)24 RecordCursor (com.apple.foundationdb.record.RecordCursor)22 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)22 TupleRange (com.apple.foundationdb.record.TupleRange)21 List (java.util.List)21 ArrayList (java.util.ArrayList)20 IndexEntry (com.apple.foundationdb.record.IndexEntry)19 CompletableFuture (java.util.concurrent.CompletableFuture)19 Nullable (javax.annotation.Nullable)18 Index (com.apple.foundationdb.record.metadata.Index)17 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)16 TupleHelpers (com.apple.foundationdb.tuple.TupleHelpers)16 LogMessageKeys (com.apple.foundationdb.record.logging.LogMessageKeys)15 Arrays (java.util.Arrays)15 Collectors (java.util.stream.Collectors)15