use of com.apple.foundationdb.record.metadata.IndexValidator 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);
}
};
}
use of com.apple.foundationdb.record.metadata.IndexValidator 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());
}
}
};
}
use of com.apple.foundationdb.record.metadata.IndexValidator 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);
}
};
}
Aggregations