org.neo4j.test.DoubleLatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of test-utils Show documentation
Show all versions of test-utils Show documentation
A set of utilities used by tests.
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class DoubleLatch {
private static final long FIVE_MINUTES = TimeUnit.MINUTES.toMillis(5);
private final CountDownLatch startSignal;
private final CountDownLatch finishSignal;
private final CountDownLatch allButOneFinishedSignal;
private final boolean awaitUninterruptibly;
public DoubleLatch() {
this(1);
}
public DoubleLatch(int numberOfContestants) {
this(numberOfContestants, false);
}
public DoubleLatch(int numberOfContestants, boolean awaitUninterruptibly) {
this.startSignal = new CountDownLatch(numberOfContestants);
this.finishSignal = new CountDownLatch(numberOfContestants);
this.allButOneFinishedSignal = new CountDownLatch(numberOfContestants - 1);
this.awaitUninterruptibly = awaitUninterruptibly;
}
public void startAndWaitForAllToStartAndFinish() {
startAndWaitForAllToStart();
waitForAllToFinish();
}
public void startAndWaitForAllToStart() {
start();
waitForAllToStart();
}
public void start() {
startSignal.countDown();
}
public void waitForAllToStart() {
awaitLatch(startSignal, awaitUninterruptibly);
}
public void finishAndWaitForAllToFinish() {
finish();
waitForAllToFinish();
}
public void finish() {
finishSignal.countDown();
allButOneFinishedSignal.countDown();
}
public long finishCount() {
return finishSignal.getCount();
}
public void waitForAllToFinish() {
awaitLatch(finishSignal, awaitUninterruptibly);
}
public void waitForAllButOneToFinish() {
awaitLatch(allButOneFinishedSignal);
}
public static void awaitLatch(CountDownLatch latch) {
awaitLatch(latch, false);
}
public static void awaitLatch(CountDownLatch latch, boolean uninterruptedWaiting) {
long now = System.currentTimeMillis();
long deadline = System.currentTimeMillis() + FIVE_MINUTES;
while (now < deadline) {
try {
long waitingTime = Math.min(Math.max(0, deadline - now), 5000L);
if (latch.await(waitingTime, TimeUnit.MILLISECONDS)) {
return;
} else {
Thread.yield();
}
} catch (InterruptedException e) {
Thread.interrupted();
if (!uninterruptedWaiting) {
throw new RuntimeException("Thread interrupted while waiting on latch", e);
}
}
now = System.currentTimeMillis();
}
throw new AssertionError("Latch specified waiting time elapsed.");
}
@Override
public String toString() {
return super.toString() + "[Start[" + startSignal.getCount() + "], Finish[" + finishSignal.getCount() + "]]";
}
}