aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorSam Berlin <sameb@google.com>2014-07-09 20:29:47 -0400
committerSam Berlin <sameb@google.com>2014-07-09 20:38:07 -0400
commit6ae9ff6c662e979efea1c5f7195c47ef5715b20a (patch)
treee523ec372ad3dac43af2ebd0386bf06c41c68672 /core
parentc66f08e3d6798e88f35be51679854568f337e7eb (diff)
downloadguice-6ae9ff6c662e979efea1c5f7195c47ef5715b20a.tar.gz
Wrap GcFinalization usage around wrappers that also await a ReferenceQueue. I
couldn't get any failures internally in 10,000 runs even w/o these changes, but on the external builds I reliably reproduced some flakes in 100 runs w/o this, and no flakes (that I saw) afterwards. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=70835114
Diffstat (limited to 'core')
-rw-r--r--core/test/com/google/inject/internal/WeakKeySetTest.java113
1 files changed, 76 insertions, 37 deletions
diff --git a/core/test/com/google/inject/internal/WeakKeySetTest.java b/core/test/com/google/inject/internal/WeakKeySetTest.java
index c3b2df8c..e1f98362 100644
--- a/core/test/com/google/inject/internal/WeakKeySetTest.java
+++ b/core/test/com/google/inject/internal/WeakKeySetTest.java
@@ -42,6 +42,7 @@ import com.google.inject.spi.TypeListenerBinding;
import junit.framework.TestCase;
import java.lang.annotation.Annotation;
+import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
@@ -63,6 +64,44 @@ public class WeakKeySetTest extends TestCase {
protected void setUp() throws Exception {
set = new WeakKeySet(new Object());
}
+
+ private static void awaitFullGc() {
+ // GcFinalization *should* do it, but doesn't work well in practice...
+ // so we put a second latch and wait for a ReferenceQueue to tell us.
+ ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+ WeakReference ref = new WeakReference<Object>(new Object(), queue);
+ GcFinalization.awaitFullGc();
+ try {
+ assertSame("queue didn't return ref in time", ref, queue.remove(5000));
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void awaitClear(WeakReference<?> ref) {
+ // GcFinalization *should* do it, but doesn't work well in practice...
+ // so we put a second latch and wait for a ReferenceQueue to tell us.
+ Object data = ref.get();
+ ReferenceQueue<Object> queue = null;
+ WeakReference extraRef = null;
+ if (data != null) {
+ queue = new ReferenceQueue<Object>();
+ extraRef = new WeakReference<Object>(data, queue);
+ data = null;
+ }
+ GcFinalization.awaitClear(ref);
+ if (queue != null) {
+ try {
+ assertSame("queue didn't return ref in time", extraRef, queue.remove(5000));
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
public void testEviction() {
TestState state = new TestState();
@@ -78,14 +117,14 @@ public class WeakKeySetTest extends TestCase {
state = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(Key.get(Integer.class)));
assertNull(set.getSources(Key.get(Integer.class)));
// Ensure there are no hanging references.
key = null;
- GcFinalization.awaitClear(weakKeyRef);
+ awaitClear(weakKeyRef);
}
public void testEviction_nullSource() {
@@ -102,14 +141,14 @@ public class WeakKeySetTest extends TestCase {
state = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(Key.get(Integer.class)));
assertNull(set.getSources(Key.get(Integer.class)));
// Ensure there are no hanging references.
key = null;
- GcFinalization.awaitClear(weakKeyRef);
+ awaitClear(weakKeyRef);
}
public void testEviction_keyOverlap_2x() {
@@ -138,7 +177,7 @@ public class WeakKeySetTest extends TestCase {
Key<Integer> key = key1 = key2 = Key.get(Integer.class);
state1 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
assertEquals(1, set.getSources(key).size());
@@ -147,7 +186,7 @@ public class WeakKeySetTest extends TestCase {
source1 = source2 = null;
- GcFinalization.awaitClear(weakSource1Ref);
+ awaitClear(weakSource1Ref);
// Key1 will be referenced as the key in the sources backingSet and won't be
// GC'd.
@@ -156,15 +195,15 @@ public class WeakKeySetTest extends TestCase {
state2 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(key));
assertNull(set.getSources(key));
- GcFinalization.awaitClear(weakKey2Ref);
- GcFinalization.awaitClear(weakSource2Ref);
+ awaitClear(weakKey2Ref);
+ awaitClear(weakSource2Ref);
// Now that the backing set is emptied, key1 is released.
- GcFinalization.awaitClear(weakKey1Ref);
+ awaitClear(weakKey1Ref);
}
public void testNoEviction_keyOverlap_2x() {
@@ -190,7 +229,7 @@ public class WeakKeySetTest extends TestCase {
Key<Integer> key = key1 = key2 = Key.get(Integer.class);
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
assertEquals(2, set.getSources(key).size());
@@ -228,7 +267,7 @@ public class WeakKeySetTest extends TestCase {
Key<Integer> key = key1 = key2 = Key.get(Integer.class);
state1 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
@@ -238,21 +277,21 @@ public class WeakKeySetTest extends TestCase {
source = null;
- GcFinalization.awaitClear(weakSourceRef);
+ awaitClear(weakSourceRef);
// Key1 will be referenced as the key in the sources backingSet and won't be
// GC'd.
state2 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(key));
assertNull(set.getSources(key));
- GcFinalization.awaitClear(weakKey2Ref);
- GcFinalization.awaitClear(weakSourceRef);
+ awaitClear(weakKey2Ref);
+ awaitClear(weakSourceRef);
// Now that the backing set is emptied, key1 is released.
- GcFinalization.awaitClear(weakKey1Ref);
+ awaitClear(weakKey1Ref);
}
public void testEviction_keyAndSourceOverlap_nonNull() {
@@ -281,7 +320,7 @@ public class WeakKeySetTest extends TestCase {
Key<Integer> key = key1 = key2 = Key.get(Integer.class);
state1 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
@@ -291,22 +330,22 @@ public class WeakKeySetTest extends TestCase {
source = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertNotNull(weakSourceRef.get());
// Key1 will be referenced as the key in the sources backingSet and won't be
// GC'd.
state2 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(key));
assertNull(set.getSources(key));
- GcFinalization.awaitClear(weakKey2Ref);
- GcFinalization.awaitClear(weakSourceRef);
+ awaitClear(weakKey2Ref);
+ awaitClear(weakSourceRef);
// Now that the backing set is emptied, key1 is released.
- GcFinalization.awaitClear(weakKey1Ref);
+ awaitClear(weakKey1Ref);
}
public void testEviction_keyOverlap_3x() {
@@ -345,7 +384,7 @@ public class WeakKeySetTest extends TestCase {
Key<Integer> key = key1 = key2 = key3 = Key.get(Integer.class);
state1 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
assertEquals(2, set.getSources(key).size());
@@ -354,33 +393,33 @@ public class WeakKeySetTest extends TestCase {
source1 = null;
// Key1 will be referenced as the key in the sources backingSet and won't be
// GC'd.
- GcFinalization.awaitClear(weakSource1Ref);
+ awaitClear(weakSource1Ref);
state2 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertTrue(set.contains(key));
assertEquals(1, set.getSources(key).size());
assertTrue(set.getSources(key).contains(source3));
- GcFinalization.awaitClear(weakKey2Ref);
+ awaitClear(weakKey2Ref);
source2 = null;
- GcFinalization.awaitClear(weakSource2Ref);
+ awaitClear(weakSource2Ref);
// Key1 will be referenced as the key in the sources backingSet and won't be
// GC'd.
state3 = null;
- GcFinalization.awaitFullGc();
+ awaitFullGc();
assertFalse(set.contains(Key.get(Integer.class)));
assertNull(set.getSources(Key.get(Integer.class)));
- GcFinalization.awaitClear(weakKey3Ref);
+ awaitClear(weakKey3Ref);
source3 = null;
- GcFinalization.awaitClear(weakSource3Ref);
+ awaitClear(weakSource3Ref);
// Now that the backing set is emptied, key1 is released.
- GcFinalization.awaitClear(weakKey1Ref);
+ awaitClear(weakKey1Ref);
}
public void testWeakKeySet_integration() {
@@ -401,7 +440,7 @@ public class WeakKeySetTest extends TestCase {
// Clear the ref, GC, and ensure that we are no longer blacklisting.
childInjector = null;
- GcFinalization.awaitClear(weakRef);
+ awaitClear(weakRef);
assertNotBlacklisted(parentInjector, Key.get(String.class));
}
@@ -434,13 +473,13 @@ public class WeakKeySetTest extends TestCase {
// Clear ref1, GC, and ensure that we still blacklist.
childInjector1 = null;
- GcFinalization.awaitClear(weakRef1);
+ awaitClear(weakRef1);
assertNotBlacklisted(parentInjector, Key.get(String.class));
assertBlacklisted(parentInjector, Key.get(Long.class));
// Clear the ref, GC, and ensure that we are no longer blacklisting.
childInjector2 = null;
- GcFinalization.awaitClear(weakRef2);
+ awaitClear(weakRef2);
assertNotBlacklisted(parentInjector, Key.get(String.class));
assertNotBlacklisted(parentInjector, Key.get(Long.class));
}
@@ -471,12 +510,12 @@ public class WeakKeySetTest extends TestCase {
// Clear ref1, GC, and ensure that we still blacklist.
childInjector1 = null;
- GcFinalization.awaitClear(weakRef1);
+ awaitClear(weakRef1);
assertBlacklisted(parentInjector, Key.get(String.class));
// Clear the ref, GC, and ensure that we are no longer blacklisting.
childInjector2 = null;
- GcFinalization.awaitClear(weakRef2);
+ awaitClear(weakRef2);
assertNotBlacklisted(parentInjector, Key.get(String.class));
}