/*
* 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.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.DataSerializable;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache30.CacheSerializableRunnable;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.test.dunit.Assert;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.LogWriterUtils;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.junit.categories.DistributedTest;
/**
* Confirm that the utils used for testing work as advertised
*
* @since GemFire 5.0
*/
@Category(DistributedTest.class)
public class PartitionedRegionTestUtilsDUnitTest extends PartitionedRegionDUnitTestCase {
final int totalNumBuckets = 5;
/**
* Test the {@link PartitionedRegion#getSomeKeys(java.util.Random)} method, making sure it returns
* keys when there are keys and {@link java.util.Collections#EMPTY_SET} when there are none.
*/
@Test
public void testGetKeys() throws Exception {
final String r = getUniqueName();
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM vm2 = host.getVM(2);
CacheSerializableRunnable create = new CacheSerializableRunnable("CreatePartitionedRegion") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(
new PartitionAttributesFactory().setTotalNumBuckets(totalNumBuckets).create());
Region p = cache.createRegion(r, attr.create());
assertNotNull(p);
assertTrue(!p.isDestroyed());
assertNull(p.get("Key"));
}
};
vm0.invoke(create);
vm1.invoke(create);
vm2.invoke(create);
vm0.invoke(new CacheSerializableRunnable("GetSomeKeys") {
public void run2() throws CacheException {
PartitionedRegion pr = (PartitionedRegion) getCache().getRegion(r);
Random rand = new Random(123);
// Assert that its empty
for (int i = 0; i < 5; i++) {
LogWriterUtils.getLogWriter().info("Invocation " + i + " of getSomeKeys");
try {
Set s = null;
s = pr.getSomeKeys(rand);
assertNotNull(s);
assertTrue(s.isEmpty());
} catch (ClassNotFoundException cnfe) {
Assert.fail("GetSomeKeys failed with ClassNotFoundException", cnfe);
} catch (IOException ioe) {
Assert.fail("GetSomeKeys failed with IOException", ioe);
}
}
final int MAXKEYS = 50;
for (int i = 0; i < MAXKEYS; i++) {
pr.put("testKey" + i, new Integer(i));
}
// Assert not empty and has value in an accepable range
for (int i = 0; i < 5; i++) {
LogWriterUtils.getLogWriter().info("Invocation " + i + " of getSomeKeys");
try {
Set s = null;
s = pr.getSomeKeys(rand);
assertNotNull(s);
assertFalse(s.isEmpty());
Integer val;
LogWriterUtils.getLogWriter().info("Invocation " + i + " got " + s.size() + " keys");
for (Iterator it = s.iterator(); it.hasNext();) {
Object key = it.next();
LogWriterUtils.getLogWriter().info("Key: " + key);
val = (Integer) pr.get(key);
assertNotNull(val);
assertTrue(val.intValue() >= 0);
assertTrue(val.intValue() < MAXKEYS);
}
} catch (ClassNotFoundException cnfe) {
Assert.fail("GetSomeKeys failed with ClassNotFoundException", cnfe);
} catch (IOException ioe) {
Assert.fail("GetSomeKeys failed with IOException", ioe);
}
}
}
});
}
/**
* Test the test method PartitionedRegion.getAllNodes Verify that it returns nodes after a value
* has been placed into the PartitionedRegion.
*
* @see PartitionedRegion#getAllNodes()
*/
public static class TestGetNodesKey implements DataSerializable {
int hc;
public TestGetNodesKey(int hc) {
this.hc = hc;
}
public TestGetNodesKey() {};
public int hashCode() {
return this.hc;
}
public void toData(DataOutput out) throws IOException {
out.writeInt(this.hc);
}
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
this.hc = in.readInt();
}
}
@Test
public void testGetNodes() throws Exception {
final String r = getUniqueName();
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm1 = host.getVM(1);
VM validator = host.getVM(2);
CacheSerializableRunnable createAndTest =
new CacheSerializableRunnable("CreatePRAndTestGetAllNodes") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(
new PartitionAttributesFactory().setTotalNumBuckets(totalNumBuckets).create());
PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
assertNotNull(p);
assertTrue(!p.isDestroyed());
// For each invocation, create a key that has a sequential hashCode.
// Putting this key into the PR should force a new bucket allocation on
// each new VM (assuming a mod on the hashCode), forcing the number of VMs to increase
// when we call getAllNodes each time this method is called.
Integer i = (Integer) p.get("Counter");
final Integer keyHash;
if (i == null) {
i = new Integer(0);
} else {
i = new Integer(i.intValue() + 1);
}
keyHash = i;
p.put("Counter", i);
p.put(new TestGetNodesKey(keyHash.intValue()), i);
Set allN = p.getAllNodes();
assertNotNull(allN);
assertTrue(!allN.isEmpty());
}
};
validator.invoke(createAndTest);
validator.invoke(new CacheSerializableRunnable("AssertGetNodesCreation1") {
public void run2() throws CacheException {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(r);
assertNotNull(p);
assertTrue(!p.isDestroyed());
Set allN = p.getAllNodes();
assertNotNull(allN);
assertEquals(1, allN.size());
}
});
vm0.invoke(createAndTest);
validator.invoke(new CacheSerializableRunnable("AssertGetNodesCreation2") {
public void run2() throws CacheException {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(r);
assertNotNull(p);
assertTrue(!p.isDestroyed());
Set allN = p.getAllNodes();
assertNotNull(allN);
assertEquals(2, allN.size());
}
});
vm1.invoke(createAndTest);
validator.invoke(new CacheSerializableRunnable("AssertGetNodesCreation3") {
public void run2() throws CacheException {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(r);
assertNotNull(p);
assertTrue(!p.isDestroyed());
Set allN = p.getAllNodes();
assertNotNull(allN);
assertEquals(3, allN.size());
}
});
}
/**
* Test the test utilities that allow investigation of a PartitionedRegion's local cache.
*/
@Test
public void testLocalCacheOps() throws Exception {
final String r = getUniqueName();
Host host = Host.getHost(0);
VM vm0 = host.getVM(0);
VM vm2 = host.getVM(2);
vm0.invoke(new CacheSerializableRunnable("CreatePR") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(new PartitionAttributesFactory()
.setTotalNumBuckets(totalNumBuckets).setLocalMaxMemory(8).create());
PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
assertNotNull(p);
}
});
// TODO enable this test when we have the LocalCache properly implemented -- mthomas 2/23/2006
// vm1.invoke(new CacheSerializableRunnable("CreatePRWithLocalCacheAndTestOps") {
// public void run2() throws CacheException
// {
// Cache cache = getCache();
// AttributesFactory attr = new AttributesFactory();
// attr.setScope(Scope.DISTRIBUTED_ACK);
// Properties lp = new Properties();
// lp.setProperty(PartitionAttributesFactory.LOCAL_MAX_MEMORY_PROPERTY, "0");
// attr.setPartitionAttributes(new PartitionAttributesFactory()
// .setLocalProperties(lp)
// .createPartitionAttributes());
//
// PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
// assertNotNull(p);
//
// final String key1 = "lcKey1"; final String val1 = "lcVal1";
// final String key2 = "lcKey2"; final String val2 = "lcVal2";
// // Test localCacheContainsKey
// assertFalse(p.localCacheContainsKey(key1));
// assertFalse(p.localCacheContainsKey(key2));
// p.put(key1, val1);
// assertFalse(p.localCacheContainsKey(key1));
// assertFalse(p.localCacheContainsKey(key2));
// assertIndexDetailsEquals(val1, p.get(key1));
// assertTrue(p.localCacheContainsKey(key1));
// assertFalse(p.localCacheContainsKey(key2));
//
// // test localCacheKeySet
// Set lset = p.localCacheKeySet();
// assertTrue(lset.contains(key1));
// assertFalse(lset.contains(key2));
//
// // test localCacheGet
// assertIndexDetailsEquals(val1, p.localCacheGet(key1));
// assertNull(p.localCacheGet(key2));
// p.put(key2, val2);
// assertNull(p.localCacheGet(key2));
// assertIndexDetailsEquals(val2, p.get(key2));
// assertIndexDetailsEquals(val2, p.localCacheGet(key2));
// }
// });
vm2.invoke(new CacheSerializableRunnable("CreatePRWithNoLocalCacheAndTestOps") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(new PartitionAttributesFactory()
.setTotalNumBuckets(totalNumBuckets).setLocalMaxMemory(0).create());
PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
assertNotNull(p);
final String key3 = "lcKey3";
final String val3 = "lcVal3";
final String key4 = "lcKey4";
final String val4 = "lcVal4";
// Test localCacheContainsKey
assertFalse(p.localCacheContainsKey(key3));
assertFalse(p.localCacheContainsKey(key4));
p.put(key3, val3);
assertFalse(p.localCacheContainsKey(key3));
assertFalse(p.localCacheContainsKey(key4));
assertEquals(val3, p.get(key3));
assertFalse(p.localCacheContainsKey(key3));
assertFalse(p.localCacheContainsKey(key4));
// test localCacheKeySet
Set lset = p.localCacheKeySet();
assertFalse(lset.contains(key3));
assertFalse(lset.contains(key4));
// test localCacheGet
assertNull(val3, p.localCacheGet(key3));
assertNull(p.localCacheGet(key4));
p.put(key4, val4);
assertNull(p.localCacheGet(key4));
assertEquals(val4, p.get(key4));
assertNull(p.localCacheGet(key4));
}
});
}
/**
* Test the test method PartitionedRegion.getAllNodes Verify that it returns nodes after a value
* has been placed into the PartitionedRegion.
*
* @see PartitionedRegion#getAllNodes()
*/
@Test
public void testGetBucketKeys() throws Exception {
final String r = getUniqueName();
Host host = Host.getHost(0);
VM vm2 = host.getVM(2);
VM vm3 = host.getVM(3);
CacheSerializableRunnable create = new CacheSerializableRunnable("CreatePR") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(
new PartitionAttributesFactory().setTotalNumBuckets(totalNumBuckets).create());
PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
assertNotNull(p);
}
};
vm2.invoke(create);
vm3.invoke(create);
// Create an accessor
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
attr.setPartitionAttributes(new PartitionAttributesFactory().setTotalNumBuckets(totalNumBuckets)
.setLocalMaxMemory(0).create());
PartitionedRegion p = (PartitionedRegion) cache.createRegion(r, attr.create());
assertNotNull(p);
final int totalBucks = p.getTotalNumberOfBuckets();
for (int i = totalBucks - 1; i >= 0; i--) {
Set s = p.getBucketKeys(i);
assertTrue(s.isEmpty());
}
class TestPRKey implements Serializable {
int hashCode;
int differentiator;
TestPRKey(int hash, int differentiator) {
this.hashCode = hash;
this.differentiator = differentiator;
}
public int hashCode() {
return hashCode;
}
public boolean equals(Object obj) {
if (!(obj instanceof TestPRKey)) {
return false;
}
return ((TestPRKey) obj).differentiator == this.differentiator;
}
public String toString() {
return "TestPRKey " + hashCode + " diff " + differentiator;
}
}
TestPRKey key;
Integer val;
// Create bucket number of keys, assuming a modulous per key hashCode
// There should be one key per bucket
p.put(new TestPRKey(0, 1), new Integer(0));
p.put(new TestPRKey(0, 2), new Integer(1));
p.put(new TestPRKey(0, 3), new Integer(2));
Set s = p.getBucketKeys(0);
assertEquals(3, s.size());
assertEquals(0, ((TestPRKey) s.iterator().next()).hashCode());
assertEquals(0, ((TestPRKey) s.iterator().next()).hashCode());
assertEquals(0, ((TestPRKey) s.iterator().next()).hashCode());
// Skip bucket zero since we have three keys there, but fill out all the rest with keys
for (int i = totalBucks - 1; i > 0; i--) {
key = new TestPRKey(i, 0);
val = new Integer(i);
p.put(key, val);
// Integer gottenVal = (Integer) p.get(key);
// assertIndexDetailsEquals("Value for key: " + key + " val " + gottenVal + " wasn't expected
// " + val, val, gottenVal);
}
// Assert that the proper number of keys are placed in each bucket
for (int i = 1; i < totalBucks; i++) {
s = p.getBucketKeys(i);
assertEquals(s.size(), 1);
key = (TestPRKey) s.iterator().next();
assertEquals(i, key.hashCode());
// assertIndexDetailsEquals(new Integer(i), p.get(key));
}
}
/**
* Test the test method {@link PartitionedRegion#getBucketOwnersForValidation(int)} Verify that
* the information it discovers is the same as the local advisor.
*/
@Test
public void testGetBucketOwners() throws Exception {
final String rName0 = getUniqueName() + "-r0";
final String rName1 = getUniqueName() + "-r1";
final String rName2 = getUniqueName() + "-r2";
final String[] regions = {rName0, rName1, rName2};
final int numBuckets = 3;
final Host host = Host.getHost(0);
final VM datastore1 = host.getVM(2);
final VM datastore2 = host.getVM(3);
final VM datastore3 = host.getVM(0);
final VM accessor = host.getVM(1);
final CacheSerializableRunnable create = new CacheSerializableRunnable("CreatePR") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
PartitionAttributesFactory paf =
new PartitionAttributesFactory().setTotalNumBuckets(numBuckets);
for (int redundancy = 0; redundancy < regions.length; redundancy++) {
paf.setRedundantCopies(redundancy);
attr.setPartitionAttributes(paf.create());
PartitionedRegion p =
(PartitionedRegion) cache.createRegion(regions[redundancy], attr.create());
assertNotNull(p);
assertEquals(0, p.size());
}
}
};
datastore1.invoke(create);
datastore2.invoke(create);
datastore3.invoke(create);
accessor.invoke(new CacheSerializableRunnable("CreateAccessorPR") {
public void run2() throws CacheException {
Cache cache = getCache();
AttributesFactory attr = new AttributesFactory();
PartitionAttributesFactory paf =
new PartitionAttributesFactory().setTotalNumBuckets(numBuckets).setLocalMaxMemory(0);
for (int redundancy = 0; redundancy < regions.length; redundancy++) {
paf.setRedundantCopies(redundancy);
attr.setPartitionAttributes(paf.create());
PartitionedRegion p =
(PartitionedRegion) cache.createRegion(regions[redundancy], attr.create());
assertNotNull(p);
assertEquals(0, p.size());
}
}
});
final CacheSerializableRunnable noBucketOwners =
new CacheSerializableRunnable("AssertNoBucketOwners") {
public void run2() throws CacheException {
String[] regions = {rName0, rName1, rName2};
for (int rs = 0; rs < regions.length; rs++) {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(regions[rs]);
assertNotNull(p);
assertTrue(!p.isDestroyed());
assertEquals(numBuckets, p.getTotalNumberOfBuckets());
try {
for (int i = 0; i < p.getTotalNumberOfBuckets(); i++) {
assertEquals(0, p.getRegionAdvisor().getBucketOwners(i).size());
assertEquals(0, p.getBucketOwnersForValidation(i).size());
}
} catch (ForceReattemptException noGood) {
Assert.fail("Unexpected force retry", noGood);
}
}
}
};
datastore1.invoke(noBucketOwners);
datastore2.invoke(noBucketOwners);
datastore3.invoke(noBucketOwners);
accessor.invoke(noBucketOwners);
accessor.invoke(new CacheSerializableRunnable("CreateOneBucket") {
public void run2() throws CacheException {
for (int rs = 0; rs < regions.length; rs++) {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(regions[rs]);
assertNotNull(p);
assertEquals(3, p.getTotalNumberOfBuckets());
// Create one bucket
p.put(new Integer(0), "zero");
assertEquals(1, p.getRegionAdvisor().getCreatedBucketsCount());
}
}
});
final CacheSerializableRunnable oneBucketOwner =
new CacheSerializableRunnable("AssertSingleBucketPrimary") {
public void run2() throws CacheException {
for (int rs = 0; rs < regions.length; rs++) {
PartitionedRegion p = (PartitionedRegion) getCache().getRegion(regions[rs]);
try {
for (Iterator it = p.getRegionAdvisor().getBucketSet().iterator(); it.hasNext();) {
Integer bid = (Integer) it.next();
assertEquals(p.getRedundantCopies() + 1,
p.getRegionAdvisor().getBucketOwners(bid.intValue()).size());
List prims = p.getBucketOwnersForValidation(bid.intValue());
assertEquals(p.getRedundantCopies() + 1, prims.size());
int primCount = 0;
for (Iterator lit = prims.iterator(); lit.hasNext();) {
Object[] memAndBoolean = (Object[]) lit.next();
assertEquals(3, memAndBoolean.length); // memberId, isPrimary and hostToken(new)
assertTrue(memAndBoolean[0] instanceof DistributedMember);
assertEquals(Boolean.class, memAndBoolean[1].getClass());
Boolean isPrimary = (Boolean) memAndBoolean[1];
if (isPrimary.booleanValue()) {
primCount++;
}
}
assertEquals(1, primCount);
}
} catch (ForceReattemptException noGood) {
Assert.fail("Unexpected force retry", noGood);
}
}
}
};
accessor.invoke(oneBucketOwner);
datastore1.invoke(oneBucketOwner);
datastore2.invoke(oneBucketOwner);
datastore3.invoke(oneBucketOwner);
}
}