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();
}
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();
}
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();
}
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();
}
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);
}
Aggregations