blob: 8d1ef38761b81242e465c8dfe7bd38ddd9da8f4c [file] [log] [blame]
/*
* 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.cache30;
import static org.apache.geode.cache.ExpirationAction.LOCAL_DESTROY;
import static org.apache.geode.cache.LossAction.LIMITED_ACCESS;
import static org.apache.geode.cache.ResumptionAction.NONE;
import static org.apache.geode.distributed.ConfigurationProperties.ROLES;
import static org.apache.geode.distributed.internal.membership.InternalRole.getRole;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.apache.geode.test.dunit.Host.getHost;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import org.junit.Test;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.AttributesMutator;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheLoaderException;
import org.apache.geode.cache.CacheTransactionManager;
import org.apache.geode.cache.CommitDistributionException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.LoaderHelper;
import org.apache.geode.cache.LossAction;
import org.apache.geode.cache.MembershipAttributes;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAccessException;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionDistributionException;
import org.apache.geode.cache.RegionEvent;
import org.apache.geode.cache.RegionMembershipListener;
import org.apache.geode.cache.RegionReinitializedException;
import org.apache.geode.cache.RequiredRoles;
import org.apache.geode.cache.ResumptionAction;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.util.RegionMembershipListenerAdapter;
import org.apache.geode.distributed.Role;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalRole;
import org.apache.geode.internal.cache.AbstractRegion;
import org.apache.geode.internal.cache.DistributedCacheOperation;
import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.apache.geode.internal.cache.LocalRegion;
import org.apache.geode.internal.cache.TXManagerImpl;
import org.apache.geode.internal.cache.TXState;
import org.apache.geode.internal.cache.TXStateInterface;
import org.apache.geode.internal.cache.TXStateProxyImpl;
import org.apache.geode.test.awaitility.GeodeAwaitility;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.SerializableRunnable;
import org.apache.geode.test.dunit.SerializableRunnableIF;
import org.apache.geode.test.dunit.ThreadUtils;
import org.apache.geode.test.dunit.WaitCriterion;
/**
* Tests region reliability defined by MembershipAttributes.
*
* @since GemFire 5.0
*/
public abstract class RegionReliabilityTestCase extends ReliabilityTestCase {
@Override
public final void preTearDownCacheTestCase() throws Exception {
DistributedCacheOperation.setBeforePutOutgoing(null);
}
/** Returns scope to execute tests under. */
protected abstract Scope getRegionScope();
protected InternalDistributedSystem createConnection(String[] roles) {
StringBuilder rolesValue = new StringBuilder();
if (roles != null) {
for (int i = 0; i < roles.length; i++) {
if (i > 0) {
rolesValue.append(",");
}
rolesValue.append(roles[i]);
}
}
Properties config = new Properties();
config.setProperty(ROLES, rolesValue.toString());
return getSystem(config);
}
protected void assertLimitedAccessThrows(Region region) throws Exception {
try {
region.clear();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.create("KEY", "VAL");
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.destroy(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.destroyRegion();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
if (region.getAttributes().getScope().isGlobal()) {
try {
region.becomeLockGrantor();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.getDistributedLock(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.getRegionDistributedLock();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
}
try {
region.invalidate(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.invalidateRegion();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.loadSnapshot(new ByteArrayInputStream(new byte[] {}));
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try { // netload TODO: configure CacheLoader in region
region.get("netload");
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try { // netsearch TODO: add 2nd VM that has the object
region.get("netsearch");
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.put(new Object(), new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
Map map = new HashMap();
map.put(new Object(), new Object());
region.putAll(map);
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
Map map = new HashMap();
map.put(new Object(), new Object());
region.putAll(map, "callbackArg");
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.remove(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
if (!region.getAttributes().getScope().isGlobal()) {
CacheTransactionManager tx = region.getCache().getCacheTransactionManager();
tx.begin();
try {
region.put("KEY-tx", "VAL-tx");
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
tx.rollback();
}
}
protected void assertNoAccessThrows(Region region) throws Exception {
assertLimitedAccessThrows(region);
try {
region.containsKey(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.containsValue(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.containsValueForKey(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.entrySet(false);
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.entrySet();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.get(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.getEntry(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.isEmpty();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.keySet();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.localDestroy(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.localInvalidate(new Object());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.localInvalidateRegion();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.saveSnapshot(new ByteArrayOutputStream());
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.size();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
region.values();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
try {
QueryService qs = region.getCache().getQueryService();
Query query = qs.newQuery("(select distinct * from " + region.getFullPath() + ").size");
query.execute();
fail("Should have thrown an RegionAccessException");
} catch (RegionAccessException ex) {
// pass...
}
}
protected void assertLimitedAccessDoesNotThrow(Region region) throws Exception {
// insert some values for test
Object[] keys = new Object[] {"hip", "hop"};
Object[] values = new Object[] {"clip", "clop"};
for (int i = 0; i < keys.length; i++) {
region.put(keys[i], values[i]);
}
// test the ops that can throw RegionAccessException for LIMITED_ACCESS
region.create("jack", "jill");
region.destroy("jack");
if (region.getAttributes().getScope().isGlobal()) {
region.becomeLockGrantor();
Lock dlock = region.getDistributedLock(keys[0]);
dlock.lock();
dlock.unlock();
Lock rlock = region.getRegionDistributedLock();
rlock.lock();
rlock.unlock();
}
// netload (configured in vm0)
assertEquals("netload", region.get("netload"));
// netsearch (entry exists in vm0)
assertEquals("netsearch", region.get("netsearch"));
region.invalidate(keys[0]);
region.invalidateRegion();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
region.saveSnapshot(baos);
region.loadSnapshot(new ByteArrayInputStream(baos.toByteArray()));
// need to get a new handle to the region...
region = getRootRegion(region.getFullPath());
region.put(keys[0], values[0]);
Map map = new HashMap();
map.put("mom", "pop");
region.putAll(map);
region.putAll(map, "callbackArg");
QueryService qs = region.getCache().getQueryService();
Query query = qs.newQuery("(select distinct * from " + region.getFullPath() + ").size");
query.execute();
region.remove(keys[0]);
if (!region.getAttributes().getScope().isGlobal()) {
CacheTransactionManager tx = region.getCache().getCacheTransactionManager();
tx.begin();
region.put("KEY-tx", "VAL-tx");
tx.commit();
}
region.clear();
region.destroyRegion();
}
protected void assertNoAccessDoesNotThrow(Region region) throws Exception {
// insert some values for test
Object[] keys = new Object[] {"bip", "bam"};
Object[] values = new Object[] {"foo", "bar"};
for (int i = 0; i < keys.length; i++) {
region.put(keys[i], values[i]);
}
// test the ops that can throw RegionAccessException for NO_ACCESS
region.containsKey(new Object());
region.containsValue(new Object());
region.containsValueForKey(new Object());
region.entrySet(false);
region.entrySet();
region.get(keys[0]);
region.getEntry(keys[0]);
region.isEmpty();
region.keySet();
region.localDestroy(keys[0]);
region.localInvalidate(keys[1]);
region.localInvalidateRegion();
region.saveSnapshot(new ByteArrayOutputStream());
region.size();
region.values();
QueryService qs = region.getCache().getQueryService();
Query query = qs.newQuery("(select distinct * from " + region.getFullPath() + ").size");
query.execute();
assertLimitedAccessDoesNotThrow(region);
}
protected void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
fail("interrupted");
}
}
// -------------------------------------------------------------------------
// Tests to be run under every permutation of config options
// Valid configurations include scope D-ACK, D-NOACK, GLOBAL
// -------------------------------------------------------------------------
/**
* Tests affect of NO_ACCESS on region operations.
*/
@Test
public void testNoAccess() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// use vm0 for netsearch and netload
Host.getHost(0).getVM(0).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(null);
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
fac.setCacheLoader(new CacheLoader() {
@Override
public Object load(LoaderHelper helper) throws CacheLoaderException {
if ("netload".equals(helper.getKey())) {
return "netload";
} else {
return null;
}
}
@Override
public void close() {}
});
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
Object netsearch = "netsearch";
region.put(netsearch, netsearch);
}
});
// test ops on Region that should throw
assertNoAccessThrows(region);
// use vm1 to create role
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
Role role = (Role) requiredRolesSet.iterator().next();
assertTrue(RequiredRoles.isRoleInRegionMembership(region, role));
// retest ops on Region to assert no longer throw
assertNoAccessDoesNotThrow(region);
}
/**
* Tests affect of NO_ACCESS on local entry expiration actions.
*/
@Test
public void testNoAccessWithLocalEntryExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// use vm1 to create role
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
// test to make sure expiration is not suspended
region.put("expireMe", "expireMe");
assertTrue(region.size() == 1);
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Close Region") {
@Override
public void run2() throws CacheException {
Region region = getRootRegion(name);
region.close();
}
});
// TODO: waitForMemberTimeout(); ?
// set expiration and sleep
AttributesMutator mutator = region.getAttributesMutator();
mutator.setEntryTimeToLive(new ExpirationAttributes(1, ExpirationAction.LOCAL_DESTROY));
sleep(200);
// make sure no values were expired
Set entries = ((LocalRegion) region).basicEntries(false);
assertTrue(entries.size() == 1);
// create region again in vm1
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
waitForEntryDestroy(region, "expireMe");
}
/**
* Tests affect of NO_ACCESS on local region expiration actions.
*/
@Test
public void testNoAccessWithLocalRegionExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
AttributesMutator mutator = region.getAttributesMutator();
mutator.setRegionTimeToLive(new ExpirationAttributes(1, ExpirationAction.LOCAL_DESTROY));
// sleep and make sure region does not expire
sleep(200);
assertFalse(region.isDestroyed());
// create region in vm1
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
waitForRegionDestroy(region);
}
/**
* Tests affect of LIMITED_ACCESS on region operations.
*/
@Test
public void testLimitedAccess() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.LIMITED_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// use vm0 for netsearch and netload
Host.getHost(0).getVM(0).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(null);
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
fac.setCacheLoader(new CacheLoader() {
@Override
public Object load(LoaderHelper helper) throws CacheLoaderException {
if ("netload".equals(helper.getKey())) {
return "netload";
} else {
return null;
}
}
@Override
public void close() {}
});
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
Object netsearch = "netsearch";
region.put(netsearch, netsearch);
}
});
// test ops on Region that should throw
assertLimitedAccessThrows(region);
// this query should not throw
QueryService qs = region.getCache().getQueryService();
Query query = qs.newQuery("(select distinct * from " + region.getFullPath() + ").size");
query.execute();
// use vm1 to create role
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
// retest ops on Region to assert no longer throw
assertLimitedAccessDoesNotThrow(region);
}
/**
* Tests affect of LIMITED_ACCESS on local entry expiration actions.
*/
@Test
public void testLimitedAccessWithLocalEntryExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LIMITED_ACCESS, NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// use vm1 to create role
getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
// test to make sure expiration is suspended
region.put("expireMe", "expireMe");
assertTrue(region.size() == 1);
getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Close Region") {
@Override
public void run2() throws CacheException {
Region region = getRootRegion(name);
region.close();
}
});
// TODO: waitForMemberTimeout(); ?
// set expiration and sleep
AttributesMutator mutator = region.getAttributesMutator();
mutator.setEntryTimeToLive(new ExpirationAttributes(1, LOCAL_DESTROY));
WaitCriterion wc1 = new WaitCriterion() {
@Override
public boolean done() {
return ((LocalRegion) region).basicEntries(false).size() == 0;
}
@Override
public String description() {
return "expected zero entries but have "
+ ((LocalRegion) region).basicEntries(false).size();
}
};
GeodeAwaitility.await().untilAsserted(wc1);
// create region again
getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
region.put("expireMe", "expireMe");
waitForEntryDestroy(region, "expireMe");
await()
.untilAsserted(() -> assertEquals(0, region.size()));
}
/**
* Tests affect of LIMITED_ACCESS on local region expiration actions.
*/
@Test
public void testLimitedAccessWithLocalRegionExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.LIMITED_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
AttributesMutator mutator = region.getAttributesMutator();
mutator.setRegionTimeToLive(new ExpirationAttributes(1, ExpirationAction.LOCAL_DESTROY));
waitForRegionDestroy(region);
}
/**
* Tests affect of FULL_ACCESS on region operations.
*/
@Test
public void testFullAccess() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.FULL_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// use vm0 for netsearch and netload
Host.getHost(0).getVM(0).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(null);
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
fac.setCacheLoader(new CacheLoader() {
@Override
public Object load(LoaderHelper helper) throws CacheLoaderException {
if ("netload".equals(helper.getKey())) {
return "netload";
} else {
return null;
}
}
@Override
public void close() {}
});
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
Object netsearch = "netsearch";
region.put(netsearch, netsearch);
}
});
// test ops on Region that should not throw
assertNoAccessDoesNotThrow(region);
}
/**
* Tests affect of FULL_ACCESS on local entry expiration actions.
*/
@Test
public void testFullAccessWithLocalEntryExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
// assign names to 4 vms...
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.FULL_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
// test to make sure expiration is not suspended
region.put("expireMe", "expireMe");
assertTrue(region.size() == 1);
// set expiration and sleep
AttributesMutator mutator = region.getAttributesMutator();
mutator.setEntryTimeToLive(new ExpirationAttributes(1, ExpirationAction.LOCAL_DESTROY));
waitForEntryDestroy(region, "expireMe");
await()
.untilAsserted(() -> assertEquals(0, region.size()));
}
public static void waitForRegionDestroy(final Region region) {
WaitCriterion wc = new WaitCriterion() {
@Override
public boolean done() {
return region.isDestroyed();
}
@Override
public String description() {
return "expected region " + region + " to be destroyed";
}
};
GeodeAwaitility.await().untilAsserted(wc);
}
public static void waitForEntryDestroy(final Region region, final Object key) {
WaitCriterion wc = new WaitCriterion() {
@Override
public boolean done() {
return region.get(key) == null;
}
@Override
public String description() {
return "expected entry " + key + " to not exist but it has the value " + region.get(key);
}
};
GeodeAwaitility.await().untilAsserted(wc);
}
/**
* Tests affect of FULL_ACCESS on local region expiration actions.
*/
@Test
public void testFullAccessWithLocalRegionExpiration() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.FULL_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setStatisticsEnabled(true);
RegionAttributes attr = fac.create();
final Region region = createExpiryRootRegion(name, attr);
// wait for memberTimeout to expire
waitForMemberTimeout();
AttributesMutator mutator = region.getAttributesMutator();
mutator.setRegionTimeToLive(new ExpirationAttributes(1, ExpirationAction.LOCAL_DESTROY));
waitForRegionDestroy(region);
}
protected static Boolean[] detectedDeparture_testCommitDistributionException = {Boolean.FALSE};
@Test
public void testCommitDistributionException() throws Exception {
if (getRegionScope().isGlobal()) {
return; // skip test under Global
}
if (getRegionScope().isDistributedNoAck()) {
return; // skip test under DistributedNoAck
}
final String name = getUniqueName();
final String roleA = name + "-A";
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
GemFireCacheImpl cache = (GemFireCacheImpl) getCache();
RegionMembershipListener listener = new RegionMembershipListenerAdapter() {
@Override
public void afterRemoteRegionDeparture(RegionEvent event) {
synchronized (detectedDeparture_testCommitDistributionException) {
detectedDeparture_testCommitDistributionException[0] = Boolean.TRUE;
detectedDeparture_testCommitDistributionException.notify();
}
}
};
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.addCacheListener(listener);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
// use vm1 to create role
Host.getHost(0).getVM(1).invoke(new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
// define the afterReleaseLocalLocks callback
SerializableRunnableIF removeRequiredRole = () -> {
Host.getHost(0).getVM(1).invoke(new SerializableRunnable("Close Region") {
@Override
public void run() {
getRootRegion(name).close();
}
});
try {
synchronized (detectedDeparture_testCommitDistributionException) {
while (detectedDeparture_testCommitDistributionException[0] == Boolean.FALSE) {
detectedDeparture_testCommitDistributionException.wait();
}
}
} catch (InterruptedException e) {
fail("interrupted");
}
};
// define the add and remove expected exceptions
final String expectedExceptions = "org.apache.geode.internal.cache.CommitReplyException";
SerializableRunnable addExpectedExceptions =
new CacheSerializableRunnable("addExpectedExceptions") {
@Override
public void run2() throws CacheException {
getCache().getLogger().info(
"<ExpectedException action=add>" + expectedExceptions + "</ExpectedException>");
}
};
SerializableRunnable removeExpectedExceptions =
new CacheSerializableRunnable("removeExpectedExceptions") {
@Override
public void run2() throws CacheException {
getCache().getLogger().info(
"<ExpectedException action=remove>" + expectedExceptions + "</ExpectedException>");
}
};
// perform the actual test...
CacheTransactionManager ctm = cache.getCacheTransactionManager();
ctm.begin();
TXStateInterface txStateProxy = ((TXManagerImpl) ctm).getTXState();
((TXStateProxyImpl) txStateProxy).forceLocalBootstrap();
TXState txState = (TXState) ((TXStateProxyImpl) txStateProxy).getRealDeal(null, null);
txState.setBeforeSend(() -> {
try {
removeRequiredRole.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
// now start a transaction and commit it
region.put("KEY", "VAL");
addExpectedExceptions.run();
Host.getHost(0).getVM(1).invoke(addExpectedExceptions);
try {
ctm.commit();
fail("Should have thrown CommitDistributionException");
} catch (CommitDistributionException e) {
// pass
} finally {
removeExpectedExceptions.run();
Host.getHost(0).getVM(1).invoke(removeExpectedExceptions);
}
}
protected static Boolean[] detectedDeparture_testRegionDistributionException = {Boolean.FALSE};
@Test
public void testRegionDistributionException() throws Exception {
if (getRegionScope().isDistributedNoAck()) {
return; // skip test under DistributedNoAck
}
final String name = getUniqueName();
final String roleA = name + "-A";
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
RegionMembershipListener listener = new RegionMembershipListenerAdapter() {
@Override
public void afterRemoteRegionDeparture(RegionEvent event) {
synchronized (detectedDeparture_testRegionDistributionException) {
detectedDeparture_testRegionDistributionException[0] = Boolean.TRUE;
detectedDeparture_testRegionDistributionException.notify();
}
}
};
// create region in controller...
MembershipAttributes ra =
new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS, ResumptionAction.NONE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setDataPolicy(DataPolicy.REPLICATE);
// fac.addCacheListener(listener);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
assertTrue(((AbstractRegion) region).requiresReliabilityCheck());
// use vm1 to create role
CacheSerializableRunnable createRegion = new CacheSerializableRunnable("Create Region") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
fac.setDataPolicy(DataPolicy.REPLICATE);
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
};
Host.getHost(0).getVM(1).invoke(createRegion);
region.put("DESTROY_ME", "VAL");
region.put("INVALIDATE_ME", "VAL");
// define the afterReleaseLocalLocks callback
SerializableRunnable removeRequiredRole = new SerializableRunnable() {
@Override
public void run() {
Host.getHost(0).getVM(1).invoke(new SerializableRunnable("Close Region") {
@Override
public void run() {
getRootRegion(name).close();
}
});
// try {
// synchronized (detectedDeparture_testRegionDistributionException) {
// while (detectedDeparture_testRegionDistributionException[0] == Boolean.FALSE) {
// detectedDeparture_testRegionDistributionException.wait();
// }
// }
// }
// catch (InterruptedException e) {}
}
};
DistributedCacheOperation.setBeforePutOutgoing(() -> {
try {
removeRequiredRole.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Runnable reset = () -> {
// synchronized (detectedDeparture_testRegionDistributionException) {
// detectedDeparture_testRegionDistributionException[0] = Boolean.FALSE;
// }
};
// PUT
try {
region.put("KEY", "VAL");
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// INVALIDATE
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
region.invalidate("INVALIDATE_ME");
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// DESTROY
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
region.destroy("DESTROY_ME");
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// CLEAR
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
region.clear();
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// PUTALL
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
Map putAll = new HashMap();
putAll.put("PUTALL_ME", "VAL");
region.putAll(putAll);
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// INVALIDATE REGION
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
region.invalidateRegion();
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
// DESTROY REGION
reset.run();
Host.getHost(0).getVM(1).invoke(createRegion);
try {
region.destroyRegion();
fail("Should have thrown RegionDistributionException");
} catch (RegionDistributionException e) {
// pass
}
}
@Test
public void testReinitialization() throws Exception {
final String name = getUniqueName();
final String roleA = name + "-A";
final String[] requiredRoles = {roleA};
Set requiredRolesSet = new HashSet();
for (final String requiredRole : requiredRoles) {
requiredRolesSet.add(InternalRole.getRole(requiredRole));
}
assertEquals(requiredRoles.length, requiredRolesSet.size());
// connect controller to system...
Properties config = new Properties();
config.setProperty(ROLES, "");
getSystem(config);
getCache();
// create region in controller...
MembershipAttributes ra = new MembershipAttributes(requiredRoles, LossAction.NO_ACCESS,
ResumptionAction.REINITIALIZE);
AttributesFactory fac = new AttributesFactory();
fac.setMembershipAttributes(ra);
fac.setScope(getRegionScope());
fac.setDataPolicy(DataPolicy.REPLICATE);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
assertTrue(((AbstractRegion) region).requiresReliabilityCheck());
assertFalse(RequiredRoles.checkForRequiredRoles(region).isEmpty());
final String key = "KEY-testReinitialization";
final String val = "VALUE-testReinitialization";
Host.getHost(0).getVM(0).invoke(new CacheSerializableRunnable("Create Data") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
fac.setDataPolicy(DataPolicy.REPLICATE);
RegionAttributes attr = fac.create();
Region region = createRootRegion(name, attr);
region.put(key, val);
}
});
final Region finalRegion = region;
Thread thread = new Thread(() -> {
try {
RequiredRoles.waitForRequiredRoles(finalRegion, -1);
} catch (InterruptedException e) {
fail("interrupted");
} catch (RegionReinitializedException ignored) {
}
});
thread.start();
// create role and verify reinitialization took place
Host.getHost(0).getVM(1).invokeAsync(new CacheSerializableRunnable("Create Role") {
@Override
public void run2() throws CacheException {
createConnection(new String[] {roleA});
AttributesFactory fac = new AttributesFactory();
fac.setScope(getRegionScope());
RegionAttributes attr = fac.create();
createRootRegion(name, attr);
}
});
ThreadUtils.join(thread, 30 * 1000);
assertTrue(region.isDestroyed());
try {
region.put("fee", "fi");
fail("Should have thrown RegionReinitializedException");
} catch (RegionReinitializedException e) {
// pass
}
try {
RequiredRoles.checkForRequiredRoles(region);
fail("Should have thrown RegionReinitializedException");
} catch (RegionReinitializedException e) {
// pass
}
try {
Role role = (Role) requiredRolesSet.iterator().next();
RequiredRoles.isRoleInRegionMembership(region, role);
fail("Should have thrown RegionReinitializedException");
} catch (RegionReinitializedException e) {
// pass
}
region = getRootRegion(name);
assertNotNull(region);
assertTrue(((AbstractRegion) region).requiresReliabilityCheck());
assertTrue(RequiredRoles.checkForRequiredRoles(region).isEmpty());
assertNotNull(region.getEntry(key));
assertEquals(val, region.getEntry(key).getValue());
}
}