Search in sources :

Example 1 with ClassGuardedAdversary

use of org.neo4j.adversaries.ClassGuardedAdversary in project neo4j by neo4j.

the class CountsRotationTest method possibleToShutdownDbWhenItIsNotHealthyAndNotAllTransactionsAreApplied.

@Test(timeout = 60_000)
public void possibleToShutdownDbWhenItIsNotHealthyAndNotAllTransactionsAreApplied() throws Exception {
    // adversary that makes page cache throw exception when node store is used
    ClassGuardedAdversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, true), NodeStore.class);
    adversary.disable();
    GraphDatabaseService db = AdversarialPageCacheGraphDatabaseFactory.create(fs, adversary).newEmbeddedDatabaseBuilder(dir).newGraphDatabase();
    CountDownLatch txStartLatch = new CountDownLatch(1);
    CountDownLatch txCommitLatch = new CountDownLatch(1);
    Future<?> result = ForkJoinPool.commonPool().submit(() -> {
        try (Transaction tx = db.beginTx()) {
            txStartLatch.countDown();
            db.createNode();
            await(txCommitLatch);
            tx.success();
        }
    });
    await(txStartLatch);
    adversary.enable();
    txCommitLatch.countDown();
    try {
        result.get();
        fail("Exception expected");
    } catch (ExecutionException ee) {
        // transaction is expected to fail because write through the page cache fails
        assertThat(ee.getCause(), instanceOf(TransactionFailureException.class));
    }
    adversary.disable();
    // shutdown should complete without any problems
    db.shutdown();
}
Also used : GraphDatabaseService(org.neo4j.graphdb.GraphDatabaseService) CountingAdversary(org.neo4j.adversaries.CountingAdversary) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Transaction(org.neo4j.graphdb.Transaction) CountDownLatch(java.util.concurrent.CountDownLatch) ExecutionException(java.util.concurrent.ExecutionException) Test(org.junit.Test)

Example 2 with ClassGuardedAdversary

use of org.neo4j.adversaries.ClassGuardedAdversary in project neo4j by neo4j.

the class RecoveryIT method recoveryShouldFixPartiallyAppliedSchemaIndexUpdates.

@Test(timeout = 60_000)
public void recoveryShouldFixPartiallyAppliedSchemaIndexUpdates() {
    Label label = Label.label("Foo");
    String property = "Bar";
    // cause failure during 'relationship.delete()' command application
    ClassGuardedAdversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, true), Command.RelationshipCommand.class);
    adversary.disable();
    File storeDir = directory.graphDbDir();
    GraphDatabaseService db = AdversarialPageCacheGraphDatabaseFactory.create(fileSystemRule.get(), adversary).newEmbeddedDatabaseBuilder(storeDir).newGraphDatabase();
    try {
        try (Transaction tx = db.beginTx()) {
            db.schema().constraintFor(label).assertPropertyIsUnique(property).create();
            tx.success();
        }
        long relationshipId = createRelationship(db);
        TransactionFailureException txFailure = null;
        try (Transaction tx = db.beginTx()) {
            Node node = db.createNode(label);
            node.setProperty(property, "B");
            // this should fail because of the adversary
            db.getRelationshipById(relationshipId).delete();
            tx.success();
            adversary.enable();
        } catch (TransactionFailureException e) {
            txFailure = e;
        }
        assertNotNull(txFailure);
        adversary.disable();
        // heal the db so it is possible to inspect the data
        healthOf(db).healed();
        // now we can observe partially committed state: node is in the index and relationship still present
        try (Transaction tx = db.beginTx()) {
            assertNotNull(findNode(db, label, property, "B"));
            assertNotNull(db.getRelationshipById(relationshipId));
            tx.success();
        }
        // panic the db again to force recovery on the next startup
        healthOf(db).panic(txFailure.getCause());
        // restart the database, now with regular page cache
        db.shutdown();
        db = startDatabase(storeDir);
        // now we observe correct state: node is in the index and relationship is removed
        try (Transaction tx = db.beginTx()) {
            assertNotNull(findNode(db, label, property, "B"));
            assertRelationshipNotExist(db, relationshipId);
            tx.success();
        }
    } finally {
        db.shutdown();
    }
}
Also used : GraphDatabaseService(org.neo4j.graphdb.GraphDatabaseService) CountingAdversary(org.neo4j.adversaries.CountingAdversary) TransactionFailureException(org.neo4j.graphdb.TransactionFailureException) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Transaction(org.neo4j.graphdb.Transaction) Command(org.neo4j.kernel.impl.transaction.command.Command) Node(org.neo4j.graphdb.Node) Label(org.neo4j.graphdb.Label) File(java.io.File) Test(org.junit.Test)

Example 3 with ClassGuardedAdversary

use of org.neo4j.adversaries.ClassGuardedAdversary in project neo4j by neo4j.

the class PartialTransactionFailureIT method concurrentlyCommittingTransactionsMustNotRotateOutLoggedCommandsOfFailingTransaction.

@Test
void concurrentlyCommittingTransactionsMustNotRotateOutLoggedCommandsOfFailingTransaction() throws Exception {
    final ClassGuardedAdversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, false), Command.RelationshipCommand.class);
    adversary.disable();
    Path storeDir = testDirectory.homePath();
    final Map<Setting<?>, Object> params = Map.of(GraphDatabaseSettings.pagecache_memory, "8m");
    managementService = new TestDatabaseManagementServiceBuilder(storeDir).setFileSystem(new AdversarialFileSystemAbstraction(adversary)).setConfig(params).build();
    GraphDatabaseAPI db = (GraphDatabaseAPI) managementService.database(DEFAULT_DATABASE_NAME);
    Node a;
    Node b;
    Node c;
    Node d;
    try (Transaction tx = db.beginTx()) {
        a = tx.createNode();
        b = tx.createNode();
        c = tx.createNode();
        d = tx.createNode();
        tx.commit();
    }
    adversary.enable();
    CountDownLatch latch = new CountDownLatch(1);
    Thread t1 = new Thread(createRelationship(db, a, b, latch), "T1");
    Thread t2 = new Thread(createRelationship(db, c, d, latch), "T2");
    t1.start();
    t2.start();
    // Wait for both threads to get going
    t1.join(10);
    t2.join(10);
    latch.countDown();
    // Wait for the transactions to finish
    t1.join(25000);
    t2.join(25000);
    managementService.shutdown();
    // We should observe the store in a consistent state
    managementService = new TestDatabaseManagementServiceBuilder(storeDir).setConfig(params).build();
    GraphDatabaseService database = managementService.database(DEFAULT_DATABASE_NAME);
    try (Transaction tx = database.beginTx()) {
        Node x = tx.getNodeById(a.getId());
        Node y = tx.getNodeById(b.getId());
        Node z = tx.getNodeById(c.getId());
        Node w = tx.getNodeById(d.getId());
        Iterator<Relationship> itrRelX = x.getRelationships().iterator();
        Iterator<Relationship> itrRelY = y.getRelationships().iterator();
        Iterator<Relationship> itrRelZ = z.getRelationships().iterator();
        Iterator<Relationship> itrRelW = w.getRelationships().iterator();
        if (itrRelX.hasNext() != itrRelY.hasNext()) {
            fail("Node x and y have inconsistent relationship counts");
        } else if (itrRelX.hasNext()) {
            Relationship rel = itrRelX.next();
            assertEquals(rel, itrRelY.next());
            assertFalse(itrRelX.hasNext());
            assertFalse(itrRelY.hasNext());
        }
        if (itrRelZ.hasNext() != itrRelW.hasNext()) {
            fail("Node z and w have inconsistent relationship counts");
        } else if (itrRelZ.hasNext()) {
            Relationship rel = itrRelZ.next();
            assertEquals(rel, itrRelW.next());
            assertFalse(itrRelZ.hasNext());
            assertFalse(itrRelW.hasNext());
        }
    }
}
Also used : Path(java.nio.file.Path) GraphDatabaseService(org.neo4j.graphdb.GraphDatabaseService) CountingAdversary(org.neo4j.adversaries.CountingAdversary) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Setting(org.neo4j.graphdb.config.Setting) Node(org.neo4j.graphdb.Node) CountDownLatch(java.util.concurrent.CountDownLatch) TestDatabaseManagementServiceBuilder(org.neo4j.test.TestDatabaseManagementServiceBuilder) GraphDatabaseAPI(org.neo4j.kernel.internal.GraphDatabaseAPI) Transaction(org.neo4j.graphdb.Transaction) Command(org.neo4j.internal.recordstorage.Command) Relationship(org.neo4j.graphdb.Relationship) AdversarialFileSystemAbstraction(org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction) Test(org.junit.jupiter.api.Test)

Example 4 with ClassGuardedAdversary

use of org.neo4j.adversaries.ClassGuardedAdversary in project neo4j by neo4j.

the class BatchingTransactionAppenderConcurrencyTest method shouldHaveAllConcurrentAppendersSeePanic.

/*
     * There was an issue where if multiple concurrent appending threads did append and they moved on
     * to await a force, where the force would fail and the one doing the force would raise a panic...
     * the other threads may not notice the panic and move on to mark those transactions as committed
     * and notice the panic later (which would be too late).
     */
@Test
void shouldHaveAllConcurrentAppendersSeePanic() throws Throwable {
    // GIVEN
    Adversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, true), failMethod(TransactionLogFile.class, "force"));
    EphemeralFileSystemAbstraction efs = new EphemeralFileSystemAbstraction();
    FileSystemAbstraction fs = new AdversarialFileSystemAbstraction(adversary, efs);
    life.add(new FileSystemLifecycleAdapter(fs));
    DatabaseHealth databaseHealth = new DatabaseHealth(mock(DatabasePanicEventGenerator.class), NullLog.getInstance());
    LogFiles logFiles = LogFilesBuilder.builder(databaseLayout, fs).withLogVersionRepository(logVersionRepository).withTransactionIdStore(transactionIdStore).withDatabaseHealth(databaseHealth).withLogEntryReader(new VersionAwareLogEntryReader(new TestCommandReaderFactory())).withStoreId(StoreId.UNKNOWN).build();
    life.add(logFiles);
    final BatchingTransactionAppender appender = life.add(new BatchingTransactionAppender(logFiles, logRotation, transactionMetadataCache, transactionIdStore, databaseHealth));
    life.start();
    // WHEN
    int numberOfAppenders = 10;
    final CountDownLatch trap = new CountDownLatch(numberOfAppenders);
    final LogAppendEvent beforeForceTrappingEvent = new LogAppendEvent.Empty() {

        @Override
        public LogForceWaitEvent beginLogForceWait() {
            trap.countDown();
            awaitLatch(trap);
            return super.beginLogForceWait();
        }
    };
    Race race = new Race();
    for (int i = 0; i < numberOfAppenders; i++) {
        race.addContestant(() -> {
            // Good, we know that this test uses an adversarial file system which will throw
            // an exception in LogFile#force, and since all these transactions
            // will append and be forced in the same batch, where the force will fail then
            // all these transactions should fail. If there's any transaction not failing then
            // it just didn't notice the panic, which would be potentially hazardous.
            assertThrows(IOException.class, () -> appender.append(tx(), beforeForceTrappingEvent));
        });
    }
    // THEN perform the race. The relevant assertions are made inside the contestants.
    race.go();
}
Also used : FileSystemLifecycleAdapter(org.neo4j.io.fs.FileSystemLifecycleAdapter) DatabaseHealth(org.neo4j.monitoring.DatabaseHealth) CountingAdversary(org.neo4j.adversaries.CountingAdversary) AdversarialFileSystemAbstraction(org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction) EphemeralFileSystemAbstraction(org.neo4j.io.fs.EphemeralFileSystemAbstraction) FileSystemAbstraction(org.neo4j.io.fs.FileSystemAbstraction) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) TransactionLogFile(org.neo4j.kernel.impl.transaction.log.files.TransactionLogFile) EphemeralFileSystemAbstraction(org.neo4j.io.fs.EphemeralFileSystemAbstraction) LogFiles(org.neo4j.kernel.impl.transaction.log.files.LogFiles) TransactionLogFiles(org.neo4j.kernel.impl.transaction.log.files.TransactionLogFiles) DatabasePanicEventGenerator(org.neo4j.kernel.monitoring.DatabasePanicEventGenerator) TestCommandReaderFactory(org.neo4j.kernel.impl.api.TestCommandReaderFactory) CountDownLatch(java.util.concurrent.CountDownLatch) LogAppendEvent(org.neo4j.kernel.impl.transaction.tracing.LogAppendEvent) Race(org.neo4j.test.Race) VersionAwareLogEntryReader(org.neo4j.kernel.impl.transaction.log.entry.VersionAwareLogEntryReader) AdversarialFileSystemAbstraction(org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction) Adversary(org.neo4j.adversaries.Adversary) CountingAdversary(org.neo4j.adversaries.CountingAdversary) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Test(org.junit.jupiter.api.Test)

Example 5 with ClassGuardedAdversary

use of org.neo4j.adversaries.ClassGuardedAdversary in project neo4j by neo4j.

the class DatabaseRecoveryIT method recoveryShouldFixPartiallyAppliedSchemaIndexUpdates.

@Test
void recoveryShouldFixPartiallyAppliedSchemaIndexUpdates() {
    Label label = Label.label("Foo");
    String property = "Bar";
    // cause failure during 'relationship.delete()' command application
    ClassGuardedAdversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, true), Command.RelationshipCommand.class);
    adversary.disable();
    Path storeDir = directory.homePath();
    DatabaseManagementService managementService = AdversarialPageCacheGraphDatabaseFactory.create(storeDir, fileSystem, adversary).build();
    GraphDatabaseService db = managementService.database(DEFAULT_DATABASE_NAME);
    try {
        try (Transaction tx = db.beginTx()) {
            tx.schema().constraintFor(label).assertPropertyIsUnique(property).create();
            tx.commit();
        }
        long relationshipId = createRelationship(db);
        TransactionFailureException txFailure = null;
        try (Transaction tx = db.beginTx()) {
            Node node = tx.createNode(label);
            node.setProperty(property, "B");
            // this should fail because of the adversary
            tx.getRelationshipById(relationshipId).delete();
            adversary.enable();
            tx.commit();
        } catch (TransactionFailureException e) {
            txFailure = e;
        }
        assertNotNull(txFailure);
        adversary.disable();
        // heal the db so it is possible to inspect the data
        healthOf(db).healed();
        // now we can observe partially committed state: node is in the index and relationship still present
        try (Transaction tx = db.beginTx()) {
            assertNotNull(findNode(label, property, "B", tx));
            assertNotNull(tx.getRelationshipById(relationshipId));
            tx.commit();
        }
        // panic the db again to force recovery on the next startup
        healthOf(db).panic(txFailure.getCause());
        // restart the database, now with regular page cache
        managementService.shutdown();
        db = startDatabase(storeDir);
        // now we observe correct state: node is in the index and relationship is removed
        try (Transaction tx = db.beginTx()) {
            assertNotNull(findNode(label, property, "B", tx));
            assertRelationshipNotExist(tx, relationshipId);
            tx.commit();
        }
    } finally {
        managementService.shutdown();
    }
}
Also used : Path(java.nio.file.Path) GraphDatabaseService(org.neo4j.graphdb.GraphDatabaseService) CountingAdversary(org.neo4j.adversaries.CountingAdversary) TransactionFailureException(org.neo4j.graphdb.TransactionFailureException) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Transaction(org.neo4j.graphdb.Transaction) Command(org.neo4j.internal.recordstorage.Command) Node(org.neo4j.graphdb.Node) Label(org.neo4j.graphdb.Label) DatabaseManagementService(org.neo4j.dbms.api.DatabaseManagementService) Test(org.junit.jupiter.api.Test)

Aggregations

ClassGuardedAdversary (org.neo4j.adversaries.ClassGuardedAdversary)5 CountingAdversary (org.neo4j.adversaries.CountingAdversary)5 GraphDatabaseService (org.neo4j.graphdb.GraphDatabaseService)4 Transaction (org.neo4j.graphdb.Transaction)4 CountDownLatch (java.util.concurrent.CountDownLatch)3 Test (org.junit.jupiter.api.Test)3 Node (org.neo4j.graphdb.Node)3 Path (java.nio.file.Path)2 Test (org.junit.Test)2 AdversarialFileSystemAbstraction (org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction)2 Label (org.neo4j.graphdb.Label)2 TransactionFailureException (org.neo4j.graphdb.TransactionFailureException)2 Command (org.neo4j.internal.recordstorage.Command)2 File (java.io.File)1 ExecutionException (java.util.concurrent.ExecutionException)1 Adversary (org.neo4j.adversaries.Adversary)1 DatabaseManagementService (org.neo4j.dbms.api.DatabaseManagementService)1 Relationship (org.neo4j.graphdb.Relationship)1 Setting (org.neo4j.graphdb.config.Setting)1 EphemeralFileSystemAbstraction (org.neo4j.io.fs.EphemeralFileSystemAbstraction)1