Search in sources :

Example 46 with Subspace

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

the class FDBRecordStore method repairRecordKeys.

/**
 * Validate and repair known potential issues with record keys. Currently, this method is capable of identifying
 * and repairing the following scenarios:
 * <ul>
 *     <li>For record stores in which record splitting is disabled but the {@code omitUnsplitRecordSuffix} flag
 *         is {@code true}, keys found missing the {@link SplitHelper#UNSPLIT_RECORD} suffix will be repaired.</li>
 *     <li>For record stores in which record splitting is disabled, but the record key suffix is found to be
 *         a value other than {@link SplitHelper#UNSPLIT_RECORD}, the {@link FDBStoreTimer.Counts#INVALID_SPLIT_SUFFIX}
 *         counter will be incremented.
 *     <li>For record stores in which record splitting is disabled, but the record key is longer than expected,
 *         the {@link FDBStoreTimer.Counts#INVALID_KEY_LENGTH} counter will be incremented.
 * </ul>
 *
 * @param continuation continuation from a previous repair attempt or {@code null} to start from the beginning
 * @param scanProperties properties to provide scan limits on the repair process
 *   record keys should be logged
 * @param isDryRun if true, no repairs are made, however counters involving irregular keys or keys that would
 *   would have been repaired are incremented
 * @return a future that completes to a continuation or {@code null} if the repair has been completed
 */
@Nonnull
public CompletableFuture<byte[]> repairRecordKeys(@Nullable byte[] continuation, @Nonnull ScanProperties scanProperties, final boolean isDryRun) {
    // If the records aren't split to begin with, then there is nothing to do.
    if (getRecordMetaData().isSplitLongRecords()) {
        return CompletableFuture.completedFuture(null);
    }
    if (scanProperties.getExecuteProperties().getIsolationLevel().isSnapshot()) {
        throw new RecordCoreArgumentException("Cannot repair record key split markers at SNAPSHOT isolation level").addLogInfo(LogMessageKeys.SCAN_PROPERTIES, scanProperties).addLogInfo(subspaceProvider.logKey(), subspaceProvider.toString(context));
    }
    final Subspace recordSubspace = recordsSubspace();
    KeyValueCursor cursor = KeyValueCursor.Builder.withSubspace(recordSubspace).setContext(getRecordContext()).setContinuation(continuation).setScanProperties(scanProperties).build();
    final AtomicReference<byte[]> nextContinuation = new AtomicReference<>();
    final FDBRecordContext context = getContext();
    return AsyncUtil.whileTrue(() -> cursor.onNext().thenApply(result -> {
        if (!result.hasNext()) {
            if (result.hasStoppedBeforeEnd()) {
                nextContinuation.set(result.getContinuation().toBytes());
            }
            return false;
        }
        repairRecordKeyIfNecessary(context, recordSubspace, result.get(), isDryRun);
        return true;
    })).thenApply(ignored -> nextContinuation.get());
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace) AtomicReference(java.util.concurrent.atomic.AtomicReference) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Nonnull(javax.annotation.Nonnull)

Example 47 with Subspace

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

the class FDBRecordStore method deleteStore.

/**
 * Delete the record store at the given {@link KeySpacePath}. This behaves like
 * {@link #deleteStore(FDBRecordContext, Subspace)} on the record store saved
 * at {@link KeySpacePath#toSubspace(FDBRecordContext)}.
 *
 * @param context the transactional context in which to delete the record store
 * @param path the path to the record store
 * @see #deleteStore(FDBRecordContext, Subspace)
 */
public static void deleteStore(FDBRecordContext context, KeySpacePath path) {
    final Subspace subspace = path.toSubspace(context);
    deleteStore(context, subspace);
}
Also used : Subspace(com.apple.foundationdb.subspace.Subspace)

Example 48 with Subspace

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

the class FDBRecordStore method countRecords.

@Override
@Nonnull
public CompletableFuture<Integer> countRecords(@Nullable Tuple low, @Nullable Tuple high, @Nonnull EndpointType lowEndpoint, @Nonnull EndpointType highEndpoint, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    final Subspace recordsSubspace = recordsSubspace();
    RecordCursor<KeyValue> keyValues = KeyValueCursor.Builder.withSubspace(recordsSubspace).setContext(context).setLow(low, lowEndpoint).setHigh(high, highEndpoint).setContinuation(continuation).setScanProperties(scanProperties.with(ExecuteProperties::clearRowAndTimeLimits).with(ExecuteProperties::clearState)).build();
    if (getRecordMetaData().isSplitLongRecords()) {
        return new SplitHelper.KeyValueUnsplitter(context, recordsSubspace, keyValues, useOldVersionFormat(), null, scanProperties.isReverse(), new CursorLimitManager(context, scanProperties.with(ExecuteProperties::clearRowAndTimeLimits))).getCount();
    } else {
        return keyValues.getCount();
    }
}
Also used : ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) KeyValue(com.apple.foundationdb.KeyValue) Subspace(com.apple.foundationdb.subspace.Subspace) CursorLimitManager(com.apple.foundationdb.record.cursors.CursorLimitManager) Nonnull(javax.annotation.Nonnull)

Example 49 with Subspace

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

the class IndexingBase method iterateRangeOnly.

/**
 * iterate cursor's items and index them.
 *
 * @param store the record store.
 * @param cursor iteration items.
 * @param getRecordToIndex function to convert cursor's item to a record that should be indexed (or null, if inapplicable)
 * @param nextResultCont when return, if hasMore is true, holds the last cursored result - unprocessed - as a
 * continuation item.
 * @param hasMore when return, true if the cursor's source is not exhausted (not more items in range).
 * @param recordsScanned when return, number of scanned records.
 * @param isIdempotent are all the built indexes idempotent
 * @param <T> cursor result's type.
 *
 * @return hasMore, nextResultCont, and recordsScanned.
 */
protected <T> CompletableFuture<Void> iterateRangeOnly(@Nonnull FDBRecordStore store, @Nonnull RecordCursor<T> cursor, @Nonnull BiFunction<FDBRecordStore, RecordCursorResult<T>, CompletableFuture<FDBStoredRecord<Message>>> getRecordToIndex, @Nonnull AtomicReference<RecordCursorResult<T>> nextResultCont, @Nonnull AtomicBoolean hasMore, @Nullable AtomicLong recordsScanned, final boolean isIdempotent) {
    final FDBStoreTimer timer = getRunner().getTimer();
    final FDBRecordContext context = store.getContext();
    // Need to do this each transaction because other index enabled state might have changed. Could cache based on that.
    // Copying the state also guards against changes made by other online building from check version.
    AtomicLong recordsScannedCounter = new AtomicLong();
    final AtomicReference<RecordCursorResult<T>> nextResult = new AtomicReference<>(null);
    return AsyncUtil.whileTrue(() -> cursor.onNext().thenCompose(result -> {
        RecordCursorResult<T> currResult;
        final boolean isExhausted;
        if (result.hasNext()) {
            // has next, process one previous item (if exists)
            currResult = nextResult.get();
            nextResult.set(result);
            if (currResult == null) {
                // that was the first item, nothing to process
                return AsyncUtil.READY_TRUE;
            }
            isExhausted = false;
        } else {
            // end of the cursor list
            timerIncrement(timer, FDBStoreTimer.Counts.ONLINE_INDEX_BUILDER_RANGES_BY_COUNT);
            if (!result.getNoNextReason().isSourceExhausted()) {
                nextResultCont.set(nextResult.get());
                hasMore.set(true);
                return AsyncUtil.READY_FALSE;
            }
            // source is exhausted, fall down to handle the last item and return with hasMore=false
            currResult = nextResult.get();
            if (currResult == null) {
                // there was no data
                hasMore.set(false);
                return AsyncUtil.READY_FALSE;
            }
            // here, process the last item and return
            nextResult.set(null);
            isExhausted = true;
        }
        // here: currResult must have value
        timerIncrement(timer, FDBStoreTimer.Counts.ONLINE_INDEX_BUILDER_RECORDS_SCANNED);
        recordsScannedCounter.incrementAndGet();
        return getRecordToIndex.apply(store, currResult).thenCompose(rec -> {
            if (null == rec) {
                if (isExhausted) {
                    hasMore.set(false);
                    return AsyncUtil.READY_FALSE;
                }
                return AsyncUtil.READY_TRUE;
            }
            // This record should be indexed. Add it to the transaction.
            if (isIdempotent) {
                store.addRecordReadConflict(rec.getPrimaryKey());
            }
            timerIncrement(timer, FDBStoreTimer.Counts.ONLINE_INDEX_BUILDER_RECORDS_INDEXED);
            final CompletableFuture<Void> updateMaintainer = updateMaintainerBuilder(store, rec);
            if (isExhausted) {
                // we've just processed the last item
                hasMore.set(false);
                return updateMaintainer.thenApply(vignore -> false);
            }
            return updateMaintainer.thenCompose(vignore -> context.getApproximateTransactionSize().thenApply(size -> {
                if (size >= common.config.getMaxWriteLimitBytes()) {
                    // the transaction becomes too big - stop iterating
                    timerIncrement(timer, FDBStoreTimer.Counts.ONLINE_INDEX_BUILDER_RANGES_BY_SIZE);
                    nextResultCont.set(nextResult.get());
                    hasMore.set(true);
                    return false;
                }
                return true;
            }));
        });
    }), cursor.getExecutor()).thenApply(vignore -> {
        long recordsScannedInTransaction = recordsScannedCounter.get();
        if (recordsScanned != null) {
            recordsScanned.addAndGet(recordsScannedInTransaction);
        }
        if (common.isTrackProgress()) {
            for (Index index : common.getTargetIndexes()) {
                final Subspace scannedRecordsSubspace = indexBuildScannedRecordsSubspace(store, index);
                store.context.ensureActive().mutate(MutationType.ADD, scannedRecordsSubspace.getKey(), FDBRecordStore.encodeRecordCount(recordsScannedInTransaction));
            }
        }
        return null;
    });
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) AsyncIterator(com.apple.foundationdb.async.AsyncIterator) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) RangeSet(com.apple.foundationdb.async.RangeSet) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Subspace(com.apple.foundationdb.subspace.Subspace) ArrayList(java.util.ArrayList) MutationType(com.apple.foundationdb.MutationType) Key(com.apple.foundationdb.record.metadata.Key) Transaction(com.apple.foundationdb.Transaction) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) BiConsumer(java.util.function.BiConsumer) IndexBuildProto(com.apple.foundationdb.record.IndexBuildProto) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) ByteArrayUtil2(com.apple.foundationdb.tuple.ByteArrayUtil2) MoreAsyncUtil(com.apple.foundationdb.async.MoreAsyncUtil) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Logger(org.slf4j.Logger) SynchronizedSessionRunner(com.apple.foundationdb.record.provider.foundationdb.synchronizedsession.SynchronizedSessionRunner) IndexState(com.apple.foundationdb.record.IndexState) Collectors(java.util.stream.Collectors) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) RecordMetaDataProvider(com.apple.foundationdb.record.RecordMetaDataProvider) Index(com.apple.foundationdb.record.metadata.Index) FDBException(com.apple.foundationdb.FDBException) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) API(com.apple.foundationdb.annotation.API) Collections(java.util.Collections) SyntheticRecordPlanner(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner) SyntheticRecordFromStoredRecordPlan(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) AtomicReference(java.util.concurrent.atomic.AtomicReference) Index(com.apple.foundationdb.record.metadata.Index) AtomicLong(java.util.concurrent.atomic.AtomicLong) Subspace(com.apple.foundationdb.subspace.Subspace)

Example 50 with Subspace

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

the class BunchedMapIterator method onHasNext.

@Override
public CompletableFuture<Boolean> onHasNext() {
    if (done) {
        return AsyncUtil.READY_FALSE;
    }
    if (currEntryList != null && currEntryIndex >= 0 && currEntryIndex < currEntryList.size()) {
        return AsyncUtil.READY_TRUE;
    }
    if (hasNextFuture == null) {
        hasNextFuture = underlying.onHasNext().thenCompose(doesHaveNext -> {
            if (doesHaveNext) {
                return AsyncUtil.whileTrue(() -> {
                    KeyValue underlyingNext = underlying.peek();
                    if (!subspace.contains(underlyingNext.getKey())) {
                        if (ByteArrayUtil.compareUnsigned(underlyingNext.getKey(), subspaceKey) * (reverse ? -1 : 1) < 0) {
                            // We haven't gotten to this subspace yet, so try the next key.
                            underlying.next();
                            return underlying.onHasNext();
                        } else {
                            // We are done iterating through this subspace. Return
                            // without advancing the scan to support scanning
                            // over multiple subspaces.
                            done = true;
                            return AsyncUtil.READY_FALSE;
                        }
                    }
                    // Advance the underlying scan.
                    underlying.next();
                    final K boundaryKey = bunchedMap.getSerializer().deserializeKey(underlyingNext.getKey(), subspaceKey.length);
                    List<Map.Entry<K, V>> nextEntryList = bunchedMap.getSerializer().deserializeEntries(boundaryKey, underlyingNext.getValue());
                    if (nextEntryList.isEmpty()) {
                        // No entries in list. Try next key.
                        return underlying.onHasNext();
                    }
                    int nextItemIndex = reverse ? nextEntryList.size() - 1 : 0;
                    if (!continuationSatisfied) {
                        while (nextItemIndex >= 0 && nextItemIndex < nextEntryList.size() && bunchedMap.getKeyComparator().compare(continuationKey, nextEntryList.get(nextItemIndex).getKey()) * (reverse ? -1 : 1) >= 0) {
                            nextItemIndex += reverse ? -1 : 1;
                        }
                        if (nextItemIndex < 0 || nextItemIndex >= nextEntryList.size()) {
                            // through this entry. Move on to the next key in the database.
                            return underlying.onHasNext();
                        } else {
                            continuationSatisfied = true;
                        }
                    }
                    // TODO: We can be more exact about conflict ranges here.
                    currEntryIndex = nextItemIndex;
                    currEntryList = nextEntryList;
                    return AsyncUtil.READY_FALSE;
                }, tr.getExecutor()).thenApply(vignore -> {
                    if (currEntryList == null || currEntryIndex < 0 || currEntryIndex >= currEntryList.size()) {
                        done = true;
                    }
                    return !done;
                });
            } else {
                // Exhausted scan.
                done = true;
                return AsyncUtil.READY_FALSE;
            }
        });
    }
    return hasNextFuture;
}
Also used : ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) 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) List(java.util.List) 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)

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