FDBRecordStore extends FDBStoreBase implements FDBRecordStoreBase<Message> { @Nonnull public static Builder newBuilder() { return new Builder(); } @SuppressWarnings("squid:S00107") protected  FDBRecordStore(@Nonnull FDBRecordContext context,
                             @Nonnull SubspaceProvider subspaceProvider,
                             int formatVersion,
                             @Nonnull RecordMetaDataProvider metaDataProvider,
                             @Nonnull RecordSerializer<Message> serializer,
                             @Nonnull IndexMaintainerRegistry indexMaintainerRegistry,
                             @Nonnull IndexMaintenanceFilter indexMaintenanceFilter,
                             @Nonnull PipelineSizer pipelineSizer,
                             @Nullable FDBRecordStoreStateCache storeStateCache); @Override FDBRecordStore getUntypedRecordStore(); @Nonnull @Override FDBRecordContext getContext(); int getFormatVersion(); int getUserVersion(); @Nullable RecordMetaDataProvider getMetaDataProvider(); @Override @Nonnull RecordMetaData getRecordMetaData(); @Nonnull RecordStoreState getRecordStoreState(); @Override @Nonnull RecordSerializer<Message> getSerializer(); @Nonnull IndexMaintainerRegistry getIndexMaintainerRegistry(); @Nonnull IndexMaintenanceFilter getIndexMaintenanceFilter(); @Override @Nonnull CompletableFuture<FDBStoredRecord<Message>> saveRecordAsync(@Nonnull final Message record, @Nonnull RecordExistenceCheck existenceCheck,
                                                                       @Nullable FDBRecordVersion version, @Nonnull final VersionstampSaveBehavior behavior); @Nonnull @API(API.Status.EXPERIMENTAL) CompletableFuture<FDBSyntheticRecord> loadSyntheticRecord(@Nonnull Tuple primaryKey); @Nonnull Subspace recordsSubspace(); @Nonnull Subspace indexSubspace(@Nonnull Index index); @Nonnull Subspace indexSubspaceFromMaintainer(@Nonnull Index index); @Nonnull Subspace indexStateSubspace(); @Nonnull Subspace indexSecondarySubspace(@Nonnull Index index); @Nonnull Subspace indexRangeSubspace(@Nonnull Index index); @Nonnull Subspace indexUniquenessViolationsSubspace(@Nonnull Index index); IndexMaintainer getIndexMaintainer(@Nonnull Index index); int getKeySizeLimit(); int getValueSizeLimit(); CompletableFuture<IndexOperationResult> performIndexOperationAsync(@Nonnull String indexName,
                                                                              @Nonnull IndexOperation operation); IndexOperationResult performIndexOperation(@Nonnull String indexName, @Nonnull IndexOperation operation); @Override @Nonnull CompletableFuture<FDBStoredRecord<Message>> loadRecordInternal(@Nonnull final Tuple primaryKey,
                                                                          @Nonnull ExecuteState executeState,
                                                                          final boolean snapshot); @Nonnull Optional<CompletableFuture<FDBRecordVersion>> loadRecordVersionAsync(@Nonnull final Tuple primaryKey); @Nonnull Optional<CompletableFuture<FDBRecordVersion>> loadRecordVersionAsync(@Nonnull final Tuple primaryKey, final boolean snapshot); @Nonnull Optional<FDBRecordVersion> loadRecordVersion(@Nonnull final Tuple primaryKey); @Nonnull Optional<FDBRecordVersion> loadRecordVersion(@Nonnull final Tuple primaryKey, final boolean snapshot); void countKeyValue(@Nonnull final FDBStoreTimer.Count key,
                              @Nonnull final FDBStoreTimer.Count keyBytes,
                              @Nonnull final FDBStoreTimer.Count valueBytes,
                              @Nonnull final KeyValue keyValue); void countKeyValue(@Nonnull final FDBStoreTimer.Count key,
                              @Nonnull final FDBStoreTimer.Count keyBytes,
                              @Nonnull final FDBStoreTimer.Count valueBytes,
                              @Nonnull final byte[] k, @Nonnull final byte[] v); @Override @Nonnull CompletableFuture<Void> preloadRecordAsync(@Nonnull final Tuple primaryKey); @Override @Nonnull CompletableFuture<Boolean> recordExistsAsync(@Nonnull final Tuple primaryKey, @Nonnull final IsolationLevel isolationLevel); @Override void addRecordReadConflict(@Nonnull Tuple primaryKey); @Override void addRecordWriteConflict(@Nonnull Tuple primaryKey); @Override @Nonnull RecordCursor<FDBStoredRecord<Message>> scanRecords(@Nullable final Tuple low, @Nullable final Tuple high,
                                                              @Nonnull final EndpointType lowEndpoint, @Nonnull final EndpointType highEndpoint,
                                                              @Nullable byte[] continuation,
                                                              @Nonnull ScanProperties scanProperties); @Nonnull RecordCursor<FDBStoredRecord<M>> scanTypedRecords(@Nonnull RecordSerializer<M> typedSerializer,
                                                                                 @Nullable final Tuple low, @Nullable final Tuple high,
                                                                                 @Nonnull final EndpointType lowEndpoint, @Nonnull final EndpointType highEndpoint,
                                                                                 @Nullable byte[] continuation,
                                                                                 @Nonnull ScanProperties scanProperties); @Override @Nonnull CompletableFuture<Integer> countRecords(
            @Nullable Tuple low, @Nullable Tuple high,
            @Nonnull EndpointType lowEndpoint, @Nonnull EndpointType highEndpoint,
            @Nullable byte[] continuation,
            @Nonnull ScanProperties scanProperties); @Override @Nonnull RecordCursor<IndexEntry> scanIndex(@Nonnull Index index, @Nonnull IndexScanType scanType,
                                              @Nonnull TupleRange range,
                                              @Nullable byte[] continuation,
                                              @Nonnull ScanProperties scanProperties); @Override @Nonnull RecordCursor<RecordIndexUniquenessViolation> scanUniquenessViolations(@Nonnull Index index, @Nonnull TupleRange range,
                                                                                 @Nullable byte[] continuation,
                                                                                 @Nonnull ScanProperties scanProperties); @Override @Nonnull CompletableFuture<Void> resolveUniquenessViolation(@Nonnull Index index, @Nonnull Tuple valueKey, @Nullable Tuple remainPrimaryKey); @Override @Nonnull CompletableFuture<Boolean> deleteRecordAsync(@Nonnull final Tuple primaryKey); static void deleteStore(FDBRecordContext context, KeySpacePath path); static void deleteStore(FDBRecordContext context, Subspace subspace); @Override void deleteAllRecords(); @Override CompletableFuture<Void> deleteRecordsWhereAsync(@Nonnull QueryComponent component); @Override PipelineSizer getPipelineSizer(); @Override CompletableFuture<Long> getSnapshotRecordCount(@Nonnull KeyExpression key, @Nonnull Key.Evaluated value); @Override CompletableFuture<Long> getSnapshotRecordCountForRecordType(@Nonnull String recordTypeName); static long decodeRecordCount(@Nullable byte[] bytes); @Override @Nonnull CompletableFuture<T> evaluateIndexRecordFunction(@Nonnull EvaluationContext evaluationContext,
                                                                @Nonnull IndexRecordFunction<T> function,
                                                                @Nonnull FDBRecord<Message> record); @Override @Nonnull CompletableFuture<T> evaluateStoreFunction(@Nonnull EvaluationContext evaluationContext,
                                                          @Nonnull StoreRecordFunction<T> function,
                                                          @Nonnull FDBRecord<Message> record); @SuppressWarnings("unchecked") @Nonnull CompletableFuture<T> evaluateTypedStoreFunction(@Nonnull EvaluationContext evaluationContext,
                                                                                  @Nonnull StoreRecordFunction<T> function,
                                                                                  @Nonnull FDBRecord<M> record); @Override @Nonnull CompletableFuture<Tuple> evaluateAggregateFunction(@Nonnull List<String> recordTypeNames,
                                                              @Nonnull IndexAggregateFunction aggregateFunction,
                                                              @Nonnull TupleRange range,
                                                              @Nonnull IsolationLevel isolationLevel); @Override @Nonnull RecordQueryPlan planQuery(@Nonnull RecordQuery query); @Nonnull static IndexState writeOnlyIfTooManyRecordsForRebuild(long recordCount, boolean indexOnNewRecordTypes); @Nonnull CompletableFuture<Boolean> checkVersion(@Nullable UserVersionChecker userVersionChecker,
                                                   @Nonnull StoreExistenceCheck existenceCheck); @API(API.Status.INTERNAL) @Nonnull static CompletableFuture<Void> checkStoreHeader(@Nonnull RecordMetaDataProto.DataStoreInfo storeHeader,
                                                           @Nonnull FDBRecordContext context,
                                                           @Nonnull SubspaceProvider subspaceProvider,
                                                           @Nonnull Subspace subspace,
                                                           @Nonnull StoreExistenceCheck existenceCheck); @Nonnull CompletableFuture<Void> rebuildAllIndexes(); @Nonnull CompletableFuture<Void> clearAndMarkIndexWriteOnly(@Nonnull String indexName); @Nonnull CompletableFuture<Void> clearAndMarkIndexWriteOnly(@Nonnull Index index); @Nonnull CompletableFuture<Boolean> setStateCacheabilityAsync(boolean cacheable); boolean setStateCacheability(boolean cacheable); @Nullable ByteString getHeaderUserField(@Nonnull String userField); @Nonnull CompletableFuture<Void> setHeaderUserFieldAsync(@Nonnull String userField, @Nonnull ByteString value); @Nonnull CompletableFuture<Void> setHeaderUserFieldAsync(@Nonnull String userField, @Nonnull byte[] value); void setHeaderUserField(@Nonnull String userField, @Nonnull ByteString value); void setHeaderUserField(@Nonnull String userField, @Nonnull byte[] value); @Nonnull CompletableFuture<Void> clearHeaderUserFieldAsync(@Nonnull String userField); void clearHeaderUserField(@Nonnull String userField); @Nonnull CompletableFuture<Boolean> markIndexWriteOnly(@Nonnull String indexName); @Nonnull CompletableFuture<Boolean> markIndexWriteOnly(@Nonnull Index index); @Nonnull CompletableFuture<Boolean> markIndexDisabled(@Nonnull String indexName); @Nonnull CompletableFuture<Boolean> markIndexDisabled(@Nonnull Index index); @Nonnull CompletableFuture<Optional<Range>> firstUnbuiltRange(@Nonnull Index index); @Nonnull CompletableFuture<Boolean> markIndexReadable(@Nonnull Index index); @Nonnull CompletableFuture<Boolean> markIndexReadable(@Nonnull String indexName); @Nonnull CompletableFuture<Boolean> uncheckedMarkIndexReadable(@Nonnull String indexName); @API(API.Status.INTERNAL) @Nonnull CompletableFuture<RecordStoreState> loadRecordStoreStateAsync(@Nonnull StoreExistenceCheck existenceCheck); @Nonnull IndexState getIndexState(@Nonnull Index index); @Nonnull IndexState getIndexState(@Nonnull String indexName); boolean isIndexReadable(@Nonnull Index index); boolean isIndexReadable(@Nonnull String indexName); boolean isIndexWriteOnly(@Nonnull Index index); boolean isIndexWriteOnly(@Nonnull String indexName); boolean isIndexDisabled(@Nonnull Index index); boolean isIndexDisabled(@Nonnull String indexName); CompletableFuture<IndexBuildState> getIndexBuildStateAsync(Index index); @Nonnull List<Index> getReadableIndexes(@Nonnull RecordTypeOrBuilder recordType); @Nonnull List<Index> getEnabledIndexes(@Nonnull RecordTypeOrBuilder recordType); @Nonnull List<Index> getReadableMultiTypeIndexes(@Nonnull RecordTypeOrBuilder recordType); @Nonnull List<Index> getEnabledMultiTypeIndexes(@Nonnull RecordTypeOrBuilder recordType); @Nonnull List<Index> getReadableUniversalIndexes(); @Nonnull List<Index> getEnabledUniversalIndexes(); @Nonnull Map<Index, IndexState> getAllIndexStates(); @Nonnull CompletableFuture<Void> rebuildIndex(@Nonnull Index index); @Nonnull @SuppressWarnings("squid:S2095") // Resource usage for indexBuilder is too complicated for rule. CompletableFuture<Void> rebuildIndex(@Nonnull final Index index, @Nullable final Collection<RecordType> recordTypes, @Nonnull RebuildIndexReason reason); @API(API.Status.INTERNAL) @VisibleForTesting Subspace getLegacyVersionSubspace(); void removeFormerIndex(FormerIndex formerIndex); void addRebuildRecordCountsJob(List<CompletableFuture<Void>> work); @API(API.Status.EXPERIMENTAL) @Nonnull RecordCursor<Tuple> getPrimaryKeyBoundaries(@Nonnull Tuple low, @Nonnull Tuple high); @Deprecated void validateMetaData(); @Nonnull CompletableFuture<byte[]> repairRecordKeys(@Nullable byte[] continuation, @Nonnull ScanProperties scanProperties); @Nonnull CompletableFuture<byte[]> repairRecordKeys(@Nullable byte[] continuation,
                                                      @Nonnull ScanProperties scanProperties,
                                                      final boolean isDryRun); @Nonnull static Builder newBuilder(); @Nonnull Builder asBuilder(); static final int DEFAULT_PIPELINE_SIZE; static final PipelineSizer DEFAULT_PIPELINE_SIZER; static final int MAX_RECORDS_FOR_REBUILD; static final int MAX_PARALLEL_INDEX_REBUILD; static final int INFO_ADDED_FORMAT_VERSION; static final int RECORD_COUNT_ADDED_FORMAT_VERSION; static final int RECORD_COUNT_KEY_ADDED_FORMAT_VERSION; static final int FORMAT_CONTROL_FORMAT_VERSION; static final int SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION; static final int SAVE_VERSION_WITH_RECORD_FORMAT_VERSION; static final int CACHEABLE_STATE_FORMAT_VERSION; static final int HEADER_USER_FIELDS_FORMAT_VERSION; static final int MAX_SUPPORTED_FORMAT_VERSION; static final int DEFAULT_FORMAT_VERSION; static final int KEY_SIZE_LIMIT; static final int VALUE_SIZE_LIMIT; @SuppressWarnings("squid:S2386")
    @SpotBugsSuppressWarnings("MS_MUTABLE_ARRAY")
    static final byte[] LITTLE_ENDIAN_INT64_ONE; @SuppressWarnings("squid:S2386")
    @SpotBugsSuppressWarnings("MS_MUTABLE_ARRAY")
    static final byte[] LITTLE_ENDIAN_INT64_MINUS_ONE; }
@Test public void scanContinuations() throws Exception { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); for (int i = 0; i < 100; i++) { recBuilder.setRecNo(i); recordStore.saveRecord(recBuilder.build()); } commit(context); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); for (Boolean builtInLimit : new Boolean[] { Boolean.TRUE, Boolean.FALSE }) { for (int limit = 1; limit <= 5; limit++) { int i = 0; byte[] continuation = null; do { try (RecordCursorIterator<FDBStoredRecord<Message>> cursor = scanContinuationsCursor(continuation, limit, false, builtInLimit).asIterator()) { while (cursor.hasNext()) { assertEquals(i, cursor.next().getPrimaryKey().getLong(0)); i++; } continuation = cursor.getContinuation(); } } while (continuation != null); assertEquals(100, i); do { try (RecordCursorIterator<FDBStoredRecord<Message>> cursor = scanContinuationsCursor(continuation, limit, true, builtInLimit).asIterator()) { while (cursor.hasNext()) { i--; assertEquals(i, cursor.next().getPrimaryKey().getLong(0)); } continuation = cursor.getContinuation(); } } while (continuation != null); assertEquals(0, i); } } commit(context); } }
@Test public void testIndexKeyTooLarge() { assertThrows(FDBExceptions.FDBStoreKeySizeException.class, () -> { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); recBuilder.setStrValueIndexed(Strings.repeat("x", 10000)); recordStore.saveRecord(recBuilder.build()); fail("exception should have been thrown before commit"); commit(context); } }); }
@Test public void testIndexValueTooLarge() { assertThrows(FDBExceptions.FDBStoreValueSizeException.class, () -> { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context, md -> { md.setSplitLongRecords(true); md.removeIndex("MySimpleRecord$str_value_indexed"); md.addIndex("MySimpleRecord", new Index( "valueIndex", field("num_value_2"), field("str_value_indexed"), IndexTypes.VALUE, Collections.emptyMap())); }); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); recBuilder.setStrValueIndexed(Strings.repeat("x", 100000)); recordStore.saveRecord(recBuilder.build()); fail("exception should have been thrown before commit"); commit(context); } }); }
@Test public void testStoredRecordSizeIsPlausible() { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context, TEST_SPLIT_HOOK); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); recBuilder.setStrValueIndexed(Strings.repeat("x", 10)); FDBStoredRecord<Message> rec1 = recordStore.saveRecord(recBuilder.build()); assertEquals(1, rec1.getKeyCount(), "small record should only need one key-value pair"); assertThat("small record should only need few key bytes", rec1.getKeySize(), allOf(greaterThan(5), lessThan(100))); assertThat("small record should only need few value bytes", rec1.getValueSize(), allOf(greaterThan(10), lessThan(100))); recBuilder.setRecNo(2); recBuilder.setStrValueIndexed(Strings.repeat("x", 100000)); FDBStoredRecord<Message> rec2 = recordStore.saveRecord(recBuilder.build()); assertThat("large record should only need several key-value pairs", rec2.getKeyCount(), allOf(greaterThan(1), lessThan(10))); assertThat("large record should only need few key bytes", rec2.getKeySize(), allOf(greaterThan(10), lessThan(100))); assertThat("large record should only need many value bytes", rec2.getValueSize(), allOf(greaterThan(100000), lessThan(101000))); FDBStoredRecord<Message> rec1x = recordStore.loadRecord(rec1.getPrimaryKey()); assertEquals(rec1.getKeyCount(), rec1x.getKeyCount(), "small record loaded key count should match"); assertEquals(rec1.getKeySize(), rec1x.getKeySize(), "small record loaded key size should match"); assertEquals(rec1.getValueSize(), rec1x.getValueSize(), "small record loaded value size should match"); FDBStoredRecord<Message> rec2x = recordStore.loadRecord(rec2.getPrimaryKey()); assertEquals(rec2.getKeyCount(), rec2x.getKeyCount(), "large record loaded key count should match"); assertEquals(rec2.getKeySize(), rec2x.getKeySize(), "large record loaded key size should match"); assertEquals(rec2.getValueSize(), rec2x.getValueSize(), "large record loaded value size should match"); commit(context); } }
@Test public void updateUnchanged() throws Exception { TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); recBuilder.setStrValueIndexed("abc"); recordStore.saveRecord(recBuilder.build()); commit(context); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); recBuilder.setStrValueIndexed("xyz"); recordStore.saveRecord(recBuilder.build()); assertEquals(2, timer.getCount(DELETE_INDEX_ENTRY) + timer.getCount(SAVE_INDEX_ENTRY), "should update one index"); commit(context); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); recordStore.saveRecord(recBuilder.build()); assertEquals(0, timer.getCount(DELETE_INDEX_ENTRY) + timer.getCount(SAVE_INDEX_ENTRY), "should not update any index"); commit(context); } }
@Test public void typeChange() throws Exception { try (FDBRecordContext context = openContext()) { createOrOpenRecordStore(context, RecordMetaData.build(TestRecords7Proto.getDescriptor())); TestRecords7Proto.MyRecord1.Builder rec1Builder = TestRecords7Proto.MyRecord1.newBuilder(); rec1Builder.setRecNo(1); rec1Builder.setStrValue("one"); recordStore.saveRecord(rec1Builder.build()); assertEquals(1L, recordStore.scanIndexRecords("MyRecord1$str_value").getCount().get().longValue(), "should have one record in index"); TestRecords7Proto.MyRecord2.Builder rec2Builder = TestRecords7Proto.MyRecord2.newBuilder(); rec2Builder.setRecNo(1); rec2Builder.setStrValue("two"); recordStore.saveRecord(rec2Builder.build()); FDBStoredRecord<Message> rec2 = recordStore.loadRecord(Tuple.from(1L)); assertNotNull(rec2); TestRecords7Proto.MyRecord2.Builder myrec = TestRecords7Proto.MyRecord2.newBuilder(); myrec.mergeFrom(rec2.getRecord()); assertEquals("two", myrec.getStrValue(), "should load second record"); assertEquals(0L, recordStore.scanIndexRecords("MyRecord1$str_value").getCount().get().longValue(), "should have no records in index"); } }
@Test public void testCommittedVersion() throws Exception { try (FDBRecordContext context = openContext()) { final long readVersion = context.getReadVersion(); openSimpleRecordStore(context); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); recordStore.saveRecord(recBuilder.build()); commit(context); assertThat(context.getCommittedVersion(), greaterThan(readVersion)); } }
@Test public void testVersionStamp() throws Exception { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder(); recBuilder.setRecNo(1); recordStore.saveRecord(recBuilder.build()); commit(context); assertNotNull(context.getVersionStamp()); long committedVersion = context.getCommittedVersion(); assertThat(committedVersion, greaterThan(0L)); assertEquals(committedVersion, ByteBuffer.wrap(context.getVersionStamp()).getLong()); } }
@Test public void testSubspaceReadWriteConflict() throws Exception { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); context.commit(); } try (FDBRecordContext context1 = openContext()) { openSimpleRecordStore(context1); FDBRecordStore recordStore1 = recordStore; recordStore1.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1).build()); try (FDBRecordContext context2 = openContext()) { openSimpleRecordStore(context2); recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(2).build()); commit(context2); } commit(context1); } try (FDBRecordContext context3 = openContext()) { openSimpleRecordStore(context3); FDBRecordStore recordStore3 = recordStore; recordStore3.addConflictForSubspace(false); recordStore3.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(3).build()); try (FDBRecordContext context4 = openContext()) { uncheckedOpenSimpleRecordStore(context4); recordStore.addConflictForSubspace(false); recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(4).build()); commit(context4); } assertThrows(FDBExceptions.FDBStoreTransactionConflictException.class, () -> commit(context3)); } }
@Test public void commitChecks() throws Exception { try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); context.addCommitCheck(checkRec1Exists()); TestRecords1Proto.MySimpleRecord rec = TestRecords1Proto.MySimpleRecord.newBuilder() .setRecNo(1L) .build(); recordStore.saveRecord(rec); assertThrows(RecordDoesNotExistException.class, () -> commit(context)); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); context.addCommitCheck(this::checkRec1Exists); assertThrows(RecordDoesNotExistException.class, () -> commit(context)); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); context.addCommitCheck(this::checkRec1Exists); TestRecords1Proto.MySimpleRecord rec = TestRecords1Proto.MySimpleRecord.newBuilder() .setRecNo(1L) .build(); recordStore.saveRecord(rec); commit(context); } try (FDBRecordContext context = openContext()) { openSimpleRecordStore(context); context.addCommitCheck(checkRec1Exists()); commit(context); } }