diff options
author | Sam Berlin <sameb@google.com> | 2014-07-09 20:29:47 -0400 |
---|---|---|
committer | Sam Berlin <sameb@google.com> | 2014-07-09 20:38:07 -0400 |
commit | 6ae9ff6c662e979efea1c5f7195c47ef5715b20a (patch) | |
tree | e523ec372ad3dac43af2ebd0386bf06c41c68672 /core | |
parent | c66f08e3d6798e88f35be51679854568f337e7eb (diff) | |
download | guice-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.java | 113 |
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)); } |