use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method addIndexStateReadConflict.
/**
* Add a read conflict key so that the transaction will fail if the index state has changed.
* @param indexName the index to conflict on, if it's state changes
*/
private void addIndexStateReadConflict(@Nonnull String indexName) {
if (!getRecordMetaData().hasIndex(indexName)) {
throw new MetaDataException("Index " + indexName + " does not exist in meta-data.");
}
if (indexStateReadConflicts.contains(indexName)) {
return;
} else {
indexStateReadConflicts.add(indexName);
}
Transaction tr = ensureContextActive();
byte[] indexStateKey = getSubspace().pack(Tuple.from(INDEX_STATE_SPACE_KEY, indexName));
tr.addReadConflictKey(indexStateKey);
}
use of com.apple.foundationdb.Transaction 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.Transaction in project fdb-record-layer by FoundationDB.
the class SplitHelper method clearPreviousSplitRecord.
private static void clearPreviousSplitRecord(@Nonnull final FDBRecordContext context, @Nonnull final Subspace subspace, @Nonnull final Tuple key, final boolean clearBasedOnPreviousSizeInfo, @Nullable FDBStoredSizes previousSizeInfo) {
final Transaction tr = context.ensureActive();
final Subspace keySplitSubspace = subspace.subspace(key);
if (clearBasedOnPreviousSizeInfo) {
if (previousSizeInfo != null) {
if (previousSizeInfo.isSplit() || previousSizeInfo.isVersionedInline()) {
// Record might be shorter than previous split.
tr.clear(keySplitSubspace.range());
} else {
// Record was previously unsplit and had unsplit suffix because we are splitting long records.
tr.clear(keySplitSubspace.pack(UNSPLIT_RECORD));
}
}
} else {
// Clears both unsplit and previous longer split.
tr.clear(keySplitSubspace.range());
}
final byte[] versionKey = keySplitSubspace.pack(RECORD_VERSION);
context.getLocalVersion(versionKey).ifPresent(localVersion -> context.removeVersionMutation(versionKey));
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class SplitHelper method saveWithSplit.
/**
* Save serialized representation using multiple keys if necessary, clearing only as much as needed.
* @param context write transaction
* @param subspace subspace to save in
* @param key key within subspace
* @param serialized serialized representation
* @param version the version to store inline with this record
* @param splitLongRecords <code>true</code> if multiple keys should be used; if <code>false</code>, <code>serialized</code> must fit in a single key
* @param omitUnsplitSuffix if <code>splitLongRecords</code> is <code>false</code>, then this will omit a suffix added to the end of the key if <code>true</code> for backwards-compatibility reasons
* @param clearBasedOnPreviousSizeInfo if <code>splitLongRecords</code>, whether to use <code>previousSizeInfo</code> to determine how much to clear
* @param previousSizeInfo if <code>clearBasedOnPreviousSizeInfo</code>, the {@link FDBStoredSizes} for any old record, or <code>null</code> if there was no old record
* @param sizeInfo optional size information to populate
*/
public static void saveWithSplit(@Nonnull final FDBRecordContext context, @Nonnull final Subspace subspace, @Nonnull final Tuple key, @Nonnull final byte[] serialized, @Nullable final FDBRecordVersion version, final boolean splitLongRecords, final boolean omitUnsplitSuffix, final boolean clearBasedOnPreviousSizeInfo, @Nullable final FDBStoredSizes previousSizeInfo, @Nullable SizeInfo sizeInfo) {
if (omitUnsplitSuffix && version != null) {
throw new RecordCoreArgumentException("Cannot include version in-line using old unsplit record format").addLogInfo(LogMessageKeys.KEY_TUPLE, key).addLogInfo(LogMessageKeys.SUBSPACE, ByteArrayUtil2.loggable(subspace.pack())).addLogInfo(LogMessageKeys.VERSION, version);
}
final Transaction tr = context.ensureActive();
if (serialized.length > SplitHelper.SPLIT_RECORD_SIZE) {
if (!splitLongRecords) {
throw new RecordCoreException("Record is too long to be stored in a single value; consider split_long_records").addLogInfo(LogMessageKeys.KEY_TUPLE, key).addLogInfo(LogMessageKeys.SUBSPACE, ByteArrayUtil2.loggable(subspace.pack())).addLogInfo(LogMessageKeys.VALUE_SIZE, serialized.length);
}
writeSplitRecord(context, subspace, key, serialized, clearBasedOnPreviousSizeInfo, previousSizeInfo, sizeInfo);
} else {
if (splitLongRecords || previousSizeInfo == null || previousSizeInfo.isVersionedInline()) {
clearPreviousSplitRecord(context, subspace, key, clearBasedOnPreviousSizeInfo, previousSizeInfo);
}
final Tuple recordKey;
if (splitLongRecords || !omitUnsplitSuffix) {
recordKey = key.add(SplitHelper.UNSPLIT_RECORD);
} else {
recordKey = key;
}
final byte[] keyBytes = subspace.pack(recordKey);
tr.set(keyBytes, serialized);
if (sizeInfo != null) {
sizeInfo.set(keyBytes, serialized);
sizeInfo.setSplit(false);
}
}
writeVersion(context, subspace, key, version, sizeInfo);
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class SplitHelper method writeVersion.
private static void writeVersion(@Nonnull final FDBRecordContext context, @Nonnull final Subspace subspace, @Nonnull final Tuple key, @Nullable final FDBRecordVersion version, @Nullable final SizeInfo sizeInfo) {
if (version == null) {
if (sizeInfo != null) {
sizeInfo.setVersionedInline(false);
}
return;
}
final Transaction tr = context.ensureActive();
final byte[] keyBytes = subspace.pack(key.add(RECORD_VERSION));
final byte[] valueBytes = packVersion(version);
if (version.isComplete()) {
tr.set(keyBytes, valueBytes);
} else {
context.addVersionMutation(MutationType.SET_VERSIONSTAMPED_VALUE, keyBytes, valueBytes);
context.addToLocalVersionCache(keyBytes, version.getLocalVersion());
}
if (sizeInfo != null) {
sizeInfo.setVersionedInline(true);
sizeInfo.add(keyBytes, valueBytes);
if (!version.isComplete()) {
// If the version isn't complete, an offset gets added to the
// end of the value to indicate where the version should be
// written. This is not made durable, so remove it from the metric.
sizeInfo.valueSize -= Integer.BYTES;
}
}
}
Aggregations