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;
}
});
}
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.");
}
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;
}
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);
}
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;
});
}
Aggregations