Search in sources :

Example 6 with RecordIndexUniquenessViolation

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

the class OnlineIndexerUniqueIndexTest method uniquenessViolations.

@Test
public void uniquenessViolations() {
    List<TestRecords1Proto.MySimpleRecord> records = LongStream.range(0, 10).mapToObj(val -> TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(val).setNumValue2(((int) val) % 5).build()).collect(Collectors.toList());
    Index index = new Index("simple$value_2", field("num_value_2"), EmptyKeyExpression.EMPTY, IndexTypes.VALUE, IndexOptions.UNIQUE_OPTIONS);
    FDBRecordStoreTestBase.RecordMetaDataHook hook = metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", index);
    // Case 1: Entirely in build.
    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()) {
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
        // Case 2: While in write-only mode.
        try (FDBRecordContext context = openContext()) {
            recordStore.deleteAllRecords();
            recordStore.markIndexWriteOnly(index).join();
            context.commit();
        }
        try (FDBRecordContext context = openContext()) {
            records.forEach(recordStore::saveRecord);
            context.commit();
        }
        try (FDBRecordContext context = openContext()) {
            assertEquals(10, (int) recordStore.scanUniquenessViolations(index).getCount().join());
            context.commit();
        }
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
    // Case 3: Some in write-only mode.
    fdb.run(context -> {
        FDBRecordStore.deleteStore(context, subspace);
        return null;
    });
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        for (int i = 0; i < 5; i++) {
            recordStore.saveRecord(records.get(i));
        }
        context.commit();
    }
    openSimpleMetaData(hook);
    try (FDBRecordContext context = openContext()) {
        recordStore.markIndexWriteOnly(index).join();
        for (int i = 5; i < records.size(); i++) {
            recordStore.saveRecord(records.get(i));
        }
        context.commit();
    }
    try (OnlineIndexer indexBuilder = OnlineIndexer.newBuilder().setDatabase(fdb).setMetaData(metaData).setIndex(index).setSubspace(subspace).build()) {
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
    // Case 4: Some in write-only mode with an initial range build that shouldn't affect anything.
    fdb.run(context -> {
        FDBRecordStore.deleteStore(context, subspace);
        return null;
    });
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        for (int i = 5; i < records.size(); i++) {
            recordStore.saveRecord(records.get(i));
        }
        context.commit();
    }
    openSimpleMetaData(hook);
    try (FDBRecordContext context = openContext()) {
        recordStore.markIndexWriteOnly(index).join();
        for (int i = 0; i < 5; i++) {
            recordStore.saveRecord(records.get(i));
        }
        context.commit();
    }
    try (OnlineIndexer indexBuilder = OnlineIndexer.newBuilder().setDatabase(fdb).setMetaData(metaData).setIndex(index).setSubspace(subspace).build()) {
        indexBuilder.buildUnbuiltRange(Key.Evaluated.scalar(0L), Key.Evaluated.scalar(5L)).join();
        try (FDBRecordContext context = openContext()) {
            assertEquals(0, (int) recordStore.scanUniquenessViolations(index).getCount().join());
            context.commit();
        }
        indexBuilder.buildUnbuiltRange(Key.Evaluated.scalar(5L), Key.Evaluated.scalar(10L)).join();
        try (FDBRecordContext context = openContext()) {
            assertEquals(10, (int) recordStore.scanUniquenessViolations(index).getCount().join());
            context.commit();
        }
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
    // Case 5: Should be caught by write-only writes after build.
    fdb.run(context -> {
        FDBRecordStore.deleteStore(context, subspace);
        return null;
    });
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        for (int i = 0; i < 5; i++) {
            recordStore.saveRecord(records.get(i));
        }
        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()) {
        indexBuilder.buildIndex();
    }
    try (FDBRecordContext context = openContext()) {
        for (int i = 5; i < records.size(); i++) {
            recordStore.saveRecord(records.get(i));
        }
        context.commit();
        fail("Did not catch uniqueness violation when done after build by write-only writes");
    } catch (RecordIndexUniquenessViolation e) {
    // passed.
    }
    // Case 6: Should be caught by write-only writes after partial build.
    fdb.run(context -> {
        FDBRecordStore.deleteStore(context, subspace);
        return null;
    });
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        for (int i = 0; i < 5; i++) {
            recordStore.saveRecord(records.get(i));
        }
        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()) {
        indexBuilder.buildUnbuiltRange(Key.Evaluated.scalar(0L), Key.Evaluated.scalar(5L)).join();
        try (FDBRecordContext context = openContext()) {
            for (int i = 5; i < records.size(); i++) {
                recordStore.saveRecord(records.get(i));
            }
            context.commit();
        }
        try (FDBRecordContext context = openContext()) {
            assertEquals(10, (int) recordStore.scanUniquenessViolations(index).getCount().join());
            context.commit();
        }
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
    // Case 7: The second of these two transactions should fail on not_committed, and then
    // there should be a uniqueness violation.
    fdb.run(context -> {
        FDBRecordStore.deleteStore(context, subspace);
        return null;
    });
    openSimpleMetaData();
    try (FDBRecordContext context = openContext()) {
        for (int i = 0; i < 5; i++) {
            recordStore.saveRecord(records.get(i));
        }
        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()) {
        try (FDBRecordContext context = openContext()) {
            context.getReadVersion();
            try (FDBRecordContext context2 = fdb.openContext()) {
                context2.getReadVersion();
                FDBRecordStore recordStore2 = recordStore.asBuilder().setContext(context2).build();
                indexBuilder.buildUnbuiltRange(recordStore, null, Key.Evaluated.scalar(5L)).join();
                recordStore2.saveRecord(records.get(8));
                context.commit();
                context2.commitAsync().handle((ignore, e) -> {
                    assertNotNull(e);
                    RuntimeException runE = FDBExceptions.wrapException(e);
                    assertThat(runE, instanceOf(RecordCoreRetriableTransactionException.class));
                    assertNotNull(runE.getCause());
                    assertThat(runE.getCause(), instanceOf(FDBException.class));
                    FDBException fdbE = (FDBException) runE.getCause();
                    assertEquals(FDBError.NOT_COMMITTED.code(), fdbE.getCode());
                    return null;
                }).join();
            }
        }
        try (FDBRecordContext context = openContext()) {
            for (int i = 5; i < records.size(); i++) {
                recordStore.saveRecord(records.get(i));
            }
            context.commit();
        }
        try (FDBRecordContext context = openContext()) {
            assertEquals(10, (int) recordStore.scanUniquenessViolations(index).getCount().join());
            context.commit();
        }
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
}
Also used : Assertions.fail(org.junit.jupiter.api.Assertions.fail) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) LongStream(java.util.stream.LongStream) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) Set(java.util.Set) Collectors(java.util.stream.Collectors) Key(com.apple.foundationdb.record.metadata.Key) Test(org.junit.jupiter.api.Test) HashSet(java.util.HashSet) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) Tuple(com.apple.foundationdb.tuple.Tuple) List(java.util.List) RecordCoreRetriableTransactionException(com.apple.foundationdb.record.RecordCoreRetriableTransactionException) Index(com.apple.foundationdb.record.metadata.Index) FDBError(com.apple.foundationdb.FDBError) FDBException(com.apple.foundationdb.FDBException) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) FDBException(com.apple.foundationdb.FDBException) Index(com.apple.foundationdb.record.metadata.Index) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) Test(org.junit.jupiter.api.Test)

Example 7 with RecordIndexUniquenessViolation

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

the class FDBRecordStoreUniqueIndexTest method buildUniqueInCheckVersion.

/**
 * Validate the behavior when a unique index is added on existing data that already has duplicates on the same data.
 * The new index should not be built, as that is impossible to do without breaking the constraints of the index, but
 * it also shouldn't fail the store opening or commit, as otherwise, the store would never be able to be opened.
 *
 * @throws Exception from store opening code
 */
@Test
public void buildUniqueInCheckVersion() throws Exception {
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context);
        // create a uniqueness violation on a field without a unique index
        recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1066L).setNumValue2(42).build());
        recordStore.saveRecord(TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(1412L).setNumValue2(42).build());
        commit(context);
    }
    final Index uniqueIndex = new Index("unique_num_value_2_index", Key.Expressions.field("num_value_2"), IndexTypes.VALUE, IndexOptions.UNIQUE_OPTIONS);
    assertTrue(uniqueIndex.isUnique());
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", uniqueIndex));
        assertFalse(recordStore.isIndexReadable(uniqueIndex), "index with uniqueness violations should not be readable after being added to the meta-data");
        final List<RecordIndexUniquenessViolation> uniquenessViolations = recordStore.scanUniquenessViolations(uniqueIndex).asList().get();
        assertThat(uniquenessViolations, not(empty()));
        for (RecordIndexUniquenessViolation uniquenessViolation : uniquenessViolations) {
            assertThat(uniquenessViolation.getPrimaryKey(), either(equalTo(Tuple.from(1066L))).or(equalTo(Tuple.from(1412L))));
        }
        commit(context);
    }
}
Also used : RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) Index(com.apple.foundationdb.record.metadata.Index) Test(org.junit.jupiter.api.Test)

Example 8 with RecordIndexUniquenessViolation

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

the class OnlineIndexerUniqueIndexTest method resolveUniquenessViolations.

@Test
public void resolveUniquenessViolations() {
    List<TestRecords1Proto.MySimpleRecord> records = LongStream.range(0, 10).mapToObj(val -> TestRecords1Proto.MySimpleRecord.newBuilder().setRecNo(val).setNumValue2(((int) val) % 5).build()).collect(Collectors.toList());
    Index index = new Index("simple$value_2", field("num_value_2"), EmptyKeyExpression.EMPTY, IndexTypes.VALUE, IndexOptions.UNIQUE_OPTIONS);
    FDBRecordStoreTestBase.RecordMetaDataHook hook = metaDataBuilder -> metaDataBuilder.addIndex("MySimpleRecord", index);
    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()) {
        indexBuilder.buildIndexAsync().handle((ignore, e) -> {
            assertNotNull(e);
            RuntimeException runE = FDBExceptions.wrapException(e);
            assertNotNull(runE);
            assertThat(runE, instanceOf(RecordIndexUniquenessViolation.class));
            return null;
        }).join();
    }
    try (FDBRecordContext context = openContext()) {
        Set<Tuple> indexEntries = new HashSet<>(recordStore.scanUniquenessViolations(index).map(v -> v.getIndexEntry().getKey()).asList().join());
        for (Tuple indexKey : indexEntries) {
            List<Tuple> primaryKeys = recordStore.scanUniquenessViolations(index, indexKey).map(RecordIndexUniquenessViolation::getPrimaryKey).asList().join();
            assertEquals(2, primaryKeys.size());
            recordStore.resolveUniquenessViolation(index, indexKey, primaryKeys.get(0)).join();
            assertEquals(0, (int) recordStore.scanUniquenessViolations(index, indexKey).getCount().join());
        }
        for (int i = 0; i < 5; i++) {
            assertNotNull(recordStore.loadRecord(Tuple.from(i)));
        }
        for (int i = 5; i < records.size(); i++) {
            assertNull(recordStore.loadRecord(Tuple.from(i)));
        }
        recordStore.markIndexReadable(index).join();
        context.commit();
    }
}
Also used : Assertions.fail(org.junit.jupiter.api.Assertions.fail) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) LongStream(java.util.stream.LongStream) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) IndexOptions(com.apple.foundationdb.record.metadata.IndexOptions) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) Set(java.util.Set) Collectors(java.util.stream.Collectors) Key(com.apple.foundationdb.record.metadata.Key) Test(org.junit.jupiter.api.Test) HashSet(java.util.HashSet) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) Tuple(com.apple.foundationdb.tuple.Tuple) List(java.util.List) RecordCoreRetriableTransactionException(com.apple.foundationdb.record.RecordCoreRetriableTransactionException) Index(com.apple.foundationdb.record.metadata.Index) FDBError(com.apple.foundationdb.FDBError) FDBException(com.apple.foundationdb.FDBException) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Index(com.apple.foundationdb.record.metadata.Index) RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) Tuple(com.apple.foundationdb.tuple.Tuple) HashSet(java.util.HashSet) Test(org.junit.jupiter.api.Test)

Example 9 with RecordIndexUniquenessViolation

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

the class FDBRecordStore method scanUniquenessViolations.

@Override
@Nonnull
public RecordCursor<RecordIndexUniquenessViolation> scanUniquenessViolations(@Nonnull Index index, @Nonnull TupleRange range, @Nullable byte[] continuation, @Nonnull ScanProperties scanProperties) {
    RecordCursor<IndexEntry> tupleCursor = getIndexMaintainer(index).scanUniquenessViolations(range, continuation, scanProperties);
    return tupleCursor.map(entry -> {
        int indexColumns = index.getColumnSize();
        Tuple valueKey = TupleHelpers.subTuple(entry.getKey(), 0, indexColumns);
        Tuple primaryKey = TupleHelpers.subTuple(entry.getKey(), indexColumns, entry.getKey().size());
        Tuple existingKey = entry.getValue();
        return new RecordIndexUniquenessViolation(index, new IndexEntry(index, valueKey, entry.getValue()), primaryKey, existingKey);
    });
}
Also used : RecordIndexUniquenessViolation(com.apple.foundationdb.record.RecordIndexUniquenessViolation) IndexEntry(com.apple.foundationdb.record.IndexEntry) Tuple(com.apple.foundationdb.tuple.Tuple) Nonnull(javax.annotation.Nonnull)

Aggregations

RecordIndexUniquenessViolation (com.apple.foundationdb.record.RecordIndexUniquenessViolation)9 Tuple (com.apple.foundationdb.tuple.Tuple)7 Index (com.apple.foundationdb.record.metadata.Index)6 IndexEntry (com.apple.foundationdb.record.IndexEntry)5 Key (com.apple.foundationdb.record.metadata.Key)5 List (java.util.List)5 Collectors (java.util.stream.Collectors)5 Nonnull (javax.annotation.Nonnull)5 Test (org.junit.jupiter.api.Test)5 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)4 TestRecords1Proto (com.apple.foundationdb.record.TestRecords1Proto)4 IndexTypes (com.apple.foundationdb.record.metadata.IndexTypes)4 EmptyKeyExpression (com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression)4 Set (java.util.Set)4 CompletableFuture (java.util.concurrent.CompletableFuture)4 FDBError (com.apple.foundationdb.FDBError)3 FDBException (com.apple.foundationdb.FDBException)3 Range (com.apple.foundationdb.Range)3 AsyncUtil (com.apple.foundationdb.async.AsyncUtil)3 EvaluationContext (com.apple.foundationdb.record.EvaluationContext)3