Search in sources :

Example 1 with MetaDataValidator

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

the class RecordMetaDataBuilder method build.

/**
 * Build and validate meta-data with specific index registry.
 * @param validate {@code true} to validate the new meta-data
 * @return new meta-data
 */
@Nonnull
public RecordMetaData build(boolean validate) {
    Map<String, RecordType> builtRecordTypes = Maps.newHashMapWithExpectedSize(recordTypes.size());
    Map<String, SyntheticRecordType<?>> builtSyntheticRecordTypes = Maps.newHashMapWithExpectedSize(syntheticRecordTypes.size());
    RecordMetaData metaData = new RecordMetaData(recordsDescriptor, getUnionDescriptor(), unionFields, builtRecordTypes, builtSyntheticRecordTypes, indexes, universalIndexes, formerIndexes, splitLongRecords, storeRecordVersions, version, subspaceKeyCounter, usesSubspaceKeyCounter, recordCountKey, localFileDescriptor != null);
    for (RecordTypeBuilder recordTypeBuilder : recordTypes.values()) {
        KeyExpression primaryKey = recordTypeBuilder.getPrimaryKey();
        if (primaryKey != null) {
            builtRecordTypes.put(recordTypeBuilder.getName(), recordTypeBuilder.build(metaData));
            for (Index index : recordTypeBuilder.getIndexes()) {
                index.setPrimaryKeyComponentPositions(buildPrimaryKeyComponentPositions(index.getRootExpression(), primaryKey));
            }
        } else {
            throw new MetaDataException("Record type " + recordTypeBuilder.getName() + " must have a primary key");
        }
    }
    if (!syntheticRecordTypes.isEmpty()) {
        DescriptorProtos.FileDescriptorProto.Builder fileBuilder = DescriptorProtos.FileDescriptorProto.newBuilder();
        fileBuilder.setName("_synthetic");
        fileBuilder.addDependency(unionDescriptor.getFile().getName());
        syntheticRecordTypes.values().forEach(recordTypeBuilder -> recordTypeBuilder.buildDescriptor(fileBuilder));
        final Descriptors.FileDescriptor fileDescriptor;
        try {
            final Descriptors.FileDescriptor[] dependencies = new Descriptors.FileDescriptor[] { unionDescriptor.getFile() };
            fileDescriptor = Descriptors.FileDescriptor.buildFrom(fileBuilder.build(), dependencies);
        } catch (Descriptors.DescriptorValidationException ex) {
            throw new MetaDataException("Could not build synthesized file descriptor", ex);
        }
        for (SyntheticRecordTypeBuilder<?> recordTypeBuilder : syntheticRecordTypes.values()) {
            builtSyntheticRecordTypes.put(recordTypeBuilder.getName(), recordTypeBuilder.build(metaData, fileDescriptor));
        }
    }
    if (validate) {
        final MetaDataValidator validator = new MetaDataValidator(metaData, indexMaintainerRegistry);
        validator.validate();
    }
    return metaData;
}
Also used : SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) LiteralKeyExpression(com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) FormerIndex(com.apple.foundationdb.record.metadata.FormerIndex) Index(com.apple.foundationdb.record.metadata.Index) SyntheticRecordTypeBuilder(com.apple.foundationdb.record.metadata.SyntheticRecordTypeBuilder) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) JoinedRecordTypeBuilder(com.apple.foundationdb.record.metadata.JoinedRecordTypeBuilder) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) RecordType(com.apple.foundationdb.record.metadata.RecordType) SyntheticRecordType(com.apple.foundationdb.record.metadata.SyntheticRecordType) Descriptors(com.google.protobuf.Descriptors) MetaDataValidator(com.apple.foundationdb.record.metadata.MetaDataValidator) Nonnull(javax.annotation.Nonnull)

Example 2 with MetaDataValidator

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

the class PermutedMinMaxIndexMaintainerFactory method getIndexValidator.

@Override
@Nonnull
public IndexValidator getIndexValidator(Index index) {
    return new IndexValidator(index) {

        @Override
        public void validate(@Nonnull MetaDataValidator metaDataValidator) {
            super.validate(metaDataValidator);
            validateGrouping(1);
            int groupingCount = ((GroupingKeyExpression) index.getRootExpression()).getGroupingCount();
            validateNotVersion();
            int permutedSize = PermutedMinMaxIndexMaintainer.getPermutedSize(index);
            if (permutedSize < 0) {
                throw new MetaDataException("permuted size cannot be negative", LogMessageKeys.INDEX_NAME, index.getName());
            } else if (permutedSize == 0) {
                throw new MetaDataException("no permutation does not need a special index type for MIN and MAX", LogMessageKeys.INDEX_NAME, index.getName());
            } else if (permutedSize > groupingCount) {
                throw new MetaDataException("permuted size cannot be larger than grouping size", LogMessageKeys.INDEX_NAME, index.getName());
            }
        }

        @Override
        public void validateChangedOptions(@Nonnull Index oldIndex, @Nonnull Set<String> changedOptions) {
            if (changedOptions.contains(IndexOptions.PERMUTED_SIZE_OPTION)) {
                throw new MetaDataException("permuted size changed", LogMessageKeys.INDEX_NAME, index.getName());
            }
            super.validateChangedOptions(oldIndex, changedOptions);
        }
    };
}
Also used : IndexValidator(com.apple.foundationdb.record.metadata.IndexValidator) Set(java.util.Set) Nonnull(javax.annotation.Nonnull) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Index(com.apple.foundationdb.record.metadata.Index) MetaDataValidator(com.apple.foundationdb.record.metadata.MetaDataValidator) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Nonnull(javax.annotation.Nonnull)

Example 3 with MetaDataValidator

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

the class BitmapValueIndexMaintainerFactory method getIndexValidator.

@Override
@Nonnull
public IndexValidator getIndexValidator(Index index) {
    return new IndexValidator(index) {

        @Override
        public void validate(@Nonnull MetaDataValidator metaDataValidator) {
            super.validate(metaDataValidator);
            validateGrouping(1);
            final GroupingKeyExpression group = (GroupingKeyExpression) index.getRootExpression();
            if (group.getGroupedCount() != 1) {
                throw new KeyExpression.InvalidExpressionException(String.format("%s index needs grouped position", index.getType()), LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.INDEX_KEY, index.getRootExpression());
            }
            validateNotVersion();
        }

        @Override
        @SuppressWarnings("fallthrough")
        public void validateIndexForRecordType(@Nonnull RecordType recordType, @Nonnull MetaDataValidator metaDataValidator) {
            final List<Descriptors.FieldDescriptor> fields = metaDataValidator.validateIndexForRecordType(index, recordType);
            switch(fields.get(fields.size() - 1).getType()) {
                case INT64:
                case UINT64:
                case INT32:
                case UINT32:
                case SINT32:
                case SINT64:
                case FIXED32:
                case FIXED64:
                case SFIXED32:
                case SFIXED64:
                    break;
                default:
                    throw new KeyExpression.InvalidExpressionException(String.format("%s index only supports integer position key", index.getType()), LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.INDEX_KEY, index.getRootExpression(), "record_type", recordType.getName());
            }
        }
    };
}
Also used : IndexValidator(com.apple.foundationdb.record.metadata.IndexValidator) RecordType(com.apple.foundationdb.record.metadata.RecordType) Nonnull(javax.annotation.Nonnull) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) MetaDataValidator(com.apple.foundationdb.record.metadata.MetaDataValidator) Nonnull(javax.annotation.Nonnull)

Example 4 with MetaDataValidator

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

the class TextIndexMaintainerFactory method getIndexValidator.

/**
 * Validates that the index provided is valid for text indexes. This means that
 * the index must:
 *
 * <ul>
 *     <li>Not be a unique index.</li>
 *     <li>Not include a {@link com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression#VERSION} expression in its root expression.</li>
 *     <li>Have a key expression whose first column is of type <code>string</code> (possibly with grouping columns
 *         before the tokenized text column) and is not repeated.</li> <!--Maybe we should support FanType.Concatenate?-->
 *     <li>Specify a valid tokenizer and tokenizer version through the index options (possibly using the defaults).</li>
 *     <li>Not define a value expression.</li>
 * </ul>
 *
 * @param index the index to validate
 * @return a validator to run against the index
 * @throws KeyExpression.InvalidExpressionException if the expression does not contain a string as its first ungrouped column
 * @throws com.apple.foundationdb.record.metadata.MetaDataException if the tokenizer is not defined, if the tokenizer version
 *                                                    is out of range, or if the index is marked as unique
 */
@Nonnull
@Override
public IndexValidator getIndexValidator(Index index) {
    return new IndexValidator(index) {

        @Override
        public void validate(@Nonnull MetaDataValidator metaDataValidator) {
            super.validate(metaDataValidator);
            validateNotVersion();
            validateNotUnique();
            // TODO: allow value expressions for covering text indexes
            validateNoValue();
            // Validate that the tokenizer exists and that the version is in a valid range.
            TextTokenizer tokenizer = TextIndexMaintainer.getTokenizer(index);
            int tokenizerVersion = TextIndexMaintainer.getIndexTokenizerVersion(index);
            tokenizer.validateVersion(tokenizerVersion);
        }

        @Override
        public void validateIndexForRecordType(@Nonnull RecordType recordType, @Nonnull MetaDataValidator metaDataValidator) {
            final List<Descriptors.FieldDescriptor> fields = metaDataValidator.validateIndexForRecordType(index, recordType);
            int textFieldPosition = TextIndexMaintainer.textFieldPosition(index.getRootExpression());
            if (textFieldPosition > fields.size()) {
                throw new KeyExpression.InvalidExpressionException("text index does not have text field after grouped fields");
            } else {
                Descriptors.FieldDescriptor textFieldDescriptor = fields.get(textFieldPosition);
                if (!textFieldDescriptor.getType().equals(Descriptors.FieldDescriptor.Type.STRING)) {
                    throw new KeyExpression.InvalidExpressionException(String.format("text index has non-string type %s as text field", textFieldDescriptor.getLiteJavaType()));
                }
                if (textFieldDescriptor.isRepeated()) {
                    throw new KeyExpression.InvalidExpressionException("text index does not allow a repeated field for text body");
                }
            }
        }

        /**
         * Validate any options that have changed. There are several options unique to text indexes which
         * may change without requiring the index be rebuilt. They are:
         *
         * <ul>
         *     <li>{@link IndexOptions#TEXT_TOKENIZER_VERSION_OPTION} which can be increased (but not decreased)</li>
         *     <li>{@link IndexOptions#TEXT_ADD_AGGRESSIVE_CONFLICT_RANGES_OPTION} which only affects what conflict ranges
         *          are added at index update time and thus has no impact on the on-disk representation</li>
         *     <li>{@link IndexOptions#TEXT_OMIT_POSITIONS_OPTION} which changes whether the position lists are included
         *          in index entries</li>
         * </ul>
         *
         * <p>
         * Note that the {@link IndexOptions#TEXT_TOKENIZER_NAME_OPTION} is <em>not</em> allowed to change
         * (without rebuilding the index).
         * </p>
         *
         * @param oldIndex an older version of this index
         * @param changedOptions the set of changed options
         */
        @Override
        protected void validateChangedOptions(@Nonnull Index oldIndex, @Nonnull Set<String> changedOptions) {
            for (String changedOption : changedOptions) {
                switch(changedOption) {
                    case IndexOptions.TEXT_ADD_AGGRESSIVE_CONFLICT_RANGES_OPTION:
                    case IndexOptions.TEXT_OMIT_POSITIONS_OPTION:
                        // without breaking compatibility.
                        break;
                    case IndexOptions.TEXT_TOKENIZER_NAME_OPTION:
                        String oldTokenizerName = TextIndexMaintainer.getTokenizer(oldIndex).getName();
                        String newTokenizerName = TextIndexMaintainer.getTokenizer(index).getName();
                        if (!oldTokenizerName.equals(newTokenizerName)) {
                            throw new MetaDataException("text tokenizer changed", LogMessageKeys.INDEX_NAME, index.getName());
                        }
                        break;
                    case IndexOptions.TEXT_TOKENIZER_VERSION_OPTION:
                        // The tokenizer version should always go up.
                        int oldTokenizerVersion = TextIndexMaintainer.getIndexTokenizerVersion(oldIndex);
                        int newTokenizerVersion = TextIndexMaintainer.getIndexTokenizerVersion(index);
                        if (oldTokenizerVersion > newTokenizerVersion) {
                            throw new MetaDataException("text tokenizer version downgraded", LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.OLD_VERSION, oldTokenizerVersion, LogMessageKeys.NEW_VERSION, newTokenizerVersion);
                        }
                        break;
                    default:
                        // Changed options that are not text options will be handled by super class
                        if (TEXT_OPTIONS.contains(changedOption)) {
                            throw new MetaDataException("index option changed", LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.INDEX_OPTION, changedOption, LogMessageKeys.OLD_OPTION, oldIndex.getOption(changedOption), LogMessageKeys.NEW_OPTION, index.getOption(changedOption));
                        }
                }
            }
            changedOptions.removeAll(TEXT_OPTIONS);
            super.validateChangedOptions(oldIndex, changedOptions);
        }
    };
}
Also used : IndexValidator(com.apple.foundationdb.record.metadata.IndexValidator) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) Nonnull(javax.annotation.Nonnull) Index(com.apple.foundationdb.record.metadata.Index) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) TextTokenizer(com.apple.foundationdb.record.provider.common.text.TextTokenizer) RecordType(com.apple.foundationdb.record.metadata.RecordType) MetaDataValidator(com.apple.foundationdb.record.metadata.MetaDataValidator) Descriptors(com.google.protobuf.Descriptors) Nonnull(javax.annotation.Nonnull)

Aggregations

MetaDataValidator (com.apple.foundationdb.record.metadata.MetaDataValidator)4 Nonnull (javax.annotation.Nonnull)4 Index (com.apple.foundationdb.record.metadata.Index)3 IndexValidator (com.apple.foundationdb.record.metadata.IndexValidator)3 MetaDataException (com.apple.foundationdb.record.metadata.MetaDataException)3 RecordType (com.apple.foundationdb.record.metadata.RecordType)3 GroupingKeyExpression (com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression)2 Descriptors (com.google.protobuf.Descriptors)2 Set (java.util.Set)2 FormerIndex (com.apple.foundationdb.record.metadata.FormerIndex)1 JoinedRecordTypeBuilder (com.apple.foundationdb.record.metadata.JoinedRecordTypeBuilder)1 RecordTypeBuilder (com.apple.foundationdb.record.metadata.RecordTypeBuilder)1 SyntheticRecordType (com.apple.foundationdb.record.metadata.SyntheticRecordType)1 SyntheticRecordTypeBuilder (com.apple.foundationdb.record.metadata.SyntheticRecordTypeBuilder)1 FieldKeyExpression (com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression)1 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)1 LiteralKeyExpression (com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression)1 TextTokenizer (com.apple.foundationdb.record.provider.common.text.TextTokenizer)1 ImmutableSet (com.google.common.collect.ImmutableSet)1