blob: 79918727bf855795b79dd3dde7e83e8bf031eab5 [file] [log] [blame]
package com.gemstone.gemfire.internal.offheap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.Vector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionShortcut;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.Chunk;
import com.gemstone.gemfire.test.junit.categories.IntegrationTest;
/**
* Basic integration tests for validating the off-heap implementation.
*
* @author Kirk Lund
*/
@Category(IntegrationTest.class)
public class OffHeapValidationJUnitTest {
private GemFireCacheImpl cache;
@Before
public void setUp() throws Exception {
this.cache = createCache();
}
@After
public void tearDown() throws Exception {
closeCache(this.cache);
}
protected GemFireCacheImpl createCache() {
Properties props = new Properties();
props.setProperty("locators", "");
props.setProperty("mcast-port", "0");
props.setProperty("off-heap-memory-size", getOffHeapMemorySize());
GemFireCacheImpl result = (GemFireCacheImpl) new CacheFactory(props).create();
return result;
}
protected void closeCache(GemFireCacheImpl gfc) {
gfc.close();
}
protected String getOffHeapMemorySize() {
return "2m";
}
protected RegionShortcut getRegionShortcut() {
return RegionShortcut.REPLICATE;
}
protected String getRegionName() {
return "region1";
}
@Test
public void testMemoryInspection() {
// validate initial state
MemoryAllocator allocator = this.cache.getOffHeapStore();
assertNotNull(allocator);
MemoryInspector inspector = allocator.getMemoryInspector();
assertNotNull(inspector);
inspector.createInspectionSnapshot();
try {
MemoryBlock firstBlock = inspector.getFirstBlock();
assertNotNull(firstBlock);
assertEquals(1024*1024*2, firstBlock.getBlockSize());
assertEquals("N/A", firstBlock.getDataType());
assertEquals(-1, firstBlock.getFreeListId());
assertTrue(firstBlock.getMemoryAddress() > 0);
assertNull(firstBlock.getNextBlock());
assertEquals(0, firstBlock.getRefCount());
assertEquals(0, firstBlock.getSlabId());
assertEquals(MemoryBlock.State.UNUSED, firstBlock.getState());
assertFalse(firstBlock.isCompressed());
assertFalse(firstBlock.isSerialized());
} finally {
inspector.clearInspectionSnapshot();
}
// create off-heap region
Region<Object, Object> region = this.cache.createRegionFactory(getRegionShortcut()).setOffHeap(true).create(getRegionName());
// perform some ops
List<ExpectedValues> expected = new ArrayList<ExpectedValues>();
// Chunk.OFF_HEAP_HEADER_SIZE + 4 ?
putString(region, expected);
putDate(region, expected);
putByteArray(region, expected);
putByteArrayArray(region, expected);
putShortArray(region, expected);
putStringArray(region, expected);
putObjectArray(region, expected);
putArrayList(region, expected);
putLinkedList(region, expected);
putHashSet(region, expected);
putLinkedHashSet(region, expected);
putHashMap(region, expected);
putIdentityHashMap(region, expected);
putHashtable(region, expected);
putProperties(region, expected);
putVector(region, expected);
putStack(region, expected);
putTreeMap(region, expected);
putTreeSet(region, expected);
putClass(region, expected);
putUUID(region, expected);
putTimestamp(region, expected);
putSerializableClass(region, expected);
// TODO: USER_DATA_SERIALIZABLE
// TODO: PDX
// TODO: PDX_ENUM
// TODO: GEMFIRE_ENUM
// TODO: PDX_INLINE_ENUM
// validate inspection
inspector.createInspectionSnapshot();
try {
MemoryBlock firstBlock = inspector.getFirstBlock();
assertEquals(MemoryBlock.State.UNUSED, firstBlock.getState());
//System.out.println(((SimpleMemoryAllocatorImpl)inspector).getInspectionSnapshot());
// sort the ExpectedValues into the same order as the MemberBlocks from inspector
Collections.sort(expected,
new Comparator<ExpectedValues>() {
@Override
public int compare(ExpectedValues o1, ExpectedValues o2) {
return Long.valueOf(o1.memoryAddress).compareTo(o2.memoryAddress);
}
});
int i = 0;
MemoryBlock block = firstBlock.getNextBlock();
while (block != null) {
ExpectedValues values = expected.get(i);
assertEquals(i + ":" + values.dataType, values.blockSize, block.getBlockSize());
assertEquals(i + ":" + values.dataType, values.dataType, block.getDataType());
assertEquals(i + ":" + values.dataType, values.freeListId, block.getFreeListId());
assertEquals(i + ":" + values.dataType, values.memoryAddress, block.getMemoryAddress());
assertEquals(i + ":" + values.dataType, values.refCount, block.getRefCount());
assertEquals(i + ":" + values.dataType, values.slabId, block.getSlabId());
assertEquals(i + ":" + values.dataType, values.isCompressed, block.isCompressed());
assertEquals(i + ":" + values.dataType, values.isSerialized, block.isSerialized());
// compare block.getDataValue() but only for String types
if (values.dataType.equals("java.lang.String")) {
Object obj = block.getDataValue();
assertNotNull(block.toString(), obj);
assertTrue(obj instanceof String);
assertEquals("this is a string", (String)obj);
}
if (values.dataType.contains("[")) { //for (int j = 0; j < ((byte[])values.dataValue).length; j++) {
// TODO
} else if (values.dataValue instanceof Collection) {
int diff = joint((Collection<?>)values.dataValue, (Collection<?>)block.getDataValue());
assertEquals(i + ":" + values.dataType, 0, diff);
} else if (values.dataValue instanceof IdentityHashMap) {
// TODO
} else if (values.dataValue instanceof Map) {
int diff = joint((Map<?,?>)values.dataValue, (Map<?,?>)block.getDataValue());
assertEquals(i + ":" + values.dataType, 0, diff);
} else {
assertEquals(i + ":" + values.dataType, values.dataValue, block.getDataValue());
}
block = block.getNextBlock();
i++;
}
assertEquals("All blocks: "+inspector.getAllBlocks(), expected.size(), i);
} finally {
inspector.clearInspectionSnapshot();
}
// perform more ops
// validate more inspection
}
@Test
public void testCompaction() {
// create fragmented state
// validate fragmented
// perform compaction
// validate freed fragments
}
/**
* Returns -1 if c1 is missing an element in c2, 1 if c2 is missing an element
* in c1, or 0 is they contain the exact same elements.
* @throws NullPointerException if either c1 or c2 is null
*/
private static int joint(Collection<?> c1, Collection<?> c2) {
if (c1.size() < c2.size()) {
return -1;
} else if (c2.size() < c1.size()) {
return 1;
}
Collection<Object> c3 = new ArrayList<Object>();
c3.addAll(c1);
c3.removeAll(c2);
if (c3.size() > 0) {
return -1;
}
c3.addAll(c2);
c3.removeAll(c1);
if (c3.size() > 0) {
return 1;
}
return 0;
}
/**
* Returns -1 if m1 is missing a key in m2, 1 if m2 is missing a key
* in m1, or 0 is they contain the exact same keys.
* @throws NullPointerException if either c1 or c2 is null
*/
private static int joint(Map<?, ?> m1, Map<?, ?> m2) {
if (m1.size() < m2.size()) {
return -1;
} else if (m2.size() < m1.size()) {
return 1;
}
Collection<Object> c3 = new ArrayList<Object>();
c3.addAll(m1.keySet());
c3.removeAll(m2.keySet());
if (c3.size() > 0) {
return -1;
}
c3.addAll(m2.keySet());
c3.removeAll(m1.keySet());
if (c3.size() > 0) {
return 1;
}
return 0;
}
private long getMemoryAddress(Region region, String key) {
Object entry = ((LocalRegion) region).getRegionEntry(key)._getValue();
assertTrue(entry instanceof Chunk);
long memoryAddress = ((Chunk)entry).getMemoryAddress();
assertTrue(memoryAddress > 0);
return memoryAddress;
}
private void putString(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyString";
String value = "this is a string";
region.put(key, value);
expected.add(new ExpectedValues(value, value.length()*2, "java.lang.String", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putDate(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyDate";
Date value = new Date();
region.put(key, value);
expected.add(new ExpectedValues(value, 24, "java.util.Date", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putByteArray(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyByteArray";
byte[] value = new byte[10];
region.put(key, value);
expected.add(new ExpectedValues(value, 24, "byte[10]", -1, getMemoryAddress(region, key), 1, 0, false, false));
}
private void putByteArrayArray(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyByteArrayArray";
byte[][] value = new byte[10][10];
region.put(key, value);
expected.add(new ExpectedValues(value, 120, "byte[][]", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putShortArray(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyShortArray(";
short[] value = new short[10];
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "short[]", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putStringArray(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyStringArray";
String[] value = new String[10];
region.put(key, value);
expected.add(new ExpectedValues(value, 24, "java.lang.String[]", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putObjectArray(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyObjectArray";
Object[] value = new Object[10];
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.lang.Object[]", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putArrayList(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyArrayList";
ArrayList<Object> value = new ArrayList<Object>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.ArrayList", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putLinkedList(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyLinkedList";
LinkedList<Object> value = new LinkedList<Object>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.LinkedList", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putHashSet(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyHashSet";
HashSet<Object> value = new HashSet<Object>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.HashSet", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putLinkedHashSet(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyLinkedHashSet";
LinkedHashSet<Object> value = new LinkedHashSet<Object>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.LinkedHashSet", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putHashMap(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyHashMap";
HashMap<Object,Object> value = new HashMap<Object,Object>();
value.put("1", "string 1");
value.put("2", "string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.util.HashMap", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putIdentityHashMap(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyIdentityHashMap";
IdentityHashMap<Object,Object> value = new IdentityHashMap<Object,Object>();
value.put("1", "string 1");
value.put("2", "string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.util.IdentityHashMap", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putHashtable(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyHashtable";
Hashtable<Object,Object> value = new Hashtable<Object,Object>();
value.put("1", "string 1");
value.put("2", "string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.util.Hashtable", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putProperties(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyProperties";
Properties value = new Properties();
value.put("1", "string 1");
value.put("2", "string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.util.Properties", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putVector(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyVector";
Vector<String> value = new Vector<String>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.Vector", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putStack(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyStack";
Stack<String> value = new Stack<String>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.Stack", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putTreeMap(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyTreeMap";
TreeMap<String, String> value = new TreeMap<String, String>();
value.put("1", "string 1");
value.put("2", "string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 48, "java.util.TreeMap", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putTreeSet(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyTreeSet";
TreeSet<String> value = new TreeSet<String>();
value.add("string 1");
value.add("string 2");
region.put(key, value);
expected.add(new ExpectedValues(value, 40, "java.util.TreeSet", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putClass(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyClass";
Class<String> value = String.class;
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.lang.Class", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putUUID(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyUUID";
UUID value = UUID.randomUUID();
region.put(key, value);
expected.add(new ExpectedValues(value, 32, "java.util.UUID", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putTimestamp(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keyTimestamp";
Timestamp value = new Timestamp(System.currentTimeMillis());
region.put(key, value);
expected.add(new ExpectedValues(value, 24, "java.sql.Timestamp", -1, getMemoryAddress(region, key), 1, 0, false, true));
}
private void putSerializableClass(Region<Object, Object> region, List<ExpectedValues> expected) {
String key = "keySerializableClass";
SerializableClass value = new SerializableClass();
region.put(key, value);
expected.add(new ExpectedValues(value, 112, "java.io.Serializable:" + SerializableClass.class.getName(), -1, getMemoryAddress(region, key), 1, 0, false, true));
}
static class ExpectedValues {
final Object dataValue;
final int blockSize;
final String dataType;
final int freeListId;
final long memoryAddress;
final int refCount;
final int slabId;
final boolean isCompressed;
final boolean isSerialized;
ExpectedValues(Object dataValue, int blockSize, String dataType, int freeListId, long memoryAddress, int refCount, int slabId, boolean isCompressed, boolean isSerialized) {
this.dataValue = dataValue;
this.blockSize = blockSize;
this.dataType = dataType;
this.freeListId = freeListId;
this.memoryAddress = memoryAddress;
this.refCount = refCount;
this.slabId = slabId;
this.isCompressed = isCompressed;
this.isSerialized = isSerialized;
}
}
@SuppressWarnings("serial")
public static class SerializableClass implements Serializable {
public boolean equals(Object obj) {
return obj instanceof SerializableClass;
}
public int hashCode() {
return 42;
}
}
}