Search in sources :

Example 1 with MutableRecordStoreState

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

the class FDBRecordStore method getRecordCountForRebuildIndexes.

/**
 * Get count of records to pass to a {@link UserVersionChecker} to decide whether to build right away. If all of the
 * new indexes are over a single type and that type has a record key prefix, then this count will only be over the
 * record type being indexed. If not, it will be the count of all records of all types, as in that case, the indexer
 * will need to scan the entire store to build each index. If determining the record count would be too costly (such
 * as if there is not an appropriate {@linkplain IndexTypes#COUNT count} index defined), this function may return
 * {@link Long#MAX_VALUE} to indicate that an unknown and unbounded number of records would have to be scanned
 * to build the index.
 *
 * @param newStore {@code true} if this is a brand new store
 * @param rebuildRecordCounts {@code true} if there is a record count key that needs to be rebuilt
 * @param indexes indexes that need to be built
 * @param singleRecordTypeWithPrefixKey either a single record type prefixed by the record type key or {@code null}
 * @return a future that completes to the record count for the version checker
 */
@Nonnull
@SuppressWarnings("PMD.EmptyCatchBlock")
protected CompletableFuture<Long> getRecordCountForRebuildIndexes(boolean newStore, boolean rebuildRecordCounts, @Nonnull Map<Index, List<RecordType>> indexes, @Nullable RecordType singleRecordTypeWithPrefixKey) {
    // Do this with the new indexes in write-only mode to avoid using one of them
    // when evaluating the snapshot record count.
    MutableRecordStoreState writeOnlyState = recordStoreStateRef.get().withWriteOnlyIndexes(indexes.keySet().stream().map(Index::getName).collect(Collectors.toList()));
    if (singleRecordTypeWithPrefixKey != null) {
        // Get a count for just those records, either from a COUNT index on just that type or from a universal COUNT index grouped by record type.
        MutableRecordStoreState saveState = recordStoreStateRef.get();
        try {
            recordStoreStateRef.set(writeOnlyState);
            return getSnapshotRecordCountForRecordType(singleRecordTypeWithPrefixKey.getName());
        } catch (RecordCoreException ex) {
        // No such index; have to use total record count.
        } finally {
            recordStoreStateRef.set(saveState);
        }
    }
    if (!rebuildRecordCounts) {
        MutableRecordStoreState saveState = recordStoreStateRef.get();
        try {
            recordStoreStateRef.set(writeOnlyState);
            // See: FDBRecordStoreBase.checkPossiblyRebuild() could take a long time if the record count index is split into many groups (https://github.com/FoundationDB/fdb-record-layer/issues/7)
            return getSnapshotRecordCount();
        } catch (RecordCoreException ex) {
        // Probably this was from the lack of appropriate index on count; treat like rebuildRecordCounts = true.
        } finally {
            recordStoreStateRef.set(saveState);
        }
    }
    // Do a scan (limited to a single record) to see if the store is empty.
    final ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setReturnedRowLimit(1).setIsolationLevel(IsolationLevel.SNAPSHOT).build();
    final ScanProperties scanProperties = new ScanProperties(executeProperties);
    final RecordCursor<FDBStoredRecord<Message>> records;
    if (singleRecordTypeWithPrefixKey == null) {
        records = scanRecords(null, scanProperties);
    } else {
        records = scanRecords(TupleRange.allOf(singleRecordTypeWithPrefixKey.getRecordTypeKeyTuple()), null, scanProperties);
    }
    return records.onNext().thenApply(result -> {
        if (result.hasNext()) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info(KeyValueLogMessage.of("version check scan found non-empty store", subspaceProvider.logKey(), subspaceProvider.toString(context)));
            }
            return Long.MAX_VALUE;
        } else {
            if (newStore ? LOGGER.isDebugEnabled() : LOGGER.isInfoEnabled()) {
                KeyValueLogMessage msg = KeyValueLogMessage.build("version check scan found empty store", subspaceProvider.logKey(), subspaceProvider.toString(context));
                if (newStore) {
                    LOGGER.debug(msg.toString());
                } else {
                    LOGGER.info(msg.toString());
                }
            }
            return 0L;
        }
    });
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) MutableRecordStoreState(com.apple.foundationdb.record.MutableRecordStoreState) ScanProperties(com.apple.foundationdb.record.ScanProperties) FormerIndex(com.apple.foundationdb.record.metadata.FormerIndex) Index(com.apple.foundationdb.record.metadata.Index) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Nonnull(javax.annotation.Nonnull) SpotBugsSuppressWarnings(com.apple.foundationdb.annotation.SpotBugsSuppressWarnings)

Aggregations

SpotBugsSuppressWarnings (com.apple.foundationdb.annotation.SpotBugsSuppressWarnings)1 ExecuteProperties (com.apple.foundationdb.record.ExecuteProperties)1 MutableRecordStoreState (com.apple.foundationdb.record.MutableRecordStoreState)1 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)1 ScanProperties (com.apple.foundationdb.record.ScanProperties)1 KeyValueLogMessage (com.apple.foundationdb.record.logging.KeyValueLogMessage)1 FormerIndex (com.apple.foundationdb.record.metadata.FormerIndex)1 Index (com.apple.foundationdb.record.metadata.Index)1 Nonnull (javax.annotation.Nonnull)1