Search in sources :

Example 21 with Range

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

the class OnlineIndexerSimpleTest method testMarkReadableClearsBuiltRanges.

@Test
public void testMarkReadableClearsBuiltRanges() {
    List<TestRecords1Proto.MySimpleRecord> records = LongStream.range(0, 200).mapToObj(val -> TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(val).setNumValue2((int) val + 1).build()).collect(Collectors.toList());
    Index index = new Index("newIndex", field("num_value_2").ungrouped(), IndexTypes.SUM);
    IndexAggregateFunction aggregateFunction = new IndexAggregateFunction(FunctionNames.SUM, index.getRootExpression(), index.getName());
    List<String> indexTypes = Collections.singletonList("MySimpleRecord");
    FDBRecordStoreTestBase.RecordMetaDataHook hook = metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", index);
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        records.forEach(recordStore::saveRecord);
        context.commit();
    }
    openSimpleMetaData(hook);
    try (OnlineIndexer indexer = OnlineIndexer.newBuilder().setDatabase(fdb).setMetaData(metaData).setIndex(index).setSubspace(subspace).build()) {
        indexer.buildIndex(true);
    }
    openSimpleMetaData(hook);
    try (FDBRecordContext context = openContext()) {
        // Verify rangeSet is cleared when index is marked readable
        final RangeSet rangeSet = new RangeSet(recordStore.indexRangeSubspace(index));
        AsyncIterator<Range> ranges = rangeSet.missingRanges(recordStore.ensureContextActive()).iterator();
        final Range range = ranges.next();
        final boolean range1IsEmpty = RangeSet.isFirstKey(range.begin) && RangeSet.isFinalKey(range.end);
        assertTrue(range1IsEmpty);
        // fake commit, happy compiler
        context.commit();
    }
}
Also used : Arrays(java.util.Arrays) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) Pair(org.apache.commons.lang3.tuple.Pair) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FDBError(com.apple.foundationdb.FDBError) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ThreadContext(org.apache.logging.log4j.ThreadContext) DO_NOT_RE_INCREASE_LIMIT(com.apple.foundationdb.record.provider.foundationdb.OnlineIndexer.DO_NOT_RE_INCREASE_LIMIT) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) ImmutableMap(com.google.common.collect.ImmutableMap) Collectors(java.util.stream.Collectors) DEFAULT_PROGRESS_LOG_INTERVAL(com.apple.foundationdb.record.provider.foundationdb.OnlineIndexer.DEFAULT_PROGRESS_LOG_INTERVAL) TupleRange(com.apple.foundationdb.record.TupleRange) Test(org.junit.jupiter.api.Test) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) List(java.util.List) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Matchers.is(org.hamcrest.Matchers.is) Queue(java.util.Queue) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) FunctionNames(com.apple.foundationdb.record.FunctionNames) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) AsyncIterator(com.apple.foundationdb.async.AsyncIterator) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) RangeSet(com.apple.foundationdb.async.RangeSet) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Key(com.apple.foundationdb.record.metadata.Key) RecordCoreRetriableTransactionException(com.apple.foundationdb.record.RecordCoreRetriableTransactionException) Matchers.lessThan(org.hamcrest.Matchers.lessThan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) LinkedList(java.util.LinkedList) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) Matchers.oneOf(org.hamcrest.Matchers.oneOf) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) LongStream(java.util.stream.LongStream) Assertions.assertSame(org.junit.jupiter.api.Assertions.assertSame) ExecutionException(java.util.concurrent.ExecutionException) Index(com.apple.foundationdb.record.metadata.Index) FDBException(com.apple.foundationdb.FDBException) Collections(java.util.Collections) RangeSet(com.apple.foundationdb.async.RangeSet) Index(com.apple.foundationdb.record.metadata.Index) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) Range(com.apple.foundationdb.Range) TupleRange(com.apple.foundationdb.record.TupleRange) Test(org.junit.jupiter.api.Test)

Example 22 with Range

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

the class OnlineIndexerSimpleTest method buildEndpointIdempotency.

@Test
public void buildEndpointIdempotency() {
    List<TestRecords1Proto.MySimpleRecord> records = LongStream.range(0, 10).mapToObj(val -> TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(val).setNumValue2((int) val + 1).build()).collect(Collectors.toList());
    Index index = new Index("simple$value_2", field("num_value_2").ungrouped(), IndexTypes.SUM);
    IndexAggregateFunction aggregateFunction = new IndexAggregateFunction(FunctionNames.SUM, index.getRootExpression(), index.getName());
    List<String> indexTypes = Collections.singletonList("MySimpleRecord");
    FDBRecordStoreTestBase.RecordMetaDataHook hook = metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", index);
    final Supplier<Tuple> getAggregate = () -> {
        Tuple ret;
        try (FDBRecordContext context = openContext()) {
            assertTrue(recordStore.uncheckedMarkIndexReadable(index.getName()).join());
            FDBRecordStore recordStore2 = recordStore.asBuilder().setContext(context).uncheckedOpen();
            ret = recordStore2.evaluateAggregateFunction(indexTypes, aggregateFunction, TupleRange.ALL, IsolationLevel.SERIALIZABLE).join();
        // Do NOT commit the change.
        }
        return ret;
    };
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        records.forEach(recordStore::saveRecord);
        context.commit();
    }
    openSimpleMetaData(hook);
    try (FDBRecordContext context = openContext()) {
        recordStore.markIndexWriteOnly(index).join();
        context.commit();
    }
    try (OnlineIndexer indexBuilder = OnlineIndexer.newBuilder().setDatabase(fdb).setMetaData(metaData).setIndex(index).setSubspace(subspace).build()) {
        final RangeSet rangeSet = new RangeSet(recordStore.indexRangeSubspace(index));
        // Build the endpoints
        TupleRange range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(0L), range.getLow());
        assertEquals(Tuple.from(9L), range.getHigh());
        assertEquals(Tuple.from(10L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(0L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(9L).pack(), null).join());
        List<Range> middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(0L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(9L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Make sure running this again doesn't change anything.
        range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(0L), range.getLow());
        assertEquals(Tuple.from(9L), range.getHigh());
        assertEquals(Tuple.from(10L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(0L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(9L).pack(), null).join());
        middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(0L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(9L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Remove the first and last records.
        try (FDBRecordContext context = openContext()) {
            recordStore.deleteRecord(Tuple.from(0L));
            recordStore.deleteRecord(Tuple.from(9L));
            context.commit();
        }
        assertEquals(Tuple.from(0L), getAggregate.get());
        // Rerun endpoints with new data.
        range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(1L), range.getLow());
        assertEquals(Tuple.from(8L), range.getHigh());
        assertEquals(Tuple.from(9L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(1L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(8L).pack(), null).join());
        middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(1L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(8L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Run it again to show that nothing has happened.
        range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(1L), range.getLow());
        assertEquals(Tuple.from(8L), range.getHigh());
        assertEquals(Tuple.from(9L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(1L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(8L).pack(), null).join());
        middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(1L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(8L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Add back the previous first and last records.
        try (FDBRecordContext context = openContext()) {
            recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(0L).setNumValue2(1).build());
            recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(9L).setNumValue2(10).build());
            context.commit();
        }
        assertEquals(Tuple.from(20L), getAggregate.get());
        // Rerun endpoints with new data.
        range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(0L), range.getLow());
        assertEquals(Tuple.from(9L), range.getHigh());
        assertEquals(Tuple.from(20L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(1L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(8L).pack(), null).join());
        middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(1L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(8L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Run it again to show that nothing has happened.
        range = indexBuilder.buildEndpoints().join();
        assertEquals(Tuple.from(0L), range.getLow());
        assertEquals(Tuple.from(9L), range.getHigh());
        assertEquals(Tuple.from(20L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), null, Tuple.from(1L).pack()).join());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database(), Tuple.from(8L).pack(), null).join());
        middleRanges = rangeSet.missingRanges(fdb.database()).join();
        assertEquals(Collections.singletonList(Tuple.from(1L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.begin)).collect(Collectors.toList()));
        assertEquals(Collections.singletonList(Tuple.from(8L)), middleRanges.stream().map(r -> Tuple.fromBytes(r.end)).collect(Collectors.toList()));
        // Straight up build the whole index.
        indexBuilder.buildIndex(false);
        assertEquals(Tuple.from(55L), getAggregate.get());
        assertEquals(Collections.emptyList(), rangeSet.missingRanges(fdb.database()).join());
    }
}
Also used : Arrays(java.util.Arrays) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) MetaDataException(com.apple.foundationdb.record.metadata.MetaDataException) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) Pair(org.apache.commons.lang3.tuple.Pair) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FDBError(com.apple.foundationdb.FDBError) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ThreadContext(org.apache.logging.log4j.ThreadContext) DO_NOT_RE_INCREASE_LIMIT(com.apple.foundationdb.record.provider.foundationdb.OnlineIndexer.DO_NOT_RE_INCREASE_LIMIT) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) ImmutableMap(com.google.common.collect.ImmutableMap) Collectors(java.util.stream.Collectors) DEFAULT_PROGRESS_LOG_INTERVAL(com.apple.foundationdb.record.provider.foundationdb.OnlineIndexer.DEFAULT_PROGRESS_LOG_INTERVAL) TupleRange(com.apple.foundationdb.record.TupleRange) Test(org.junit.jupiter.api.Test) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) List(java.util.List) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Matchers.is(org.hamcrest.Matchers.is) Queue(java.util.Queue) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) FunctionNames(com.apple.foundationdb.record.FunctionNames) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) AsyncIterator(com.apple.foundationdb.async.AsyncIterator) CompletableFuture(java.util.concurrent.CompletableFuture) AsyncUtil(com.apple.foundationdb.async.AsyncUtil) RangeSet(com.apple.foundationdb.async.RangeSet) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Key(com.apple.foundationdb.record.metadata.Key) RecordCoreRetriableTransactionException(com.apple.foundationdb.record.RecordCoreRetriableTransactionException) Matchers.lessThan(org.hamcrest.Matchers.lessThan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) LinkedList(java.util.LinkedList) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) Matchers.oneOf(org.hamcrest.Matchers.oneOf) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) LongStream(java.util.stream.LongStream) Assertions.assertSame(org.junit.jupiter.api.Assertions.assertSame) ExecutionException(java.util.concurrent.ExecutionException) Index(com.apple.foundationdb.record.metadata.Index) FDBException(com.apple.foundationdb.FDBException) Collections(java.util.Collections) RangeSet(com.apple.foundationdb.async.RangeSet) Index(com.apple.foundationdb.record.metadata.Index) IndexAggregateFunction(com.apple.foundationdb.record.metadata.IndexAggregateFunction) Range(com.apple.foundationdb.Range) TupleRange(com.apple.foundationdb.record.TupleRange) TupleRange(com.apple.foundationdb.record.TupleRange) Tuple(com.apple.foundationdb.tuple.Tuple) Test(org.junit.jupiter.api.Test)

Example 23 with Range

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

the class HighContentionAllocatorTest method testCheckForRootConflicts.

@Test
@Tag(Tags.WipesFDB)
void testCheckForRootConflicts() {
    Range everything = new Range(new byte[] { (byte) 0x00 }, new byte[] { (byte) 0xFF });
    database.run(context -> {
        context.ensureActive().clear(everything);
        return null;
    });
    try (FDBRecordContext context = database.openContext()) {
        HighContentionAllocator hca = HighContentionAllocator.forRoot(context, keySpace.path("test-path"));
        // so write something for all of those keys
        for (int i = 0; i < 64; i++) {
            byte[] key = Tuple.from(i, "string-" + i).pack();
            byte[] value = new byte[0];
            context.ensureActive().set(key, value);
        }
        try {
            hca.allocate("some-string").join();
            fail("allocate should fail in the same transaction");
        } catch (Exception e) {
            assertThat("a", e.getCause().getMessage(), is("database already has keys in allocation range"));
        }
        // check that the hca marks these keys as invalid
        // the thing here is that when the post allocation hook fails the allocator still writes a key,
        // that's actually a good thing since it will prevent us from trying to allocate that key again
        // but we need to make sure we have a way to exclude from the reverse lookup
        Subspace allocationSubspace = hca.getAllocationSubspace();
        Range initialwindow = new Range(allocationSubspace.getKey(), allocationSubspace.pack(64));
        List<KeyValue> allocatedValues = context.ensureActive().getRange(initialwindow).asList().join();
        byte[] valueBytes = allocatedValues.get(0).getValue();
        assertThat("there's exactly one allocation key", allocatedValues, hasSize(1));
        assertArrayEquals(valueBytes, new byte[] { (byte) 0xFD }, "the value is set to the magic byte");
        context.commit();
    }
    try (FDBRecordContext context = database.openContext()) {
        HighContentionAllocator hca = HighContentionAllocator.forRoot(context, keySpace.path("test-path"));
        try {
            hca.allocate("some-string").join();
            fail("allocate should fail in new transaction");
        } catch (Exception e) {
            assertThat("a", e.getCause().getMessage(), is("database already has keys in allocation range"));
        }
    }
    database.run(context -> {
        context.ensureActive().clear(everything);
        return null;
    });
}
Also used : KeyValue(com.apple.foundationdb.KeyValue) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) Subspace(com.apple.foundationdb.subspace.Subspace) Range(com.apple.foundationdb.Range) Test(org.junit.jupiter.api.Test) Tag(org.junit.jupiter.api.Tag)

Example 24 with Range

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

the class StringInterningLayerTest method testFilterInvalidAllocationValues.

@Test
@Tag(Tags.WipesFDB)
void testFilterInvalidAllocationValues() {
    Range everything = new Range(new byte[] { (byte) 0x00 }, new byte[] { (byte) 0xFF });
    database.run(context -> {
        context.ensureActive().clear(everything);
        return null;
    });
    try (FDBRecordContext context = database.openContext()) {
        StringInterningLayer interningLayer = new StringInterningLayer(testSubspace, true);
        // so write something for all of those keys
        for (int i = 0; i < 64; i++) {
            byte[] key = Tuple.from(i, "string-" + i).pack();
            byte[] value = new byte[0];
            context.ensureActive().set(key, value);
        }
        try {
            interningLayer.intern(context, "a-string").join();
            fail("intern should throw exception");
        } catch (Exception e) {
            assertThat("a", e.getCause().getMessage(), is("database already has keys in allocation range"));
        }
        Optional<ResolverResult> maybeRead = interningLayer.read(context, "a-string").join();
        assertThat("we don't read anything", maybeRead, is(Optional.empty()));
    }
}
Also used : FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) ResolverResult(com.apple.foundationdb.record.provider.foundationdb.keyspace.ResolverResult) Range(com.apple.foundationdb.Range) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) NoSuchElementException(java.util.NoSuchElementException) CompletionException(java.util.concurrent.CompletionException) Test(org.junit.jupiter.api.Test) Tag(org.junit.jupiter.api.Tag)

Example 25 with Range

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

the class FDBRecordStoreTest method prefixPrimaryKeysWithNullByteAfterPrefix.

/**
 * If there are two primary keys that overlap in the just the right way, then one can have the representation
 * of one record's primary key be a strict prefix of the other record's. With older versions of the Record Layer,
 * this could lead to problems where attempting to load the record with the shorter key would also read data for
 * the record with the longer key. See <a href="https://github.com/FoundationDB/fdb-record-layer/issues/782">Issue #782</a>.
 *
 * <p>
 * This test is parameterized by format version because the fix involves being more particular about the range that
 * is scanned. In particular, the scan range is now only over those keys which are strict prefixes of the primary
 * key. This is fine as long as there aren't any data stored at that key. Prior to {@link FDBRecordStore#SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION},
 * there could be data in that key was not true if {@code splitLongRecords} was {@code false}. Parameterizing here
 * tests those older configurations.
 * </p>
 *
 * @param formatVersion format version to use when running the test
 * @param splitLongRecords whether the test should split long records or not
 */
@ParameterizedTest(name = "prefixPrimaryKeysWithNullByteAfterPrefix [formatVersion = {0}, splitLongRecords = {1}]")
@MethodSource("formatVersionAndSplitArgs")
public void prefixPrimaryKeysWithNullByteAfterPrefix(int formatVersion, boolean splitLongRecords) throws Exception {
    final RecordMetaDataHook hook = metaData -> {
        metaData.setSplitLongRecords(splitLongRecords);
        metaData.getRecordType("MySimpleRecord").setPrimaryKey(field("str_value_indexed"));
    };
    final FDBRecordStore.Builder storeBuilder;
    // The primary key for record1 is a prefix of the primary key for record2, and the first byte in record2's primary
    // key is a null byte. Because FDB's Tuple layer null terminates its representation of strings, this means that
    // the keys used to store record1 forms a prefix of the keys storing record2. However, the null byte should be
    // escaped in such a way that it is possible to read only the keys for record1. This is necessary to properly load
    // the record by primary key.
    final TestRecords1Proto.MySimpleRecord record1 = TestRecords1Proto.MySimpleRecord.newBuilder().setStrValueIndexed("foo").setNumValue3Indexed(1066).build();
    final TestRecords1Proto.MySimpleRecord record2 = TestRecords1Proto.MySimpleRecord.newBuilder().setStrValueIndexed("foo\0bar").setNumValue3Indexed(1415).build();
    // Save the two records
    try (FDBRecordContext context = openContext()) {
        uncheckedOpenSimpleRecordStore(context, hook);
        storeBuilder = recordStore.asBuilder().setFormatVersion(formatVersion);
        final FDBRecordStore store = storeBuilder.create();
        store.saveRecord(record1);
        store.saveRecord(record2);
        commit(context);
    }
    // Load by scanning records
    try (FDBRecordContext context = openContext()) {
        final FDBRecordStore store = storeBuilder.setContext(context).open();
        final List<FDBStoredRecord<Message>> records = store.scanRecords(null, ScanProperties.FORWARD_SCAN).asList().get();
        assertThat(records, hasSize(2));
        assertEquals(record1, records.get(0).getRecord());
        assertEquals(record2, records.get(1).getRecord());
    }
    // Load by primary key
    try (FDBRecordContext context = openContext()) {
        final FDBRecordStore store = storeBuilder.setContext(context).open();
        FDBStoredRecord<Message> storedRecord1 = store.loadRecord(Tuple.from(record1.getStrValueIndexed()));
        assertNotNull(storedRecord1, "record1 was missing");
        assertEquals(record1, storedRecord1.getRecord());
        FDBStoredRecord<Message> storedRecord2 = store.loadRecord(Tuple.from(record2.getStrValueIndexed()));
        assertNotNull(storedRecord2, "record2 was missing");
        assertEquals(record2, storedRecord2.getRecord());
    }
    // Load by query
    try (FDBRecordContext context = openContext()) {
        final FDBRecordStore store = storeBuilder.setContext(context).open();
        final RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").equalsParameter("num")).build();
        final RecordQueryPlan plan = store.planQuery(query);
        assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[EQUALS $num]")))));
        // Record 1
        List<FDBQueriedRecord<Message>> record1List = plan.execute(store, EvaluationContext.forBinding("num", 1066)).asList().get();
        assertThat(record1List, hasSize(1));
        FDBQueriedRecord<Message> queriedRecord1 = record1List.get(0);
        assertEquals(record1, queriedRecord1.getRecord());
        // Record 2
        List<FDBQueriedRecord<Message>> record2List = plan.execute(store, EvaluationContext.forBinding("num", 1415)).asList().get();
        assertThat(record2List, hasSize(1));
        FDBQueriedRecord<Message> queriedRecord2 = record2List.get(0);
        assertEquals(record2, queriedRecord2.getRecord());
    }
}
Also used : IndexEntry(com.apple.foundationdb.record.IndexEntry) DescriptorProtos(com.google.protobuf.DescriptorProtos) DELETE_INDEX_ENTRY(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer.Events.DELETE_INDEX_ENTRY) Arrays(java.util.Arrays) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) RecordCoreStorageException(com.apple.foundationdb.record.RecordCoreStorageException) ByteBuffer(java.nio.ByteBuffer) RecordSerializer(com.apple.foundationdb.record.provider.common.RecordSerializer) RecordSerializationException(com.apple.foundationdb.record.provider.common.RecordSerializationException) IndexScanType(com.apple.foundationdb.record.IndexScanType) Tuple(com.apple.foundationdb.tuple.Tuple) Range(com.apple.foundationdb.Range) FDBError(com.apple.foundationdb.FDBError) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Expressions.concatenateFields(com.apple.foundationdb.record.metadata.Key.Expressions.concatenateFields) RecordMetaDataProto(com.apple.foundationdb.record.RecordMetaDataProto) RecordMetaDataOptionsProto(com.apple.foundationdb.record.RecordMetaDataOptionsProto) Is.is(org.hamcrest.core.Is.is) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) Tag(org.junit.jupiter.api.Tag) MethodSource(org.junit.jupiter.params.provider.MethodSource) TestRecords7Proto(com.apple.foundationdb.record.TestRecords7Proto) ByteArrayUtil(com.apple.foundationdb.tuple.ByteArrayUtil) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Matchers.allOf(org.hamcrest.Matchers.allOf) Set(java.util.Set) Collectors(java.util.stream.Collectors) TupleRange(com.apple.foundationdb.record.TupleRange) ByteString(com.google.protobuf.ByteString) Test(org.junit.jupiter.api.Test) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) KeySpacePath(com.apple.foundationdb.record.provider.foundationdb.keyspace.KeySpacePath) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) List(java.util.List) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) RecordMetaDataProvider(com.apple.foundationdb.record.RecordMetaDataProvider) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) Matchers.equalTo(org.hamcrest.Matchers.equalTo) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) TestRecordsWithHeaderProto(com.apple.foundationdb.record.TestRecordsWithHeaderProto) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) Matchers.containsString(org.hamcrest.Matchers.containsString) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) TestNoUnionProto(com.apple.foundationdb.record.TestNoUnionProto) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) TestRecordsDuplicateUnionFields(com.apple.foundationdb.record.TestRecordsDuplicateUnionFields) DynamicMessage(com.google.protobuf.DynamicMessage) Descriptors(com.google.protobuf.Descriptors) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) CompletableFuture(java.util.concurrent.CompletableFuture) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Strings(com.google.common.base.Strings) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) ScanProperties(com.apple.foundationdb.record.ScanProperties) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) Matchers.lessThan(org.hamcrest.Matchers.lessThan) Assumptions.assumeTrue(org.junit.jupiter.api.Assumptions.assumeTrue) Matchers.hasSize(org.hamcrest.Matchers.hasSize) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) Nullable(javax.annotation.Nullable) Charsets(com.google.common.base.Charsets) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) Tags(com.apple.test.Tags) ScanComparisons(com.apple.foundationdb.record.query.plan.ScanComparisons) Assertions.assertSame(org.junit.jupiter.api.Assertions.assertSame) ExecutionException(java.util.concurrent.ExecutionException) Consumer(java.util.function.Consumer) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) TestRecordsImportProto(com.apple.foundationdb.record.TestRecordsImportProto) Index(com.apple.foundationdb.record.metadata.Index) FDBException(com.apple.foundationdb.FDBException) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) Collections(java.util.Collections) SAVE_INDEX_ENTRY(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer.Events.SAVE_INDEX_ENTRY) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) DynamicMessage(com.google.protobuf.DynamicMessage) Message(com.google.protobuf.Message) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Aggregations

Range (com.apple.foundationdb.Range)38 Nonnull (javax.annotation.Nonnull)28 TupleRange (com.apple.foundationdb.record.TupleRange)26 Tuple (com.apple.foundationdb.tuple.Tuple)24 List (java.util.List)23 RangeSet (com.apple.foundationdb.async.RangeSet)22 CompletableFuture (java.util.concurrent.CompletableFuture)22 Index (com.apple.foundationdb.record.metadata.Index)21 Subspace (com.apple.foundationdb.subspace.Subspace)19 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)18 LogMessageKeys (com.apple.foundationdb.record.logging.LogMessageKeys)18 IsolationLevel (com.apple.foundationdb.record.IsolationLevel)17 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)17 Message (com.google.protobuf.Message)17 Collectors (java.util.stream.Collectors)17 Nullable (javax.annotation.Nullable)17 Transaction (com.apple.foundationdb.Transaction)16 AsyncIterator (com.apple.foundationdb.async.AsyncIterator)16 RecordCursor (com.apple.foundationdb.record.RecordCursor)16 ExecuteProperties (com.apple.foundationdb.record.ExecuteProperties)15