Search in sources :

Example 1 with SyntheticRecordFromStoredRecordPlan

use of com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan 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 2 with SyntheticRecordFromStoredRecordPlan

use of com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan 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

SyntheticRecordFromStoredRecordPlan (com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordFromStoredRecordPlan)2 SyntheticRecordPlanner (com.apple.foundationdb.record.query.plan.synthetic.SyntheticRecordPlanner)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 AggregateFunctionNotSupportedException (com.apple.foundationdb.record.AggregateFunctionNotSupportedException)1 ByteScanLimiter (com.apple.foundationdb.record.ByteScanLimiter)1 CursorStreamingMode (com.apple.foundationdb.record.CursorStreamingMode)1 EndpointType (com.apple.foundationdb.record.EndpointType)1 EvaluationContext (com.apple.foundationdb.record.EvaluationContext)1