Search in sources :

Example 1 with SyntheticRecordPlanner

use of com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner in project fdb-record-layer by FoundationDB.

the class IndexingCommon method fillTargetIndexers.

private void fillTargetIndexers(@Nonnull List<Index> targetIndexes, @Nullable Collection<RecordType> recordTypes) {
    boolean presetTypes = false;
    if (recordTypes != null) {
        if (targetIndexes.size() > 1) {
            throw new IndexingBase.ValidationException("Can't use preset record types with multi target indexing");
        }
        presetTypes = true;
    }
    if (recordStoreBuilder.getMetaDataProvider() == null) {
        throw new MetaDataException("record store builder must include metadata");
    }
    final RecordMetaData metaData = recordStoreBuilder.getMetaDataProvider().getRecordMetaData();
    for (Index targetIndex : targetIndexes) {
        Collection<RecordType> types;
        if (presetTypes) {
            types = recordTypes;
        } else {
            types = metaData.recordTypesForIndex(targetIndex);
        }
        boolean isSynthetic = false;
        if (types.stream().anyMatch(RecordType::isSynthetic)) {
            types = new SyntheticRecordPlanner(metaData, new RecordStoreState(null, null)).storedRecordTypesForIndex(targetIndex, types);
            isSynthetic = true;
        }
        targetIndexContexts.add(new IndexContext(targetIndex, types, isSynthetic));
        allRecordTypes.addAll(types);
    }
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordType(com.apple.foundationdb.record.metadata.RecordType) SyntheticRecordPlanner(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner) Index(com.apple.foundationdb.record.metadata.Index) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException)

Example 2 with SyntheticRecordPlanner

use of com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner in project fdb-record-layer by FoundationDB.

the class FDBRecordStore method updateSyntheticIndexes.

@API(API.Status.EXPERIMENTAL)
private <M extends Message> void updateSyntheticIndexes(@Nullable FDBStoredRecord<M> oldRecord, @Nullable FDBStoredRecord<M> newRecord, @Nonnull final List<CompletableFuture<Void>> futures) {
    final SyntheticRecordPlanner planner = new SyntheticRecordPlanner(this);
    // Index maintainers are not required to be thread-safe, so only do one synthetic record at a time.
    final int pipelineSize = 1;
    if (oldRecord != null && newRecord != null && oldRecord.getRecordType() == newRecord.getRecordType()) {
        // TODO: An important optimization here is determining that no field used in the join condition or
        // indexed in the synthetic record is changed, in which case all this can be skipped.
        final SyntheticRecordFromStoredRecordPlan plan = planner.fromStoredType(newRecord.getRecordType(), true);
        if (plan == null) {
            return;
        }
        final Map<RecordType, Collection<IndexMaintainer>> maintainers = getSyntheticMaintainers(plan.getSyntheticRecordTypes());
        final Map<Tuple, FDBSyntheticRecord> oldRecords = new ConcurrentHashMap<>();
        CompletableFuture<Void> future = plan.execute(this, oldRecord).forEach(syntheticRecord -> oldRecords.put(syntheticRecord.getPrimaryKey(), syntheticRecord));
        // @SpotBugsSuppressWarnings("NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE", justification = "https://github.com/spotbugs/spotbugs/issues/552")
        @Nonnull final FDBStoredRecord<M> theNewRecord = newRecord;
        future = future.thenCompose(v -> plan.execute(this, theNewRecord).forEachAsync(syntheticRecord -> runSyntheticMaintainers(maintainers, oldRecords.remove(syntheticRecord.getPrimaryKey()), syntheticRecord), pipelineSize));
        future = future.thenCompose(v -> {
            // Any synthetic record that was generated by the plan on the old record but not by the plan on the new record needs to be removed from its indexes.
            final List<CompletableFuture<Void>> subFutures = new ArrayList<>();
            for (FDBSyntheticRecord oldSyntheticRecord : oldRecords.values()) {
                CompletableFuture<Void> subFuture = runSyntheticMaintainers(maintainers, oldSyntheticRecord, null);
                if (!MoreAsyncUtil.isCompletedNormally(subFuture)) {
                    subFutures.add(subFuture);
                }
            }
            if (subFutures.isEmpty()) {
                return AsyncUtil.DONE;
            } else if (subFutures.size() == 1) {
                return subFutures.get(0);
            } else {
                return AsyncUtil.whenAll(subFutures);
            }
        });
        futures.add(future);
    } else {
        if (oldRecord != null) {
            final SyntheticRecordFromStoredRecordPlan plan = planner.fromStoredType(oldRecord.getRecordType(), true);
            if (plan != null) {
                final Map<RecordType, Collection<IndexMaintainer>> maintainers = getSyntheticMaintainers(plan.getSyntheticRecordTypes());
                futures.add(plan.execute(this, oldRecord).forEachAsync(syntheticRecord -> runSyntheticMaintainers(maintainers, syntheticRecord, null), pipelineSize));
            }
        }
        if (newRecord != null) {
            final SyntheticRecordFromStoredRecordPlan plan = planner.fromStoredType(newRecord.getRecordType(), true);
            if (plan != null) {
                final Map<RecordType, Collection<IndexMaintainer>> maintainers = getSyntheticMaintainers(plan.getSyntheticRecordTypes());
                futures.add(plan.execute(this, newRecord).forEachAsync(syntheticRecord -> runSyntheticMaintainers(maintainers, null, syntheticRecord), pipelineSize));
            }
        }
    }
}
Also used : LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) UnaryOperator(java.util.function.UnaryOperator) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) RecordSerializer(com.apple.foundationdb.record.provider.common.RecordSerializer) Subspace(com.apple.foundationdb.subspace.Subspace) MutationType(com.apple.foundationdb.MutationType) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Map(java.util.Map) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) QueryToKeyMatcher(com.apple.foundationdb.record.query.QueryToKeyMatcher) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) Set(java.util.Set) TupleRange(com.apple.foundationdb.record.TupleRange) KeySpacePath(com.apple.foundationdb.record.provider.foundationdb.keyspace.KeySpacePath) ByteOrder(java.nio.ByteOrder) SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) RecordMetaDataProvider(com.apple.foundationdb.record.RecordMetaDataProvider) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) API(com.apple.foundationdb.annotation.API) FunctionNames(com.apple.foundationdb.record.FunctionNames) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RangeSet(com.apple.foundationdb.async.RangeSet) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Supplier(java.util.function.Supplier) FormerIndex(com.apple.foundationdb.record.metadata.FormerIndex) ArrayList(java.util.ArrayList) ByteScanLimiter(com.apple.foundationdb.record.ByteScanLimiter) ParameterRelationshipGraph(com.apple.foundationdb.record.query.ParameterRelationshipGraph) LoggableException(com.apple.foundationdb.util.LoggableException) CloseableAsyncIterator(com.apple.foundationdb.async.CloseableAsyncIterator) IndexRecordFunction(com.apple.foundationdb.record.metadata.IndexRecordFunction) Nullable(javax.annotation.Nullable) ByteArrayUtil2(com.apple.foundationdb.tuple.ByteArrayUtil2) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) CursorLimitManager(com.apple.foundationdb.record.cursors.CursorLimitManager) ExecuteState(com.apple.foundationdb.record.ExecuteState) AtomicLong(java.util.concurrent.atomic.AtomicLong) RecordType(com.apple.foundationdb.record.metadata.RecordType) Index(com.apple.foundationdb.record.metadata.Index) DynamicMessageRecordSerializer(com.apple.foundationdb.record.provider.common.DynamicMessageRecordSerializer) SyntheticRecordPlanner(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner) IndexEntry(com.apple.foundationdb.record.IndexEntry) LoggerFactory(org.slf4j.LoggerFactory) RecordCoreStorageException(com.apple.foundationdb.record.RecordCoreStorageException) ByteBuffer(java.nio.ByteBuffer) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) Transaction(com.apple.foundationdb.Transaction) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) PipelineOperation(com.apple.foundationdb.record.PipelineOperation) RecordMetaDataProto(com.apple.foundationdb.record.RecordMetaDataProto) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) KeyValue(com.apple.foundationdb.KeyValue) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) IndexQueryabilityFilter(com.apple.foundationdb.record.query.IndexQueryabilityFilter) AndComponent(com.apple.foundationdb.record.query.expressions.AndComponent) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Collectors(java.util.stream.Collectors) ByteString(com.google.protobuf.ByteString) List(java.util.List) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) AggregateFunctionNotSupportedException(com.apple.foundationdb.record.AggregateFunctionNotSupportedException) RecordTypeKeyComparison(com.apple.foundationdb.record.query.expressions.RecordTypeKeyComparison) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Optional(java.util.Optional) MutableRecordStoreState(com.apple.foundationdb.record.MutableRecordStoreState) RecordTypeOrBuilder(com.apple.foundationdb.record.metadata.RecordTypeOrBuilder) SyntheticRecordFromStoredRecordPlan(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan) SpotBugsSuppressWarnings(com.apple.foundationdb.annotation.SpotBugsSuppressWarnings) Descriptors(com.google.protobuf.Descriptors) AsyncIterator(com.apple.foundationdb.async.AsyncIterator) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) CursorStreamingMode(com.apple.foundationdb.record.CursorStreamingMode) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) EndpointType(com.apple.foundationdb.record.EndpointType) ScanProperties(com.apple.foundationdb.record.ScanProperties) Suppliers(com.google.common.base.Suppliers) LinkedList(java.util.LinkedList) Nonnull(javax.annotation.Nonnull) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) MoreAsyncUtil(com.apple.foundationdb.async.MoreAsyncUtil) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) IndexState(com.apple.foundationdb.record.IndexState) StoreRecordFunction(com.apple.foundationdb.record.metadata.StoreRecordFunction) ReadTransaction(com.apple.foundationdb.ReadTransaction) AsyncIterable(com.apple.foundationdb.async.AsyncIterable) FDBRecordStoreStateCache(com.apple.foundationdb.record.provider.foundationdb.storestate.FDBRecordStoreStateCache) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Collections(java.util.Collections) SyntheticRecordPlanner(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner) Nonnull(javax.annotation.Nonnull) CompletableFuture(java.util.concurrent.CompletableFuture) SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) RecordType(com.apple.foundationdb.record.metadata.RecordType) Collection(java.util.Collection) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SyntheticRecordFromStoredRecordPlan(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan) Tuple(com.apple.foundationdb.tuple.Tuple) API(com.apple.foundationdb.annotation.API)

Example 3 with SyntheticRecordPlanner

use of com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner in project fdb-record-layer by FoundationDB.

the class IndexingBase method updateMaintainerBuilder.

private CompletableFuture<Void> updateMaintainerBuilder(@Nonnull FDBRecordStore store, FDBStoredRecord<Message> rec) {
    return forEachTargetIndexContext(indexContext -> {
        if (!indexContext.recordTypes.contains(rec.getRecordType())) {
            // This particular index is not affected by rec
            return AsyncUtil.DONE;
        }
        if (indexContext.isSynthetic) {
            // This particular index is synthetic, handle with care
            final SyntheticRecordPlanner syntheticPlanner = new SyntheticRecordPlanner(store.getRecordMetaData(), store.getRecordStoreState().withWriteOnlyIndexes(Collections.singletonList(indexContext.index.getName())));
            final SyntheticRecordFromStoredRecordPlan syntheticPlan = syntheticPlanner.forIndex(indexContext.index);
            final IndexMaintainer maintainer = store.getIndexMaintainer(indexContext.index);
            return syntheticPlan.execute(store, rec).forEachAsync(syntheticRecord -> maintainer.update(null, syntheticRecord), 1);
        }
        // update simple index
        return store.getIndexMaintainer(indexContext.index).update(null, rec);
    });
}
Also used : SyntheticRecordPlanner(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner) SyntheticRecordFromStoredRecordPlan(com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan)

Aggregations

SyntheticRecordPlanner (com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner)3 RecordMetaData (com.apple.foundationdb.record.RecordMetaData)2 RecordStoreState (com.apple.foundationdb.record.RecordStoreState)2 Index (com.apple.foundationdb.record.metadata.Index)2 MetaDataException (com.apple.foundationdb.record.metadata.MetaDataException)2 RecordType (com.apple.foundationdb.record.metadata.RecordType)2 SyntheticRecordFromStoredRecordPlan (com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan)2 KeyValue (com.apple.foundationdb.KeyValue)1 MutationType (com.apple.foundationdb.MutationType)1 Range (com.apple.foundationdb.Range)1 ReadTransaction (com.apple.foundationdb.ReadTransaction)1 Transaction (com.apple.foundationdb.Transaction)1 API (com.apple.foundationdb.annotation.API)1 SpotBugsSuppressWarnings (com.apple.foundationdb.annotation.SpotBugsSuppressWarnings)1 AsyncIterable (com.apple.foundationdb.async.AsyncIterable)1 AsyncIterator (com.apple.foundationdb.async.AsyncIterator)1 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)1 CloseableAsyncIterator (com.apple.foundationdb.async.CloseableAsyncIterator)1 MoreAsyncUtil (com.apple.foundationdb.async.MoreAsyncUtil)1 RangeSet (com.apple.foundationdb.async.RangeSet)1