use of com.apple.foundationdb.record.RecordMetaData in project fdb-record-layer by FoundationDB.
the class RecordTypeKeyTest method testExplicitKeys.
@Test
public void testExplicitKeys() throws Exception {
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecords1Proto.getDescriptor());
final RecordTypeBuilder t1 = metaDataBuilder.getRecordType("MySimpleRecord");
final RecordTypeBuilder t2 = metaDataBuilder.getRecordType("MyOtherRecord");
final KeyExpression pkey = concat(recordType(), field("rec_no"));
t1.setPrimaryKey(pkey);
t1.setRecordTypeKey("t1");
t2.setPrimaryKey(pkey);
RecordMetaData metaData = metaDataBuilder.getRecordMetaData();
assertEquals("t1", metaData.getRecordType("MySimpleRecord").getExplicitRecordTypeKey());
assertNull(metaData.getRecordType("MyOtherRecord").getExplicitRecordTypeKey());
metaData = RecordMetaData.build(metaData.toProto());
assertEquals("t1", metaData.getRecordType("MySimpleRecord").getExplicitRecordTypeKey());
assertNull(metaData.getRecordType("MyOtherRecord").getExplicitRecordTypeKey());
}
use of com.apple.foundationdb.record.RecordMetaData in project fdb-record-layer by FoundationDB.
the class MetaDataProtoEditorTest method nestedFieldIsTypeUnqualified.
@Test
public void nestedFieldIsTypeUnqualified() throws Descriptors.DescriptorValidationException {
final DescriptorProtos.FileDescriptorProto.Builder fileBuilder = TestRecordsDoubleNestedProto.getDescriptor().toProto().toBuilder();
final DescriptorProtos.FieldDescriptorProto.Builder innerBuilder = fileBuilder.getMessageTypeBuilderList().stream().filter(message -> message.getName().equals("OuterRecord")).flatMap(message -> message.getFieldBuilderList().stream()).filter(field -> field.getName().equals("inner")).findAny().get();
// Unqualify the inner field
innerBuilder.setTypeName("MiddleRecord.InnerRecord");
// Ensure that the type actually resolves to the same type
Descriptors.FileDescriptor modifiedFileDescriptor = Descriptors.FileDescriptor.buildFrom(fileBuilder.build(), TestRecordsDoubleNestedProto.getDescriptor().getDependencies().toArray(new Descriptors.FileDescriptor[0]));
Descriptors.Descriptor innerRecordDescriptor = modifiedFileDescriptor.findMessageTypeByName("OuterRecord").findNestedTypeByName("MiddleRecord").findNestedTypeByName("InnerRecord");
assertNotNull(innerRecordDescriptor);
assertSame(innerRecordDescriptor, modifiedFileDescriptor.findMessageTypeByName("OuterRecord").findFieldByName("inner").getMessageType());
assertEquals(FieldTypeMatch.MIGHT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord.MiddleRecord.InnerRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH_AS_NESTED, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord.MiddleRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH_AS_NESTED, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", "MiddleRecord.InnerRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH_AS_NESTED, fieldIsType(fileBuilder, "OuterRecord", "inner", "MiddleRecord"));
assertEquals(FieldTypeMatch.DOES_NOT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", ".com.apple.foundationdb.record.test.doublenested.OtherRecord"));
innerBuilder.setTypeName("OuterRecord.MiddleRecord.InnerRecord");
modifiedFileDescriptor = Descriptors.FileDescriptor.buildFrom(fileBuilder.build(), TestRecordsDoubleNestedProto.getDescriptor().getDependencies().toArray(new Descriptors.FileDescriptor[0]));
innerRecordDescriptor = modifiedFileDescriptor.findMessageTypeByName("OuterRecord").findNestedTypeByName("MiddleRecord").findNestedTypeByName("InnerRecord");
assertNotNull(innerRecordDescriptor);
assertSame(innerRecordDescriptor, modifiedFileDescriptor.findMessageTypeByName("OuterRecord").findFieldByName("inner").getMessageType());
assertEquals(FieldTypeMatch.MIGHT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord.MiddleRecord.InnerRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH_AS_NESTED, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord.MiddleRecord"));
assertEquals(FieldTypeMatch.MIGHT_MATCH_AS_NESTED, fieldIsType(fileBuilder, "OuterRecord", "inner", "OuterRecord"));
assertEquals(FieldTypeMatch.DOES_NOT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", "MiddleRecord.InnerRecord"));
assertEquals(FieldTypeMatch.DOES_NOT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", "MiddleRecord"));
assertEquals(FieldTypeMatch.DOES_NOT_MATCH, fieldIsType(fileBuilder, "OuterRecord", "inner", ".com.apple.foundationdb.record.test.doublenested.OtherRecord"));
RecordMetaData metaData = RecordMetaData.build(modifiedFileDescriptor);
RecordMetaDataProto.MetaData.Builder metaDataProtoBuilder = metaData.toProto().toBuilder();
MetaDataProtoEditor.AmbiguousTypeNameException e = assertThrows(MetaDataProtoEditor.AmbiguousTypeNameException.class, () -> MetaDataProtoEditor.renameRecordType(metaDataProtoBuilder, "OuterRecord", "OtterRecord"));
assertEquals("Field inner in message .com.apple.foundationdb.record.test.doublenested.OuterRecord of type OuterRecord.MiddleRecord.InnerRecord might be of type .com.apple.foundationdb.record.test.doublenested.OuterRecord", e.getMessage());
}
use of com.apple.foundationdb.record.RecordMetaData in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreStateCacheTest method conflictWhenCachedChanged.
/**
* Make sure that if one transaction changes the store header then an open store in another transaction that
* loaded the store state from cache will fail at commit time with conflict.
*/
@ParameterizedTest(name = "conflictWhenCachedChanged (test context = {0})")
@MethodSource("testContextSource")
public void conflictWhenCachedChanged(@Nonnull StateCacheTestContext testContext) throws Exception {
FDBRecordStoreStateCache origStoreStateCache = fdb.getStoreStateCache();
try {
fdb.setStoreStateCache(testContext.getCache(fdb));
RecordMetaData metaData1 = RecordMetaData.build(TestRecords1Proto.getDescriptor());
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecords1Proto.getDescriptor());
metaDataBuilder.addIndex("MySimpleRecord", "num_value_2");
RecordMetaData metaData2 = metaDataBuilder.getRecordMetaData();
assertThat(metaData1.getVersion(), lessThan(metaData2.getVersion()));
FDBRecordStore.Builder storeBuilder;
// Initialize the record store with a meta-data store
try (FDBRecordContext context = openContext()) {
context.getTimer().reset();
FDBRecordStore recordStore = FDBRecordStore.newBuilder().setContext(context).setMetaDataProvider(metaData1).setKeySpacePath(path).create();
assertEquals(1, context.getTimer().getCount(FDBStoreTimer.Counts.STORE_STATE_CACHE_MISS));
assertEquals(metaData1.getVersion(), recordStore.getRecordStoreState().getStoreHeader().getMetaDataversion());
commit(context);
storeBuilder = recordStore.asBuilder();
}
// Load the record store state into the cache.
try (FDBRecordContext context1 = testContext.getCachedContext(fdb, storeBuilder);
FDBRecordContext context2 = testContext.getCachedContext(fdb, storeBuilder)) {
context1.setTimer(new FDBStoreTimer());
context2.setTimer(new FDBStoreTimer());
FDBRecordStore recordStore1 = storeBuilder.copyBuilder().setContext(context1).setMetaDataProvider(metaData1).open();
assertEquals(1, context1.getTimer().getCount(FDBStoreTimer.Counts.STORE_STATE_CACHE_HIT));
assertEquals(metaData1.getVersion(), recordStore1.getRecordMetaData().getVersion());
assertEquals(metaData1.getVersion(), recordStore1.getRecordStoreState().getStoreHeader().getMetaDataversion());
// Update the meta-data in the second transaction
FDBRecordStore recordStore2 = storeBuilder.copyBuilder().setContext(context2).setMetaDataProvider(metaData2).open();
assertEquals(1, context2.getTimer().getCount(FDBStoreTimer.Counts.STORE_STATE_CACHE_HIT));
assertEquals(Collections.singletonList(recordStore2.getRecordMetaData().getRecordType("MySimpleRecord")), recordStore2.getRecordMetaData().recordTypesForIndex(recordStore2.getRecordMetaData().getIndex("MySimpleRecord$num_value_2")));
assertEquals(metaData2.getVersion(), recordStore2.getRecordMetaData().getVersion());
assertEquals(metaData2.getVersion(), recordStore2.getRecordStoreState().getStoreHeader().getMetaDataversion());
context2.commit();
// Add a write to context1 so that the conflict ranges actually get checked.
recordStore1.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066).setNumValue2(1415).build());
// Should conflict on store header even though not actually read in this transaction
assertThrows(FDBExceptions.FDBStoreTransactionConflictException.class, context1::commit);
}
// New transaction should now see the new meta-data version
try (FDBRecordContext context = openContext()) {
context.getTimer().reset();
// Trying to load with the old meta-data should fail
assertThrows(RecordStoreStaleMetaDataVersionException.class, () -> storeBuilder.copyBuilder().setContext(context).setMetaDataProvider(metaData1).open());
assertEquals(1, context.getTimer().getCount(FDBStoreTimer.Counts.STORE_STATE_CACHE_MISS));
// Trying to load with the new meta-data should succeed
FDBRecordStore recordStore = storeBuilder.copyBuilder().setContext(context).setMetaDataProvider(metaData2).open();
assertEquals(1, context.getTimer().getCount(FDBStoreTimer.Counts.STORE_STATE_CACHE_HIT));
assertEquals(metaData2.getVersion(), recordStore.getRecordStoreState().getStoreHeader().getMetaDataversion());
}
} finally {
fdb.setStoreStateCache(origStoreStateCache);
}
}
use of com.apple.foundationdb.record.RecordMetaData in project fdb-record-layer by FoundationDB.
the class MetaDataEvolutionValidatorTestV3 method proto2ToProto3.
/**
* Validate that if the syntax is changed, then the meta-data evolution is invalidated.
*/
@Test
public void proto2ToProto3() {
assertInvalid("message descriptor proto syntax changed", TestRecords3Proto.UnionDescriptor.getDescriptor(), TestRecords3ProtoV3.UnionDescriptor.getDescriptor());
assertInvalid("message descriptor proto syntax changed", TestRecords3ProtoV3.UnionDescriptor.getDescriptor(), TestRecords3Proto.UnionDescriptor.getDescriptor());
RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecords3Proto.getDescriptor());
metaDataBuilder.getRecordType("MyHierarchicalRecord").setPrimaryKey(Key.Expressions.concatenateFields("parent_path", "child_name"));
RecordMetaData metaData1 = metaDataBuilder.getRecordMetaData();
RecordMetaData metaData2 = replaceRecordsDescriptor(metaData1, TestRecords3ProtoV3.getDescriptor());
assertInvalid("message descriptor proto syntax changed", metaData1, metaData2);
}
use of com.apple.foundationdb.record.RecordMetaData in project fdb-record-layer by FoundationDB.
the class FDBMetaDataStoreTest method updateRecordsWithNewUnionField.
@ParameterizedTest(name = "updateRecordsWithNewUnionField [reorderFields = {0}]")
@BooleanSource
public void updateRecordsWithNewUnionField(boolean reorderFields) {
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
RecordMetaData metaData = RecordMetaData.build(TestRecords1Proto.getDescriptor());
metaDataStore.saveRecordMetaData(metaData);
context.commit();
assertNotNull(metaDataStore.getRecordMetaData().getRecordType("MySimpleRecord"));
}
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
RecordMetaData oldMetaData = metaDataStore.getRecordMetaData();
metaDataStore.mutateMetaData(metaDataProtoBuilder -> {
final DescriptorProtos.FileDescriptorProto.Builder records = metaDataProtoBuilder.getRecordsBuilder();
records.getMessageTypeBuilderList().stream().filter(message -> message.getName().equals(RecordMetaDataBuilder.DEFAULT_UNION_NAME)).forEach(unionMessage -> {
unionMessage.getFieldBuilderList().stream().filter(field -> field.getName().equals("_MySimpleRecord")).forEach(field -> field.setName("_MySimpleRecord_old"));
int newFieldNumber = unionMessage.getFieldBuilderList().stream().mapToInt(DescriptorProtos.FieldDescriptorProto.Builder::getNumber).max().orElse(0) + 1;
DescriptorProtos.FieldDescriptorProto newField = DescriptorProtos.FieldDescriptorProto.newBuilder().setLabel(DescriptorProtos.FieldDescriptorProto.Label.LABEL_OPTIONAL).setType(DescriptorProtos.FieldDescriptorProto.Type.TYPE_MESSAGE).setTypeName("." + TestRecords1Proto.MySimpleRecord.getDescriptor().getFullName()).setName("_MySimpleRecord_new").setNumber(newFieldNumber).build();
if (reorderFields) {
List<DescriptorProtos.FieldDescriptorProto> fieldList = new ArrayList<>(unionMessage.getFieldBuilderList().size() + 1);
fieldList.add(newField);
fieldList.addAll(unionMessage.getFieldList());
unionMessage.clearField();
unionMessage.addAllField(fieldList);
} else {
unionMessage.addField(newField);
}
});
});
RecordMetaData newMetaData = metaDataStore.getRecordMetaData();
RecordType oldSimpleRecord = oldMetaData.getRecordType("MySimpleRecord");
assertEquals(TestRecords1EvolvedProto.RecordTypeUnion._MYSIMPLERECORD_FIELD_NUMBER, oldMetaData.getUnionFieldForRecordType(oldSimpleRecord).getNumber());
RecordType newSimpleRecord = newMetaData.getRecordType("MySimpleRecord");
assertSame(newMetaData.getUnionDescriptor().findFieldByName("_MySimpleRecord_new"), newMetaData.getUnionFieldForRecordType(newSimpleRecord));
assertThat(oldMetaData.getUnionFieldForRecordType(oldSimpleRecord).getNumber(), lessThan(newMetaData.getUnionFieldForRecordType(newSimpleRecord).getNumber()));
assertEquals(oldSimpleRecord.getSinceVersion(), newSimpleRecord.getSinceVersion());
context.commit();
}
try (FDBRecordContext context = fdb.openContext()) {
openMetaDataStore(context);
RecordMetaData metaData = metaDataStore.getRecordMetaData();
RecordType simpleRecord = metaData.getRecordType("MySimpleRecord");
assertEquals("_MySimpleRecord_new", metaData.getUnionFieldForRecordType(simpleRecord).getName());
int newFieldNumber = TestRecords1Proto.RecordTypeUnion.getDescriptor().getFields().stream().mapToInt(Descriptors.FieldDescriptor::getNumber).max().orElse(0) + 1;
assertEquals(newFieldNumber, metaData.getUnionFieldForRecordType(simpleRecord).getNumber());
}
}
Aggregations