private <T> SimpleField<T> buildSimpleField(SimpleSchemaField field, String fieldName, FieldType<T> fieldType) { assert field.getEncodingSignature() == fieldType.getEncodingSignature(); return new SimpleField<>(fieldName, field.getStorageId(), this.schema, fieldType, field.isIndexed()); }
@Override public FieldType<?> caseSimpleSchemaField(SimpleSchemaField field) { final FieldType<?> fieldType = JsckInfo.this.config.getFieldTypeRegistry().getFieldType( field.getType(), field.getEncodingSignature()); if (fieldType == null) { throw new IllegalArgumentException("no FieldType named `" + field.getType() + "'" + (field.getEncodingSignature() != 0 ? " with signature " + field.getEncodingSignature() : "") + " (used by " + field + " in schema version " + schemaVersion + ") was found in the configured FieldTypeRepository"); } assert fieldType.getEncodingSignature() == field.getEncodingSignature(); return fieldType; } });
@Override void readAttributes(XMLStreamReader reader, int formatVersion) throws XMLStreamException { super.readAttributes(reader, formatVersion); final String typeAttr = this.getAttr(reader, XMLConstants.TYPE_ATTRIBUTE, false); if (typeAttr != null) this.setType(typeAttr); final Boolean indexedAttr = this.getBooleanAttr(reader, XMLConstants.INDEXED_ATTRIBUTE, false); if (indexedAttr != null) this.setIndexed(indexedAttr); final Long encodingSignatureAttr = this.getLongAttr(reader, XMLConstants.ENCODING_SIGNATURE_ATTRIBUTE, false); if (encodingSignatureAttr != null) this.setEncodingSignature(encodingSignatureAttr); }
@Override public SimpleField<?> caseSimpleSchemaField(SimpleSchemaField field) { final String fieldTypeName = field.getType(); final long signature = field.getEncodingSignature(); final FieldType<?> fieldType = this.fieldTypeRegistry.getFieldType(fieldTypeName, signature); if (fieldType == null) { final StringBuilder buf = new StringBuilder("unknown field type `" + fieldTypeName + "'"); if (signature != 0) buf.append(" with signature ").append(signature); buf.append(" for field `").append(field.getName()).append('\''); boolean foundAny = false; for (FieldType<?> otherFieldType : this.fieldTypeRegistry.getAll()) { if (otherFieldType.getName().equals(fieldTypeName)) { if (!foundAny) { buf.append(" (note: field type(s) named `").append(fieldTypeName) .append("' exist but with different signature(s): "); foundAny = true; } else buf.append(", "); buf.append(otherFieldType.getEncodingSignature()); } } if (foundAny) buf.append(')'); throw new IllegalArgumentException(buf.toString()); } return this.buildSimpleField(field, field.getName(), fieldType); }
SimpleIndex(JsckInfo info, int schemaVersion, SimpleSchemaField field) { super(info, field.getStorageId()); assert field.isIndexed(); this.type = this.info.findFieldType(schemaVersion, field).genericizeForIndex(); }
@Override public Void caseSimpleSchemaField(SimpleSchemaField field) { if (field.isIndexed()) ObjectType.this.indexedSimpleFields.add(field); return null; } @Override
void initialize(JSimpleDB jdb, SimpleSchemaField schemaField) { super.initialize(jdb, schemaField); schemaField.setType(this.fieldType.getName()); schemaField.setIndexed(this.indexed); }
FieldType<?> findFieldType(final int schemaVersion, final SimpleSchemaField schemaField) { return schemaField.visit(new SchemaFieldSwitchAdapter<FieldType<?>>() { @Override public FieldType<?> caseEnumSchemaField(EnumSchemaField field) { return new EnumFieldType(field.getIdentifiers()); } @Override public FieldType<?> caseReferenceSchemaField(ReferenceSchemaField field) { return new ReferenceFieldType(field.getObjectTypes()); } @Override public FieldType<?> caseSimpleSchemaField(SimpleSchemaField field) { final FieldType<?> fieldType = JsckInfo.this.config.getFieldTypeRegistry().getFieldType( field.getType(), field.getEncodingSignature()); if (fieldType == null) { throw new IllegalArgumentException("no FieldType named `" + field.getType() + "'" + (field.getEncodingSignature() != 0 ? " with signature " + field.getEncodingSignature() : "") + " (used by " + field + " in schema version " + schemaVersion + ") was found in the configured FieldTypeRepository"); } assert fieldType.getEncodingSignature() == field.getEncodingSignature(); return fieldType; } }); }
@Override public Void caseSimpleSchemaField(SimpleSchemaField field) { final byte[] value = ObjectType.this.checkSimpleField(info, id, field, fieldPrefix, i); simpleFieldValues.put(field.getStorageId(), value); if (value != null) indexedSimpleFieldsWithDefaultValues.remove(field); return null; } @Override
@Override public Void caseSimpleSchemaField(SimpleSchemaField field) { final FieldType<?> fieldType = info.getConfig().getFieldTypeRegistry().getFieldType(field.getType()); ObjectType.this.simpleFieldTypes.put(field.getStorageId(), fieldType); return null; } @Override
@Override public EnumSchemaField clone() { final EnumSchemaField clone = (EnumSchemaField)super.clone(); clone.idents = new ArrayList<>(this.idents); return clone; } }
@Override SimpleSchemaField toSchemaItem(JSimpleDB jdb) { final SimpleSchemaField schemaField = new SimpleSchemaField(); this.initialize(jdb, schemaField); return schemaField; }
@Override public Diffs differencesFrom(SimpleSchemaField that) { final Diffs diffs = new Diffs(super.differencesFrom(that)); this.addTypeDifference(diffs, that); if (this.encodingSignature != that.encodingSignature) diffs.add("changed field type encoding signature from " + that.encodingSignature + " to " + this.encodingSignature); if (this.indexed != that.indexed) diffs.add((this.indexed ? "added" : "removed") + " index on field"); return diffs; }
private byte[] checkSimpleField(JsckInfo info, ObjId id, SimpleSchemaField field, byte[] prefix, PeekingIterator<KVPair> i) { // Get field type final FieldType<?> fieldType = this.simpleFieldTypes.get(field.getStorageId()); assert fieldType != null; // Get field key/value pair final KVPair pair = i.next(); assert pair != null; assert ByteUtil.isPrefixOf(prefix, pair.getKey()); // Check for trailing garbage in key if (pair.getKey().length > prefix.length) { info.handle(new InvalidKey(pair).setDetail(id, field, "trailing garbage " + Jsck.ds(new ByteReader(pair.getKey(), prefix.length)))); return null; } // Decode value byte[] value = pair.getValue(); final ByteReader reader = new ByteReader(pair.getValue()); if (!this.validateSimpleFieldValue(info, id, field, pair, reader)) value = null; // We should not see default values in simple fields that are not sub-fields of complex fields if (value != null && ByteUtil.compare(value, fieldType.getDefaultValue()) == 0) { info.handle(new InvalidValue(pair).setDetail("default value; should not be present")); value = null; } // Verify index entry if (field.isIndexed()) this.verifySimpleIndexEntry(info, id, field, value != null ? value : fieldType.getDefaultValue()); // Done return value; }
@Override public Void caseSimpleSchemaField(SimpleSchemaField field) { if (field.isIndexed()) JsckInfo.this.addStorage(schemaVersion, new SimpleFieldIndex(JsckInfo.this, schemaVersion, field)); return null; }
@Override protected Void caseCollectionSchemaField(CollectionSchemaField field) { field.getElementField().visit(this); return null; } @Override
private void verifySimpleIndexEntry(JsckInfo info, ObjId id, SimpleSchemaField subField, ComplexSchemaField field, byte[] value, byte[] suffix) { this.verifySimpleIndexEntry(info, id, subField.getStorageId(), "sub-" + subField + " of " + field + " index", value, suffix); }
@Override public ReferenceSchemaField clone() { final ReferenceSchemaField clone = (ReferenceSchemaField)super.clone(); if (clone.objectTypes != null) clone.objectTypes = new TreeSet<>(clone.objectTypes); return clone; } }
@Override public Void caseSetSchemaField(SetSchemaField field) { if (field.getElementField().isIndexed()) JsckInfo.this.addStorage(schemaVersion, new SetElementIndex(JsckInfo.this, schemaVersion, field)); return null; }