GEODE-1818: fix NPE in Bug37377DUnitTest This closes #235
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/8a644c25 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/8a644c25 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/8a644c25 Branch: refs/heads/feature/GEODE-420 Commit: 8a644c25de9c4bc5a413de96dfac88451fda7fc8 Parents: ea5516c Author: Scott Jewell <[email protected]> Authored: Wed Aug 31 10:54:05 2016 -0700 Committer: Darrel Schneider <[email protected]> Committed: Thu Sep 1 09:26:03 2016 -0700 ---------------------------------------------------------------------- .../internal/cache/Bug37377DUnitTest.java | 393 +++++++++---------- 1 file changed, 176 insertions(+), 217 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8a644c25/geode-core/src/test/java/com/gemstone/gemfire/internal/cache/Bug37377DUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/cache/Bug37377DUnitTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/cache/Bug37377DUnitTest.java index 0531100..35e9caf 100644 --- a/geode-core/src/test/java/com/gemstone/gemfire/internal/cache/Bug37377DUnitTest.java +++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/cache/Bug37377DUnitTest.java @@ -22,32 +22,22 @@ import org.junit.Test; import static org.junit.Assert.*; import com.gemstone.gemfire.test.dunit.cache.internal.JUnit4CacheTestCase; -import com.gemstone.gemfire.test.dunit.internal.JUnit4DistributedTestCase; import com.gemstone.gemfire.test.junit.categories.DistributedTest; import java.io.File; import java.util.Properties; +import java.util.concurrent.CountDownLatch; import com.gemstone.gemfire.cache.AttributesFactory; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheFactory; import com.gemstone.gemfire.cache.DataPolicy; -import com.gemstone.gemfire.cache.EntryEvent; -import com.gemstone.gemfire.cache.Operation; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.RegionAttributes; import com.gemstone.gemfire.cache.Scope; -import com.gemstone.gemfire.cache30.CacheSerializableRunnable; -import com.gemstone.gemfire.cache30.CacheTestCase; import com.gemstone.gemfire.distributed.DistributedSystem; -import com.gemstone.gemfire.internal.cache.lru.EnableLRU; -import com.gemstone.gemfire.internal.util.concurrent.CustomEntryConcurrentHashMap.HashEntry; -import com.gemstone.gemfire.test.dunit.AsyncInvocation; import com.gemstone.gemfire.test.dunit.Host; -import com.gemstone.gemfire.test.dunit.SerializableRunnable; -import com.gemstone.gemfire.test.dunit.ThreadUtils; import com.gemstone.gemfire.test.dunit.VM; -import com.gemstone.gemfire.test.dunit.Wait; /** * Bug37377 DUNIT Test: The Clear operation during a GII in progress can leave a @@ -67,9 +57,7 @@ public class Bug37377DUnitTest extends JUnit4CacheTestCase protected static DistributedSystem distributedSystem = null; - private static VM vm0 = null; - - private static VM vm1 = null; + VM vm0, vm1; protected static Cache cache = null; @@ -77,6 +65,10 @@ public class Bug37377DUnitTest extends JUnit4CacheTestCase private static final int maxEntries = 10000; + transient private static CountDownLatch clearLatch = new CountDownLatch(1); + + static Boolean clearOccured = false; + public Bug37377DUnitTest() { super(); File file1 = new File(getTestMethodName() + "1"); @@ -99,206 +91,161 @@ public class Bug37377DUnitTest extends JUnit4CacheTestCase @Override public final void preTearDownCacheTestCase() throws Exception { - vm1.invoke(destroyRegion()); - vm0.invoke(destroyRegion()); + vm1.invoke(() -> destroyRegion()); + vm0.invoke(() -> destroyRegion()); } /** * This method is used to create Cache in VM0 - * - * @return CacheSerializableRunnable */ - private CacheSerializableRunnable createCacheForVM0() - { - SerializableRunnable createCache = new CacheSerializableRunnable( - "createCache") { - public void run2() - { - try { - - distributedSystem = (new Bug37377DUnitTest()) - .getSystem(props); - assertTrue(distributedSystem != null); - cache = CacheFactory.create(distributedSystem); - assertTrue(cache != null); - AttributesFactory factory = new AttributesFactory(); - factory.setScope(Scope.DISTRIBUTED_ACK); - factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); - factory.setDiskSynchronous(false); - factory.setDiskStoreName(cache.createDiskStoreFactory() - .setDiskDirs(dirs) - .create("Bug37377DUnitTest") - .getName()); - RegionAttributes attr = factory.create(); - cache.createRegion(regionName, attr); - } - catch (Exception ex) { - ex.printStackTrace(); - fail("Error Creating cache / region "); - } - } - }; - return (CacheSerializableRunnable)createCache; + @SuppressWarnings("deprecation") + private void createCacheForVM0() { + try { + + distributedSystem = (new Bug37377DUnitTest()) + .getSystem(props); + assertTrue(distributedSystem != null); + cache = CacheFactory.create(distributedSystem); + assertTrue(cache != null); + AttributesFactory factory = new AttributesFactory(); + factory.setScope(Scope.DISTRIBUTED_ACK); + factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); + factory.setDiskSynchronous(false); + factory.setDiskStoreName(cache.createDiskStoreFactory() + .setDiskDirs(dirs) + .create("Bug37377DUnitTest") + .getName()); + RegionAttributes attr = factory.create(); + cache.createRegion(regionName, attr); + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Error Creating cache / region "); + } } /** * This method is used to create Cache in VM1 - * - * @return CacheSerializableRunnable */ - private CacheSerializableRunnable createCacheForVM1() - { - SerializableRunnable createCache = new CacheSerializableRunnable( - "createCache") { - public void run2() - { - try { - distributedSystem = (new Bug37377DUnitTest()) - .getSystem(props); - assertTrue(distributedSystem != null); - cache = CacheFactory.create(distributedSystem); - assertTrue("cache found null", cache != null); - - AttributesFactory factory = new AttributesFactory(); - factory.setScope(Scope.DISTRIBUTED_ACK); - factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); - factory.setDiskSynchronous(false); - factory.setDiskStoreName(cache.createDiskStoreFactory() - .setDiskDirs(dirs) - .create("Bug37377DUnitTest") - .getName()); - RegionAttributes attr = factory.create(); - DistributedRegion distRegion = new DistributedRegion(regionName, - attr, null, (GemFireCacheImpl)cache, new InternalRegionArguments() - .setDestroyLockFlag(true).setRecreateFlag(false) - .setSnapshotInputStream(null).setImageTarget(null)); -// assertTrue("Distributed Region is null", distRegion != null); (cannot be null) - - ((AbstractRegionMap)distRegion.entries) - .setEntryFactory(TestAbstractDiskRegionEntry.getEntryFactory()); - - LocalRegion region = (LocalRegion)((GemFireCacheImpl)cache) - .createVMRegion(regionName, attr, new InternalRegionArguments() - .setInternalMetaRegion(distRegion).setDestroyLockFlag(true) - .setSnapshotInputStream(null).setImageTarget(null)); - assertTrue("Local Region is null", region != null); + @SuppressWarnings("deprecation") + private void createCacheForVM1() { + try { + distributedSystem = (new Bug37377DUnitTest()) + .getSystem(props); + assertTrue(distributedSystem != null); + cache = CacheFactory.create(distributedSystem); + assertTrue("cache found null", cache != null); + + AttributesFactory factory = new AttributesFactory(); + factory.setScope(Scope.DISTRIBUTED_ACK); + factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); + factory.setDiskSynchronous(false); + factory.setDiskStoreName(cache.createDiskStoreFactory() + .setDiskDirs(dirs) + .create("Bug37377DUnitTest") + .getName()); + RegionAttributes attr = factory.create(); + DistributedRegion distRegion = new DistributedRegion(regionName, + attr, null, (GemFireCacheImpl)cache, new InternalRegionArguments() + .setDestroyLockFlag(true).setRecreateFlag(false) + .setSnapshotInputStream(null).setImageTarget(null)); + // assertTrue("Distributed Region is null", distRegion != null); (cannot be null) + + TestAbstractDiskRegionEntry.setMembers(vm1, vm0); // vm1 is thisVM, vm0 is otherVM + + ((AbstractRegionMap)distRegion.entries) + .setEntryFactory(TestAbstractDiskRegionEntry.getEntryFactory()); + + LocalRegion region = (LocalRegion)((GemFireCacheImpl)cache) + .createVMRegion(regionName, attr, new InternalRegionArguments() + .setInternalMetaRegion(distRegion).setDestroyLockFlag(true) + .setSnapshotInputStream(null).setImageTarget(null)); + assertTrue("Local Region is null", region != null); - } - catch (Exception ex) { - ex.printStackTrace(); - fail("Error Creating cache / region " + ex); - } - } - }; - return (CacheSerializableRunnable)createCache; + } + catch (Exception ex) { + ex.printStackTrace(); + fail("Error Creating cache / region " + ex); + } } /** * This method puts in maxEntries in the Region - * - * @return CacheSerializableRunnable */ - private CacheSerializableRunnable putSomeEntries() - { - SerializableRunnable puts = new CacheSerializableRunnable("putSomeEntries") { - public void run2() - { - assertTrue("Cache is found as null ", cache != null); - Region rgn = cache.getRegion(regionName); - for (int i = 0; i < maxEntries; i++) { - rgn.put(new Long(i), new Long(i)); - } - } - }; - return (CacheSerializableRunnable)puts; + private void putSomeEntries() { + assertTrue("Cache is found as null ", cache != null); + Region rgn = cache.getRegion(regionName); + for (int i = 0; i < maxEntries; i++) { + rgn.put(new Long(i), new Long(i)); + } } /** - * This method destroys the Region + * This method clears the region and + * notifies the other member when complete * - * @return CacheSerializableRunnable + * @throws InterruptedException */ - private CacheSerializableRunnable destroyRegion() - { - SerializableRunnable puts = new CacheSerializableRunnable("destroyRegion") { - public void run2() - { - try { - assertTrue("Cache is found as null ", cache != null); - - Region rgn = cache.getRegion(regionName); - rgn.localDestroyRegion(); - cache.close(); - } - catch (Exception ex) { - - } - } - }; - return (CacheSerializableRunnable)puts; + private static void invokeRemoteClearAndWait(VM remoteVM, VM thisVM) { + remoteVM.invoke(() -> clearRegionAndNotify(thisVM)); + try { + clearLatch.await(); + } catch (InterruptedException e) { + fail("wait for remote clear to complete failed"); + } } /** - * This method is used to close cache on the calling VM - * - * @return CacheSerializableRunnable + * This method clears the region and + * notifies the other member when complete */ - private CacheSerializableRunnable closeCacheForVM(final int vmNo) - { - SerializableRunnable cclose = new CacheSerializableRunnable( - "closeCacheForVM") { - public void run2() - { - if (vmNo == 0) { - cache.getRegion(regionName).localDestroyRegion(); - } - assertTrue("Cache is found as null ", cache != null); - cache.close(); - } - }; - return (CacheSerializableRunnable)cclose; + private static void clearRegionAndNotify(VM otherVM) { + assertTrue("Cache is found as null ", cache != null); + Region rgn = cache.getRegion(regionName); + rgn.clear(); + otherVM.invoke(() -> notifyClearComplete()); } /** - * This method is used to close cache on the calling VM - * - * @return CacheSerializableRunnable + * Decrement countdown latch to notify clear complete */ - private CacheSerializableRunnable closeCacheInVM() - { - SerializableRunnable cclose = new CacheSerializableRunnable( - "closeCacheInVM") { - public void run2() - { - - cache.getRegion(regionName).localDestroyRegion(); - assertTrue("Cache is found as null ", cache != null); - cache.close(); - } - }; - return (CacheSerializableRunnable)cclose; + private static void notifyClearComplete() { + clearLatch.countDown(); } /** - * This method verifies that the reintialized region size should be zero - * - * @return CacheSerializableRunnable + * This method destroys the Region */ - private CacheSerializableRunnable verifyExtraEntryFromOpLogs() - { - SerializableRunnable verify = new CacheSerializableRunnable( - "verifyExtraEntryFromOpLogs") { - public void run2() - { - assertTrue("Cache is found as null ", cache != null); - Region rgn = cache.getRegion(regionName); - // should be zero after reinit - assertEquals(0, rgn.size()); - } - }; - return (CacheSerializableRunnable)verify; + private void destroyRegion() { + try { + assertTrue("Cache is found as null ", cache != null); + Region rgn = cache.getRegion(regionName); + rgn.localDestroyRegion(); + cache.close(); + } + catch (Exception ex) {} + } + /** + * This method closes the cache on the specified VM + */ + private void closeCacheForVM(final int vmNo) { + if (vmNo == 0) { + cache.getRegion(regionName).localDestroyRegion(); + } + assertTrue("Cache is found as null ", cache != null); + cache.close(); + } + + /** + * This method verifies that the reintialized region size is zero + */ + private void verifyExtraEntryFromOpLogs() { + assertTrue("Cache is found as null ", cache != null); + Region rgn = cache.getRegion(regionName); + // should be zero after clear + assertEquals(0, rgn.size()); } /** @@ -309,44 +256,45 @@ public class Bug37377DUnitTest extends JUnit4CacheTestCase */ @Test - public void testGIIputWithClear() - { - vm0.invoke(createCacheForVM0()); - vm0.invoke(putSomeEntries()); - AsyncInvocation as1 = vm1.invokeAsync(createCacheForVM1()); - Wait.pause(10000); - ThreadUtils.join(as1, 30 * 1000); - vm0.invoke(closeCacheForVM(0)); - vm1.invoke(closeCacheForVM(1)); - vm1.invoke(createCacheForVM1()); - vm1.invoke(verifyExtraEntryFromOpLogs()); + public void testGIIputWithClear() { + vm0.invoke(() -> createCacheForVM0()); + vm0.invoke(() -> putSomeEntries()); + + vm1.invoke(() -> createCacheForVM1()); + + vm0.invoke(() -> closeCacheForVM(0)); + vm1.invoke(() -> closeCacheForVM(1)); + + vm1.invoke(() -> createCacheForVM1()); + vm1.invoke(() -> verifyExtraEntryFromOpLogs()); } - static class TestAbstractDiskRegionEntry extends VMThinDiskRegionEntryHeapObjectKey - { - protected TestAbstractDiskRegionEntry(RegionEntryContext r, Object key, - Object value) { + static class TestAbstractDiskRegionEntry extends VersionedThinDiskRegionEntryHeapObjectKey { + static private VM thisVM, otherVM; + + static void setMembers(VM localVM, VM remoteVM) { + thisVM = localVM; + otherVM = remoteVM; + } + + protected TestAbstractDiskRegionEntry(RegionEntryContext r, Object key, Object value) { super(r, key, value); } - - private static RegionEntryFactory factory = new RegionEntryFactory() { - public final RegionEntry createEntry(RegionEntryContext r, Object key, - Object value) - { + private static RegionEntryFactory factory = new RegionEntryFactory() { + + public final RegionEntry createEntry(RegionEntryContext r, Object key, Object value) { return new TestAbstractDiskRegionEntry(r, key, value); } - public final Class getEntryClass() - { - + public final Class getEntryClass() { return TestAbstractDiskRegionEntry.class; } public RegionEntryFactory makeVersioned() { return this; } - + public RegionEntryFactory makeOnHeap() { return this; } @@ -358,24 +306,35 @@ public class Bug37377DUnitTest extends JUnit4CacheTestCase */ @Override public boolean initialImageInit(final LocalRegion r, - final long lastModifiedTime, - final Object newValue, - final boolean create, - final boolean wasRecovered, - final boolean versionTagAccepted) throws RegionClearedException + final long lastModifiedTime, + final Object newValue, + final boolean create, + final boolean wasRecovered, + final boolean versionTagAccepted) throws RegionClearedException { - RegionEventImpl event = new RegionEventImpl(r, Operation.REGION_CLEAR, - null, true /* isOriginRemote */, - r.cache.getMyId()); - ((DistributedRegion)r).cmnClearRegion(event, false, false); - boolean result = super.initialImageInit(r, lastModifiedTime, newValue, create, wasRecovered, versionTagAccepted); - fail("expected RegionClearedException"); - return result; + synchronized(clearOccured) { + if(!clearOccured) { + // Force other member to perform a clear during our GII + invokeRemoteClearAndWait(otherVM, thisVM); + clearOccured = true; + } + } + + // Continue GII processing, which should throw RegionClearedException after the clear + try { + boolean result = super.initialImageInit(r, lastModifiedTime, newValue, create, wasRecovered, versionTagAccepted); + } catch (RegionClearedException rce) { + throw rce; + } catch (Exception ex) { + fail("Caught exception during initialImageInit: " + ex ); + } + + return true; } - public static RegionEntryFactory getEntryFactory() - { + public static RegionEntryFactory getEntryFactory() { return factory; } } } +
