Search in sources :

Example 6 with RecordCoreException

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

the class RankIndexMaintainer method scan.

@Nonnull
@Override
public RecordCursor<IndexEntry> scan(@Nonnull IndexScanType scanType, @Nonnull TupleRange rankRange, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    if (scanType == IndexScanType.BY_VALUE) {
        return scan(rankRange, continuation, scanProperties);
    } else if (scanType != IndexScanType.BY_RANK) {
        throw new RecordCoreException("Can only scan rank index by rank or by value.");
    }
    final Subspace extraSubspace = getSecondarySubspace();
    final CompletableFuture<TupleRange> scoreRangeFuture = RankedSetIndexHelper.rankRangeToScoreRange(state, getGroupingCount(), extraSubspace, config, rankRange);
    return RecordCursor.mapFuture(getExecutor(), scoreRangeFuture, continuation, (scoreRange, scoreContinuation) -> {
        if (scoreRange == null) {
            return RecordCursor.empty(getExecutor());
        } else {
            return scan(scoreRange, scoreContinuation, scanProperties);
        }
    });
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Subspace(com.apple.foundationdb.subspace.Subspace) TupleRange(com.apple.foundationdb.record.TupleRange) Nonnull(javax.annotation.Nonnull)

Example 7 with RecordCoreException

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

the class BitmapValueIndexMaintainer method scan.

@Nonnull
@Override
public RecordCursor<IndexEntry> scan(@Nonnull IndexScanType scanType, @Nonnull TupleRange range, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    if (scanType != IndexScanType.BY_GROUP) {
        throw new RecordCoreException("Can only scan bitmap index by group.");
    }
    final int groupPrefixSize = getGroupingCount();
    final long startPosition;
    if (range.getLow() != null && range.getLow().size() > groupPrefixSize && range.getLow().get(groupPrefixSize) != null) {
        if (range.getLowEndpoint() == EndpointType.RANGE_EXCLUSIVE) {
            startPosition = range.getLow().getLong(groupPrefixSize) + 1;
        } else {
            startPosition = range.getLow().getLong(groupPrefixSize);
        }
        if (startPosition % entrySize != 0) {
            range = new TupleRange(range.getLow().popBack().add(startPosition - Math.floorMod(startPosition, (long) entrySize)), range.getHigh(), EndpointType.RANGE_INCLUSIVE, range.getHighEndpoint());
        }
    } else {
        startPosition = Long.MIN_VALUE;
    }
    final long endPosition;
    if (range.getHigh() != null && range.getHigh().size() > groupPrefixSize && range.getHigh().get(groupPrefixSize) != null) {
        if (range.getHighEndpoint() == EndpointType.RANGE_INCLUSIVE) {
            endPosition = range.getHigh().getLong(groupPrefixSize) + 1;
        } else {
            endPosition = range.getHigh().getLong(groupPrefixSize);
        }
        if (endPosition % entrySize != 0) {
            range = new TupleRange(range.getLow(), range.getHigh().popBack().add(endPosition + Math.floorMod(entrySize - endPosition, (long) entrySize)), range.getLowEndpoint(), EndpointType.RANGE_INCLUSIVE);
        }
    } else {
        endPosition = Long.MAX_VALUE;
    }
    return scan(range, continuation, scanProperties).map(indexEntry -> {
        final long entryStart = indexEntry.getKey().getLong(groupPrefixSize);
        final byte[] entryBitmap = indexEntry.getValue().getBytes(0);
        final long entryEnd = entryStart + entryBitmap.length * 8;
        if (entryStart < startPosition || entryEnd > endPosition) {
            final long trimmedStart = Math.max(entryStart, startPosition);
            final long trimmedEnd = Math.min(entryEnd, endPosition);
            if (trimmedStart < trimmedEnd) {
                final Tuple trimmedKey = indexEntry.getKey().popBack().add(trimmedStart);
                final byte[] trimmedBitmap = new byte[((int) (trimmedEnd - trimmedStart) + 7) / 8];
                for (long i = trimmedStart; i < trimmedEnd; i++) {
                    int offset = (int) (i - entryStart);
                    if ((entryBitmap[offset / 8] & (byte) (1 << (offset % 8))) != 0) {
                        int trimmedOffset = (int) (i - trimmedStart);
                        trimmedBitmap[trimmedOffset / 8] |= (byte) (1 << (trimmedOffset % 8));
                    }
                }
                final Tuple subValue = Tuple.from(trimmedBitmap);
                return Optional.of(new IndexEntry(indexEntry.getIndex(), trimmedKey, subValue));
            } else {
                return Optional.<IndexEntry>empty();
            }
        } else {
            return Optional.of(indexEntry);
        }
    }).filter(Optional::isPresent).map(Optional::get);
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Optional(java.util.Optional) IndexEntry(com.apple.foundationdb.record.IndexEntry) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 8 with RecordCoreException

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

the class BitmapValueIndexMaintainer method updateIndexKeys.

@Override
@Nonnull
protected <M extends Message> CompletableFuture<Void> updateIndexKeys(@Nonnull final FDBIndexableRecord<M> savedRecord, final boolean remove, @Nonnull final List<IndexEntry> indexEntries) {
    final int groupPrefixSize = getGroupingCount();
    final List<CompletableFuture<Void>> futures = unique && !remove ? new ArrayList<>(indexEntries.size()) : null;
    for (IndexEntry indexEntry : indexEntries) {
        final long startTime = System.nanoTime();
        final Tuple groupKey = TupleHelpers.subTuple(indexEntry.getKey(), 0, groupPrefixSize);
        Object positionObject = indexEntry.getKey().get(groupPrefixSize);
        if (positionObject == null) {
            continue;
        }
        if (!(positionObject instanceof Number)) {
            // This should be prevented by the checks in the meta-data builder, but just in case
            throw new RecordCoreException("position field in index entry is not a number").addLogInfo(LogMessageKeys.KEY, indexEntry.getKey(), LogMessageKeys.INDEX_NAME, state.index.getName(), LogMessageKeys.INDEX_TYPE, state.index.getType());
        }
        long position = ((Number) positionObject).longValue();
        final int offset = (int) Math.floorMod(position, (long) entrySize);
        position -= offset;
        final byte[] key = state.indexSubspace.pack(groupKey.add(position));
        // This has to be the same size every time, with all the unset bits, or else it gets truncated.
        // We really could use a new mutation that took a linear bit position to set / clear and only did length extension or something like that.
        final byte[] bitmap = new byte[(entrySize + 7) / 8];
        if (remove) {
            if (state.store.isIndexWriteOnly(state.index)) {
                // If the index isn't built, it's possible this key wasn't reached.
                // So initialize it to zeros (or leave it alone).
                state.transaction.mutate(MutationType.BIT_OR, key, bitmap);
            }
            // Otherwise the entry must already exist for us to be removing it,
            // so there is no danger that this will store all (but one) ones in a new key.
            Arrays.fill(bitmap, (byte) 0xFF);
            bitmap[offset / 8] &= ~(byte) (1 << (offset % 8));
            state.transaction.mutate(MutationType.BIT_AND, key, bitmap);
            Arrays.fill(bitmap, (byte) 0x00);
            state.transaction.mutate(MutationType.COMPARE_AND_CLEAR, key, bitmap);
        } else {
            if (unique) {
                // Snapshot read to see if the bit is already set.
                CompletableFuture<Void> future = state.transaction.snapshot().get(key).thenAccept(existing -> {
                    if (existing != null && (existing[offset / 8] & (byte) (1 << (offset % 8))) != 0) {
                        throw new RecordIndexUniquenessViolation(state.index, indexEntry, savedRecord.getPrimaryKey(), // Unfortunately, we don't know the other key.
                        null);
                    }
                });
                futures.add(future);
                // Then arrange to conflict for the position with any concurrent update.
                final byte[] conflictKey = new Subspace(key).pack(offset);
                state.transaction.addReadConflictKey(conflictKey);
                state.transaction.addWriteConflictKey(conflictKey);
            }
            bitmap[offset / 8] |= (byte) (1 << (offset % 8));
            state.transaction.mutate(MutationType.BIT_OR, key, bitmap);
        }
        if (state.store.getTimer() != null) {
            state.store.getTimer().recordSinceNanoTime(FDBStoreTimer.Events.MUTATE_INDEX_ENTRY, startTime);
        }
    }
    return futures != null ? AsyncUtil.whenAll(futures) : AsyncUtil.DONE;
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) CompletableFuture(java.util.concurrent.CompletableFuture) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) Subspace(com.apple.foundationdb.subspace.Subspace) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Example 9 with RecordCoreException

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

the class ComparatorCursor method compareAllStates.

private boolean compareAllStates(final List<KeyedMergeCursorState<T>> cursorStates) {
    final long startTime = System.nanoTime();
    List<Object> referenceKey = getReferenceState(cursorStates).getComparisonKey();
    for (KeyedMergeCursorState<T> cursorState : cursorStates) {
        // No point comparing the reference key to itself
        if (cursorState.getComparisonKey() == referenceKey) {
            continue;
        }
        int compare = KeyComparisons.KEY_COMPARATOR.compare(cursorState.getComparisonKey(), referenceKey);
        if (compare != 0) {
            logComparisonFailure(referenceKey, cursorState.getComparisonKey());
            if (abortOnComparisonFailure) {
                throw new RecordCoreException("Comparison of plans failed").addLogInfo(LogMessageKeys.EXPECTED, referenceKey).addLogInfo(LogMessageKeys.ACTUAL, cursorState.getComparisonKey()).addLogInfo(LogMessageKeys.PLAN_HASH, planHashSupplier.get());
            } else {
                return false;
            }
        }
    }
    logCounters(cursorStates, startTime);
    return true;
}
Also used : RecordCoreException(com.apple.foundationdb.record.RecordCoreException)

Example 10 with RecordCoreException

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

the class SyntheticRecordPlanner method forIndex.

/**
 * Construct a plan for generating synthetic records for a given index.
 *
 * The generated records will be of indexed record types.
 *
 * Used by the {@link com.apple.foundationdb.record.provider.foundationdb.OnlineIndexer} to build from a full scan of stored records.
 * @param index an index on synthetic record types
 * @return a plan that can be applied to scanned records to generate synthetic records
 */
@Nonnull
public SyntheticRecordFromStoredRecordPlan forIndex(@Nonnull Index index) {
    final Collection<RecordType> recordTypes = recordMetaData.recordTypesForIndex(index);
    if (recordTypes.size() == 1) {
        final RecordType recordType = recordTypes.iterator().next();
        if (!recordType.isSynthetic()) {
            throw new RecordCoreException("Index does not apply to synthetic record types " + index);
        }
        return forType((SyntheticRecordType<?>) recordType);
    }
    Multimap<String, SyntheticRecordFromStoredRecordPlan> byType = ArrayListMultimap.create();
    for (RecordType recordType : recordTypes) {
        if (!(recordType instanceof JoinedRecordType)) {
            throw unknownSyntheticType(recordType);
        }
        JoinedRecordType joinedRecordType = (JoinedRecordType) recordType;
        Optional<JoinedRecordType.JoinConstituent> maybeConstituent = joinedRecordType.getConstituents().stream().filter(c -> !c.isOuterJoined()).findFirst();
        if (maybeConstituent.isPresent()) {
            addToByType(byType, joinedRecordType, maybeConstituent.get());
        } else {
            for (JoinedRecordType.JoinConstituent joinConstituent : joinedRecordType.getConstituents()) {
                addToByType(byType, joinedRecordType, joinConstituent);
            }
        }
    }
    return createByType(byType);
}
Also used : ArrayListMultimap(com.google.common.collect.ArrayListMultimap) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) HashMap(java.util.HashMap) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Multimap(com.google.common.collect.Multimap) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ArrayList(java.util.ArrayList) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) HashSet(java.util.HashSet) JoinedRecordType(com.apple.foundationdb.record.metadata.JoinedRecordType) FDBRecordStore(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStore) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Map(java.util.Map) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) Collection(java.util.Collection) Set(java.util.Set) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) List(java.util.List) RecordType(com.apple.foundationdb.record.metadata.RecordType) SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) Index(com.apple.foundationdb.record.metadata.Index) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) Optional(java.util.Optional) API(com.apple.foundationdb.annotation.API) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) JoinedRecordType(com.apple.foundationdb.record.metadata.JoinedRecordType) RecordType(com.apple.foundationdb.record.metadata.RecordType) SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) JoinedRecordType(com.apple.foundationdb.record.metadata.JoinedRecordType) Nonnull(javax.annotation.Nonnull)

Aggregations

RecordCoreException (com.apple.foundationdb.record.RecordCoreException)121 Nonnull (javax.annotation.Nonnull)58 Test (org.junit.jupiter.api.Test)42 Index (com.apple.foundationdb.record.metadata.Index)37 List (java.util.List)35 Nullable (javax.annotation.Nullable)31 Tuple (com.apple.foundationdb.tuple.Tuple)29 ArrayList (java.util.ArrayList)27 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)26 CompletableFuture (java.util.concurrent.CompletableFuture)25 Collectors (java.util.stream.Collectors)24 Collections (java.util.Collections)22 GroupingKeyExpression (com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression)19 Set (java.util.Set)19 Function (java.util.function.Function)19 IndexEntry (com.apple.foundationdb.record.IndexEntry)17 TupleRange (com.apple.foundationdb.record.TupleRange)17 IndexTypes (com.apple.foundationdb.record.metadata.IndexTypes)17 RecordCursor (com.apple.foundationdb.record.RecordCursor)16 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)15