Search in sources :

Example 1 with IndexEntry

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

the class IndexingScrubDangling method deleteIndexIfDangling.

@Nullable
private CompletableFuture<FDBStoredRecord<Message>> deleteIndexIfDangling(FDBRecordStore store, final RecordCursorResult<FDBIndexedRecord<Message>> cursorResult) {
    // This will always return null (!) - but sometimes will delete a dangling index
    FDBIndexedRecord<Message> indexResult = cursorResult.get();
    if (!indexResult.hasStoredRecord()) {
        // Here: Oh, No! this index is dangling!
        danglingCount.incrementAndGet();
        final FDBStoreTimer timer = getRunner().getTimer();
        timerIncrement(timer, FDBStoreTimer.Counts.INDEX_SCRUBBER_DANGLING_ENTRIES);
        final IndexEntry indexEntry = indexResult.getIndexEntry();
        final Tuple valueKey = indexEntry.getKey();
        final byte[] keyBytes = store.indexSubspace(common.getIndex()).pack(valueKey);
        if (LOGGER.isWarnEnabled() && logWarningCounter > 0) {
            logWarningCounter--;
            LOGGER.warn(KeyValueLogMessage.build("Scrubber: dangling index entry", LogMessageKeys.KEY, valueKey.toString()).addKeysAndValues(common.indexLogMessageKeyValues()).toString());
        }
        if (scrubbingPolicy.allowRepair()) {
            // remove this index entry
            // Note that there no record can be added to the conflict list, so we'll add the index entry itself.
            store.addRecordReadConflict(indexEntry.getPrimaryKey());
            store.getContext().ensureActive().clear(keyBytes);
        }
    }
    return CompletableFuture.completedFuture(null);
}
Also used : KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Message(com.google.protobuf.Message) IndexEntry(com.apple.foundationdb.record.IndexEntry) Tuple(com.apple.foundationdb.tuple.Tuple) Nullable(javax.annotation.Nullable)

Example 2 with IndexEntry

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

the class IndexingScrubMissing method getRecordIfMissingIndex.

@Nullable
private CompletableFuture<FDBStoredRecord<Message>> getRecordIfMissingIndex(FDBRecordStore store, final RecordCursorResult<FDBStoredRecord<Message>> currResult) {
    final FDBStoredRecord<Message> rec = currResult.get();
    // return true if an index is missing and updated
    if (!common.getAllRecordTypes().contains(rec.getRecordType())) {
        return CompletableFuture.completedFuture(null);
    }
    final Index index = common.getIndex();
    final IndexMaintainer maintainer = store.getIndexMaintainer(index);
    List<IndexEntry> indexEntryNoPKs = maintainer.filteredIndexEntries(rec);
    if (indexEntryNoPKs == null) {
        return CompletableFuture.completedFuture(null);
    }
    return AsyncUtil.getAll(indexEntryNoPKs.stream().map(entry -> {
        // should I convert it to a single nested statement?
        final IndexEntry indexEntry = new IndexEntry(index, FDBRecordStoreBase.indexEntryKey(index, entry.getKey(), rec.getPrimaryKey()), entry.getValue());
        final Tuple valueKey = indexEntry.getKey();
        final byte[] keyBytes = maintainer.getIndexSubspace().pack(valueKey);
        return maintainer.state.transaction.get(keyBytes).thenApply(indexVal -> indexVal == null ? valueKey : null);
    }).collect(Collectors.toList())).thenApply(list -> {
        List<Tuple> missingIndexesKeys = list.stream().filter(Objects::nonNull).collect(Collectors.toList());
        if (missingIndexesKeys.isEmpty()) {
            return null;
        }
        // (Maybe) report an error and (maybe) return this record to be index
        if (LOGGER.isWarnEnabled() && logWarningCounter > 0) {
            logWarningCounter--;
            LOGGER.warn(KeyValueLogMessage.build("Scrubber: missing index entry", LogMessageKeys.KEY, rec.getPrimaryKey().toString(), LogMessageKeys.INDEX_KEY, missingIndexesKeys.toString()).addKeysAndValues(common.indexLogMessageKeyValues()).toString());
        }
        missingCount.incrementAndGet();
        final FDBStoreTimer timer = getRunner().getTimer();
        timerIncrement(timer, FDBStoreTimer.Counts.INDEX_SCRUBBER_MISSING_ENTRIES);
        if (scrubbingPolicy.allowRepair()) {
            // record to be indexed
            return rec;
        }
        // report only mode
        return null;
    });
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) Arrays(java.util.Arrays) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) 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) Subspace(com.apple.foundationdb.subspace.Subspace) Transaction(com.apple.foundationdb.Transaction) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) ScanProperties(com.apple.foundationdb.record.ScanProperties) IndexBuildProto(com.apple.foundationdb.record.IndexBuildProto) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) Logger(org.slf4j.Logger) IndexState(com.apple.foundationdb.record.IndexState) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) Objects(java.util.Objects) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) RecordMetaDataProvider(com.apple.foundationdb.record.RecordMetaDataProvider) Index(com.apple.foundationdb.record.metadata.Index) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) API(com.apple.foundationdb.annotation.API) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Message(com.google.protobuf.Message) IndexEntry(com.apple.foundationdb.record.IndexEntry) Index(com.apple.foundationdb.record.metadata.Index) Tuple(com.apple.foundationdb.tuple.Tuple) Nullable(javax.annotation.Nullable)

Example 3 with IndexEntry

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

the class StandardIndexMaintainer method filteredIndexEntries.

/**
 * Filter out index keys according to {@link IndexMaintenanceFilter}.
 * Keys that do not pass the filter will not be stored / removed from the index.
 * @param <M> the message type of the record
 * @param savedRecord record for key evaluation
 * @return filtered list of index keys for the given record
 */
@Override
@Nullable
public <M extends Message> List<IndexEntry> filteredIndexEntries(@Nullable final FDBIndexableRecord<M> savedRecord) {
    if (savedRecord == null) {
        return null;
    }
    final Message record = savedRecord.getRecord();
    long startTime = System.nanoTime();
    boolean filterIndexKeys = false;
    switch(state.filter.maintainIndex(state.index, record)) {
        case NONE:
            if (state.store.getTimer() != null) {
                state.store.getTimer().recordSinceNanoTime(FDBStoreTimer.Events.SKIP_INDEX_RECORD, startTime);
            }
            return null;
        case SOME:
            filterIndexKeys = true;
            break;
        case ALL:
        default:
            break;
    }
    List<IndexEntry> indexEntries = evaluateIndex(savedRecord);
    if (!filterIndexKeys) {
        return indexEntries;
    }
    int i = 0;
    while (i < indexEntries.size()) {
        if (state.filter.maintainIndexValue(state.index, record, indexEntries.get(i))) {
            i++;
        } else {
            indexEntries = makeMutable(indexEntries);
            indexEntries.remove(i);
            long endTime = System.nanoTime();
            if (state.store.getTimer() != null) {
                state.store.getTimer().record(FDBStoreTimer.Events.SKIP_INDEX_ENTRY, endTime - startTime);
            }
            startTime = endTime;
        }
    }
    return indexEntries;
}
Also used : KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Message(com.google.protobuf.Message) IndexEntry(com.apple.foundationdb.record.IndexEntry) Nullable(javax.annotation.Nullable)

Example 4 with IndexEntry

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

the class StandardIndexMaintainer method evaluateIndex.

/**
 * Apply the key and value expressions to a <code>record</code>.
 * @param <M> the message type of the record
 * @param record the record from which the index will extract its key and value
 * @return a list of index keys and values
 */
@Override
public <M extends Message> List<IndexEntry> evaluateIndex(@Nonnull FDBRecord<M> record) {
    final KeyExpression rootExpression = state.index.getRootExpression();
    final List<Key.Evaluated> indexKeys = rootExpression.evaluate(record);
    // so we have to tease them apart.
    if (rootExpression instanceof KeyWithValueExpression) {
        final KeyWithValueExpression keyWithValueExpression = (KeyWithValueExpression) rootExpression;
        return indexKeys.stream().map(key -> new IndexEntry(state.index, keyWithValueExpression.getKey(key), keyWithValueExpression.getValue(key))).collect(Collectors.toList());
    }
    return indexKeys.stream().map(key -> new IndexEntry(state.index, key)).collect(Collectors.toList());
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) IndexMaintainerState(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) LoggerFactory(org.slf4j.LoggerFactory) Subspace(com.apple.foundationdb.subspace.Subspace) Transaction(com.apple.foundationdb.Transaction) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) PipelineOperation(com.apple.foundationdb.record.PipelineOperation) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) FDBExceptions(com.apple.foundationdb.record.provider.foundationdb.FDBExceptions) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) QueryToKeyMatcher(com.apple.foundationdb.record.query.QueryToKeyMatcher) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) FDBIndexableRecord(com.apple.foundationdb.record.provider.foundationdb.FDBIndexableRecord) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) KeyValue(com.apple.foundationdb.KeyValue) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) Objects(java.util.Objects) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) API(com.apple.foundationdb.annotation.API) SplitHelper.unpackKey(com.apple.foundationdb.record.provider.foundationdb.SplitHelper.unpackKey) IndexMaintainer(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainer) IndexMaintenanceFilter(com.apple.foundationdb.record.provider.foundationdb.IndexMaintenanceFilter) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) KeyWithValueExpression(com.apple.foundationdb.record.metadata.expressions.KeyWithValueExpression) IndexOperation(com.apple.foundationdb.record.provider.foundationdb.IndexOperation) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) RangeSet(com.apple.foundationdb.async.RangeSet) Function(java.util.function.Function) CursorStreamingMode(com.apple.foundationdb.record.CursorStreamingMode) ArrayList(java.util.ArrayList) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) ScanProperties(com.apple.foundationdb.record.ScanProperties) IndexRecordFunction(com.apple.foundationdb.record.metadata.IndexRecordFunction) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) IndexOperationResult(com.apple.foundationdb.record.provider.foundationdb.IndexOperationResult) MoreAsyncUtil(com.apple.foundationdb.async.MoreAsyncUtil) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) Logger(org.slf4j.Logger) Executor(java.util.concurrent.Executor) RecordType(com.apple.foundationdb.record.metadata.RecordType) AsyncIterable(com.apple.foundationdb.async.AsyncIterable) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) Collections(java.util.Collections) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) IndexEntry(com.apple.foundationdb.record.IndexEntry) KeyWithValueExpression(com.apple.foundationdb.record.metadata.expressions.KeyWithValueExpression)

Example 5 with IndexEntry

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

the class StandardIndexMaintainer method checkUniqueness.

protected <M extends Message> void checkUniqueness(@Nonnull FDBIndexableRecord<M> savedRecord, @Nonnull IndexEntry indexEntry) {
    Tuple valueKey = indexEntry.getKey();
    AsyncIterable<KeyValue> kvs = state.transaction.getRange(state.indexSubspace.range(valueKey));
    Tuple primaryKey = savedRecord.getPrimaryKey();
    final CompletableFuture<Void> checker = state.store.getContext().instrument(FDBStoreTimer.Events.CHECK_INDEX_UNIQUENESS, AsyncUtil.forEach(kvs, kv -> {
        Tuple existingEntry = unpackKey(getIndexSubspace(), kv);
        Tuple existingKey = state.index.getEntryPrimaryKey(existingEntry);
        if (!TupleHelpers.equals(primaryKey, existingKey)) {
            if (state.store.isIndexWriteOnly(state.index)) {
                addUniquenessViolation(valueKey, primaryKey, existingKey);
                addUniquenessViolation(valueKey, existingKey, primaryKey);
            } else {
                throw new RecordIndexUniquenessViolation(state.index, indexEntry, primaryKey, existingKey);
            }
        }
    }, getExecutor()));
    // Add a pre-commit check to prevent accidentally committing and getting into an invalid state.
    state.store.addIndexUniquenessCommitCheck(state.index, checker);
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) IndexMaintainerState(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) LoggerFactory(org.slf4j.LoggerFactory) Subspace(com.apple.foundationdb.subspace.Subspace) Transaction(com.apple.foundationdb.Transaction) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) PipelineOperation(com.apple.foundationdb.record.PipelineOperation) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) FDBExceptions(com.apple.foundationdb.record.provider.foundationdb.FDBExceptions) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) QueryToKeyMatcher(com.apple.foundationdb.record.query.QueryToKeyMatcher) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) FDBIndexableRecord(com.apple.foundationdb.record.provider.foundationdb.FDBIndexableRecord) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) KeyValue(com.apple.foundationdb.KeyValue) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) Objects(java.util.Objects) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) API(com.apple.foundationdb.annotation.API) SplitHelper.unpackKey(com.apple.foundationdb.record.provider.foundationdb.SplitHelper.unpackKey) IndexMaintainer(com.apple.foundationdb.record.provider.foundationdb.IndexMaintainer) IndexMaintenanceFilter(com.apple.foundationdb.record.provider.foundationdb.IndexMaintenanceFilter) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) KeyWithValueExpression(com.apple.foundationdb.record.metadata.expressions.KeyWithValueExpression) IndexOperation(com.apple.foundationdb.record.provider.foundationdb.IndexOperation) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) RangeSet(com.apple.foundationdb.async.RangeSet) Function(java.util.function.Function) CursorStreamingMode(com.apple.foundationdb.record.CursorStreamingMode) ArrayList(java.util.ArrayList) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) ScanProperties(com.apple.foundationdb.record.ScanProperties) IndexRecordFunction(com.apple.foundationdb.record.metadata.IndexRecordFunction) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) IndexOperationResult(com.apple.foundationdb.record.provider.foundationdb.IndexOperationResult) MoreAsyncUtil(com.apple.foundationdb.async.MoreAsyncUtil) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) Logger(org.slf4j.Logger) Executor(java.util.concurrent.Executor) RecordType(com.apple.foundationdb.record.metadata.RecordType) AsyncIterable(com.apple.foundationdb.async.AsyncIterable) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) Collections(java.util.Collections) KeyValue(com.apple.foundationdb.KeyValue) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) Tuple(com.apple.foundationdb.tuple.Tuple)

Aggregations

IndexEntry (com.apple.foundationdb.record.IndexEntry)74 Tuple (com.apple.foundationdb.tuple.Tuple)41 Nonnull (javax.annotation.Nonnull)37 Index (com.apple.foundationdb.record.metadata.Index)34 Test (org.junit.jupiter.api.Test)34 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)32 Message (com.google.protobuf.Message)32 ScanProperties (com.apple.foundationdb.record.ScanProperties)29 ArrayList (java.util.ArrayList)29 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)28 TupleRange (com.apple.foundationdb.record.TupleRange)28 List (java.util.List)28 Nullable (javax.annotation.Nullable)27 IndexScanType (com.apple.foundationdb.record.IndexScanType)24 RecordCursor (com.apple.foundationdb.record.RecordCursor)22 CompletableFuture (java.util.concurrent.CompletableFuture)21 Collectors (java.util.stream.Collectors)21 ExecuteProperties (com.apple.foundationdb.record.ExecuteProperties)20 TupleHelpers (com.apple.foundationdb.tuple.TupleHelpers)20 FDBStoreTimer (com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer)19