blob: 98f8dc3081635150e13a0997b60500a39add4585 [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.cache30;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.*;
import com.gemstone.gemfire.cache.util.*;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import dunit.*;
/**
* Make sure entry expiration does not happen during gii for bug 35214
*
* @author darrel
* @since 5.0
*/
public class Bug35214DUnitTest extends CacheTestCase {
protected volatile int expirationCount = 0;
private final static int ENTRY_COUNT = 100;
protected static volatile boolean callbackFailure;
public Bug35214DUnitTest(String name) {
super(name);
}
private VM getOtherVm() {
Host host = Host.getHost(0);
return host.getVM(0);
}
private void initOtherVm() {
VM vm = getOtherVm();
vm.invoke(new CacheSerializableRunnable("init") {
public void run2() throws CacheException {
getCache();
AttributesFactory af = new AttributesFactory();
af.setScope(Scope.DISTRIBUTED_ACK);
Region r1 = createRootRegion("r1", af.create());
for (int i=1; i <= ENTRY_COUNT; i++) {
r1.put("key"+i, "value" + i);
}
}
});
}
private AsyncInvocation updateOtherVm() throws Throwable {
VM vm = getOtherVm();
AsyncInvocation otherUpdater = vm.invokeAsync(new CacheSerializableRunnable("update") {
public void run2() throws CacheException {
Region r1 = getRootRegion("r1");
// let the main guys gii get started; we want to do updates
// during his gii
{
// wait for profile of getInitialImage cache to show up
com.gemstone.gemfire.internal.cache.CacheDistributionAdvisor adv =
((com.gemstone.gemfire.internal.cache.DistributedRegion)r1).getCacheDistributionAdvisor();
int numProfiles;
int expectedProfiles = 1;
for (;;) {
numProfiles = adv.adviseInitialImage(null).getReplicates().size();
if (numProfiles < expectedProfiles) {
// getLogWriter().info("PROFILE CHECK: Found " + numProfiles +
// " getInitialImage Profiles (waiting for " + expectedProfiles + ")");
//pause(5);
}
else {
getLogWriter().info("PROFILE CHECK: Found " + numProfiles + " getInitialImage Profiles (OK)");
break;
}
}
}
// start doing updates of the keys to see if we can get deadlocked
int updateCount = 1;
do {
for (int i=1; i <= ENTRY_COUNT; i++) {
String key = "key" + i;
if (r1.containsKey(key)) {
r1.destroy(key);
} else {
r1.put(key, "value" + i + "uc" + updateCount);
}
}
} while (updateCount++ < 20);
// do one more loop with no destroys
for (int i=1; i <= ENTRY_COUNT; i++) {
String key = "key" + i;
if (!r1.containsKey(key)) {
r1.put(key, "value" + i + "uc" + updateCount);
}
}
}
});
// FIXME this thread does not terminate
// DistributedTestCase.join(otherUpdater, 5 * 60 * 1000, getLogWriter());
// if(otherUpdater.exceptionOccurred()){
// fail("otherUpdater failed", otherUpdater.getException());
// }
return otherUpdater;
}
////////////////////// Test Methods //////////////////////
protected boolean afterRegionCreateSeen = false;
protected static void callbackAssertTrue(String msg, boolean cond) {
if (cond)
return;
callbackFailure = true;
// Throws ignored error, but...
assertTrue(msg, cond);
}
/**
* make sure entries do not expire during a GII
*/
public void testNoEntryExpireDuringGII() throws Exception {
initOtherVm();
AsyncInvocation updater = null;
try {
updater = updateOtherVm();
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable e1) {
fail("failed due to "+e1, e1);
}
System.setProperty(LocalRegion.EXPIRY_MS_PROPERTY, "true");
com.gemstone.gemfire.internal.cache.InitialImageOperation.slowImageProcessing = 30;
callbackFailure = false;
try {
AttributesFactory af = new AttributesFactory();
af.setDataPolicy(DataPolicy.REPLICATE);
af.setScope(Scope.DISTRIBUTED_ACK);
af.setStatisticsEnabled(true);
af.setEntryIdleTimeout(new ExpirationAttributes(1, ExpirationAction.INVALIDATE));
CacheListener cl1 = new CacheListenerAdapter() {
public void afterRegionCreate(RegionEvent re) {
afterRegionCreateSeen = true;
}
public void afterInvalidate(EntryEvent e) {
callbackAssertTrue("afterregionCreate not seen",
afterRegionCreateSeen);
// make sure region is initialized
callbackAssertTrue("not initialized",
((LocalRegion)e.getRegion()).isInitialized());
expirationCount++;
com.gemstone.gemfire.internal.cache.InitialImageOperation.slowImageProcessing = 0;
}
};
af.addCacheListener(cl1);
final Region r1 = createRootRegion("r1", af.create());
DistributedTestCase.join(updater, 60 * 1000, getLogWriter());
WaitCriterion ev = new WaitCriterion() {
public boolean done() {
return r1.values().size() == 0;
}
public String description() {
return "region never became empty";
}
};
DistributedTestCase.waitForCriterion(ev, 2 * 1000, 200, true);
{
assertEquals(0, r1.values().size());
assertEquals(ENTRY_COUNT, r1.keys().size());
}
}
finally {
com.gemstone.gemfire.internal.cache.InitialImageOperation.slowImageProcessing = 0;
System.getProperties().remove(LocalRegion.EXPIRY_MS_PROPERTY);
assertEquals(null, System.getProperty(LocalRegion.EXPIRY_MS_PROPERTY));
}
assertFalse("Errors in callbacks; check logs for details", callbackFailure);
}
}