Search in sources :

Example 66 with RecordQuery

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

the class VersionIndexTest method queryOnVersion.

@ParameterizedTest(name = "queryOnVersion [formatVersion = {0}, splitLongRecords = {1}]")
@MethodSource("formatVersionArguments")
@SuppressWarnings("try")
public void queryOnVersion(int testFormatVersion, boolean testSplitLongRecords) {
    formatVersion = testFormatVersion;
    splitLongRecords = testSplitLongRecords;
    List<MySimpleRecord> simpleRecords = IntStream.range(0, 30).mapToObj(id -> MySimpleRecord.newBuilder().setRecNo(id * 2).setNumValue2(id % 2).setNumValue3Indexed(id % 3).build()).collect(Collectors.toList());
    List<TestRecords1Proto.MyOtherRecord> otherRecords = IntStream.range(0, 30).mapToObj(id -> TestRecords1Proto.MyOtherRecord.newBuilder().setRecNo(id * 2 + 1).setNumValue2(id % 2).setNumValue3Indexed(id % 3).build()).collect(Collectors.toList());
    Iterator<MySimpleRecord> simpleIterator = simpleRecords.iterator();
    Iterator<TestRecords1Proto.MyOtherRecord> otherIterator = otherRecords.iterator();
    while (simpleIterator.hasNext()) {
        try (FDBRecordContext context = openContext(simpleVersionHook)) {
            int done = 0;
            while (simpleIterator.hasNext() && done != 5) {
                recordStore.saveRecord(simpleIterator.next());
                recordStore.saveRecord(otherIterator.next());
                done += 1;
            }
            context.commit();
        }
    }
    // Query all records.
    try (FDBRecordContext context = openContext(simpleVersionHook)) {
        List<Long> expectedKeys = Stream.concat(simpleRecords.stream().map(MySimpleRecord::getRecNo), otherRecords.stream().map(TestRecords1Proto.MyOtherRecord::getRecNo)).sorted().collect(Collectors.toList());
        FDBRecordVersion last = null;
        List<Long> receivedKeys = new ArrayList<>();
        int totalSeen = 0;
        while (true) {
            RecordQueryPlan plan;
            if (last == null) {
                RecordQuery query = RecordQuery.newBuilder().setSort(VersionKeyExpression.VERSION).build();
                plan = planner.plan(query);
                assertEquals("Index(globalVersion <,>)", plan.toString());
            } else {
                RecordQuery query = RecordQuery.newBuilder().setFilter(Query.version().greaterThan(last)).setSort(VersionKeyExpression.VERSION).build();
                plan = planner.plan(query);
                assertEquals("Index(globalVersion ([" + last.toVersionstamp() + "],>)", plan.toString());
            }
            RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(10).build()).asIterator();
            boolean hasAny = false;
            while (cursor.hasNext()) {
                hasAny = true;
                FDBQueriedRecord<Message> record = cursor.next();
                assertTrue(record.hasVersion());
                if (last != null) {
                    assertThat(last, lessThan(record.getVersion()));
                }
                last = record.getVersion();
                receivedKeys.add(field("rec_no").evaluateSingleton(record.getStoredRecord()).toTuple().getLong(0));
                totalSeen += 1;
            }
            if (!hasAny) {
                break;
            }
        }
        assertEquals(simpleRecords.size() + otherRecords.size(), totalSeen);
        assertEquals(expectedKeys, receivedKeys);
    }
    // Query MySimpleRecord based on value.
    try (FDBRecordContext context = openContext(simpleVersionHook)) {
        List<Long> expectedKeys = simpleRecords.stream().filter(rec -> rec.getNumValue2() == 0).map(MySimpleRecord::getRecNo).collect(Collectors.toList());
        List<Long> receivedKeys = new ArrayList<>();
        FDBRecordVersion last = null;
        int totalSeen = 0;
        while (true) {
            RecordCursorIterator<? extends FDBRecord<Message>> cursor;
            if (last == null) {
                RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_2").equalsValue(0)).setSort(VersionKeyExpression.VERSION).build();
                RecordQueryPlan plan = planner.plan(query);
                assertEquals("Index(MySimpleRecord$num2-version [[0],[0]])", plan.toString());
                cursor = recordStore.executeQuery(plan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(3).build()).asIterator();
            } else {
                RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("num_value_2").equalsValue(0), Query.version().greaterThan(last))).setSort(VersionKeyExpression.VERSION).build();
                RecordQueryPlan plan = planner.plan(query);
                assertEquals("Index(MySimpleRecord$num2-version ([0, " + last.toVersionstamp() + "],[0]])", plan.toString());
                cursor = recordStore.executeQuery(plan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(3).build()).asIterator();
            }
            boolean hasAny = false;
            while (cursor.hasNext()) {
                hasAny = true;
                FDBRecord<Message> record = cursor.next();
                MySimpleRecord simpleRecord = MySimpleRecord.newBuilder().mergeFrom(record.getRecord()).build();
                assertEquals(0, simpleRecord.getNumValue2());
                assertTrue(record.hasVersion());
                if (last != null) {
                    assertThat(last, lessThan(record.getVersion()));
                }
                last = record.getVersion();
                receivedKeys.add(simpleRecord.getRecNo());
                totalSeen += 1;
            }
            if (!hasAny) {
                break;
            }
        }
        assertEquals((simpleRecords.size() + 1) / 2, totalSeen);
        assertEquals(expectedKeys, receivedKeys);
    }
    // Query that requires also filtering
    try (FDBRecordContext context = openContext(simpleVersionHook)) {
        List<Long> expectedKeys = simpleRecords.stream().filter(rec -> rec.getNumValue2() == 0 && rec.getNumValue3Indexed() == 0).map(MySimpleRecord::getRecNo).collect(Collectors.toList());
        List<Long> receivedKeys = new ArrayList<>();
        FDBRecordVersion last = null;
        int totalSeen = 0;
        while (true) {
            RecordCursorIterator<? extends FDBRecord<Message>> cursor;
            if (last == null) {
                RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("num_value_2").equalsValue(0), Query.field("num_value_3_indexed").equalsValue(0))).setSort(VersionKeyExpression.VERSION).build();
                RecordQueryPlan plan = planner.plan(query);
                assertEquals("Index(MySimpleRecord$num2-version [[0],[0]]) | num_value_3_indexed EQUALS 0", plan.toString());
                cursor = recordStore.executeQuery(plan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()).asIterator();
            } else {
                RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("num_value_2").equalsValue(0), Query.field("num_value_3_indexed").equalsValue(0), Query.version().greaterThan(last))).setSort(VersionKeyExpression.VERSION).build();
                RecordQueryPlan plan = planner.plan(query);
                assertEquals("Index(MySimpleRecord$num2-version ([0, " + last.toVersionstamp() + "],[0]]) | num_value_3_indexed EQUALS 0", plan.toString());
                cursor = recordStore.executeQuery(plan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(2).build()).asIterator();
            }
            boolean hasAny = false;
            while (cursor.hasNext()) {
                hasAny = true;
                FDBRecord<Message> record = cursor.next();
                MySimpleRecord simpleRecord = MySimpleRecord.newBuilder().mergeFrom(record.getRecord()).build();
                assertEquals(0, simpleRecord.getNumValue2());
                assertTrue(record.hasVersion());
                if (last != null) {
                    assertThat(last, lessThan(record.getVersion()));
                }
                last = record.getVersion();
                receivedKeys.add(simpleRecord.getRecNo());
                totalSeen += 1;
            }
            if (!hasAny) {
                break;
            }
        }
        assertEquals(simpleRecords.size() / 6, totalSeen);
        assertEquals(expectedKeys, receivedKeys);
    }
    // Query that can't be satisfied with an index scan.
    try (FDBRecordContext context = openContext(simpleVersionHook)) {
        // Preliminary query to get a read version.
        RecordQuery prelimQuery = RecordQuery.newBuilder().setSort(VersionKeyExpression.VERSION).build();
        RecordQueryPlan prelimPlan = planner.plan(prelimQuery);
        FDBRecordVersion chosenVersion = recordStore.executeQuery(prelimPlan, null, ExecuteProperties.newBuilder().setReturnedRowLimit(10).build()).asList().thenApply(list -> list.get(list.size() - 1).getVersion()).join();
        RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.version().greaterThan(chosenVersion)).setSort(field("num_value_3_indexed")).build();
        RecordQueryPlan plan = planner.plan(query);
        assertEquals("Index(MySimpleRecord$num_value_3_indexed <,>) | version GREATER_THAN " + chosenVersion.toString(), plan.toString());
        List<FDBQueriedRecord<Message>> records = recordStore.executeQuery(plan).asList().join();
        int last = -1;
        for (FDBQueriedRecord<Message> record : records) {
            MySimpleRecord simpleRecord = MySimpleRecord.newBuilder().mergeFrom(record.getRecord()).build();
            assertThat(last, lessThanOrEqualTo(simpleRecord.getNumValue3Indexed()));
            assertTrue(record.hasVersion());
            assertThat(chosenVersion, lessThan(record.getVersion()));
            last = simpleRecord.getNumValue3Indexed();
        }
        assertEquals(simpleRecords.size() - 5, records.size());
    }
}
Also used : BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Subspace(com.apple.foundationdb.subspace.Subspace) IndexScanType(com.apple.foundationdb.record.IndexScanType) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) Map(java.util.Map) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Tag(org.junit.jupiter.api.Tag) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) Matchers.allOf(org.hamcrest.Matchers.allOf) FDBDatabase(com.apple.foundationdb.record.provider.foundationdb.FDBDatabase) Arguments(org.junit.jupiter.params.provider.Arguments) Assertions.assertNotSame(org.junit.jupiter.api.Assertions.assertNotSame) TupleRange(com.apple.foundationdb.record.TupleRange) Stream(java.util.stream.Stream) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Expressions.function(com.apple.foundationdb.record.metadata.Key.Expressions.function) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) FunctionKeyExpression(com.apple.foundationdb.record.metadata.expressions.FunctionKeyExpression) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) MySimpleRecord(com.apple.foundationdb.record.TestRecords1Proto.MySimpleRecord) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) FDBTestBase(com.apple.foundationdb.record.provider.foundationdb.FDBTestBase) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) Matchers.lessThan(org.hamcrest.Matchers.lessThan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nullable(javax.annotation.Nullable) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) Tags(com.apple.test.Tags) ExecutionException(java.util.concurrent.ExecutionException) Assertions.assertArrayEquals(org.junit.jupiter.api.Assertions.assertArrayEquals) TestRecords2Proto(com.apple.foundationdb.record.TestRecords2Proto) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Matchers.hasItem(org.hamcrest.Matchers.hasItem) Index(com.apple.foundationdb.record.metadata.Index) Assumptions(org.junit.jupiter.api.Assumptions) TreeMap(java.util.TreeMap) AutoService(com.google.auto.service.AutoService) IndexEntry(com.apple.foundationdb.record.IndexEntry) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) Tuple(com.apple.foundationdb.tuple.Tuple) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) MethodSource(org.junit.jupiter.params.provider.MethodSource) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Matchers.lessThanOrEqualTo(org.hamcrest.Matchers.lessThanOrEqualTo) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Collectors(java.util.stream.Collectors) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) ObjectPlanHash(com.apple.foundationdb.record.ObjectPlanHash) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Optional(java.util.Optional) SortedMap(java.util.SortedMap) IntStream(java.util.stream.IntStream) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) HashMap(java.util.HashMap) TestKeySpace(com.apple.foundationdb.record.provider.foundationdb.TestKeySpace) PlanHashable(com.apple.foundationdb.record.PlanHashable) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBRecordStore(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStore) ScanProperties(com.apple.foundationdb.record.ScanProperties) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Versionstamp(com.apple.foundationdb.tuple.Versionstamp) Iterator(java.util.Iterator) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) RecordMetaDataHook(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase.RecordMetaDataHook) FDBDatabaseFactory(com.apple.foundationdb.record.provider.foundationdb.FDBDatabaseFactory) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) RecordFunction(com.apple.foundationdb.record.RecordFunction) Collections(java.util.Collections) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Message(com.google.protobuf.Message) ArrayList(java.util.ArrayList) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) MySimpleRecord(com.apple.foundationdb.record.TestRecords1Proto.MySimpleRecord) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 67 with RecordQuery

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

the class VersionIndexTest method withMetaDataRebuilds.

@ParameterizedTest(name = "withMetaDataRebuilds [formatVersion = {0}, splitLongRecords = {1}]")
@MethodSource("formatVersionArguments")
@SuppressWarnings("try")
public void withMetaDataRebuilds(int testFormatVersion, boolean testSplitLongRecords) {
    formatVersion = testFormatVersion;
    splitLongRecords = testSplitLongRecords;
    RecordMetaDataHook firstHook = metaDataBuilder -> {
        metaDataBuilder.setSplitLongRecords(splitLongRecords);
        metaDataBuilder.addUniversalIndex(new Index("globalCount", new GroupingKeyExpression(EmptyKeyExpression.EMPTY, 0), IndexTypes.COUNT));
        metaDataBuilder.addUniversalIndex(new Index("globalVersion", VersionKeyExpression.VERSION, IndexTypes.VERSION));
    };
    RecordMetaDataHook secondHook = metaDataBuilder -> {
        firstHook.apply(metaDataBuilder);
        metaDataBuilder.removeIndex("globalVersion");
        metaDataBuilder.setStoreRecordVersions(false);
    };
    RecordMetaDataHook thirdHook = metaDataBuilder -> {
        secondHook.apply(metaDataBuilder);
        metaDataBuilder.setStoreRecordVersions(true);
        metaDataBuilder.addUniversalIndex(new Index("globalVersion2", VersionKeyExpression.VERSION, IndexTypes.VERSION));
    };
    MySimpleRecord record1 = MySimpleRecord.newBuilder().setRecNo(1066L).build();
    FDBRecordVersion version1;
    MySimpleRecord record2 = MySimpleRecord.newBuilder().setRecNo(1776L).build();
    MySimpleRecord record3 = MySimpleRecord.newBuilder().setRecNo(1955L).build();
    FDBRecordVersion version3;
    RecordQuery query = RecordQuery.newBuilder().setSort(VersionKeyExpression.VERSION).build();
    // First with version on.
    try (FDBRecordContext context = openContext(firstHook)) {
        FDBStoredRecord<?> storedRecord = recordStore.saveRecord(record1);
        assertTrue(storedRecord.hasVersion());
        context.commit();
        version1 = FDBRecordVersion.complete(context.getVersionStamp(), storedRecord.getVersion().getLocalVersion());
    }
    try (FDBRecordContext context = openContext(firstHook)) {
        FDBStoredRecord<?> loadedRecord = recordStore.loadRecord(Tuple.from(1066L));
        assertNotNull(loadedRecord);
        assertTrue(loadedRecord.hasVersion());
        assertEquals(version1, loadedRecord.getVersion());
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan("globalVersion"));
        List<FDBQueriedRecord<Message>> records = recordStore.executeQuery(plan).asList().join();
        assertEquals(1, records.size());
        FDBQueriedRecord<Message> queriedRecord = records.get(0);
        assertEquals(Tuple.from(1066L), queriedRecord.getPrimaryKey());
        assertTrue(queriedRecord.hasVersion());
        assertEquals(version1, queriedRecord.getVersion());
    }
    // Now with version off.
    try (FDBRecordContext context = openContext(secondHook)) {
        FDBStoredRecord<?> storedRecord = recordStore.saveRecord(record2);
        assertFalse(storedRecord.hasVersion());
        context.commit();
    }
    try (FDBRecordContext context = openContext(secondHook)) {
        FDBStoredRecord<?> loadedRecord1 = recordStore.loadRecord(Tuple.from(1066L));
        assertNotNull(loadedRecord1);
        assertEquals(testFormatVersion >= FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION, loadedRecord1.hasVersion());
        FDBStoredRecord<?> loadedRecord2 = recordStore.loadRecord(Tuple.from(1776L));
        assertNotNull(loadedRecord2);
        assertFalse(loadedRecord2.hasVersion());
        assertThrows(RecordCoreException.class, () -> {
            RecordQueryPlan plan = planner.plan(query);
            fail("Came up with plan " + plan.toString() + " when it should be impossible");
        });
    }
    // Now with version back on.
    try (FDBRecordContext context = openContext(thirdHook)) {
        FDBStoredRecord<?> storedRecord = recordStore.saveRecord(record3);
        assertTrue(storedRecord.hasVersion());
        context.commit();
        version3 = FDBRecordVersion.complete(context.getVersionStamp(), storedRecord.getVersion().getLocalVersion());
    }
    try (FDBRecordContext context = openContext(thirdHook)) {
        FDBStoredRecord<?> loadedRecord1 = recordStore.loadRecord(Tuple.from(1066L));
        assertEquals(testFormatVersion >= FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION, loadedRecord1.hasVersion());
        FDBStoredRecord<?> loadedRecord2 = recordStore.loadRecord(Tuple.from(1776L));
        assertFalse(loadedRecord2.hasVersion());
        FDBStoredRecord<?> loadedRecord3 = recordStore.loadRecord(Tuple.from(1955L));
        assertTrue(loadedRecord3.hasVersion());
        assertEquals(version3, loadedRecord3.getVersion());
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan("globalVersion2"));
        List<FDBQueriedRecord<Message>> records = recordStore.executeQuery(plan).asList().join();
        assertEquals(3, records.size());
        if (testFormatVersion < FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION) {
            FDBQueriedRecord<Message> queriedRecord1 = records.get(0);
            assertEquals(Tuple.from(1066L), queriedRecord1.getPrimaryKey());
            assertFalse(queriedRecord1.hasVersion());
            FDBQueriedRecord<Message> queriedRecord2 = records.get(1);
            assertEquals(Tuple.from(1776L), queriedRecord2.getPrimaryKey());
            assertFalse(queriedRecord2.hasVersion());
        } else {
            FDBQueriedRecord<Message> queriedRecord1 = records.get(0);
            assertEquals(Tuple.from(1776L), queriedRecord1.getPrimaryKey());
            assertFalse(queriedRecord1.hasVersion());
            FDBQueriedRecord<Message> queriedRecord2 = records.get(1);
            assertEquals(Tuple.from(1066L), queriedRecord2.getPrimaryKey());
            assertTrue(queriedRecord2.hasVersion());
            assertEquals(version1, queriedRecord2.getVersion());
        }
        FDBQueriedRecord<Message> queriedRecord3 = records.get(2);
        assertEquals(Tuple.from(1955L), queriedRecord3.getPrimaryKey());
        assertTrue(queriedRecord3.hasVersion());
        assertEquals(version3, queriedRecord3.getVersion());
    }
}
Also used : BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Subspace(com.apple.foundationdb.subspace.Subspace) IndexScanType(com.apple.foundationdb.record.IndexScanType) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) Map(java.util.Map) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Tag(org.junit.jupiter.api.Tag) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) Matchers.allOf(org.hamcrest.Matchers.allOf) FDBDatabase(com.apple.foundationdb.record.provider.foundationdb.FDBDatabase) Arguments(org.junit.jupiter.params.provider.Arguments) Assertions.assertNotSame(org.junit.jupiter.api.Assertions.assertNotSame) TupleRange(com.apple.foundationdb.record.TupleRange) Stream(java.util.stream.Stream) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Expressions.function(com.apple.foundationdb.record.metadata.Key.Expressions.function) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) FunctionKeyExpression(com.apple.foundationdb.record.metadata.expressions.FunctionKeyExpression) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) MySimpleRecord(com.apple.foundationdb.record.TestRecords1Proto.MySimpleRecord) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) FDBTestBase(com.apple.foundationdb.record.provider.foundationdb.FDBTestBase) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) Matchers.lessThan(org.hamcrest.Matchers.lessThan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nullable(javax.annotation.Nullable) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) Tags(com.apple.test.Tags) ExecutionException(java.util.concurrent.ExecutionException) Assertions.assertArrayEquals(org.junit.jupiter.api.Assertions.assertArrayEquals) TestRecords2Proto(com.apple.foundationdb.record.TestRecords2Proto) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Matchers.hasItem(org.hamcrest.Matchers.hasItem) Index(com.apple.foundationdb.record.metadata.Index) Assumptions(org.junit.jupiter.api.Assumptions) TreeMap(java.util.TreeMap) AutoService(com.google.auto.service.AutoService) IndexEntry(com.apple.foundationdb.record.IndexEntry) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) Tuple(com.apple.foundationdb.tuple.Tuple) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) MethodSource(org.junit.jupiter.params.provider.MethodSource) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Matchers.lessThanOrEqualTo(org.hamcrest.Matchers.lessThanOrEqualTo) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Collectors(java.util.stream.Collectors) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) ObjectPlanHash(com.apple.foundationdb.record.ObjectPlanHash) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Optional(java.util.Optional) SortedMap(java.util.SortedMap) IntStream(java.util.stream.IntStream) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) HashMap(java.util.HashMap) TestKeySpace(com.apple.foundationdb.record.provider.foundationdb.TestKeySpace) PlanHashable(com.apple.foundationdb.record.PlanHashable) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBRecordStore(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStore) ScanProperties(com.apple.foundationdb.record.ScanProperties) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Versionstamp(com.apple.foundationdb.tuple.Versionstamp) Iterator(java.util.Iterator) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) RecordMetaDataHook(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase.RecordMetaDataHook) FDBDatabaseFactory(com.apple.foundationdb.record.provider.foundationdb.FDBDatabaseFactory) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) RecordFunction(com.apple.foundationdb.record.RecordFunction) Collections(java.util.Collections) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Message(com.google.protobuf.Message) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Index(com.apple.foundationdb.record.metadata.Index) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) RecordMetaDataHook(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase.RecordMetaDataHook) MySimpleRecord(com.apple.foundationdb.record.TestRecords1Proto.MySimpleRecord) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 68 with RecordQuery

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

the class VersionIndexTest method upgradeFormatVersions.

@ParameterizedTest(name = "upgradeFormatVersions [formatVersion = {0}, splitLongRecords = {1}]")
@MethodSource("formatVersionArguments")
@SuppressWarnings("try")
public void upgradeFormatVersions(int testFormatVersion, boolean splitLongRecords) {
    formatVersion = testFormatVersion;
    final RecordMetaDataHook hook = metaDataBuilder -> {
        simpleVersionHook.apply(metaDataBuilder);
        metaDataBuilder.setSplitLongRecords(splitLongRecords);
    };
    final List<Message> records = Arrays.asList(MySimpleRecord.newBuilder().setRecNo(1066L).setNumValue2(1).build(), MySimpleRecord.newBuilder().setRecNo(1415L).setNumValue2(1).build(), MySimpleRecord.newBuilder().setRecNo(1776L).setNumValue2(2).build());
    List<FDBStoredRecord<Message>> storedRecords;
    try (FDBRecordContext context = openContext(hook)) {
        List<FDBStoredRecord<Message>> storedRecordsWithIncompletes = records.stream().map(recordStore::saveRecord).collect(Collectors.toList());
        context.commit();
        byte[] globalVersion = context.getVersionStamp();
        storedRecords = storedRecordsWithIncompletes.stream().map(record -> record.withCommittedVersion(globalVersion)).collect(Collectors.toList());
    }
    try (FDBRecordContext context = openContext(hook)) {
        if (testFormatVersion < FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION) {
            validateUsingOlderVersionFormat(storedRecords);
        } else {
            validateUsingNewerVersionFormat(storedRecords);
        }
    }
    // Update to the current format version
    formatVersion = FDBRecordStore.MAX_SUPPORTED_FORMAT_VERSION;
    if (testFormatVersion < FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION && (splitLongRecords || testFormatVersion >= FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION)) {
        // After format version upgrade, each record should now store that it has the version inlined
        storedRecords = storedRecords.stream().map(record -> new FDBStoredRecord<>(record.getPrimaryKey(), record.getRecordType(), record.getRecord(), record.getKeyCount() + 1, record.getKeySize() * 2 + 1, record.getValueSize() + 1 + FDBRecordVersion.VERSION_LENGTH, record.isSplit(), true, record.getVersion())).collect(Collectors.toList());
    }
    try (FDBRecordContext context = openContext(hook)) {
        if (!splitLongRecords && testFormatVersion < FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION) {
            validateUsingOlderVersionFormat(storedRecords);
        } else {
            validateUsingNewerVersionFormat(storedRecords);
        }
        for (FDBStoredRecord<Message> storedRecord : storedRecords) {
            Optional<FDBRecordVersion> loadedVersion = recordStore.loadRecordVersion(storedRecord.getPrimaryKey());
            assertTrue(loadedVersion.isPresent());
            assertEquals(storedRecord.getVersion(), loadedVersion.get());
            RecordQuery query = RecordQuery.newBuilder().setFilter(Query.version().equalsValue(storedRecord.getVersion())).build();
            RecordQueryPlan plan = planner.plan(query);
            final String endpointString = "[" + storedRecord.getVersion().toVersionstamp(false).toString() + "]";
            assertThat(plan, indexScan(allOf(indexName("globalVersion"), bounds(hasTupleString("[" + endpointString + "," + endpointString + "]")))));
            List<FDBStoredRecord<Message>> queriedRecords = recordStore.executeQuery(plan).map(FDBQueriedRecord::getStoredRecord).asList().join();
            assertEquals(Collections.singletonList(storedRecord), queriedRecords);
        }
        assertTrue(recordStore.deleteRecord(storedRecords.get(0).getPrimaryKey()));
        final List<FDBStoredRecord<Message>> fewerRecords = storedRecords.subList(1, storedRecords.size());
        if (!splitLongRecords && testFormatVersion < FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION) {
            validateUsingOlderVersionFormat(fewerRecords);
        } else {
            validateUsingNewerVersionFormat(fewerRecords);
        }
        recordStore.saveRecord(storedRecords.get(0).getRecord());
        if (!splitLongRecords && testFormatVersion < FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION) {
            validateUsingOlderVersionFormat(fewerRecords);
        } else {
            validateUsingNewerVersionFormat(fewerRecords);
        }
    // do not commit (so we can do a second upgrade)
    }
    final Index newValueIndex = new Index("MySimpleRecord$num2", field("num_value_2"), IndexTypes.VALUE);
    final Index newVersionIndex = new Index("MySimpleRecord$version-num2", concat(VersionKeyExpression.VERSION, field("num_value_2")), IndexTypes.VERSION);
    final RecordMetaDataHook hookWithNewIndexes = metaDataBuilder -> {
        hook.apply(metaDataBuilder);
        metaDataBuilder.addIndex("MySimpleRecord", newValueIndex);
        metaDataBuilder.addIndex("MySimpleRecord", newVersionIndex);
    };
    final List<FDBStoredRecord<Message>> newStoredRecords;
    try (FDBRecordContext context = openContext(hookWithNewIndexes)) {
        assertTrue(recordStore.getRecordStoreState().isReadable(newValueIndex));
        boolean performedMigration = testFormatVersion < FDBRecordStore.SAVE_VERSION_WITH_RECORD_FORMAT_VERSION && (splitLongRecords || testFormatVersion >= FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION);
        assertNotEquals(performedMigration, recordStore.getRecordStoreState().isReadable(newVersionIndex));
        if (recordStore.getRecordStoreState().isReadable(newVersionIndex)) {
            // Validate versions are the same for all records in index and in primary store
            List<Pair<Tuple, FDBRecordVersion>> recordScannedValues = recordStore.scanRecords(null, ScanProperties.FORWARD_SCAN).map(record -> Pair.of(record.getPrimaryKey(), record.getVersion())).asList().join();
            List<Pair<Tuple, FDBRecordVersion>> indexedScannedValues = recordStore.scanIndex(newVersionIndex, IndexScanType.BY_VALUE, TupleRange.ALL, null, ScanProperties.FORWARD_SCAN).map(indexEntry -> Pair.of(TupleHelpers.subTuple(indexEntry.getKey(), 2, indexEntry.getKey().size()), FDBRecordVersion.fromVersionstamp(indexEntry.getKey().getVersionstamp(0), false))).asList().join();
            assertEquals(recordScannedValues, indexedScannedValues);
        }
        // Save record at newer version
        assertTrue(recordStore.deleteRecord(storedRecords.get(0).getPrimaryKey()));
        FDBStoredRecord<Message> newRecord0 = recordStore.saveRecord(storedRecords.get(0).getRecord());
        FDBStoredRecord<Message> newRecord2 = recordStore.saveRecord(storedRecords.get(2).getRecord());
        assertEquals(newRecord0.getVersion(), recordStore.loadRecordVersion(newRecord0.getPrimaryKey()).get());
        assertEquals(newRecord2.getVersion(), recordStore.loadRecordVersion(newRecord2.getPrimaryKey()).get());
        context.commit();
        byte[] versionstamp = context.getVersionStamp();
        newStoredRecords = Arrays.asList(newRecord0.withVersion(FDBRecordVersion.complete(versionstamp, 0)), storedRecords.get(1), newRecord2.withVersion(FDBRecordVersion.complete(versionstamp, 1)));
    }
    try (FDBRecordContext context = openContext(hookWithNewIndexes)) {
        if (!splitLongRecords && testFormatVersion < FDBRecordStore.SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION) {
            validateUsingOlderVersionFormat(newStoredRecords);
        } else {
            validateUsingNewerVersionFormat(newStoredRecords);
        }
    }
}
Also used : BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) FDBRecord(com.apple.foundationdb.record.provider.foundationdb.FDBRecord) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Subspace(com.apple.foundationdb.subspace.Subspace) IndexScanType(com.apple.foundationdb.record.IndexScanType) Pair(org.apache.commons.lang3.tuple.Pair) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) Map(java.util.Map) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) Tag(org.junit.jupiter.api.Tag) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) Matchers.allOf(org.hamcrest.Matchers.allOf) FDBDatabase(com.apple.foundationdb.record.provider.foundationdb.FDBDatabase) Arguments(org.junit.jupiter.params.provider.Arguments) Assertions.assertNotSame(org.junit.jupiter.api.Assertions.assertNotSame) TupleRange(com.apple.foundationdb.record.TupleRange) Stream(java.util.stream.Stream) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) TupleHelpers(com.apple.foundationdb.tuple.TupleHelpers) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Expressions.function(com.apple.foundationdb.record.metadata.Key.Expressions.function) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) FunctionKeyExpression(com.apple.foundationdb.record.metadata.expressions.FunctionKeyExpression) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) MySimpleRecord(com.apple.foundationdb.record.TestRecords1Proto.MySimpleRecord) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) FDBTestBase(com.apple.foundationdb.record.provider.foundationdb.FDBTestBase) ArrayList(java.util.ArrayList) Lists(com.google.common.collect.Lists) Matchers.lessThan(org.hamcrest.Matchers.lessThan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nullable(javax.annotation.Nullable) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) Tags(com.apple.test.Tags) ExecutionException(java.util.concurrent.ExecutionException) Assertions.assertArrayEquals(org.junit.jupiter.api.Assertions.assertArrayEquals) TestRecords2Proto(com.apple.foundationdb.record.TestRecords2Proto) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Matchers.hasItem(org.hamcrest.Matchers.hasItem) Index(com.apple.foundationdb.record.metadata.Index) Assumptions(org.junit.jupiter.api.Assumptions) TreeMap(java.util.TreeMap) AutoService(com.google.auto.service.AutoService) IndexEntry(com.apple.foundationdb.record.IndexEntry) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) Tuple(com.apple.foundationdb.tuple.Tuple) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FDBRecordStoreBase(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase) MethodSource(org.junit.jupiter.params.provider.MethodSource) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Matchers.lessThanOrEqualTo(org.hamcrest.Matchers.lessThanOrEqualTo) RecordCoreArgumentException(com.apple.foundationdb.record.RecordCoreArgumentException) Collectors(java.util.stream.Collectors) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) KeyValueCursor(com.apple.foundationdb.record.provider.foundationdb.KeyValueCursor) List(java.util.List) ObjectPlanHash(com.apple.foundationdb.record.ObjectPlanHash) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Optional(java.util.Optional) SortedMap(java.util.SortedMap) IntStream(java.util.stream.IntStream) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) HashMap(java.util.HashMap) TestKeySpace(com.apple.foundationdb.record.provider.foundationdb.TestKeySpace) PlanHashable(com.apple.foundationdb.record.PlanHashable) Key(com.apple.foundationdb.record.metadata.Key) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBRecordStore(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStore) ScanProperties(com.apple.foundationdb.record.ScanProperties) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Versionstamp(com.apple.foundationdb.tuple.Versionstamp) Iterator(java.util.Iterator) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) RecordMetaDataHook(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase.RecordMetaDataHook) FDBDatabaseFactory(com.apple.foundationdb.record.provider.foundationdb.FDBDatabaseFactory) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) RecordFunction(com.apple.foundationdb.record.RecordFunction) Collections(java.util.Collections) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Message(com.google.protobuf.Message) Index(com.apple.foundationdb.record.metadata.Index) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) FDBRecordVersion(com.apple.foundationdb.record.provider.foundationdb.FDBRecordVersion) RecordMetaDataHook(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreTestBase.RecordMetaDataHook) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Pair(org.apache.commons.lang3.tuple.Pair) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 69 with RecordQuery

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

the class TextIndexTest method performQueryWithIndexScan.

@Nonnull
private Set<Long> performQueryWithIndexScan(@Nonnull RecordMetaDataHook hook, @Nonnull Index index, @Nonnull QueryComponent filter) throws Exception {
    final ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setTimeLimit(3000).build();
    final RecordQuery query = RecordQuery.newBuilder().setRecordType(SIMPLE_DOC).setRequiredResults(Collections.singletonList(field("doc_id"))).setFilter(filter).build();
    Set<Long> results = new HashSet<>();
    RecordQueryPlan plan;
    byte[] continuation;
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context, hook);
        RecordQueryPlanner planner = new RecordQueryPlanner(recordStore.getRecordMetaData(), recordStore.getRecordStoreState());
        plan = planner.plan(query);
        assertThat(filter, instanceOf(FieldWithComparison.class));
        FieldWithComparison fieldFilter = (FieldWithComparison) filter;
        if (fieldFilter.getComparison() instanceof Comparisons.TextContainsAllPrefixesComparison && ((Comparisons.TextContainsAllPrefixesComparison) fieldFilter.getComparison()).isStrict()) {
            // Strict field field comparisons cannot be covering
            assertThat(plan, descendant(textIndexScan(indexName(index.getName()))));
        } else {
            assertThat(plan, descendant(coveringIndexScan(textIndexScan(indexName(index.getName())))));
        }
        try (RecordCursor<Long> cursor = recordStore.executeQuery(plan, null, executeProperties).map(record -> record.getPrimaryKey().getLong(0))) {
            cursor.forEach(results::add).get();
            continuation = cursor.getNext().getContinuation().toBytes();
        }
    }
    while (continuation != null) {
        try (FDBRecordContext context = openContext()) {
            openRecordStore(context, hook);
            try (RecordCursor<Long> cursor = recordStore.executeQuery(plan, continuation, executeProperties).map(record -> record.getPrimaryKey().getLong(0))) {
                cursor.forEach(results::add).get();
                continuation = cursor.getNext().getContinuation().toBytes();
            }
        }
    }
    return results;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) FieldWithComparison(com.apple.foundationdb.record.query.expressions.FieldWithComparison) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) HashSet(java.util.HashSet) Nonnull(javax.annotation.Nonnull)

Example 70 with RecordQuery

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

the class TextIndexTest method queryDocumentsWithScanLimit.

@Test
public void queryDocumentsWithScanLimit() throws Exception {
    // Load a big (ish) data set
    final int recordCount = 100;
    final int batchSize = 10;
    for (int i = 0; i < recordCount; i += batchSize) {
        try (FDBRecordContext context = openContext()) {
            openRecordStore(context);
            for (int j = 0; j < batchSize; j++) {
                SimpleDocument document = SimpleDocument.newBuilder().setDocId(i + j).setText((i + j) % 2 == 0 ? "some" : "text").build();
                recordStore.saveRecord(document);
            }
            commit(context);
        }
    }
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context);
        RecordQuery query = RecordQuery.newBuilder().setRecordType(SIMPLE_DOC).setFilter(Query.field("text").text().containsAll("some text")).build();
        RecordQueryPlan plan = planner.plan(query);
        boolean done = false;
        int totalKeysLoaded = 0;
        byte[] continuation = null;
        while (!done) {
            final int priorKeysLoaded = getLoadTextEntryCount(recordStore);
            ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setScannedRecordsLimit(50).build();
            RecordCursor<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan, continuation, executeProperties);
            assertEquals(Collections.emptyList(), cursor.asList().get());
            RecordCursorResult<FDBQueriedRecord<Message>> noNextResult = cursor.getNext();
            assertThat(noNextResult.hasNext(), is(false));
            final int newKeysLoaded = getLoadTextEntryCount(recordStore);
            totalKeysLoaded += newKeysLoaded - priorKeysLoaded;
            if (!noNextResult.getNoNextReason().isSourceExhausted()) {
                assertEquals(50, newKeysLoaded - priorKeysLoaded);
                assertEquals(RecordCursor.NoNextReason.SCAN_LIMIT_REACHED, noNextResult.getNoNextReason());
                assertNotNull(noNextResult.getContinuation().toBytes());
            } else {
                assertNull(noNextResult.getContinuation().toBytes());
                done = true;
            }
            continuation = noNextResult.getContinuation().toBytes();
        }
        assertEquals(recordCount + 2, totalKeysLoaded);
        commit(context);
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) SimpleDocument(com.apple.foundationdb.record.TestRecordsTextProto.SimpleDocument) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Test(org.junit.jupiter.api.Test)

Aggregations

RecordQuery (com.apple.foundationdb.record.query.RecordQuery)334 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)250 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)222 Test (org.junit.jupiter.api.Test)205 Message (com.google.protobuf.Message)166 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)163 Index (com.apple.foundationdb.record.metadata.Index)114 Query (com.apple.foundationdb.record.query.expressions.Query)114 Tags (com.apple.test.Tags)112 Tag (org.junit.jupiter.api.Tag)112 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)108 RecordQueryPlanner (com.apple.foundationdb.record.query.plan.RecordQueryPlanner)107 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)106 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)102 Arrays (java.util.Arrays)99 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)98 Collections (java.util.Collections)97 List (java.util.List)96 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)95 Assertions.assertTrue (org.junit.jupiter.api.Assertions.assertTrue)93