Improve EngineSearcher tracking
Currently we fail tests is any searcher reference is pending. Yet, on a slow machine the freeContext calls that are async could still be in flight so if there are pending searchers we wait for a bit to make sure we don't fail if a freeContext call is in flight. The MockEngine now also contains the stack trace of the first close call if a searcher is closed twice.
This commit is contained in:
parent
57d6944f0f
commit
500469fd28
|
@ -49,11 +49,11 @@ public abstract class ElasticSearchTestCase extends AbstractRandomizedTest {
|
||||||
|
|
||||||
public static final String CHILD_VM_ID = System.getProperty("junit4.childvm.id", "" + System.currentTimeMillis());
|
public static final String CHILD_VM_ID = System.getProperty("junit4.childvm.id", "" + System.currentTimeMillis());
|
||||||
|
|
||||||
public boolean awaitBusy(Predicate<?> breakPredicate) throws InterruptedException {
|
public static boolean awaitBusy(Predicate<?> breakPredicate) throws InterruptedException {
|
||||||
return awaitBusy(breakPredicate, 10, TimeUnit.SECONDS);
|
return awaitBusy(breakPredicate, 10, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean awaitBusy(Predicate<?> breakPredicate, long maxWaitTime, TimeUnit unit) throws InterruptedException {
|
public static boolean awaitBusy(Predicate<?> breakPredicate, long maxWaitTime, TimeUnit unit) throws InterruptedException {
|
||||||
long maxTimeInMillis = TimeUnit.MILLISECONDS.convert(maxWaitTime, unit);
|
long maxTimeInMillis = TimeUnit.MILLISECONDS.convert(maxWaitTime, unit);
|
||||||
long iterations = Math.max(Math.round(Math.log10(maxTimeInMillis) / Math.log10(2)), 1);
|
long iterations = Math.max(Math.round(Math.log10(maxTimeInMillis) / Math.log10(2)), 1);
|
||||||
long timeInMillis = 1;
|
long timeInMillis = 1;
|
||||||
|
@ -102,9 +102,22 @@ public abstract class ElasticSearchTestCase extends AbstractRandomizedTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureAllSearchersClosed() {
|
public static void ensureAllSearchersClosed() {
|
||||||
|
/* in some cases we finish a test faster than the freeContext calls make it to the
|
||||||
|
* shards. Let's wait for some time if there are still searchers. If the are really
|
||||||
|
* pending we will fail anyway.*/
|
||||||
|
try {
|
||||||
|
if (awaitBusy(new Predicate<Object>() {
|
||||||
|
public boolean apply(Object o) {
|
||||||
|
return MockRobinEngine.INFLIGHT_ENGINE_SEARCHERS.isEmpty();
|
||||||
|
}
|
||||||
|
}, 5, TimeUnit.SECONDS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
if (MockRobinEngine.INFLIGHT_ENGINE_SEARCHERS.isEmpty()) {
|
if (MockRobinEngine.INFLIGHT_ENGINE_SEARCHERS.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
RuntimeException ex = null;
|
RuntimeException ex = null;
|
||||||
StringBuilder builder = new StringBuilder("Unclosed Searchers instance for shards: [");
|
StringBuilder builder = new StringBuilder("Unclosed Searchers instance for shards: [");
|
||||||
|
|
|
@ -95,6 +95,8 @@ public final class MockRobinEngine extends RobinEngine implements Engine {
|
||||||
public static final class AssertingSearcher implements Searcher {
|
public static final class AssertingSearcher implements Searcher {
|
||||||
private final Searcher searcher;
|
private final Searcher searcher;
|
||||||
private final ShardId shardId;
|
private final ShardId shardId;
|
||||||
|
private RuntimeException firstReleaseStack;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
|
||||||
public AssertingSearcher(Searcher searcher, ShardId shardId) {
|
public AssertingSearcher(Searcher searcher, ShardId shardId) {
|
||||||
this.searcher = searcher;
|
this.searcher = searcher;
|
||||||
|
@ -110,7 +112,16 @@ public final class MockRobinEngine extends RobinEngine implements Engine {
|
||||||
@Override
|
@Override
|
||||||
public boolean release() throws ElasticSearchException {
|
public boolean release() throws ElasticSearchException {
|
||||||
RuntimeException remove = INFLIGHT_ENGINE_SEARCHERS.remove(this);
|
RuntimeException remove = INFLIGHT_ENGINE_SEARCHERS.remove(this);
|
||||||
assert remove != null : "Released Searcher more than once, source [" + searcher.source() + "]";
|
synchronized (lock) {
|
||||||
|
// make sure we only get this once and store the stack of the first caller!
|
||||||
|
if (remove == null) {
|
||||||
|
assert firstReleaseStack != null;
|
||||||
|
throw new AssertionError("Released Searcher more than once, source [" + searcher.source() + "]", firstReleaseStack);
|
||||||
|
} else {
|
||||||
|
assert firstReleaseStack == null;
|
||||||
|
firstReleaseStack = new RuntimeException("Searcher Released first here, source [" + searcher.source() + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
return searcher.release();
|
return searcher.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue