Search in sources :

Example 51 with RecordMetaData

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

the class FDBCoveringIndexQueryTest method coveringWithAdditionalNestedFilter.

/**
 * Verify that an extra covering filter can use a nested field.
 */
@DualPlannerTest
void coveringWithAdditionalNestedFilter() {
    try (FDBRecordContext context = openContext()) {
        RecordMetaDataBuilder builder = RecordMetaData.newBuilder().setRecords(TestRecordsWithHeaderProto.getDescriptor());
        builder.getRecordType("MyRecord").setPrimaryKey(field("header").nest(field("rec_no")));
        builder.addIndex("MyRecord", "multi", concat(field("str_value"), field("header").nest(concatenateFields("path", "num"))));
        RecordMetaData metaData = builder.getRecordMetaData();
        createOrOpenRecordStore(context, metaData);
        RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.and(Query.field("str_value").equalsValue("abc"), Query.field("header").matches(Query.field("num").equalsValue(1)))).build();
        // Fetch(Covering(Index(multi [[abc],[abc]]) -> [str_value: KEY[0], header: [num: KEY[2], path: KEY[1], rec_no: KEY[3]]]) | header/{num EQUALS 1})
        RecordQueryPlan plan = planner.plan(query);
        if (planner instanceof RecordQueryPlanner) {
            final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(filterPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi")).and(scanComparisons(range("[[abc],[abc]]")))))).where(queryComponents(exactly(equalsObject(Query.field("header").matches(Query.field("num").equalsValue(1)))))));
            assertMatchesExactly(plan, planMatcher);
            assertEquals(-1536005152, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(1350035332, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-1843652335, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        } else {
            final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(predicatesFilterPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi")).and(scanComparisons(range("[[abc],[abc]]")))))).where(predicates(only(valuePredicate(fieldValue("header.num"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 1))))));
            assertMatchesExactly(plan, planMatcher);
            assertEquals(1623341655, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(2019556616, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-1174131051, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordQueryPlanMatchers.scanComparisons(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.scanComparisons) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 52 with RecordMetaData

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

the class FDBRecordStoreOpeningTest method conflictWithHeaderChange.

/**
 * Validate that if the store header changes then an open record store in another transaction is failed with
 * a conflict.
 */
@Test
public void conflictWithHeaderChange() {
    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()));
    try (FDBRecordContext context = openContext()) {
        FDBRecordStore recordStore = storeBuilder(context, metaData1).create();
        assertEquals(metaData1.getVersion(), recordStore.getRecordStoreState().getStoreHeader().getMetaDataversion());
        commit(context);
    }
    try (FDBRecordContext context1 = openContext();
        FDBRecordContext context2 = openContext()) {
        FDBRecordStore recordStore1 = storeBuilder(context1, metaData1).open();
        assertEquals(metaData1.getVersion(), recordStore1.getRecordStoreState().getStoreHeader().getMetaDataversion());
        FDBRecordStore recordStore2 = storeBuilder(context2, metaData2).open();
        assertEquals(metaData2.getVersion(), recordStore2.getRecordStoreState().getStoreHeader().getMetaDataversion());
        commit(context2);
        // Add a write to the first record store to make sure that the conflict are actually checked.
        recordStore1.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066L).setNumValue2(1415).build());
        assertThrows(FDBExceptions.FDBStoreTransactionConflictException.class, context1::commit);
    }
    try (FDBRecordContext context = openContext()) {
        assertThrows(RecordStoreStaleMetaDataVersionException.class, () -> storeBuilder(context, metaData1).open());
        FDBRecordStore recordStore = storeBuilder(context, metaData2).open();
        assertEquals(metaData2.getVersion(), recordStore.getRecordStoreState().getStoreHeader().getMetaDataversion());
        commit(context);
    }
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) Test(org.junit.jupiter.api.Test)

Example 53 with RecordMetaData

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

the class FDBRecordStoreOpeningTest method storeExistenceChecksWithNoRecords.

@Test
public void storeExistenceChecksWithNoRecords() throws Exception {
    RecordMetaData metaData = RecordMetaData.build(TestRecords1Proto.getDescriptor());
    FDBRecordStore.Builder storeBuilder;
    try (FDBRecordContext context = openContext()) {
        storeBuilder = storeBuilder(context, metaData);
        FDBRecordStore store = storeBuilder.create();
        // delete the header
        store.ensureContextActive().clear(getStoreInfoKey(store));
        commit(context);
    }
    // Should be able to recover from a completely empty record store
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        FDBRecordStore store = storeBuilder.createOrOpen();
        // put a range subspace in for an index so that a future store opening can see it
        store.ensureContextActive().clear(getStoreInfoKey(store));
        Index foundIndex = metaData.getAllIndexes().stream().findAny().orElseGet(() -> fail("no indexes defined in meta-data"));
        new RangeSet(store.indexRangeSubspace(foundIndex)).insertRange(context.ensureActive(), null, null).get();
        // re-delete the header
        store.ensureContextActive().clear(getStoreInfoKey(store));
        commit(context);
    }
    // should be recoverable using ERROR_IF_NO_INFO_AND_HAS_RECORDS_OR_INDEXES
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        assertThrows(RecordStoreNoInfoAndNotEmptyException.class, storeBuilder::createOrOpen);
        commit(context);
    }
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        // do not perform checkVersion yet
        FDBRecordStore store = storeBuilder.build();
        assertNull(context.ensureActive().get(getStoreInfoKey(store)).get());
        assertTrue(store.checkVersion(null, FDBRecordStoreBase.StoreExistenceCheck.ERROR_IF_NO_INFO_AND_HAS_RECORDS_OR_INDEXES).get());
        commit(context);
    }
    // Delete everything except a value in the index build space
    try (FDBRecordContext context = openContext()) {
        FDBRecordStore store = storeBuilder.setContext(context).open();
        final Subspace subspace = OnlineIndexer.indexBuildScannedRecordsSubspace(store, metaData.getIndex("MySimpleRecord$str_value_indexed"));
        // set a key in the INDEX_BUILD_SPACE
        context.ensureActive().set(subspace.getKey(), FDBRecordStore.encodeRecordCount(1215));
        context.ensureActive().clear(store.getSubspace().getKey(), subspace.getKey());
        commit(context);
    }
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        assertThrows(RecordStoreNoInfoAndNotEmptyException.class, storeBuilder::createOrOpen);
    }
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context).createOrOpen(FDBRecordStoreBase.StoreExistenceCheck.ERROR_IF_NO_INFO_AND_HAS_RECORDS_OR_INDEXES);
        commit(context);
    }
    // Insert a record, then delete the store header
    try (FDBRecordContext context = openContext()) {
        // open as the previous open with the relaxed existence check should have fixed the store header
        FDBRecordStore store = storeBuilder.setContext(context).open();
        store.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066L).build());
        store.ensureContextActive().clear(getStoreInfoKey(store));
        commit(context);
    }
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        assertThrows(RecordStoreNoInfoAndNotEmptyException.class, storeBuilder::createOrOpen);
        assertThrows(RecordStoreNoInfoAndNotEmptyException.class, () -> storeBuilder.createOrOpen(FDBRecordStoreBase.StoreExistenceCheck.ERROR_IF_NO_INFO_AND_HAS_RECORDS_OR_INDEXES));
        commit(context);
    }
    // Delete the record store, then insert a key at an unknown keyspace
    try (FDBRecordContext context = openContext()) {
        FDBRecordStore.deleteStore(context, path);
        Subspace subspace = path.toSubspace(context);
        context.ensureActive().set(subspace.pack("unknown_keyspace"), Tuple.from("doesn't matter").pack());
        commit(context);
    }
    try (FDBRecordContext context = openContext()) {
        storeBuilder.setContext(context);
        assertThrows(RecordStoreNoInfoAndNotEmptyException.class, storeBuilder::createOrOpen);
        RecordCoreException err = assertThrows(RecordCoreException.class, () -> storeBuilder.createOrOpen(FDBRecordStoreBase.StoreExistenceCheck.ERROR_IF_NO_INFO_AND_HAS_RECORDS_OR_INDEXES));
        assertEquals("Unrecognized keyspace: unknown_keyspace", err.getMessage());
        commit(context);
    }
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) Subspace(com.apple.foundationdb.subspace.Subspace) RangeSet(com.apple.foundationdb.async.RangeSet) Index(com.apple.foundationdb.record.metadata.Index) Test(org.junit.jupiter.api.Test)

Example 54 with RecordMetaData

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

the class FDBRecordStoreOpeningTest method sizeBasedUserVersionChecker.

@Test
public void sizeBasedUserVersionChecker() {
    final Index universalCountIndex = new Index("countIndex", new GroupingKeyExpression(EmptyKeyExpression.EMPTY, 0), IndexTypes.COUNT);
    final RecordMetaDataBuilder metaDataBuilder = RecordMetaData.newBuilder().setRecords(TestRecords1Proto.getDescriptor());
    metaDataBuilder.addUniversalIndex(universalCountIndex);
    final RecordMetaData metaData1 = metaDataBuilder.getRecordMetaData();
    // Open the store and make sure estimate size path is used
    try (FDBRecordContext context = openContext()) {
        final SizeBasedUserVersionChecker userVersionChecker = new SizeBasedUserVersionChecker(IndexState.READABLE);
        final FDBRecordStore recordStore = storeBuilder(context, metaData1).setUserVersionChecker(userVersionChecker).create();
        assertThat("should have checked the size at least once", userVersionChecker.getCheckSizeCount(), greaterThan(0L));
        assertEquals(1, timer.getCount(FDBStoreTimer.Events.ESTIMATE_SIZE));
        assertTrue(recordStore.getRecordStoreState().allIndexesReadable(), "all indexes should be readable on new store opening");
        commit(context);
    }
    // Re-open the store and make sure the estimate is never used
    try (FDBRecordContext context = openContext()) {
        final SizeBasedUserVersionChecker userVersionChecker = new SizeBasedUserVersionChecker(IndexState.DISABLED);
        final FDBRecordStore recordStore = storeBuilder(context, metaData1).setUserVersionChecker(userVersionChecker).open();
        assertEquals(0, userVersionChecker.getCheckSizeCount(), "should not have checked the size on already created store");
        assertEquals(0, timer.getCount(FDBStoreTimer.Events.ESTIMATE_SIZE), "should not have estimated the size on already created store");
        assertTrue(recordStore.getRecordStoreState().allIndexesReadable(), "all indexes should be readable on already created store opening");
        commit(context);
    }
    // Add two indexes
    final String indexName1 = "index1";
    final String indexName2 = "index2";
    metaDataBuilder.addIndex("MySimpleRecord", indexName1, "num_value_2");
    metaDataBuilder.addIndex("MySimpleRecord", indexName2, "num_value_2");
    final RecordMetaData metaData2 = metaDataBuilder.getRecordMetaData();
    try (FDBRecordContext context = openContext()) {
        final SizeBasedUserVersionChecker userVersionChecker = new SizeBasedUserVersionChecker(IndexState.DISABLED);
        final FDBRecordStore recordStore = storeBuilder(context, metaData2).setUserVersionChecker(userVersionChecker).open();
        assertEquals(2, userVersionChecker.getCheckSizeCount(), "should have checked the size once for each index");
        assertEquals(1, timer.getCount(FDBStoreTimer.Events.ESTIMATE_SIZE), "should have only checked the database for the size once");
        assertEquals(ImmutableSet.of(indexName1, indexName2), recordStore.getRecordStoreState().getDisabledIndexNames());
        commit(context);
    }
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Index(com.apple.foundationdb.record.metadata.Index) ByteString(com.google.protobuf.ByteString) Test(org.junit.jupiter.api.Test)

Example 55 with RecordMetaData

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

the class FDBRecordStoreOpeningTest method testUpdateRecords.

@Test
public void testUpdateRecords() {
    KeySpacePath metaDataPath;
    Subspace metaDataSubspace;
    try (FDBRecordContext context = fdb.openContext()) {
        metaDataPath = TestKeySpace.getKeyspacePath("record-test", "unit", "metadataStore");
        metaDataSubspace = metaDataPath.toSubspace(context);
        context.ensureActive().clear(Range.startsWith(metaDataSubspace.pack()));
        context.commit();
    }
    try (FDBRecordContext context = fdb.openContext()) {
        RecordMetaData origMetaData = RecordMetaData.build(TestRecords1Proto.getDescriptor());
        final int version = origMetaData.getVersion();
        FDBMetaDataStore metaDataStore = createMetaDataStore(context, metaDataPath, metaDataSubspace, TestRecords1Proto.getDescriptor());
        FDBRecordStore recordStore = storeBuilder(context, origMetaData).setMetaDataStore(metaDataStore).createOrOpen();
        assertEquals(version, recordStore.getRecordMetaData().getVersion());
        TestRecords1Proto.MySimpleRecord record = TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066L).setNumValue2(42).setStrValueIndexed("value").setNumValue3Indexed(1729).build();
        recordStore.saveRecord(record);
        // Update the records without a local descriptor. Storing an evolved record must fail.
        final TestRecords1EvolvedProto.MySimpleRecord evolvedRecord = TestRecords1EvolvedProto.MySimpleRecord.newBuilder().setRecNo(1067L).setNumValue2(43).setStrValueIndexed("evolved value").setNumValue3Indexed(1730).build();
        metaDataStore = createMetaDataStore(context, metaDataPath, metaDataSubspace, null);
        // Bumps the version
        metaDataStore.updateRecords(TestRecords1EvolvedProto.getDescriptor());
        final FDBRecordStore recordStoreWithNoLocalFileDescriptor = storeBuilder(context, origMetaData).setMetaDataStore(metaDataStore).open();
        assertEquals(version + 1, recordStoreWithNoLocalFileDescriptor.getRecordMetaData().getVersion());
        MetaDataException e = assertThrows(MetaDataException.class, () -> recordStoreWithNoLocalFileDescriptor.saveRecord(evolvedRecord));
        assertEquals(e.getMessage(), "descriptor did not match record type");
        // Update the records with a local descriptor. Storing an evolved record must succeed this time.
        metaDataStore = createMetaDataStore(context, metaDataPath, metaDataSubspace, TestRecords1EvolvedProto.getDescriptor());
        // Bumps the version
        metaDataStore.updateRecords(TestRecords1EvolvedProto.getDescriptor());
        recordStore = storeBuilder(context, origMetaData).setMetaDataStore(metaDataStore).open();
        assertEquals(version + 2, recordStore.getRecordMetaData().getVersion());
        recordStore.saveRecord(evolvedRecord);
        // Evolve the meta-data one more time and use it for local file descriptor. SaveRecord will succeed.
        final TestRecords1EvolvedAgainProto.MySimpleRecord evolvedAgainRecord = TestRecords1EvolvedAgainProto.MySimpleRecord.newBuilder().setRecNo(1066L).setNumValue2(42).setStrValueIndexed("value").setNumValue3Indexed(1729).build();
        metaDataStore = createMetaDataStore(context, metaDataPath, metaDataSubspace, TestRecords1EvolvedAgainProto.getDescriptor());
        // Bumps the version
        metaDataStore.updateRecords(TestRecords1EvolvedProto.getDescriptor());
        recordStore = storeBuilder(context, origMetaData).setMetaDataStore(metaDataStore).open();
        assertEquals(version + 3, recordStore.getRecordMetaData().getVersion());
        recordStore.saveRecord(evolvedAgainRecord);
    }
}
Also used : RecordMetaData(com.apple.foundationdb.record.RecordMetaData) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) TestRecords1EvolvedAgainProto(com.apple.foundationdb.record.TestRecords1EvolvedAgainProto) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Subspace(com.apple.foundationdb.subspace.Subspace) TestRecords1EvolvedProto(com.apple.foundationdb.record.TestRecords1EvolvedProto) KeySpacePath(com.apple.foundationdb.record.provider.foundationdb.keyspace.KeySpacePath) Test(org.junit.jupiter.api.Test)

Aggregations

RecordMetaData (com.apple.foundationdb.record.RecordMetaData)168 Test (org.junit.jupiter.api.Test)130 RecordMetaDataBuilder (com.apple.foundationdb.record.RecordMetaDataBuilder)81 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)66 Nonnull (javax.annotation.Nonnull)47 Descriptors (com.google.protobuf.Descriptors)44 RecordMetaDataProto (com.apple.foundationdb.record.RecordMetaDataProto)39 MetaDataException (com.apple.foundationdb.record.metadata.MetaDataException)39 MetaDataProtoTest (com.apple.foundationdb.record.metadata.MetaDataProtoTest)38 Tuple (com.apple.foundationdb.tuple.Tuple)36 List (java.util.List)33 ArrayList (java.util.ArrayList)31 TestRecords1Proto (com.apple.foundationdb.record.TestRecords1Proto)30 Index (com.apple.foundationdb.record.metadata.Index)30 DescriptorProtos (com.google.protobuf.DescriptorProtos)30 Collectors (java.util.stream.Collectors)30 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)27 ByteString (com.google.protobuf.ByteString)27 Assertions.assertNotNull (org.junit.jupiter.api.Assertions.assertNotNull)27 RecordMetaDataOptionsProto (com.apple.foundationdb.record.RecordMetaDataOptionsProto)26