use of com.apple.foundationdb.tuple.Tuple in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method serializeAndSaveRecord.
@Nonnull
private <M extends Message> FDBStoredRecord<M> serializeAndSaveRecord(@Nonnull RecordSerializer<M> typedSerializer, @Nonnull final FDBStoredRecordBuilder<M> recordBuilder, @Nonnull final RecordMetaData metaData, @Nullable FDBStoredSizes oldSizeInfo) {
final Tuple primaryKey = recordBuilder.getPrimaryKey();
final FDBRecordVersion version = recordBuilder.getVersion();
final byte[] serialized = typedSerializer.serialize(metaData, recordBuilder.getRecordType(), recordBuilder.getRecord(), getTimer());
final FDBRecordVersion splitVersion = useOldVersionFormat() ? null : version;
final SplitHelper.SizeInfo sizeInfo = new SplitHelper.SizeInfo();
// clear out cache of older value if present
preloadCache.invalidate(primaryKey);
SplitHelper.saveWithSplit(context, recordsSubspace(), recordBuilder.getPrimaryKey(), serialized, splitVersion, metaData.isSplitLongRecords(), omitUnsplitRecordSuffix, true, oldSizeInfo, sizeInfo);
countKeysAndValues(FDBStoreTimer.Counts.SAVE_RECORD_KEY, FDBStoreTimer.Counts.SAVE_RECORD_KEY_BYTES, FDBStoreTimer.Counts.SAVE_RECORD_VALUE_BYTES, sizeInfo);
recordBuilder.setSize(sizeInfo);
if (version != null && useOldVersionFormat()) {
saveVersionWithOldFormat(primaryKey, version);
}
return recordBuilder.build();
}
use of com.apple.foundationdb.tuple.Tuple in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method getPrimaryKeyBoundaries.
/**
* Return a cursor of boundaries separating the key ranges maintained by each FDB server. This information can be
* useful for splitting a large task (e.g., rebuilding an index for a large record store) into smaller tasks (e.g.,
* rebuilding the index for records in certain primary key ranges) more evenly so that they can be executed in a
* parallel fashion efficiently. The returned boundaries are an estimate from FDB's locality API and may not
* represent the exact boundary locations at any database version.
* <p>
* The boundaries are returned as a cursor which is sorted and does not contain any duplicates. The first element of
* the list is greater than or equal to <code>low</code>, and the last element is less than or equal to
* <code>high</code>.
* <p>
* This implementation may not work when there are too many shard boundaries to complete in a single transaction.
* <p>
* Note: the returned cursor is blocking and must not be used in an asynchronous context
*
* @param low low endpoint of primary key range (inclusive)
* @param high high endpoint of primary key range (exclusive)
* @return the list of boundary primary keys
*/
@API(API.Status.EXPERIMENTAL)
@Nonnull
public RecordCursor<Tuple> getPrimaryKeyBoundaries(@Nonnull Tuple low, @Nonnull Tuple high) {
final Transaction transaction = ensureContextActive();
byte[] rangeStart = recordsSubspace().pack(low);
byte[] rangeEnd = recordsSubspace().pack(high);
CloseableAsyncIterator<byte[]> cursor = context.getDatabase().getLocalityProvider().getBoundaryKeys(transaction, rangeStart, rangeEnd);
final boolean hasSplitRecordSuffix = hasSplitRecordSuffix();
DistinctFilterCursorClosure closure = new DistinctFilterCursorClosure();
return RecordCursor.flatMapPipelined(ignore -> RecordCursor.fromIterator(getExecutor(), cursor), (result, ignore) -> RecordCursor.fromIterator(getExecutor(), transaction.snapshot().getRange(result, rangeEnd, 1).iterator()), null, DEFAULT_PIPELINE_SIZE).map(keyValue -> {
Tuple recordKey = recordsSubspace().unpack(keyValue.getKey());
return hasSplitRecordSuffix ? recordKey.popBack() : recordKey;
}).filter(closure::pred);
}
use of com.apple.foundationdb.tuple.Tuple in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method getSnapshotRecordCount.
@Override
public CompletableFuture<Long> getSnapshotRecordCount(@Nonnull KeyExpression key, @Nonnull Key.Evaluated value, @Nonnull IndexQueryabilityFilter indexQueryabilityFilter) {
if (getRecordMetaData().getRecordCountKey() != null) {
if (key.getColumnSize() != value.size()) {
throw recordCoreException("key and value are not the same size");
}
final ReadTransaction tr = context.readTransaction(true);
final Tuple subkey = Tuple.from(RECORD_COUNT_KEY).addAll(value.toTupleAppropriateList());
if (getRecordMetaData().getRecordCountKey().equals(key)) {
return tr.get(getSubspace().pack(subkey)).thenApply(FDBRecordStore::decodeRecordCount);
} else if (key.isPrefixKey(getRecordMetaData().getRecordCountKey())) {
AsyncIterable<KeyValue> kvs = tr.getRange(getSubspace().range(Tuple.from(RECORD_COUNT_KEY)));
return MoreAsyncUtil.reduce(getExecutor(), kvs.iterator(), 0L, (count, kv) -> count + decodeRecordCount(kv.getValue()));
}
}
return evaluateAggregateFunction(Collections.emptyList(), IndexFunctionHelper.count(key), TupleRange.allOf(value.toTuple()), IsolationLevel.SNAPSHOT, indexQueryabilityFilter).thenApply(tuple -> tuple.getLong(0));
}
use of com.apple.foundationdb.tuple.Tuple in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method loadRecordVersionAsync.
/**
* Async version of {@link #loadRecordVersion(Tuple, boolean)}.
* @param primaryKey the primary key of the record
* @param snapshot whether to snapshot read
* @return a future that completes with the version of the record of {@code Optional.empty()} if versions are not enabled for this store
*/
@Nonnull
public Optional<CompletableFuture<FDBRecordVersion>> loadRecordVersionAsync(@Nonnull final Tuple primaryKey, final boolean snapshot) {
final RecordMetaData metaData = metaDataProvider.getRecordMetaData();
if (useOldVersionFormat() && !metaData.isStoreRecordVersions()) {
// a priori that this will return an empty optional, so we return it without doing any I/O.
return Optional.empty();
} else {
byte[] versionKey = getSubspace().pack(recordVersionKey(primaryKey));
Optional<CompletableFuture<FDBRecordVersion>> cachedOptional = context.getLocalVersion(versionKey).map(localVersion -> CompletableFuture.completedFuture(FDBRecordVersion.incomplete(localVersion)));
if (cachedOptional.isPresent()) {
return cachedOptional;
}
final ReadTransaction tr = snapshot ? ensureContextActive().snapshot() : ensureContextActive();
return Optional.of(tr.get(versionKey).thenApply(valueBytes -> {
if (valueBytes == null) {
return null;
} else if (useOldVersionFormat()) {
return FDBRecordVersion.complete(valueBytes, false);
} else {
return SplitHelper.unpackVersion(valueBytes);
}
}));
}
}
use of com.apple.foundationdb.tuple.Tuple in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method saveTypedRecord.
@Nonnull
@API(API.Status.INTERNAL)
protected <M extends Message> CompletableFuture<FDBStoredRecord<M>> saveTypedRecord(@Nonnull RecordSerializer<M> typedSerializer, @Nonnull M rec, @Nonnull RecordExistenceCheck existenceCheck, @Nullable FDBRecordVersion version, @Nonnull VersionstampSaveBehavior behavior) {
final RecordMetaData metaData = metaDataProvider.getRecordMetaData();
final Descriptors.Descriptor recordDescriptor = rec.getDescriptorForType();
final RecordType recordType = metaData.getRecordTypeForDescriptor(recordDescriptor);
final KeyExpression primaryKeyExpression = recordType.getPrimaryKey();
final FDBStoredRecordBuilder<M> recordBuilder = FDBStoredRecord.newBuilder(rec).setRecordType(recordType);
final FDBRecordVersion recordVersion = recordVersionForSave(metaData, version, behavior);
recordBuilder.setVersion(recordVersion);
final Tuple primaryKey = primaryKeyExpression.evaluateSingleton(recordBuilder).toTuple();
recordBuilder.setPrimaryKey(primaryKey);
final CompletableFuture<FDBStoredRecord<M>> result = loadExistingRecord(typedSerializer, primaryKey).thenCompose(oldRecord -> {
if (oldRecord == null) {
if (existenceCheck.errorIfNotExists()) {
throw new RecordDoesNotExistException("record does not exist", LogMessageKeys.PRIMARY_KEY, primaryKey);
}
} else {
if (existenceCheck.errorIfExists()) {
throw new RecordAlreadyExistsException("record already exists", LogMessageKeys.PRIMARY_KEY, primaryKey);
}
if (existenceCheck.errorIfTypeChanged() && oldRecord.getRecordType() != recordType) {
throw new RecordTypeChangedException("record type changed", LogMessageKeys.PRIMARY_KEY, primaryKey, LogMessageKeys.ACTUAL_TYPE, oldRecord.getRecordType().getName(), LogMessageKeys.EXPECTED_TYPE, recordType.getName());
}
}
final FDBStoredRecord<M> newRecord = serializeAndSaveRecord(typedSerializer, recordBuilder, metaData, oldRecord);
if (oldRecord == null) {
addRecordCount(metaData, newRecord, LITTLE_ENDIAN_INT64_ONE);
} else {
if (getTimer() != null) {
getTimer().increment(FDBStoreTimer.Counts.REPLACE_RECORD_VALUE_BYTES, oldRecord.getValueSize());
}
}
return updateSecondaryIndexes(oldRecord, newRecord).thenApply(v -> newRecord);
});
return context.instrument(FDBStoreTimer.Events.SAVE_RECORD, result);
}
Aggregations