Search in sources :

Example 76 with Transaction

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);
}
Also used : Transaction(com.apple.foundationdb.Transaction) ReadTransaction(com.apple.foundationdb.ReadTransaction) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException)

Example 77 with Transaction

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;
}
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 78 with Transaction

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));
}
Also used : Transaction(com.apple.foundationdb.Transaction) ReadTransaction(com.apple.foundationdb.ReadTransaction) Subspace(com.apple.foundationdb.subspace.Subspace)

Example 79 with Transaction

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);
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Transaction(com.apple.foundationdb.Transaction) ReadTransaction(com.apple.foundationdb.ReadTransaction) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Tuple(com.apple.foundationdb.tuple.Tuple)

Example 80 with Transaction

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;
        }
    }
}
Also used : Transaction(com.apple.foundationdb.Transaction) ReadTransaction(com.apple.foundationdb.ReadTransaction)

Aggregations

Transaction (com.apple.foundationdb.Transaction)84 ReadTransaction (com.apple.foundationdb.ReadTransaction)34 Tuple (com.apple.foundationdb.tuple.Tuple)34 Test (org.junit.jupiter.api.Test)33 Nonnull (javax.annotation.Nonnull)28 ArrayList (java.util.ArrayList)26 List (java.util.List)26 CompletableFuture (java.util.concurrent.CompletableFuture)26 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)22 Subspace (com.apple.foundationdb.subspace.Subspace)21 Collectors (java.util.stream.Collectors)19 Nullable (javax.annotation.Nullable)19 KeyValue (com.apple.foundationdb.KeyValue)18 Map (java.util.Map)18 KeyValueLogMessage (com.apple.foundationdb.record.logging.KeyValueLogMessage)17 Range (com.apple.foundationdb.Range)16 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)16 AtomicReference (java.util.concurrent.atomic.AtomicReference)16 Collections (java.util.Collections)15 RecordCursor (com.apple.foundationdb.record.RecordCursor)14