/*
* 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.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.PartitionedRegionStorageException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.geode.cache30.CacheSerializableRunnable;
import org.apache.geode.internal.cache.lru.Sizeable;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.LogWriterUtils;
import org.apache.geode.test.dunit.SerializableRunnable;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.junit.categories.DistributedTest;
/**
* This class is to test localMaxMemory property of partition region while creation of bucket.
*/
@Category(DistributedTest.class)
public class PartitionedRegionLocalMaxMemoryDUnitTest extends PartitionedRegionDUnitTestCase {
/** Prefix is used in name of Partition Region */
private static String prPrefix = null;
/** Maximum number of regions * */
static int MAX_REGIONS = 1;
/** local maxmemory used for the creation of the partition region */
int localMaxMemory = 1;
/** to store references of 4 vms */
VM vm[] = new VM[4];
/**
* This test performs following operations <br>
* 1.Create Partition region with localMaxMemory = 1MB on all the VMs </br>
* <br>
* 2.Put objects in partition region so that only one bucket gets created and size of that bucket
* exceeds localMaxMemory <br>
* 3.Put object such that new bucket gets formed</br>
* <br>
* 4.Test should throw PartitionedRegionStorageException when it tries to create new bucket</br>
*/
@Test
public void testLocalMaxMemoryInPartitionedRegion() {
Host host = Host.getHost(0);
/** creating 4 VMs */
this.vm[0] = host.getVM(0);
this.vm[1] = host.getVM(1);
this.vm[2] = null;
this.vm[3] = null;
/** Prefix will be used for naming the partititon Region */
prPrefix = "testLocalMaxMemoryInPartitionedRegion";
/** these indices represents range of partition regions present in each VM */
int startIndexForRegion = 0;
int endIndexForRegion = MAX_REGIONS;
int startIndexForNode = 0;
int endIndexForNode = 2;
// creating partition region on 4 nodes with
// localMaxMemory=1MB redundancy = 3
List vmList = addNodeToList(startIndexForNode, endIndexForNode);
localMaxMemory = 1;
final int redundancy = 1;
System.setProperty(PartitionedRegion.RETRY_TIMEOUT_PROPERTY, "20000");
createPartitionRegion(vmList, startIndexForRegion, endIndexForRegion, localMaxMemory,
redundancy, false);
System.setProperty(PartitionedRegion.RETRY_TIMEOUT_PROPERTY,
Integer.toString(PartitionedRegionHelper.DEFAULT_TOTAL_WAIT_RETRY_ITERATION));
putFromOneVm(vm[0], true);
putFromOneVm(vm[0], false);
destroyRegion(vm[0]);
}
/**
* This test makes sure that we don't enforce the localMaxMemory setting when eviction is enabled.
*/
@Test
public void testLocalMaxMemoryInPartitionedRegionWithEviction() {
Host host = Host.getHost(0);
/** creating 4 VMs */
this.vm[0] = host.getVM(0);
this.vm[1] = host.getVM(1);
this.vm[2] = null;
this.vm[3] = null;
/** Prefix will be used for naming the partititon Region */
prPrefix = "testLocalMaxMemoryInPartitionedRegion";
/** these indices represents range of partition regions present in each VM */
int startIndexForRegion = 0;
int endIndexForRegion = MAX_REGIONS;
int startIndexForNode = 0;
int endIndexForNode = 2;
// creating partition region on 4 nodes with
// localMaxMemory=1MB redundancy = 3
List vmList = addNodeToList(startIndexForNode, endIndexForNode);
localMaxMemory = 1;
final int redundancy = 1;
System.setProperty(PartitionedRegion.RETRY_TIMEOUT_PROPERTY, "20000");
createPartitionRegion(vmList, startIndexForRegion, endIndexForRegion, localMaxMemory,
redundancy, true);
System.setProperty(PartitionedRegion.RETRY_TIMEOUT_PROPERTY,
Integer.toString(PartitionedRegionHelper.DEFAULT_TOTAL_WAIT_RETRY_ITERATION));
putFromOneVm(vm[0], true);
putFromOneVm(vm[0], true);
destroyRegion(vm[0]);
}
/**
* function is used perform put() operation from one VM
*
* @param vm
* @param objectFlg
*/
private void putFromOneVm(VM vm, boolean objectFlg) {
vm.invoke(putObjectInPartitionRegion(objectFlg));
}
/**
* This function is used to put objects of different hashcode depending upon value of objectFlag
*
* @param objectFlg
* @return
*/
private CacheSerializableRunnable putObjectInPartitionRegion(final boolean objectFlg) {
CacheSerializableRunnable putObject = new CacheSerializableRunnable("putObject") {
public void run2() {
Cache cache = getCache();
PartitionedRegion pr = (PartitionedRegion) cache
.getRegion(Region.SEPARATOR + "testLocalMaxMemoryInPartitionedRegion0");
assertNotNull("Name of region : " + pr.getName(), pr);
int i = 0;
if (objectFlg == true) {
long size = 0;
while ((size =
pr.getDataStore().currentAllocatedMemory()) < PartitionedRegionHelper.BYTES_PER_MB) {
cache.getLogger().info("size: " + size);
Object obj = new TestObject1("testObject1" + i, 10);
pr.put(obj, obj);
i++;
}
assertEquals(1, pr.getDataStore().localBucket2RegionMap.size());
LogWriterUtils.getLogWriter()
.info("putObjectInPartitionRegion() - Put operation done successfully");
} else {
final String expectedExceptions = PartitionedRegionStorageException.class.getName();
getCache().getLogger()
.info("<ExpectedException action=add>" + expectedExceptions + "</ExpectedException>");
try {
TestObject1 kv = new TestObject1("testObject1" + i, 21);
pr.put(kv, kv);
fail("Bucket gets created even if no memory is available");
} catch (PartitionedRegionStorageException e) {
LogWriterUtils.getLogWriter().info(
"putObjectInPartitionRegion()- got correct PartitionedRegionStorageException while creating bucket when no memory is available");
}
getCache().getLogger().info(
"<ExpectedException action=remove>" + expectedExceptions + "</ExpectedException>");
}
}
};
return putObject;
}
/**
* This function createas multiple partition regions on nodes specified in the vmList
*
* @param evict
*/
private void createPartitionRegion(List vmList, int startIndexForRegion, int endIndexForRegion,
int localMaxMemory, int redundancy, boolean evict) {
Iterator nodeIterator = vmList.iterator();
while (nodeIterator.hasNext()) {
VM vm = (VM) nodeIterator.next();
vm.invoke(createMultiplePartitionRegion(prPrefix, startIndexForRegion, endIndexForRegion,
redundancy, localMaxMemory, evict));
}
}
/**
* This function adds nodes to node list
*
* @param startIndexForNode
* @param endIndexForNode
* @return
*/
private List addNodeToList(int startIndexForNode, int endIndexForNode) {
List localvmList = new ArrayList();
for (int i = startIndexForNode; i < endIndexForNode; i++) {
localvmList.add(vm[i]);
}
return localvmList;
}
/**
* this function creates vms in given host
*
* @param host
*/
private void createVMs(Host host) {
for (int i = 0; i < 4; i++) {
vm[i] = host.getVM(i);
}
}
private void destroyRegion(VM vm) {
SerializableRunnable destroyObj = new CacheSerializableRunnable("destroyObj") {
public void run2() {
Cache cache = getCache();
PartitionedRegion pr = (PartitionedRegion) cache
.getRegion(Region.SEPARATOR + "testLocalMaxMemoryInPartitionedRegion0");
assertNotNull("Name of region : " + pr.getName(), pr);
pr.destroyRegion();
}
};
vm.invoke(destroyObj);
}
/**
* Object used for the put() operation as key and object
*/
static public class TestObject1 implements DataSerializable, Sizeable {
String name;
byte arr[] = new byte[1024 * 4];
int identifier;
public TestObject1() {}
public TestObject1(String objectName, int objectIndentifier) {
this.name = objectName;
Arrays.fill(this.arr, (byte) 'A');
this.identifier = objectIndentifier;
}
public int hashCode() {
return this.identifier;
}
public boolean equals(TestObject1 obj) {
return (this.name.equals(obj.name) && Arrays.equals(this.arr, obj.arr));
}
public void toData(DataOutput out) throws IOException {
DataSerializer.writeByteArray(this.arr, out);
DataSerializer.writeString(this.name, out);
out.writeInt(this.identifier);
}
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
this.arr = DataSerializer.readByteArray(in);
this.name = DataSerializer.readString(in);
this.identifier = in.readInt();
}
public int getSizeInBytes() {
return ObjectSizer.DEFAULT.sizeof(arr) + ObjectSizer.DEFAULT.sizeof(name)
+ ObjectSizer.DEFAULT.sizeof(identifier) + Sizeable.PER_OBJECT_OVERHEAD * 3;
}
}
}