Search in sources :

Example 16 with Subspace

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

the class TimeWindowLeaderboardIndexMaintainer method saveSubDirectory.

protected void saveSubDirectory(@Nonnull TimeWindowLeaderboardSubDirectory subdirectory) {
    final Subspace extraSubspace = getSecondarySubspace();
    state.transaction.set(extraSubspace.pack(SUB_DIRECTORY_PREFIX.addAll(subdirectory.getGroup())), subdirectory.toProto().toByteArray());
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace)

Example 17 with Subspace

use of com.apple.foundationdb.subspace.Subspace 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 18 with Subspace

use of com.apple.foundationdb.subspace.Subspace 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 19 with Subspace

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

the class TimeWindowLeaderboardIndexMaintainer method updateIndexKeys.

@Override
protected <M extends Message> CompletableFuture<Void> updateIndexKeys(@Nonnull final FDBIndexableRecord<M> savedRecord, final boolean remove, @Nonnull final List<IndexEntry> indexEntries) {
    final Subspace extraSubspace = getSecondarySubspace();
    // The value for the index key cannot vary from entry-to-entry, so get the value only from the first entry.
    final Tuple entryValue = indexEntries.isEmpty() ? TupleHelpers.EMPTY : indexEntries.get(0).getValue();
    return loadDirectory().thenCompose(directory -> {
        if (directory == null) {
            return AsyncUtil.DONE;
        }
        return groupOrderedScoreIndexKeys(indexEntries, directory, true).thenCompose(groupedScores -> {
            final List<CompletableFuture<Void>> futures = new ArrayList<>();
            for (Iterable<TimeWindowLeaderboard> directoryEntry : directory.getLeaderboards().values()) {
                for (TimeWindowLeaderboard leaderboard : directoryEntry) {
                    for (Map.Entry<Tuple, Collection<OrderedScoreIndexKey>> groupEntry : groupedScores.entrySet()) {
                        final Optional<OrderedScoreIndexKey> bestContainedScore = groupEntry.getValue().stream().filter(score -> leaderboard.containsTimestamp(score.timestamp)).findFirst();
                        if (bestContainedScore.isPresent()) {
                            final Tuple groupKey = groupEntry.getKey();
                            final OrderedScoreIndexKey indexKey = bestContainedScore.get();
                            final Tuple leaderboardGroupKey = leaderboard.getSubspaceKey().addAll(groupKey);
                            // Update the ordinary B-tree for this leaderboard.
                            final Tuple entryKey = leaderboardGroupKey.addAll(indexKey.scoreKey);
                            CompletableFuture<Void> updateOrdinaryIndex = updateOneKeyAsync(savedRecord, remove, new IndexEntry(state.index, entryKey, entryValue));
                            if (!MoreAsyncUtil.isCompletedNormally(updateOrdinaryIndex)) {
                                futures.add(updateOrdinaryIndex);
                            }
                            // Update the corresponding rankset for this leaderboard.
                            // Notice that as each leaderboard has its own subspace key and at most one score
                            // per record is chosen per leaderboard, this is the only time this record will be
                            // indexed in this rankSubspace. Compare/contrast: RankIndexMaintainer::updateIndexKeys
                            final Subspace rankSubspace = extraSubspace.subspace(leaderboardGroupKey);
                            final RankedSet.Config leaderboardConfig = config.toBuilder().setNLevels(leaderboard.getNLevels()).build();
                            futures.add(RankedSetIndexHelper.updateRankedSet(state, rankSubspace, leaderboardConfig, entryKey, indexKey.scoreKey, remove));
                        }
                    }
                }
            }
            Optional<Long> latestTimestamp = groupedScores.values().stream().flatMap(Collection::stream).map(OrderedScoreIndexKey::getTimestamp).max(Long::compareTo);
            if (latestTimestamp.isPresent()) {
                // Keep track of the latest timestamp for any indexed entry.
                // Then, if time window update adds an index that starts before then, we have to index existing records.
                state.transaction.mutate(MutationType.MAX, state.indexSubspace.getKey(), AtomicMutation.Standard.encodeSignedLong(latestTimestamp.get()));
            }
            return AsyncUtil.whenAll(futures);
        });
    });
}
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) ArrayList(java.util.ArrayList) RankedSet(com.apple.foundationdb.async.RankedSet) IndexEntry(com.apple.foundationdb.record.IndexEntry) CompletableFuture(java.util.concurrent.CompletableFuture) Subspace(com.apple.foundationdb.subspace.Subspace) Collection(java.util.Collection) Map(java.util.Map) HashMap(java.util.HashMap) Tuple(com.apple.foundationdb.tuple.Tuple)

Example 20 with Subspace

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

the class TimeWindowLeaderboardIndexMaintainer method loadSubDirectory.

@Nonnull
protected CompletableFuture<TimeWindowLeaderboardSubDirectory> loadSubDirectory(@Nonnull TimeWindowLeaderboardDirectory directory, @Nonnull Tuple group) {
    TimeWindowLeaderboardSubDirectory subdirectory = directory.getSubDirectory(group);
    if (subdirectory != null) {
        return CompletableFuture.completedFuture(subdirectory);
    }
    final Subspace extraSubspace = getSecondarySubspace();
    return state.transaction.get(extraSubspace.pack(SUB_DIRECTORY_PREFIX.addAll(group))).thenApply(bytes -> {
        final TimeWindowLeaderboardSubDirectory newsub;
        if (bytes == null) {
            newsub = new TimeWindowLeaderboardSubDirectory(group, directory.isHighScoreFirst());
        } else {
            TimeWindowLeaderboardProto.TimeWindowLeaderboardSubDirectory.Builder builder = TimeWindowLeaderboardProto.TimeWindowLeaderboardSubDirectory.newBuilder();
            try {
                builder.mergeFrom(bytes);
            } catch (InvalidProtocolBufferException ex) {
                throw new RecordCoreStorageException("error decoding leaderboard sub-directory", ex);
            }
            newsub = new TimeWindowLeaderboardSubDirectory(group, builder.build());
        }
        directory.addSubDirectory(newsub);
        return newsub;
    });
}
Also used : RecordCoreStorageException(com.apple.foundationdb.record.RecordCoreStorageException) Subspace(com.apple.foundationdb.subspace.Subspace) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Nonnull(javax.annotation.Nonnull)

Aggregations

Subspace (com.apple.foundationdb.subspace.Subspace)61 Nonnull (javax.annotation.Nonnull)33 Tuple (com.apple.foundationdb.tuple.Tuple)28 List (java.util.List)23 ArrayList (java.util.ArrayList)21 CompletableFuture (java.util.concurrent.CompletableFuture)21 Nullable (javax.annotation.Nullable)20 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)19 KeyValue (com.apple.foundationdb.KeyValue)18 Map (java.util.Map)18 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)17 API (com.apple.foundationdb.annotation.API)16 ScanProperties (com.apple.foundationdb.record.ScanProperties)15 Collections (java.util.Collections)15 Test (org.junit.jupiter.api.Test)15 Transaction (com.apple.foundationdb.Transaction)14 RecordCursor (com.apple.foundationdb.record.RecordCursor)14 TupleRange (com.apple.foundationdb.record.TupleRange)14 LogMessageKeys (com.apple.foundationdb.record.logging.LogMessageKeys)14 Message (com.google.protobuf.Message)14