use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class RecordTypeKeyTest method testIndexScan.
@Test
public void testIndexScan() throws Exception {
// This means that some record types do not have a record type key, so an index scan will be better.
RecordMetaDataHook hook = metaData -> {
final RecordTypeBuilder t1 = metaData.getRecordType("MySimpleRecord");
final KeyExpression pkey = concat(recordType(), field("rec_no"));
t1.setPrimaryKey(pkey);
metaData.removeIndex(COUNT_INDEX.getName());
metaData.removeIndex(COUNT_UPDATES_INDEX.getName());
};
List<FDBStoredRecord<Message>> recs = saveSomeRecords(hook);
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").build();
RecordQueryPlan plan = planner.plan(query);
assertEquals(recs.subList(0, 2), recordStore.executeQuery(query).map(FDBQueriedRecord::getStoredRecord).asList().join());
assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$str_value_indexed"), unbounded())));
}
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class RecordTypeKeyTest method testSortOnIndexWithComparisonOnSecondColumn.
@ParameterizedTest(name = "testSortOnSingleRecordType [sortExpr = {0}, reverse = {1}]")
@MethodSource("sortArgs")
@Disabled
public void testSortOnIndexWithComparisonOnSecondColumn(@Nonnull KeyExpression sortExpr, boolean reverse) throws Exception {
final Index index = new Index("recno-type", concat(field("num_value_2"), recordType()));
RecordMetaDataHook hook = metaData -> {
BASIC_HOOK.apply(metaData);
metaData.addUniversalIndex(index);
};
// Save an additional record which matches the predicate in order to ensure the reverse parameter of the
// query is honored (as the additional record allows forward and reverse scans to be distinguished)
final List<FDBStoredRecord<Message>> recs = saveSomeRecords(hook);
FDBStoredRecord<Message> additionalRecord;
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
TestRecords1Proto.MySimpleRecord record = TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066).setNumValue2(2).build();
FDBStoredRecord<Message> storedRecord = recordStore.saveRecord(record);
commit(context);
additionalRecord = storedRecord.withCommittedVersion(context.getVersionStamp());
}
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_2").equalsValue(2)).setSort(sortExpr, reverse).build();
final RecordQueryPlan plan = planner.plan(query);
List<FDBStoredRecord<Message>> expectedResults = Arrays.asList(recs.get(1), additionalRecord);
if (reverse) {
expectedResults = Lists.reverse(expectedResults);
}
assertEquals(expectedResults, recordStore.executeQuery(query).map(FDBQueriedRecord::getStoredRecord).asList().join());
assertThat(plan, indexScan(allOf(indexName(index.getName()), bounds(hasTupleString("[EQUALS 2, IS MySimpleRecord]")))));
}
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class OnlineIndexerBuildValueIndexTest method valueRebuild.
private void valueRebuild(@Nonnull List<TestRecords1Proto.MySimpleRecord> records, @Nullable List<TestRecords1Proto.MySimpleRecord> recordsWhileBuilding, int agents, boolean overlap, boolean splitLongRecords) {
Index index = new Index("newIndex", field("num_value_2"));
Function<FDBQueriedRecord<Message>, Integer> projection = rec -> {
TestRecords1Proto.MySimpleRecord simple = TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(rec.getRecord()).build();
if (simple.hasNumValue2()) {
return simple.getNumValue2();
} else {
return Integer.MIN_VALUE;
}
};
List<RecordQuery> queries = records.stream().map(record -> {
Integer value2 = (record.hasNumValue2()) ? record.getNumValue2() : null;
return RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(value2 != null ? Query.field("num_value_2").equalsValue(record.getNumValue2()) : Query.field("num_value_2").isNull()).build();
}).collect(Collectors.toList());
Function<TestRecords1Proto.MySimpleRecord, Integer> indexValue = msg -> msg.hasNumValue2() ? msg.getNumValue2() : null;
Map<Integer, List<Message>> valueMap = group(records, indexValue);
Runnable beforeBuild = () -> {
try (FDBRecordContext context = openContext()) {
for (int i = 0; i < queries.size(); i++) {
Integer value2 = (records.get(i).hasNumValue2()) ? records.get(i).getNumValue2() : null;
String planString = "Scan(<,>) | [MySimpleRecord] | " + ((value2 == null) ? "num_value_2 IS_NULL" : "num_value_2 EQUALS " + value2);
executeQuery(queries.get(i), planString, valueMap.get(value2));
}
context.commit();
}
};
List<TestRecords1Proto.MySimpleRecord> updatedRecords;
List<RecordQuery> updatedQueries;
Map<Integer, List<Message>> updatedValueMap;
if (recordsWhileBuilding == null || recordsWhileBuilding.size() == 0) {
updatedRecords = records;
updatedQueries = queries;
updatedValueMap = valueMap;
} else {
updatedRecords = updated(records, recordsWhileBuilding);
updatedQueries = updatedRecords.stream().map(record -> {
Integer value2 = (record.hasNumValue2()) ? record.getNumValue2() : null;
return RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(value2 != null ? Query.field("num_value_2").equalsValue(record.getNumValue2()) : Query.field("num_value_2").isNull()).build();
}).collect(Collectors.toList());
updatedValueMap = group(updatedRecords, indexValue);
}
Runnable afterBuild = new Runnable() {
@SuppressWarnings("try")
@Override
public void run() {
try (FDBRecordContext context = openContext()) {
// The build job shouldn't affect the reads.
for (int i = 0; i < updatedQueries.size(); i++) {
Integer value2 = (updatedRecords.get(i).hasNumValue2()) ? updatedRecords.get(i).getNumValue2() : null;
String planString = "Scan(<,>) | [MySimpleRecord] | " + ((value2 == null) ? "num_value_2 IS_NULL" : "num_value_2 EQUALS " + value2);
executeQuery(updatedQueries.get(i), planString, updatedValueMap.get(value2));
}
}
}
};
Runnable afterReadable = () -> {
try (FDBRecordContext context = openContext()) {
for (int i = 0; i < updatedQueries.size(); i++) {
Integer value2 = (updatedRecords.get(i).hasNumValue2()) ? updatedRecords.get(i).getNumValue2() : null;
executeQuery(updatedQueries.get(i), "Index(newIndex [[" + value2 + "],[" + value2 + "]])", updatedValueMap.get(value2));
}
RecordQuery sortQuery = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setSort(field("num_value_2")).build();
executeQuery(sortQuery, "Index(newIndex <,>)", updatedRecords.stream().map(msg -> (msg.hasNumValue2()) ? msg.getNumValue2() : Integer.MIN_VALUE).sorted().collect(Collectors.toList()), projection);
context.commit();
}
};
singleRebuild(records, recordsWhileBuilding, agents, overlap, splitLongRecords, index, beforeBuild, afterBuild, afterReadable);
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class OnlineIndexerBuildVersionIndexTest method versionRebuild.
private void versionRebuild(@Nonnull List<TestRecords1Proto.MySimpleRecord> records, @Nullable List<TestRecords1Proto.MySimpleRecord> recordsWhileBuilding, int agents, boolean overlap) {
final Index index = new Index("newVersionIndex", concat(field("num_value_2"), VersionKeyExpression.VERSION), IndexTypes.VERSION);
final Function<FDBQueriedRecord<Message>, Tuple> projection = rec -> {
TestRecords1Proto.MySimpleRecord simple = TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(rec.getRecord()).build();
Integer numValue2 = (simple.hasNumValue2()) ? simple.getNumValue2() : null;
FDBRecordVersion version = rec.hasVersion() ? rec.getVersion() : null;
if (version != null) {
assertTrue(version.isComplete());
}
return Tuple.from(numValue2, (version == null) ? null : version.toVersionstamp());
};
List<RecordQuery> queries = records.stream().map(record -> {
Integer value2 = (record.hasNumValue2()) ? record.getNumValue2() : null;
return RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(value2 != null ? Query.field("num_value_2").equalsValue(record.getNumValue2()) : Query.field("num_value_2").isNull()).setSort(VersionKeyExpression.VERSION).build();
}).collect(Collectors.toList());
Function<TestRecords1Proto.MySimpleRecord, Integer> indexValue = msg -> msg.hasNumValue2() ? msg.getNumValue2() : null;
Map<Integer, List<Message>> valueMap = group(records, indexValue);
Map<Long, FDBRecordVersion> versionMap = new HashMap<>(records.size() + (recordsWhileBuilding == null ? 0 : recordsWhileBuilding.size()));
AtomicReference<FDBRecordVersion> greatestVersion = new AtomicReference<>(null);
final Runnable beforeBuild = () -> {
try (FDBRecordContext context = openContext()) {
for (int i = 0; i < queries.size(); i++) {
Integer value2 = (records.get(i).hasNumValue2()) ? records.get(i).getNumValue2() : null;
try {
executeQuery(queries.get(i), "Index(newVersionIndex [[" + value2 + "],[" + value2 + "])", valueMap.get(value2));
fail("somehow executed query with new index before build");
} catch (RecordCoreException e) {
assertEquals("Cannot sort without appropriate index: Version", e.getMessage());
}
}
// Load all the version information for the records that were initially there.
for (TestRecords1Proto.MySimpleRecord simple : records) {
recordStore.loadRecordVersion(Tuple.from(simple.getRecNo())).ifPresent(version -> {
versionMap.put(simple.getRecNo(), version);
if (greatestVersion.get() == null || version.compareTo(greatestVersion.get()) > 0) {
greatestVersion.set(version);
}
});
}
context.commit();
}
};
List<TestRecords1Proto.MySimpleRecord> updatedRecords;
List<RecordQuery> updatedQueries;
Map<Integer, List<Message>> updatedValueMap;
if (recordsWhileBuilding == null || recordsWhileBuilding.size() == 0) {
updatedRecords = records;
updatedQueries = queries;
updatedValueMap = valueMap;
} else {
updatedRecords = updated(records, recordsWhileBuilding);
updatedQueries = updatedRecords.stream().map(record -> {
Integer value2 = (record.hasNumValue2()) ? record.getNumValue2() : null;
return RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(value2 != null ? Query.field("num_value_2").equalsValue(record.getNumValue2()) : Query.field("num_value_2").isNull()).setSort(VersionKeyExpression.VERSION).build();
}).collect(Collectors.toList());
updatedValueMap = group(updatedRecords, indexValue);
}
Map<Long, FDBRecordVersion> updatedVersionMap = new HashMap<>(versionMap.size());
Set<Long> newRecordKeys = (recordsWhileBuilding == null) ? Collections.emptySet() : recordsWhileBuilding.stream().map(TestRecords1Proto.MySimpleRecord::getRecNo).collect(Collectors.toSet());
Runnable afterBuild = new Runnable() {
@SuppressWarnings("try")
@Override
public void run() {
try (FDBRecordContext context = openContext()) {
// The build job shouldn't affect the reads.
for (int i = 0; i < updatedQueries.size(); i++) {
Integer value2 = (updatedRecords.get(i).hasNumValue2()) ? updatedRecords.get(i).getNumValue2() : null;
try {
executeQuery(updatedQueries.get(i), "Index(newVersionIndex [[" + value2 + "],[" + value2 + "])", updatedValueMap.get(value2));
fail("somehow executed query with new index before readable");
} catch (RecordCoreException e) {
assertEquals("Cannot sort without appropriate index: Version", e.getMessage());
}
}
// Load all the version information for records that are there now and that values are sane.
for (TestRecords1Proto.MySimpleRecord simple : updatedRecords) {
recordStore.loadRecordVersion(Tuple.from(simple.getRecNo())).ifPresent(version -> {
assertTrue(version.isComplete());
if (newRecordKeys.contains(simple.getRecNo())) {
assertThat(version, greaterThan(greatestVersion.get()));
if (versionMap.containsKey(simple.getRecNo())) {
assertThat(version, greaterThan(versionMap.get(simple.getRecNo())));
}
} else {
if (versionMap.containsKey(simple.getRecNo())) {
assertEquals(versionMap.get(simple.getRecNo()), version);
}
}
updatedVersionMap.put(simple.getRecNo(), version);
});
}
}
}
};
Runnable afterReadable = () -> {
Descriptors.FieldDescriptor recNoFieldDescriptor = TestRecords1Proto.MySimpleRecord.getDescriptor().findFieldByName("rec_no");
try (FDBRecordContext context = openContext()) {
for (int i = 0; i < updatedQueries.size(); i++) {
Integer value2 = (updatedRecords.get(i).hasNumValue2()) ? updatedRecords.get(i).getNumValue2() : null;
List<Tuple> sortedValues = updatedValueMap.get(value2).stream().map(msg -> {
FDBRecordVersion version = updatedVersionMap.get(((Number) msg.getField(recNoFieldDescriptor)).longValue());
return Tuple.from(value2, version == null ? null : version.toVersionstamp());
}).sorted().collect(Collectors.toList());
executeQuery(updatedQueries.get(i), "Index(newVersionIndex [[" + value2 + "],[" + value2 + "]])", sortedValues, projection);
}
context.commit();
}
};
singleRebuild(records, recordsWhileBuilding, agents, overlap, false, index, beforeBuild, afterBuild, afterReadable);
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreQueryTest method nullableInt32.
@DualPlannerTest
void nullableInt32() throws Exception {
try (FDBRecordContext context = openContext()) {
final List<UUID> uuids = setupTupleFields(context);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MyFieldsRecord").setFilter(Query.field("fint32").isNull()).build();
RecordQueryPlan plan = planner.plan(query);
assertMatchesExactly(plan, indexPlan().where(indexName("MyFieldsRecord$fint32")).and(scanComparisons(range("[[null],[null]]"))));
assertEquals(uuids.subList(3, 4), recordStore.executeQuery(plan).map(r -> r.getPrimaryKey().getUUID(0)).asList().join());
}
}
Aggregations