Search in sources :

Example 26 with Tuple

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

the class IndexingByRecords method buildRange.

/**
 * Builds (transactionally) the index by adding records with primary keys within the given range.
 * This will look for gaps of keys within the given range that haven't yet been rebuilt and then
 * rebuild only those ranges. As a result, if this method is called twice, the first time, it will
 * build whatever needs to be built, and then the second time, it will notice that there are no ranges
 * that need to be built, so it will do nothing. In this way, it is idempotent and thus safe to
 * use in retry loops.
 *
 * This method will fail if there is too much work to be done in a single transaction. If one wants
 * to handle building a range that does not fit in a single transaction, one should use the
 * {@link #buildRange(Key.Evaluated, Key.Evaluated) buildRange()}
 * function that takes an {@link FDBDatabase} as its first parameter.
 *
 * @param store the record store in which to rebuild the range
 * @param start the (inclusive) beginning primary key of the range to build (or <code>null</code> to go to the end)
 * @param end the (exclusive) end primary key of the range to build (or <code>null</code> to go to the end)
 * @return a future that will be ready when the build has completed
 */
@Nonnull
public CompletableFuture<Void> buildRange(@Nonnull FDBRecordStore store, @Nullable Key.Evaluated start, @Nullable Key.Evaluated end) {
    RangeSet rangeSet = new RangeSet(store.indexRangeSubspace(common.getIndex()));
    byte[] startBytes = packOrNull(convertOrNull(start));
    byte[] endBytes = packOrNull(convertOrNull(end));
    AsyncIterator<Range> ranges = rangeSet.missingRanges(store.ensureContextActive(), startBytes, endBytes).iterator();
    return ranges.onHasNext().thenCompose(hasNext -> {
        if (hasNext) {
            return AsyncUtil.whileTrue(() -> {
                Range toBuild = ranges.next();
                Tuple startTuple = Tuple.fromBytes(toBuild.begin);
                Tuple endTuple = RangeSet.isFinalKey(toBuild.end) ? null : Tuple.fromBytes(toBuild.end);
                AtomicReference<Tuple> currStart = new AtomicReference<>(startTuple);
                return AsyncUtil.whileTrue(() -> buildUnbuiltRange(store, currStart.get(), endTuple, null).thenApply(realEnd -> {
                    if (realEnd != null && !realEnd.equals(endTuple)) {
                        currStart.set(realEnd);
                        return true;
                    } else {
                        return false;
                    }
                }), store.getExecutor()).thenCompose(vignore -> ranges.onHasNext());
            }, store.getExecutor());
        } else {
            return AsyncUtil.DONE;
        }
    });
}
Also used : RangeSet(com.apple.foundationdb.async.RangeSet) AtomicReference(java.util.concurrent.atomic.AtomicReference) Range(com.apple.foundationdb.Range) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 27 with Tuple

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

the class FDBRecordStoreBase method scanIndexRecordsBetween.

/**
 * Scan the records pointed to by an index between two indexed values.
 * @param indexName the name of the index
 * @param low the low value for the first indexed field
 * @param high the high value for the first indexed field
 * @return a cursor that return records pointed to by the index
 */
@Nonnull
default RecordCursor<FDBIndexedRecord<M>> scanIndexRecordsBetween(@Nonnull final String indexName, @Nullable final Object low, @Nullable final Object high) {
    final Tuple lowTuple = Tuple.from(low);
    final Tuple highTuple = Tuple.from(high);
    final TupleRange range = new TupleRange(lowTuple, highTuple, EndpointType.RANGE_INCLUSIVE, EndpointType.RANGE_INCLUSIVE);
    return scanIndexRecords(indexName, IndexScanType.BY_VALUE, range, null, ScanProperties.FORWARD_SCAN);
}
Also used : TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 28 with Tuple

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

the class FDBRecordStoreBase method scanIndexRecordsEqual.

/**
 * Scan the records pointed to by an index equal to indexed values.
 * @param indexName the name of the index
 * @param values a left-subset of values of indexed fields
 * @return a cursor that return records pointed to by the index
 */
@Nonnull
default RecordCursor<FDBIndexedRecord<M>> scanIndexRecordsEqual(@Nonnull final String indexName, @Nonnull final Object... values) {
    final Tuple tuple = Tuple.from(values);
    final TupleRange range = TupleRange.allOf(tuple);
    return scanIndexRecords(indexName, IndexScanType.BY_VALUE, range, null, ScanProperties.FORWARD_SCAN);
}
Also used : TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 29 with Tuple

use of com.apple.foundationdb.tuple.Tuple 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 30 with Tuple

use of com.apple.foundationdb.tuple.Tuple 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)

Aggregations

Tuple (com.apple.foundationdb.tuple.Tuple)163 Nonnull (javax.annotation.Nonnull)80 List (java.util.List)66 Test (org.junit.jupiter.api.Test)66 TupleRange (com.apple.foundationdb.record.TupleRange)62 ArrayList (java.util.ArrayList)57 Message (com.google.protobuf.Message)56 Nullable (javax.annotation.Nullable)50 IndexEntry (com.apple.foundationdb.record.IndexEntry)48 Index (com.apple.foundationdb.record.metadata.Index)47 Subspace (com.apple.foundationdb.subspace.Subspace)47 CompletableFuture (java.util.concurrent.CompletableFuture)46 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)45 ScanProperties (com.apple.foundationdb.record.ScanProperties)43 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)42 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)41 Collectors (java.util.stream.Collectors)41 Collections (java.util.Collections)40 Transaction (com.apple.foundationdb.Transaction)38 RecordCursor (com.apple.foundationdb.record.RecordCursor)38