Search in sources :

Example 51 with Subspace

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

the class BunchedMapMultiIterator method getNextMapIterator.

private CompletableFuture<Boolean> getNextMapIterator() {
    return underlying.onHasNext().thenCompose(doesHaveNext -> {
        if (doesHaveNext) {
            KeyValue nextKv = underlying.peek();
            if (!subspace.contains(nextKv.getKey())) {
                if (ByteArrayUtil.compareUnsigned(nextKv.getKey(), subspaceKey) * (reverse ? -1 : 1) > 0) {
                    // We have already gone past the end of the subspace. We are done.
                    underlying.cancel();
                    return AsyncUtil.READY_FALSE;
                } else {
                    // much reading, and it shouldn't make too many recursive calls.
                    return AsyncUtil.whileTrue(() -> {
                        KeyValue kv = underlying.peek();
                        if (ByteArrayUtil.compareUnsigned(kv.getKey(), subspaceKey) * (reverse ? -1 : 1) >= 0) {
                            return AsyncUtil.READY_FALSE;
                        } else {
                            underlying.next();
                            return underlying.onHasNext();
                        }
                    }, tr.getExecutor()).thenCompose(vignore -> getNextMapIterator());
                }
            }
            Subspace nextSubspace = splitter.subspaceOf(nextKv.getKey());
            byte[] nextSubspaceKey = nextSubspace.getKey();
            byte[] nextSubspaceSuffix = Arrays.copyOfRange(nextSubspaceKey, subspaceKey.length, nextSubspaceKey.length);
            K continuationKey = null;
            if (!continuationSatisfied) {
                if (ByteArrayUtil.startsWith(continuation, nextSubspaceSuffix)) {
                    continuationKey = bunchedMap.getSerializer().deserializeKey(continuation, nextSubspaceSuffix.length);
                    continuationSatisfied = true;
                } else if (ByteArrayUtil.compareUnsigned(nextSubspaceSuffix, continuation) * (reverse ? -1 : 1) > 0) {
                    // We have already satisfied the continuation, so we are can just say it is satisfied
                    continuationSatisfied = true;
                    continuationKey = null;
                } else {
                    // current subspace.
                    return AsyncUtil.whileTrue(() -> {
                        KeyValue kv = underlying.peek();
                        if (nextSubspace.contains(kv.getKey())) {
                            underlying.next();
                            return underlying.onHasNext();
                        } else {
                            return AsyncUtil.READY_FALSE;
                        }
                    }, tr.getExecutor()).thenCompose(vignore -> getNextMapIterator());
                }
            }
            BunchedMapIterator<K, V> nextMapIterator = new BunchedMapIterator<>(underlying, tr, nextSubspace, nextSubspaceKey, bunchedMap, continuationKey, (limit == ReadTransaction.ROW_LIMIT_UNLIMITED) ? ReadTransaction.ROW_LIMIT_UNLIMITED : limit - returned, reverse);
            final T nextSubspaceTag = splitter.subspaceTag(nextSubspace);
            return nextMapIterator.onHasNext().thenCompose(mapHasNext -> {
                if (mapHasNext) {
                    currentSubspace = nextSubspace;
                    currentSubspaceKey = nextSubspaceKey;
                    currentSubspaceSuffix = nextSubspaceSuffix;
                    currentSubspaceTag = nextSubspaceTag;
                    mapIterator = nextMapIterator;
                    Map.Entry<K, V> mapEntry = mapIterator.next();
                    nextEntry = new BunchedMapScanEntry<>(currentSubspace, currentSubspaceTag, mapEntry.getKey(), mapEntry.getValue());
                    return AsyncUtil.READY_TRUE;
                } else {
                    // we will only be recursing down a finite amount.
                    return getNextMapIterator();
                }
            });
        } else {
            done = true;
            return AsyncUtil.READY_FALSE;
        }
    });
}
Also used : ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) Arrays(java.util.Arrays) KeyValue(com.apple.foundationdb.KeyValue) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) ReadTransaction(com.apple.foundationdb.ReadTransaction) Subspace(com.apple.foundationdb.subspace.Subspace) Map(java.util.Map) API(com.apple.foundationdb.annotation.API) NoSuchElementException(java.util.NoSuchElementException) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) AsyncPeekIterator(com.apple.foundationdb.async.AsyncPeekIterator) KeyValue(com.apple.foundationdb.KeyValue) Subspace(com.apple.foundationdb.subspace.Subspace) Map(java.util.Map)

Example 52 with Subspace

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

the class PermutedMinMaxIndexMaintainer method scan.

@Nonnull
@Override
public RecordCursor<IndexEntry> scan(@Nonnull IndexScanType scanType, @Nonnull TupleRange range, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    if (scanType == IndexScanType.BY_VALUE) {
        return scan(range, continuation, scanProperties);
    }
    if (scanType == IndexScanType.BY_GROUP) {
        final Subspace permutedSubspace = getSecondarySubspace();
        final RecordCursor<KeyValue> keyValues = KeyValueCursor.Builder.withSubspace(permutedSubspace).setContext(state.context).setRange(range).setContinuation(continuation).setScanProperties(scanProperties).build();
        return keyValues.map(kv -> {
            state.store.countKeyValue(FDBStoreTimer.Counts.LOAD_INDEX_KEY, FDBStoreTimer.Counts.LOAD_INDEX_KEY_BYTES, FDBStoreTimer.Counts.LOAD_INDEX_VALUE_BYTES, kv);
            return unpackKeyValue(permutedSubspace, kv);
        });
    }
    throw new RecordCoreException("Can only scan permuted index by value or group.");
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) KeyValue(com.apple.foundationdb.KeyValue) Subspace(com.apple.foundationdb.subspace.Subspace) Nonnull(javax.annotation.Nonnull)

Example 53 with Subspace

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

the class PermutedMinMaxIndexMaintainer method updateIndexKeys.

@Override
protected <M extends Message> CompletableFuture<Void> updateIndexKeys(@Nonnull final FDBIndexableRecord<M> savedRecord, final boolean remove, @Nonnull final List<IndexEntry> indexEntries) {
    final int groupPrefixSize = getGroupingCount();
    final int totalSize = state.index.getColumnSize();
    final Subspace permutedSubspace = getSecondarySubspace();
    for (IndexEntry indexEntry : indexEntries) {
        final Tuple groupKey = TupleHelpers.subTuple(indexEntry.getKey(), 0, groupPrefixSize);
        final Tuple value = TupleHelpers.subTuple(indexEntry.getKey(), groupPrefixSize, totalSize);
        final int permutePosition = groupPrefixSize - permutedSize;
        final Tuple groupPrefix = TupleHelpers.subTuple(groupKey, 0, permutePosition);
        final Tuple groupSuffix = TupleHelpers.subTuple(groupKey, permutePosition, groupPrefixSize);
        if (remove) {
            // First remove from ordinary tree.
            return updateOneKeyAsync(savedRecord, remove, indexEntry).thenCompose(vignore -> {
                final byte[] permutedKeyToRemove = permutedSubspace.pack(groupPrefix.addAll(value).addAll(groupSuffix));
                // See if value is the current minimum/maximum.
                return state.store.ensureContextActive().get(permutedKeyToRemove).thenCompose(permutedValueExists -> {
                    if (permutedValueExists == null) {
                        // No, nothing more to do.
                        return AsyncUtil.DONE;
                    }
                    return getExtremum(groupKey).thenApply(extremum -> {
                        if (extremum == null) {
                            // No replacement, just remove.
                            state.store.ensureContextActive().clear(permutedKeyToRemove);
                        } else {
                            final Tuple remainingValue = TupleHelpers.subTuple(extremum, groupPrefixSize, totalSize);
                            if (!value.equals(remainingValue)) {
                                // New extremum: remove existing and store it.
                                final byte[] permutedKeyToAdd = permutedSubspace.pack(groupPrefix.addAll(remainingValue).addAll(groupSuffix));
                                final Transaction tr = state.store.ensureContextActive();
                                tr.clear(permutedKeyToRemove);
                                tr.set(permutedKeyToAdd, TupleHelpers.EMPTY.pack());
                            }
                        }
                        return null;
                    });
                });
            });
        } else {
            // Get existing minimum/maximum.
            return getExtremum(groupKey).thenApply(extremum -> {
                final boolean addPermuted;
                if (extremum == null) {
                    // New group.
                    addPermuted = true;
                } else {
                    final Tuple currentValue = TupleHelpers.subTuple(extremum, groupPrefixSize, totalSize);
                    int compare = value.compareTo(currentValue);
                    addPermuted = type == Type.MIN ? compare < 0 : compare > 0;
                    // Replace if new value is better.
                    if (addPermuted) {
                        final byte[] permutedKeyToRemove = permutedSubspace.pack(groupPrefix.addAll(currentValue).addAll(groupSuffix));
                        state.store.ensureContextActive().clear(permutedKeyToRemove);
                    }
                }
                if (addPermuted) {
                    final byte[] permutedKeyToAdd = permutedSubspace.pack(groupPrefix.addAll(value).addAll(groupSuffix));
                    state.store.ensureContextActive().set(permutedKeyToAdd, TupleHelpers.EMPTY.pack());
                }
                return null;
            }).thenCompose(// Ordinary is second.
            vignore -> updateOneKeyAsync(savedRecord, remove, indexEntry));
        }
    }
    return AsyncUtil.DONE;
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) IndexMaintainerState(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Subspace(com.apple.foundationdb.subspace.Subspace) Key(com.apple.foundationdb.record.metadata.Key) Transaction(com.apple.foundationdb.Transaction) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) ScanProperties(com.apple.foundationdb.record.ScanProperties) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) QueryToKeyMatcher(com.apple.foundationdb.record.query.QueryToKeyMatcher) FDBIndexableRecord(com.apple.foundationdb.record.provider.foundationdb.FDBIndexableRecord) KeyValue(com.apple.foundationdb.KeyValue) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) TupleRange(com.apple.foundationdb.record.TupleRange) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) Index(com.apple.foundationdb.record.metadata.Index) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) API(com.apple.foundationdb.annotation.API) Transaction(com.apple.foundationdb.Transaction) Subspace(com.apple.foundationdb.subspace.Subspace) IndexEntry(com.apple.foundationdb.record.IndexEntry) Tuple(com.apple.foundationdb.tuple.Tuple)

Example 54 with Subspace

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

Example 55 with Subspace

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

the class RankIndexMaintainer method deleteWhere.

@Override
public CompletableFuture<Void> deleteWhere(Transaction tr, @Nonnull Tuple prefix) {
    return super.deleteWhere(tr, prefix).thenApply(v -> {
        // NOTE: Range.startsWith(), Subspace.range() and so on cover keys *strictly* within the range, but we sometimes
        // store data at the prefix key itself.
        final Subspace rankSubspace = getSecondarySubspace();
        final byte[] key = rankSubspace.pack(prefix);
        tr.clear(key, ByteArrayUtil.strinc(key));
        return v;
    });
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace)

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