Search in sources :

Example 1 with Race

use of org.neo4j.test.Race in project neo4j by neo4j.

the class ConsistentPropertyReadsIT method shouldReadConsistentPropertyValues.

@Test
public void shouldReadConsistentPropertyValues() throws Throwable {
    // GIVEN
    final Node[] nodes = new Node[10];
    final String[] keys = new String[] { "1", "2", "3" };
    final String[] values = new String[] { longString('a'), longString('b'), longString('c') };
    try (Transaction tx = db.beginTx()) {
        for (int i = 0; i < nodes.length; i++) {
            nodes[i] = db.createNode();
            for (int j = 0; j < keys.length; j++) {
                nodes[i].setProperty(keys[j], values[0]);
            }
        }
        tx.success();
    }
    int updaters = 10;
    final AtomicLong updatersDone = new AtomicLong(updaters);
    Race race = new Race();
    for (int i = 0; i < updaters; i++) {
        // Changers
        race.addContestant(new Runnable() {

            @Override
            public void run() {
                try {
                    ThreadLocalRandom random = ThreadLocalRandom.current();
                    for (int j = 0; j < 100; j++) {
                        Node node = nodes[random.nextInt(nodes.length)];
                        String key = keys[random.nextInt(keys.length)];
                        try (Transaction tx = db.beginTx()) {
                            node.removeProperty(key);
                            tx.success();
                        }
                        try (Transaction tx = db.beginTx()) {
                            node.setProperty(key, values[random.nextInt(values.length)]);
                            tx.success();
                        }
                    }
                } finally {
                    updatersDone.decrementAndGet();
                }
            }
        });
    }
    for (int i = 0; i < 100; i++) {
        // Readers
        race.addContestant(new Runnable() {

            @Override
            public void run() {
                ThreadLocalRandom random = ThreadLocalRandom.current();
                while (updatersDone.get() > 0) {
                    try (Transaction tx = db.beginTx()) {
                        String value = (String) nodes[random.nextInt(nodes.length)].getProperty(keys[random.nextInt(keys.length)], null);
                        assertTrue(value, value == null || ArrayUtil.contains(values, value));
                        tx.success();
                    }
                }
            }
        });
    }
    // WHEN
    race.go();
}
Also used : AtomicLong(java.util.concurrent.atomic.AtomicLong) Race(org.neo4j.test.Race) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) Test(org.junit.Test)

Example 2 with Race

use of org.neo4j.test.Race in project neo4j by neo4j.

the class TestConcurrentRelationshipChainLoadingIssue method tryOnce.

private void tryOnce(final GraphDatabaseAPI db, final Node node) throws Throwable {
    Race race = new Race().withRandomStartDelays();
    race.addContestants(Runtime.getRuntime().availableProcessors(), () -> {
        try (Transaction ignored = db.beginTx()) {
            assertEquals(relCount, count(node.getRelationships()));
        }
    });
    race.go();
}
Also used : Transaction(org.neo4j.graphdb.Transaction) Race(org.neo4j.test.Race)

Example 3 with Race

use of org.neo4j.test.Race 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
public void shouldHaveAllConcurrentAppendersSeePanic() throws Throwable {
    // GIVEN
    Adversary adversary = new ClassGuardedAdversary(new CountingAdversary(1, true), failMethod(BatchingTransactionAppender.class, "force"));
    EphemeralFileSystemAbstraction efs = new EphemeralFileSystemAbstraction();
    File directory = new File("dir").getCanonicalFile();
    efs.mkdirs(directory);
    FileSystemAbstraction fs = new AdversarialFileSystemAbstraction(adversary, efs);
    life.add(new FileSystemLifecycleAdapter(fs));
    DatabaseHealth databaseHealth = new DatabaseHealth(mock(DatabasePanicEventGenerator.class), NullLog.getInstance());
    PhysicalLogFiles logFiles = new PhysicalLogFiles(directory, fs);
    LogFile logFile = life.add(new PhysicalLogFile(fs, logFiles, kibiBytes(10), transactionIdStore::getLastCommittedTransactionId, new DeadSimpleLogVersionRepository(0), new PhysicalLogFile.Monitor.Adapter(), logHeaderCache));
    final BatchingTransactionAppender appender = life.add(new BatchingTransactionAppender(logFile, logRotation, transactionMetadataCache, transactionIdStore, legacyIndexTransactionOrdering, 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(() -> {
            try {
                // Append to the log, the LogAppenderEvent will have all of the appending threads
                // do wait for all of the other threads to start the force thing
                appender.append(tx(), beforeForceTrappingEvent);
                fail("No transaction should be considered appended");
            } catch (IOException e) {
            // Good, we know that this test uses an adversarial file system which will throw
            // an exception in BatchingTransactionAppender#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.
            }
        });
    }
    // 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.kernel.internal.DatabaseHealth) CountingAdversary(org.neo4j.adversaries.CountingAdversary) AdversarialFileSystemAbstraction(org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction) EphemeralFileSystemAbstraction(org.neo4j.graphdb.mockfs.EphemeralFileSystemAbstraction) FileSystemAbstraction(org.neo4j.io.fs.FileSystemAbstraction) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) EphemeralFileSystemAbstraction(org.neo4j.graphdb.mockfs.EphemeralFileSystemAbstraction) DatabasePanicEventGenerator(org.neo4j.kernel.impl.core.DatabasePanicEventGenerator) FileSystemLifecycleAdapter(org.neo4j.io.fs.FileSystemLifecycleAdapter) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) LogAppendEvent(org.neo4j.kernel.impl.transaction.tracing.LogAppendEvent) DeadSimpleLogVersionRepository(org.neo4j.kernel.impl.transaction.DeadSimpleLogVersionRepository) Race(org.neo4j.test.Race) File(java.io.File) AdversarialFileSystemAbstraction(org.neo4j.adversaries.fs.AdversarialFileSystemAbstraction) Adversary(org.neo4j.adversaries.Adversary) CountingAdversary(org.neo4j.adversaries.CountingAdversary) ClassGuardedAdversary(org.neo4j.adversaries.ClassGuardedAdversary) Test(org.junit.Test)

Example 4 with Race

use of org.neo4j.test.Race in project neo4j by neo4j.

the class RelationshipCreateDeleteLockOrderingIT method shouldNotDeadlockWhenConcurrentCreateAndDeleteRelationships.

@Test
public void shouldNotDeadlockWhenConcurrentCreateAndDeleteRelationships() throws Throwable {
    // GIVEN (A) -[R]-> (B)
    final Node a;
    final Node b;
    try (Transaction tx = db.beginTx()) {
        (a = db.createNode()).createRelationshipTo(b = db.createNode(), MyRelTypes.TEST);
        tx.success();
    }
    // WHEN
    Race race = new Race();
    // a bunch of deleters
    for (int i = 0; i < 30; i++) {
        race.addContestant(new Runnable() {

            @Override
            public void run() {
                try (Transaction tx = db.beginTx()) {
                    Node node = random.nextBoolean() ? a : b;
                    for (Relationship relationship : node.getRelationships()) {
                        try {
                            relationship.delete();
                        } catch (NotFoundException e) {
                            // This is OK and expected since there are multiple threads deleting
                            assertTrue(e.getMessage().contains("already deleted"));
                        }
                    }
                    tx.success();
                }
            }
        });
    }
    // a bunch of creators
    for (int i = 0; i < 30; i++) {
        race.addContestant(new Runnable() {

            @Override
            public void run() {
                try (Transaction tx = db.beginTx()) {
                    boolean order = random.nextBoolean();
                    Node start = order ? a : b;
                    Node end = order ? b : a;
                    start.createRelationshipTo(end, MyRelTypes.TEST);
                    tx.success();
                }
            }
        });
    }
    // THEN there should be no thread throwing exception, especially DeadlockDetectedException
    race.go();
}
Also used : Transaction(org.neo4j.graphdb.Transaction) Node(org.neo4j.graphdb.Node) Race(org.neo4j.test.Race) Relationship(org.neo4j.graphdb.Relationship) NotFoundException(org.neo4j.graphdb.NotFoundException) Test(org.junit.Test)

Example 5 with Race

use of org.neo4j.test.Race in project neo4j by neo4j.

the class DelayedBufferTest method shouldHandleTheWholeWorkloadShebang.

@Test
public void shouldHandleTheWholeWorkloadShebang() throws Throwable {
    // GIVEN
    final int size = 1_000;
    final long bufferTime = 3;
    VerifyingConsumer consumer = new VerifyingConsumer(size);
    final Clock clock = Clocks.systemClock();
    Supplier<Long> chunkThreshold = clock::millis;
    Predicate<Long> safeThreshold = time -> clock.millis() - bufferTime >= time;
    final DelayedBuffer<Long> buffer = new DelayedBuffer<>(chunkThreshold, safeThreshold, 10, consumer);
    MaintenanceThread maintenance = new MaintenanceThread(buffer, 5);
    Race adders = new Race();
    final int numberOfAdders = 20;
    final byte[] offeredIds = new byte[size];
    for (int i = 0; i < numberOfAdders; i++) {
        final int finalI = i;
        adders.addContestant(new Runnable() {

            @Override
            public void run() {
                for (int j = 0; j < size; j++) {
                    if (j % numberOfAdders == finalI) {
                        buffer.offer(j);
                        offeredIds[j] = 1;
                        parkNanos(MILLISECONDS.toNanos(current().nextInt(2)));
                    }
                }
            }
        });
    }
    // WHEN (multi-threadded) offering of ids
    adders.go();
    // ... ensuring the test is sane itself (did we really offer all these IDs?)
    for (int i = 0; i < size; i++) {
        assertEquals("ID " + i, (byte) 1, offeredIds[i]);
    }
    maintenance.halt();
    buffer.close();
    // THEN
    consumer.assertHaveOnlySeenRange(0, size - 1);
}
Also used : Suppliers.singleton(org.neo4j.function.Suppliers.singleton) ThreadLocalRandom.current(java.util.concurrent.ThreadLocalRandom.current) Predicate(java.util.function.Predicate) Predicates(org.neo4j.function.Predicates) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Test(org.junit.Test) LockSupport.parkNanos(java.util.concurrent.locks.LockSupport.parkNanos) MILLISECONDS(java.util.concurrent.TimeUnit.MILLISECONDS) Supplier(java.util.function.Supplier) LockSupport(java.util.concurrent.locks.LockSupport) Consumer(java.util.function.Consumer) AtomicLong(java.util.concurrent.atomic.AtomicLong) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) Utils.safeCastLongToInt(org.neo4j.unsafe.impl.batchimport.Utils.safeCastLongToInt) Assert.assertFalse(org.junit.Assert.assertFalse) Clock(java.time.Clock) Assert.fail(org.junit.Assert.fail) Clocks(org.neo4j.time.Clocks) Race(org.neo4j.test.Race) Assert.assertEquals(org.junit.Assert.assertEquals) Mockito.mock(org.mockito.Mockito.mock) Clock(java.time.Clock) Race(org.neo4j.test.Race) AtomicLong(java.util.concurrent.atomic.AtomicLong) Test(org.junit.Test)

Aggregations

Race (org.neo4j.test.Race)26 Test (org.junit.Test)24 AtomicLong (java.util.concurrent.atomic.AtomicLong)10 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)5 Transaction (org.neo4j.graphdb.Transaction)5 Node (org.neo4j.graphdb.Node)4 NotFoundException (org.neo4j.graphdb.NotFoundException)4 DelegatingPagedFile (org.neo4j.io.pagecache.DelegatingPagedFile)3 IOException (java.io.IOException)2 ThreadLocalRandom (java.util.concurrent.ThreadLocalRandom)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 Relationship (org.neo4j.graphdb.Relationship)2 PageCursor (org.neo4j.io.pagecache.PageCursor)2 PagedFile (org.neo4j.io.pagecache.PagedFile)2 DelegatingPageCursor (org.neo4j.io.pagecache.impl.DelegatingPageCursor)2 File (java.io.File)1 Clock (java.time.Clock)1 ArrayList (java.util.ArrayList)1 ArrayBlockingQueue (java.util.concurrent.ArrayBlockingQueue)1 CountDownLatch (java.util.concurrent.CountDownLatch)1