blob: 906b5d704e984b08ef5fe1a487b2613b1bba2cf9 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.internal.cache;
import java.io.File;
import java.util.Properties;
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 dunit.AsyncInvocation;
import dunit.DistributedTestCase;
import dunit.Host;
import dunit.SerializableRunnable;
import dunit.VM;
/**
* 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.
*
* @author pbatra
*/
public class Bug37377DUnitTest extends CacheTestCase
{
protected static String regionName = "TestRegion";
static Properties props = new Properties();
protected static DistributedSystem distributedSystem = null;
private static VM vm0 = null;
private static VM vm1 = null;
protected static Cache cache = null;
protected static File[] dirs = null;
private static final int maxEntries = 10000;
/**
* Constructor
*
* @param name
*/
public Bug37377DUnitTest(String name) {
super(name);
File file1 = new File(name + "1");
file1.mkdir();
file1.deleteOnExit();
File file2 = new File(name + "2");
file2.mkdir();
file2.deleteOnExit();
dirs = new File[2];
dirs[0] = file1;
dirs[1] = file2;
}
public void setUp() throws Exception
{
super.setUp();
final Host host = Host.getHost(0);
vm0 = host.getVM(0);
vm1 = host.getVM(1);
}
public void tearDown2() throws Exception
{
vm1.invoke(destroyRegion());
vm0.invoke(destroyRegion());
super.tearDown2();
}
/**
* 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("vm0_diskReg"))
.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;
}
/**
* 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("vm1_diskReg"))
.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);
}
catch (Exception ex) {
ex.printStackTrace();
fail("Error Creating cache / region " + ex);
}
}
};
return (CacheSerializableRunnable)createCache;
}
/**
* 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;
}
/**
* This method destroys the Region
*
* @return CacheSerializableRunnable
*/
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;
}
/**
* This method is used to close cache on the calling VM
*
* @return CacheSerializableRunnable
*/
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;
}
/**
* This method is used to close cache on the calling VM
*
* @return CacheSerializableRunnable
*/
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;
}
/**
* This method verifies that the reintialized region size should be zero
*
* @return CacheSerializableRunnable
*/
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;
}
/**
* 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.
*
*/
public void testGIIputWithClear()
{
vm0.invoke(createCacheForVM0());
vm0.invoke(putSomeEntries());
AsyncInvocation as1 = vm1.invokeAsync(createCacheForVM1());
pause(10000);
DistributedTestCase.join(as1, 30 * 1000, getLogWriter());
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) {
super(r, key, 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()
{
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 LocalRegion r,
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;
}
public static RegionEntryFactory getEntryFactory()
{
return factory;
}
}
}