This is an automated email from the ASF dual-hosted git repository. klund pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/geode.git
commit 3e2619fe630f4b6bcb124908a7354e7bc10e4b4c Author: Kirk Lund <[email protected]> AuthorDate: Wed Mar 21 15:16:42 2018 -0700 GEODE-1279: Rename Bug37377DUnitTest as ClearDuringGiiOplogWithMissingCreateRegressionTest --- .../geode/internal/cache/Bug37377DUnitTest.java | 317 --------------------- ...ingGiiOplogWithMissingCreateRegressionTest.java | 229 +++++++++++++++ 2 files changed, 229 insertions(+), 317 deletions(-) diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/Bug37377DUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/Bug37377DUnitTest.java deleted file mode 100644 index 35e00c1..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/Bug37377DUnitTest.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.cache; - -import static org.junit.Assert.*; - -import java.io.File; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.cache.AttributesFactory; -import org.apache.geode.cache.Cache; -import org.apache.geode.cache.CacheFactory; -import org.apache.geode.cache.DataPolicy; -import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionAttributes; -import org.apache.geode.cache.Scope; -import org.apache.geode.distributed.DistributedSystem; -import org.apache.geode.internal.cache.entries.VersionedThinDiskRegionEntryHeapObjectKey; -import org.apache.geode.test.dunit.Host; -import org.apache.geode.test.dunit.VM; -import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase; -import org.apache.geode.test.junit.categories.DistributedTest; - -/** - * Bug37377 DUNIT Test: The Clear operation during a GII in progress can leave a Entry in the Oplog - * due to a race condition wherein the clearFlag getting set after the entry gets written to the - * disk, The Test verifies the existence of the scenario. - * - */ - -@Category(DistributedTest.class) -public class Bug37377DUnitTest extends JUnit4CacheTestCase { - - protected static String regionName = "TestRegion"; - - static Properties props = new Properties(); - - protected static DistributedSystem distributedSystem = null; - - VM vm0, vm1; - - protected static Cache cache = null; - - protected static File[] dirs = null; - - private static final int maxEntries = 10000; - - private static transient CountDownLatch clearLatch = new CountDownLatch(1); - - static Boolean clearOccurred = false; - - public Bug37377DUnitTest() { - super(); - File file1 = new File(getTestMethodName() + "1"); - file1.mkdir(); - file1.deleteOnExit(); - File file2 = new File(getTestMethodName() + "2"); - file2.mkdir(); - file2.deleteOnExit(); - dirs = new File[2]; - dirs[0] = file1; - dirs[1] = file2; - } - - @Override - public final void postSetUp() throws Exception { - final Host host = Host.getHost(0); - vm0 = host.getVM(0); - vm1 = host.getVM(1); - } - - @Override - public final void preTearDownCacheTestCase() throws Exception { - vm1.invoke(() -> destroyRegion()); - vm0.invoke(() -> destroyRegion()); - } - - /** - * This method is used to create Cache in VM0 - */ - - @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 - */ - @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); - } - } - - /** - * This method puts in maxEntries in the Region - */ - 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 clears the region and notifies the other member when complete - */ - 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 clears the region and notifies the other member when complete - */ - private static void clearRegionAndNotify(VM otherVM) { - assertTrue("Cache is found as null ", cache != null); - Region rgn = cache.getRegion(regionName); - rgn.clear(); - otherVM.invoke(() -> notifyClearComplete()); - } - - /** - * Decrement countdown latch to notify clear complete - */ - private static void notifyClearComplete() { - clearLatch.countDown(); - } - - /** - * This method destroys the Region - */ - 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()); - } - - /** - * The Clear operation during a GII in progress can leave a Entry in the Oplog due to a race - * condition wherein the clearFlag getting set after the entry gets written to the disk, The Test - * verifies the existence of the scenario. - * - */ - - @Test - 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 VersionedThinDiskRegionEntryHeapObjectKey { - private static 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 RegionEntry createEntry(RegionEntryContext r, Object key, Object value) { - return new TestAbstractDiskRegionEntry(r, key, value); - } - - public Class getEntryClass() { - return TestAbstractDiskRegionEntry.class; - } - - public RegionEntryFactory makeVersioned() { - return this; - } - - public RegionEntryFactory makeOnHeap() { - return this; - } - }; - - /** - * Overridden setValue method to call clear Region before actually writing the entry - */ - @Override - public boolean initialImageInit(final InternalRegion r, final long lastModifiedTime, - final Object newValue, final boolean create, final boolean wasRecovered, - final boolean versionTagAccepted) throws RegionClearedException { - synchronized (clearOccurred) { - if (!clearOccurred) { - // Force other member to perform a clear during our GII - invokeRemoteClearAndWait(otherVM, thisVM); - clearOccurred = 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() { - return factory; - } - } -} diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/ClearDuringGiiOplogWithMissingCreateRegressionTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/ClearDuringGiiOplogWithMissingCreateRegressionTest.java new file mode 100644 index 0000000..066de28 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/ClearDuringGiiOplogWithMissingCreateRegressionTest.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.cache; + +import static org.apache.geode.test.dunit.Host.getHost; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.AttributesFactory; +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.DiskStore; +import org.apache.geode.cache.DiskStoreFactory; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.Scope; +import org.apache.geode.internal.cache.entries.VersionedThinDiskRegionEntryHeapObjectKey; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.cache.CacheTestCase; +import org.apache.geode.test.junit.categories.DistributedTest; +import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder; +import org.apache.geode.test.junit.rules.serializable.SerializableTestName; + +/** + * Bug37377 DUNIT Test: The Clear operation during a GII in progress can leave a Entry in the Oplog + * due to a race condition wherein the clearFlag getting set after the entry gets written to the + * disk, The Test verifies the existence of the scenario. + * + * <p> + * TRAC #37377: Clear operation with GII in progress may result in a deleted entry to be logged in + * the oplog without accompanying create + */ +@Category(DistributedTest.class) +public class ClearDuringGiiOplogWithMissingCreateRegressionTest extends CacheTestCase { + + private static final int PUT_COUNT = 10000; + + private String uniqueName; + private String regionName; + private File[] foldersForServer1; + private File[] foldersForServer2; + + private VM server1; + private VM server2; + + @Rule + public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder(); + + @Rule + public SerializableTestName testName = new SerializableTestName(); + + @Before + public void setUp() throws Exception { + server1 = getHost(0).getVM(0); + server2 = getHost(0).getVM(1); + + uniqueName = getClass().getSimpleName() + "_" + testName.getMethodName(); + regionName = uniqueName; + + File server1Disk1 = temporaryFolder.newFolder(uniqueName + "_server1_disk1"); + foldersForServer1 = new File[] {server1Disk1}; + + File server2Disk1 = temporaryFolder.newFolder(uniqueName + "_server2_disk1"); + foldersForServer2 = new File[] {server2Disk1}; + } + + @After + public void tearDown() throws Exception { + disconnectAllFromDS(); + } + + /** + * The Clear operation during a GII in progress can leave a Entry in the Oplog due to a race + * condition wherein the clearFlag getting set after the entry gets written to the disk, The Test + * verifies the existence of the scenario. + */ + @Test + public void clearDuringGiiShouldOplogCreateAndDelete() { + server1.invoke(() -> createCacheForVM0()); + server1.invoke(() -> { + Region<Integer, Integer> region = getCache().getRegion(regionName); + for (int i = 0; i < PUT_COUNT; i++) { + region.put(i, i); + } + }); + + server2.invoke(() -> createCacheForVM1()); + + server1.invoke(() -> { + getCache().getRegion(regionName).localDestroyRegion(); + getCache().close(); + }); + + server2.invoke(() -> getCache().close()); + + server2.invoke(() -> createCacheForVM1()); + server2.invoke(() -> assertThatRegionSizeIsZero()); + } + + /** + * This method is used to create Cache in VM0 + */ + private void createCacheForVM0() { + DiskStoreFactory dsf = getCache().createDiskStoreFactory(); + dsf.setDiskDirs(foldersForServer1); + + DiskStore diskStore = dsf.create(uniqueName); + + AttributesFactory factory = new AttributesFactory(); + factory.setScope(Scope.DISTRIBUTED_ACK); + factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); + factory.setDiskSynchronous(false); + factory.setDiskStoreName(diskStore.getName()); + + getCache().createRegion(regionName, factory.create()); + } + + /** + * This method is used to create Cache in VM1 + */ + private void createCacheForVM1() throws IOException, ClassNotFoundException { + DiskStoreFactory dsf = getCache().createDiskStoreFactory(); + dsf.setDiskDirs(foldersForServer2); + + DiskStore diskStore = dsf.create(uniqueName); + + AttributesFactory factory = new AttributesFactory(); + factory.setScope(Scope.DISTRIBUTED_ACK); + factory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); + factory.setDiskSynchronous(false); + factory.setDiskStoreName(diskStore.getName()); + + DistributedRegion distRegion = new DistributedRegion(regionName, factory.create(), null, + getCache(), new InternalRegionArguments().setDestroyLockFlag(true).setRecreateFlag(false) + .setSnapshotInputStream(null).setImageTarget(null)); + + distRegion.entries.setEntryFactory(new TestableDiskRegionEntryFactory()); + + getCache().createVMRegion(regionName, factory.create(), + new InternalRegionArguments().setInternalMetaRegion(distRegion).setDestroyLockFlag(true) + .setSnapshotInputStream(null).setImageTarget(null)); + } + + /** + * This method clears the region and notifies the other member when complete + */ + private void invokeRemoteClearAndWait() { + server1.invoke(() -> { + Region region = getCache().getRegion(regionName); + region.clear(); + }); + } + + private void assertThatRegionSizeIsZero() { + assertThat(getCache().getRegion(regionName).size()).isZero(); + } + + private class TestableDiskRegionEntry extends VersionedThinDiskRegionEntryHeapObjectKey { + + TestableDiskRegionEntry(RegionEntryContext context, Object key, Object value) { + super(context, key, value); + } + + /** + * Overridden setValue method to call clear Region before actually writing the entry + */ + @Override + public boolean initialImageInit(final InternalRegion region, final long lastModified, + final Object newValue, final boolean create, final boolean wasRecovered, + final boolean acceptedVersionTag) throws RegionClearedException { + + invokeRemoteClearAndWait(); + + // Continue GII processing, which should throw RegionClearedException after the clear + boolean result; + try { + result = super.initialImageInit(region, lastModified, newValue, create, wasRecovered, + acceptedVersionTag); + } catch (RegionClearedException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException("initialImageInit threw " + e.getClass().getSimpleName(), e); + } + + return result; + } + } + + private class TestableDiskRegionEntryFactory implements RegionEntryFactory { + + @Override + public RegionEntry createEntry(RegionEntryContext r, Object key, Object value) { + return new TestableDiskRegionEntry(r, key, value); + } + + @Override + public Class getEntryClass() { + return TestableDiskRegionEntry.class; + } + + @Override + public RegionEntryFactory makeVersioned() { + return this; + } + + @Override + public RegionEntryFactory makeOnHeap() { + return this; + } + } +} -- To stop receiving notification emails like this one, please contact [email protected].
