Search in sources :

Example 1 with RankedSet

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

the class TimeWindowLeaderboardIndexMaintainer method evaluateEqualRange.

private CompletableFuture<Tuple> evaluateEqualRange(@Nonnull TupleRange range, @Nonnull EvaluateEqualRange function) {
    final Tuple tuple = range.getLow();
    final int type = (int) tuple.getLong(0);
    final long timestamp = tuple.getLong(1);
    final int groupingCount = getGroupingCount();
    final Tuple groupKey = TupleHelpers.subTuple(tuple, 2, 2 + groupingCount);
    final Tuple values = TupleHelpers.subTuple(tuple, 2 + groupingCount, tuple.size());
    final CompletableFuture<TimeWindowLeaderboard> leaderboardFuture = oldestLeaderboardMatching(type, timestamp);
    return leaderboardFuture.thenCompose(leaderboard -> {
        if (leaderboard == null) {
            return CompletableFuture.completedFuture(null);
        }
        final Tuple leaderboardGroupKey = leaderboard.getSubspaceKey().addAll(groupKey);
        final Subspace extraSubspace = getSecondarySubspace();
        final Subspace rankSubspace = extraSubspace.subspace(leaderboardGroupKey);
        final RankedSet.Config leaderboardConfig = config.toBuilder().setNLevels(leaderboard.getNLevels()).build();
        final RankedSet rankedSet = new RankedSetIndexHelper.InstrumentedRankedSet(state, rankSubspace, leaderboardConfig);
        return function.apply(leaderboard, rankedSet, groupKey, values);
    });
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace) RankedSet(com.apple.foundationdb.async.RankedSet) Tuple(com.apple.foundationdb.tuple.Tuple)

Example 2 with RankedSet

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

the class TimeWindowLeaderboardIndexMaintainer method timeWindowRankAndEntry.

@Nonnull
public <M extends Message> CompletableFuture<Pair<Long, Tuple>> timeWindowRankAndEntry(@Nonnull FDBRecord<M> record, int type, long timestamp) {
    final List<IndexEntry> indexEntries = evaluateIndex(record);
    final CompletableFuture<TimeWindowLeaderboard> leaderboardFuture = oldestLeaderboardMatching(type, timestamp);
    return leaderboardFuture.thenCompose(leaderboard -> {
        if (leaderboard == null) {
            return CompletableFuture.completedFuture(null);
        }
        return groupOrderedScoreIndexKeys(indexEntries, leaderboard.getDirectory(), true).thenCompose(groupedScores -> {
            if (groupedScores.isEmpty()) {
                return CompletableFuture.completedFuture(null);
            }
            if (groupedScores.size() > 1) {
                throw new RecordCoreException("Record has more than one group of scores");
            }
            Map.Entry<Tuple, Collection<OrderedScoreIndexKey>> groupEntry = groupedScores.entrySet().iterator().next();
            Optional<OrderedScoreIndexKey> bestContainedScore = groupEntry.getValue().stream().filter(score -> leaderboard.containsTimestamp(score.timestamp)).findFirst();
            if (!bestContainedScore.isPresent()) {
                return CompletableFuture.completedFuture(null);
            }
            // bestContainedScore should be the one stored in the leaderboard's ranked set; get its rank there.
            final Tuple groupKey = groupEntry.getKey();
            return isHighScoreFirst(leaderboard.getDirectory(), groupKey).thenCompose(highScoreFirst -> {
                final OrderedScoreIndexKey indexKey = bestContainedScore.get();
                final Tuple leaderboardGroupKey = leaderboard.getSubspaceKey().addAll(groupKey);
                final Subspace extraSubspace = getSecondarySubspace();
                final Subspace rankSubspace = extraSubspace.subspace(leaderboardGroupKey);
                final RankedSet.Config leaderboardConfig = config.toBuilder().setNLevels(leaderboard.getNLevels()).build();
                final RankedSet rankedSet = new RankedSetIndexHelper.InstrumentedRankedSet(state, rankSubspace, leaderboardConfig);
                // Undo any negation needed to find entry.
                final Tuple entry = highScoreFirst ? negateScoreForHighScoreFirst(indexKey.scoreKey, 0) : indexKey.scoreKey;
                return RankedSetIndexHelper.rankForScore(state, rankedSet, indexKey.scoreKey, true).thenApply(rank -> Pair.of(rank, entry));
            });
        });
    });
}
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) RankedSet(com.apple.foundationdb.async.RankedSet) IndexEntry(com.apple.foundationdb.record.IndexEntry) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Subspace(com.apple.foundationdb.subspace.Subspace) Collection(java.util.Collection) Map(java.util.Map) HashMap(java.util.HashMap) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 3 with RankedSet

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

the class RankedSetIndexHelper method updateRankedSet.

@Nonnull
public static CompletableFuture<Void> updateRankedSet(@Nonnull IndexMaintainerState state, @Nonnull Subspace rankSubspace, @Nonnull RankedSet.Config config, @Nonnull Tuple valueKey, @Nonnull Tuple scoreKey, boolean remove) {
    final RankedSet rankedSet = new InstrumentedRankedSet(state, rankSubspace, config);
    final byte[] score = scoreKey.pack();
    CompletableFuture<Void> result = init(state, rankedSet).thenCompose(v -> {
        if (remove) {
            if (config.isCountDuplicates()) {
                // Decrement count and possibly remove.
                return removeFromRankedSet(state, rankedSet, score);
            } else {
                // If no one else has this score, remove from ranked set.
                return state.transaction.getRange(state.indexSubspace.range(valueKey)).iterator().onHasNext().thenCompose(hasNext -> hasNext ? AsyncUtil.DONE : removeFromRankedSet(state, rankedSet, score));
            }
        } else {
            return rankedSet.add(state.transaction, score).thenApply(added -> null);
        }
    });
    return state.store.instrument(Events.RANKED_SET_UPDATE, result);
}
Also used : RankedSet(com.apple.foundationdb.async.RankedSet) Nonnull(javax.annotation.Nonnull)

Example 4 with RankedSet

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

the class RankedSetIndexHelper method rankRangeToScoreRange.

@Nonnull
public static CompletableFuture<TupleRange> rankRangeToScoreRange(@Nonnull IndexMaintainerState state, int groupPrefixSize, @Nonnull Subspace rankSubspace, @Nonnull RankedSet.Config config, @Nonnull TupleRange rankRange) {
    final Tuple prefix = groupPrefix(groupPrefixSize, rankRange, rankSubspace);
    if (prefix != null) {
        rankSubspace = rankSubspace.subspace(prefix);
    }
    // Map low and high ranks to scores and scan main index with those.
    Number lowRankNum = extractRank(groupPrefixSize, rankRange.getLow());
    boolean startFromBeginning = lowRankNum == null || lowRankNum.longValue() < 0L;
    EndpointType lowEndpoint = startFromBeginning ? EndpointType.RANGE_INCLUSIVE : rankRange.getLowEndpoint();
    Number highRankNum = extractRank(groupPrefixSize, rankRange.getHigh());
    EndpointType highEndpoint = rankRange.getHighEndpoint();
    if (highRankNum != null && (highRankNum.longValue() < 0L || highEndpoint == EndpointType.RANGE_EXCLUSIVE && highRankNum.longValue() == 0L)) {
        // This range is below 0, so we know the range is empty without having to look.
        return CompletableFuture.completedFuture(null);
    }
    if (highRankNum != null && highEndpoint == EndpointType.RANGE_EXCLUSIVE && lowEndpoint == EndpointType.RANGE_EXCLUSIVE && highRankNum.equals(lowRankNum)) {
        // This range is exclusively empty.
        return CompletableFuture.completedFuture(null);
    }
    if (startFromBeginning && highRankNum == null) {
        // Scanning whole range, no need to convert any ranks.
        return CompletableFuture.completedFuture(TupleRange.allOf(prefix));
    }
    final RankedSet rankedSet = new InstrumentedRankedSet(state, rankSubspace, config);
    return init(state, rankedSet).thenCompose(v -> {
        CompletableFuture<Tuple> lowScoreFuture = scoreForRank(state, rankedSet, startFromBeginning ? 0L : lowRankNum, null);
        CompletableFuture<Tuple> highScoreFuture = scoreForRank(state, rankedSet, highRankNum, null);
        return lowScoreFuture.thenCombine(highScoreFuture, (lowScore, highScore) -> {
            // from low until the end.
            if (lowScore == null) {
                return null;
            }
            EndpointType adjustedHighEndpoint = highScore != null ? highEndpoint : prefix != null ? EndpointType.RANGE_INCLUSIVE : EndpointType.TREE_END;
            TupleRange scoreRange = new TupleRange(lowScore, highScore, lowEndpoint, adjustedHighEndpoint);
            if (prefix != null) {
                scoreRange = scoreRange.prepend(prefix);
            }
            return scoreRange;
        });
    });
}
Also used : EndpointType(com.apple.foundationdb.record.EndpointType) RankedSet(com.apple.foundationdb.async.RankedSet) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 5 with RankedSet

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

the class RankIndexMaintainer method rank.

protected <M extends Message> CompletableFuture<Long> rank(@Nonnull EvaluationContext context, @Nullable IndexRecordFunction<Long> function, @Nonnull FDBRecord<M> record) {
    final int groupPrefixSize = getGroupingCount();
    Key.Evaluated indexKey = IndexFunctionHelper.recordFunctionIndexEntry(state.store, state.index, context, function, record, groupPrefixSize);
    if (indexKey == null) {
        return CompletableFuture.completedFuture(null);
    }
    Tuple scoreValue = indexKey.toTuple();
    Subspace rankSubspace = getSecondarySubspace();
    if (groupPrefixSize > 0) {
        Tuple prefix = Tuple.fromList(scoreValue.getItems().subList(0, groupPrefixSize));
        rankSubspace = rankSubspace.subspace(prefix);
        scoreValue = Tuple.fromList(scoreValue.getItems().subList(groupPrefixSize, scoreValue.size()));
    }
    RankedSet rankedSet = new RankedSetIndexHelper.InstrumentedRankedSet(state, rankSubspace, config);
    return RankedSetIndexHelper.rankForScore(state, rankedSet, scoreValue, true);
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace) RankedSet(com.apple.foundationdb.async.RankedSet) Key(com.apple.foundationdb.record.metadata.Key) Tuple(com.apple.foundationdb.tuple.Tuple)

Aggregations

RankedSet (com.apple.foundationdb.async.RankedSet)6 Tuple (com.apple.foundationdb.tuple.Tuple)5 Subspace (com.apple.foundationdb.subspace.Subspace)4 EndpointType (com.apple.foundationdb.record.EndpointType)2 TupleRange (com.apple.foundationdb.record.TupleRange)2 Nonnull (javax.annotation.Nonnull)2 MutationType (com.apple.foundationdb.MutationType)1 Transaction (com.apple.foundationdb.Transaction)1 API (com.apple.foundationdb.annotation.API)1 SpotBugsSuppressWarnings (com.apple.foundationdb.annotation.SpotBugsSuppressWarnings)1 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)1 MoreAsyncUtil (com.apple.foundationdb.async.MoreAsyncUtil)1 EvaluationContext (com.apple.foundationdb.record.EvaluationContext)1 FunctionNames (com.apple.foundationdb.record.FunctionNames)1 IndexEntry (com.apple.foundationdb.record.IndexEntry)1 IndexScanType (com.apple.foundationdb.record.IndexScanType)1 IsolationLevel (com.apple.foundationdb.record.IsolationLevel)1 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)1 RecordCoreStorageException (com.apple.foundationdb.record.RecordCoreStorageException)1 RecordCursor (com.apple.foundationdb.record.RecordCursor)1