geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dschnei...@apache.org
Subject incubator-geode git commit: GEODE-607: improve SimpleMemoryAllocatorImpl unit test coverage
Date Wed, 02 Dec 2015 19:38:38 GMT
Repository: incubator-geode
Updated Branches:
  refs/heads/develop e19fa40ca -> f9744623d


GEODE-607: improve SimpleMemoryAllocatorImpl unit test coverage

Also changed ChunkType to an interface and removed dead code.
Refactored duplicate code into AbstractStoredObject.
Removed some more sqlf dead code.


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/f9744623
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/f9744623
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/f9744623

Branch: refs/heads/develop
Commit: f9744623ddb03b2920e85be5a68c4d4c2b4a3243
Parents: e19fa40
Author: Darrel Schneider <dschneider@pivotal.io>
Authored: Wed Nov 25 11:43:15 2015 -0800
Committer: Darrel Schneider <dschneider@pivotal.io>
Committed: Wed Dec 2 11:34:34 2015 -0800

----------------------------------------------------------------------
 .../internal/offheap/AbstractStoredObject.java  | 107 ++++++
 .../gemfire/internal/offheap/Chunk.java         |   1 -
 .../gemfire/internal/offheap/ChunkType.java     |  14 +-
 .../gemfire/internal/offheap/DataAsAddress.java |  87 +----
 .../gemfire/internal/offheap/Fragment.java      |  14 +
 .../internal/offheap/FreeListManager.java       |  14 +
 .../gemfire/internal/offheap/GemFireChunk.java  |   8 -
 .../internal/offheap/MemoryAllocator.java       |   2 -
 .../internal/offheap/MemoryBlockNode.java       |  14 +-
 .../internal/offheap/MemoryInspector.java       |   6 -
 .../offheap/OffHeapCachedDeserializable.java    |  85 +----
 .../internal/offheap/OffHeapStorage.java        |   1 -
 .../offheap/SimpleMemoryAllocatorImpl.java      | 284 +++++++-------
 .../internal/offheap/UnsafeMemoryChunk.java     |  10 +
 .../offheap/NullOffHeapMemoryStats.java         |   6 +
 .../offheap/NullOutOfOffHeapMemoryListener.java |   6 +
 .../offheap/SimpleMemoryAllocatorJUnitTest.java | 369 +++++++++++++++++--
 17 files changed, 643 insertions(+), 385 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/AbstractStoredObject.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/AbstractStoredObject.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/AbstractStoredObject.java
new file mode 100644
index 0000000..6dad277
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/AbstractStoredObject.java
@@ -0,0 +1,107 @@
+/*
+ * 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 com.gemstone.gemfire.internal.offheap;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.internal.DataSerializableFixedID;
+import com.gemstone.gemfire.internal.InternalDataSerializer;
+import com.gemstone.gemfire.internal.cache.RegionEntry;
+import com.gemstone.gemfire.internal.lang.StringUtils;
+
+public abstract class AbstractStoredObject implements StoredObject {
+  @Override
+  public Object getValueAsDeserializedHeapObject() {
+    return getDeserializedValue(null,null);
+  }
+  
+  @Override
+  public byte[] getValueAsHeapByteArray() {
+    if (isSerialized()) {
+      return getSerializedValue();
+    } else {
+      return (byte[])getDeserializedForReading();
+    }
+  }
+
+  @Override
+  public String getStringForm() {
+    try {
+      return StringUtils.forceToString(getDeserializedForReading());
+    } catch (RuntimeException ex) {
+      return "Could not convert object to string because " + ex;
+    }
+  }
+
+  @Override
+  public Object getDeserializedForReading() {
+    return getDeserializedValue(null,null);
+  }
+
+  @Override
+  public Object getDeserializedWritableCopy(Region r, RegionEntry re) {
+    return getDeserializedValue(null,null);
+  }
+
+  @Override
+  public Object getValue() {
+    if (isSerialized()) {
+      return getSerializedValue();
+    } else {
+      throw new IllegalStateException("Can not call getValue on StoredObject that is not serialized");
+    }
+  }
+
+  @Override
+  public void writeValueAsByteArray(DataOutput out) throws IOException {
+    DataSerializer.writeByteArray(getSerializedValue(), out);
+  }
+
+  @Override
+  public void sendTo(DataOutput out) throws IOException {
+    if (isSerialized()) {
+      out.write(getSerializedValue());
+    } else {
+      Object objToSend = (byte[]) getDeserializedForReading(); // deserialized as a byte[]
+      DataSerializer.writeObject(objToSend, out);
+    }
+  }
+
+  @Override
+  public void sendAsByteArray(DataOutput out) throws IOException {
+    byte[] bytes;
+    if (isSerialized()) {
+      bytes = getSerializedValue();
+    } else {
+      bytes = (byte[]) getDeserializedForReading();
+    }
+    DataSerializer.writeByteArray(bytes, out);
+    
+  }
+
+  @Override
+  public void sendAsCachedDeserializable(DataOutput out) throws IOException {
+    if (!isSerialized()) {
+      throw new IllegalStateException("sendAsCachedDeserializable can only be called on serialized StoredObjects");
+    }
+    InternalDataSerializer.writeDSFIDHeader(DataSerializableFixedID.VM_CACHED_DESERIALIZABLE, out);
+    sendAsByteArray(out);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Chunk.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Chunk.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Chunk.java
index e32a1c6..ed4bc43 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Chunk.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Chunk.java
@@ -389,7 +389,6 @@ import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
     @Override
     public void writeBytes(int offset, byte[] bytes, int bytesOffset, int size) {
       assert offset+size <= getDataSize();
-      SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(getBaseDataAddress() + offset, size);
       UnsafeMemoryChunk.writeAbsoluteBytes(getBaseDataAddress() + offset, bytes, bytesOffset, size);
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/ChunkType.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/ChunkType.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/ChunkType.java
index 9841368..e48bb62 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/ChunkType.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/ChunkType.java
@@ -17,10 +17,14 @@
 package com.gemstone.gemfire.internal.offheap;
 
 /**
- * Used to create new chunks of a certain type.
+ * Describes the type of data stored in a chunk.
  */
-public abstract class ChunkType {
-  public abstract int getSrcType();
-  public abstract Chunk newChunk(long memoryAddress);
-  public abstract Chunk newChunk(long memoryAddress, int chunkSize);
+public interface ChunkType {
+  /**
+   * Returns an int that describes that type of
+   * data stored in the chunk.
+   * Currently the only supported type is
+   * Chunk.SRC_TYPE_GFE.
+   */
+  public int getSrcType();
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/DataAsAddress.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/DataAsAddress.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/DataAsAddress.java
index 61204ba..5b14389 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/DataAsAddress.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/DataAsAddress.java
@@ -16,18 +16,11 @@
  */
 package com.gemstone.gemfire.internal.offheap;
 
-import java.io.DataOutput;
-import java.io.IOException;
-
-import com.gemstone.gemfire.DataSerializer;
 import com.gemstone.gemfire.cache.Region;
-import com.gemstone.gemfire.internal.DataSerializableFixedID;
-import com.gemstone.gemfire.internal.InternalDataSerializer;
 import com.gemstone.gemfire.internal.cache.BytesAndBitsForCompactor;
 import com.gemstone.gemfire.internal.cache.EntryBits;
 import com.gemstone.gemfire.internal.cache.RegionEntry;
 import com.gemstone.gemfire.internal.cache.RegionEntryContext;
-import com.gemstone.gemfire.internal.lang.StringUtils;
 
 /**
  * Used to represent offheap addresses whose
@@ -35,7 +28,7 @@ import com.gemstone.gemfire.internal.lang.StringUtils;
  * location.
  * Instances of this class have a very short lifetime.
  */
-public class DataAsAddress implements StoredObject {
+public class DataAsAddress extends AbstractStoredObject {
   private final long address;
   
   public DataAsAddress(long addr) {
@@ -88,53 +81,6 @@ public class DataAsAddress implements StoredObject {
   }
 
   @Override
-  public Object getDeserializedForReading() {
-    return getDeserializedValue(null,null);
-  }
-  
-  @Override
-  public Object getValueAsDeserializedHeapObject() {
-    return getDeserializedValue(null,null);
-  }
-  
-  @Override
-  public byte[] getValueAsHeapByteArray() {
-    if (isSerialized()) {
-      return getSerializedValue();
-    } else {
-      return (byte[])getDeserializedForReading();
-    }
-  }
-
-  @Override
-  public String getStringForm() {
-    try {
-      return StringUtils.forceToString(getDeserializedForReading());
-    } catch (RuntimeException ex) {
-      return "Could not convert object to string because " + ex;
-    }
-  }
-
-  @Override
-  public Object getDeserializedWritableCopy(Region r, RegionEntry re) {
-    return getDeserializedValue(null,null);
-  }
-
-  @Override
-  public Object getValue() {
-    if (isSerialized()) {
-      return getSerializedValue();
-    } else {
-      throw new IllegalStateException("Can not call getValue on StoredObject that is not serialized");
-    }
-  }
-
-  @Override
-  public void writeValueAsByteArray(DataOutput out) throws IOException {
-    DataSerializer.writeByteArray(getSerializedValue(), out);
-  }
-
-  @Override
   public void fillSerializedValue(BytesAndBitsForCompactor wrapper,
       byte userBits) {
     byte[] value;
@@ -153,37 +99,6 @@ public class DataAsAddress implements StoredObject {
   }
   
   @Override
-  public void sendTo(DataOutput out) throws IOException {
-    if (isSerialized()) {
-      out.write(getSerializedValue());
-    } else {
-      Object objToSend = (byte[]) getDeserializedForReading(); // deserialized as a byte[]
-      DataSerializer.writeObject(objToSend, out);
-    }
-  }
-
-  @Override
-  public void sendAsByteArray(DataOutput out) throws IOException {
-    byte[] bytes;
-    if (isSerialized()) {
-      bytes = getSerializedValue();
-    } else {
-      bytes = (byte[]) getDeserializedForReading();
-    }
-    DataSerializer.writeByteArray(bytes, out);
-    
-  }
-  
-  @Override
-  public void sendAsCachedDeserializable(DataOutput out) throws IOException {
-    if (!isSerialized()) {
-      throw new IllegalStateException("sendAsCachedDeserializable can only be called on serialized StoredObjects");
-    }
-    InternalDataSerializer.writeDSFIDHeader(DataSerializableFixedID.VM_CACHED_DESERIALIZABLE, out);
-    sendAsByteArray(out);
-  }
-
-  @Override
   public boolean isSerialized() {
     return OffHeapRegionEntryHelper.isSerialized(this.address);
   }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Fragment.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Fragment.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Fragment.java
index bd05ddb..ef56627 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Fragment.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/Fragment.java
@@ -122,4 +122,18 @@ public class Fragment implements MemoryBlock {
   public ChunkType getChunkType() {
     return null;
   }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (o instanceof Fragment) {
+      return getMemoryAddress() == ((Fragment) o).getMemoryAddress();
+    }
+    return false;
+  }
+  
+  @Override
+  public int hashCode() {
+    long value = this.getMemoryAddress();
+    return (int)(value ^ (value >>> 32));
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/FreeListManager.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/FreeListManager.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/FreeListManager.java
index 48a0756..10e4148 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/FreeListManager.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/FreeListManager.java
@@ -803,5 +803,19 @@ public class FreeListManager {
     public ChunkType getChunkType() {
       return null;
     }
+    
+    @Override
+    public boolean equals(Object o) {
+      if (o instanceof TinyMemoryBlock) {
+        return getMemoryAddress() == ((TinyMemoryBlock) o).getMemoryAddress();
+      }
+      return false;
+    }
+    
+    @Override
+    public int hashCode() {
+      long value = this.getMemoryAddress();
+      return (int)(value ^ (value >>> 32));
+    }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/GemFireChunk.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/GemFireChunk.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/GemFireChunk.java
index 3167613..20e4a2f 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/GemFireChunk.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/GemFireChunk.java
@@ -28,14 +28,6 @@ public class GemFireChunk extends Chunk {
     public int getSrcType() {
       return Chunk.SRC_TYPE_GFE;
     }
-    @Override
-    public Chunk newChunk(long memoryAddress) {
-      return new GemFireChunk(memoryAddress);
-    }
-    @Override
-    public Chunk newChunk(long memoryAddress, int chunkSize) {
-      return new GemFireChunk(memoryAddress, chunkSize);
-    }
   };
   public GemFireChunk(long memoryAddress, int chunkSize) {
     super(memoryAddress, chunkSize, TYPE);

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryAllocator.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryAllocator.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryAllocator.java
index 231ff3a..0a014de 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryAllocator.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryAllocator.java
@@ -16,8 +16,6 @@
  */
 package com.gemstone.gemfire.internal.offheap;
 
-import com.gemstone.gemfire.compression.Compressor;
-
 /**
  * Basic contract for a heap that manages off heap memory. Any MemoryChunks allocated from a heap
  * are returned to that heap when freed.

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryBlockNode.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryBlockNode.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryBlockNode.java
index 3f5f4dc..546feee 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryBlockNode.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryBlockNode.java
@@ -21,7 +21,6 @@ import java.util.Arrays;
 
 import com.gemstone.gemfire.DataSerializer;
 import com.gemstone.gemfire.cache.CacheClosedException;
-import com.gemstone.gemfire.internal.offheap.MemoryBlock.State;
 
 /**
  * Basic implementation of MemoryBlock for test validation only.
@@ -155,4 +154,17 @@ public class MemoryBlockNode implements MemoryBlock {
   public ChunkType getChunkType() {
     return this.block.getChunkType();
   }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (o instanceof MemoryBlockNode) {
+      o = ((MemoryBlockNode)o).block;
+    }
+    return this.block.equals(o);
+  }
+  
+  @Override
+  public int hashCode() {
+    return this.block.hashCode();
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryInspector.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryInspector.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryInspector.java
index acf6d04..cde24bc 100755
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryInspector.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/MemoryInspector.java
@@ -36,12 +36,6 @@ public interface MemoryInspector {
   
   public List<MemoryBlock> getAllocatedBlocks();
   
-  public List<MemoryBlock> getDeallocatedBlocks();
-  
-  public List<MemoryBlock> getUnusedBlocks();
-  
-  public MemoryBlock getBlockContaining(long memoryAddress);
-  
   public MemoryBlock getBlockAfter(MemoryBlock block);
   
   public List<MemoryBlock> getOrphans();

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapCachedDeserializable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapCachedDeserializable.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapCachedDeserializable.java
index 143fb25..1ec722d 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapCachedDeserializable.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapCachedDeserializable.java
@@ -16,20 +16,11 @@
  */
 package com.gemstone.gemfire.internal.offheap;
 
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.Arrays;
-
-import com.gemstone.gemfire.DataSerializer;
 import com.gemstone.gemfire.cache.Region;
 import com.gemstone.gemfire.internal.DSCODE;
-import com.gemstone.gemfire.internal.DataSerializableFixedID;
-import com.gemstone.gemfire.internal.InternalDataSerializer;
 import com.gemstone.gemfire.internal.cache.BytesAndBitsForCompactor;
-import com.gemstone.gemfire.internal.cache.CachedDeserializableFactory;
 import com.gemstone.gemfire.internal.cache.EntryBits;
 import com.gemstone.gemfire.internal.cache.RegionEntry;
-import com.gemstone.gemfire.internal.lang.StringUtils;
 import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
 
 /**
@@ -39,7 +30,7 @@ import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
  * @author darrel
  * @since 9.0
  */
-public abstract class OffHeapCachedDeserializable implements MemoryChunkWithRefCount {
+public abstract class OffHeapCachedDeserializable extends AbstractStoredObject implements MemoryChunkWithRefCount {
   public abstract void setSerializedValue(byte[] value);
   @Override
   public abstract byte[] getSerializedValue();
@@ -51,53 +42,6 @@ public abstract class OffHeapCachedDeserializable implements MemoryChunkWithRefC
   public abstract Object getDeserializedValue(Region r, RegionEntry re);
 
   @Override
-  public Object getValueAsDeserializedHeapObject() {
-    return getDeserializedValue(null, null);
-  }
-  
-  @Override
-  public byte[] getValueAsHeapByteArray() {
-    if (isSerialized()) {
-      return getSerializedValue();
-    } else {
-      return (byte[])getDeserializedForReading();
-    }
-  }
-  
-  @Override
-  public Object getDeserializedForReading() {
-    return getDeserializedValue(null, null);
-  }
-
-  @Override
-  public String getStringForm() {
-    try {
-      return StringUtils.forceToString(getDeserializedForReading());
-    } catch (RuntimeException ex) {
-      return "Could not convert object to string because " + ex;
-    }
-  }
-
-  @Override
-  public Object getDeserializedWritableCopy(Region r, RegionEntry re) {
-    return getDeserializedValue(null, null);
-  }
-
-  @Override
-  public Object getValue() {
-    if (isSerialized()) {
-      return getSerializedValue();
-    } else {
-      throw new IllegalStateException("Can not call getValue on StoredObject that is not serialized");
-    }
-  }
-
-  @Override
-  public void writeValueAsByteArray(DataOutput out) throws IOException {
-    DataSerializer.writeByteArray(getSerializedValue(), out);
-  }
-
-  @Override
   public void fillSerializedValue(BytesAndBitsForCompactor wrapper, byte userBits) {
     if (isSerialized()) {
       userBits = EntryBits.setSerialized(userBits, true);
@@ -114,33 +58,6 @@ public abstract class OffHeapCachedDeserializable implements MemoryChunkWithRefC
   public String toString() {
     return getShortClassName()+"@"+this.hashCode();
   }
-  @Override
-  public void sendTo(DataOutput out) throws IOException {
-    if (isSerialized()) {
-      out.write(getSerializedValue());
-    } else {
-      Object objToSend = (byte[]) getDeserializedForReading(); // deserialized as a byte[]
-      DataSerializer.writeObject(objToSend, out);
-    }
-  }
-  @Override
-  public void sendAsByteArray(DataOutput out) throws IOException {
-    byte[] bytes;
-    if (isSerialized()) {
-      bytes = getSerializedValue();
-    } else {
-      bytes = (byte[]) getDeserializedForReading();
-    }
-    DataSerializer.writeByteArray(bytes, out);
-  }
-  @Override
-  public void sendAsCachedDeserializable(DataOutput out) throws IOException {
-    if (!isSerialized()) {
-      throw new IllegalStateException("sendAsCachedDeserializable can only be called on serialized StoredObjects");
-    }
-    InternalDataSerializer.writeDSFIDHeader(DataSerializableFixedID.VM_CACHED_DESERIALIZABLE, out);
-    sendAsByteArray(out);
-  }
   public boolean checkDataEquals(@Unretained OffHeapCachedDeserializable other) {
     if (this == other) {
       return true;

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapStorage.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapStorage.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapStorage.java
index 1a6cc8b..ef584f1 100755
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapStorage.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapStorage.java
@@ -183,7 +183,6 @@ public class OffHeapStorage implements OffHeapMemoryStats {
       }
     }
     
-    //TODO:Asif: Fix it
     MemoryAllocator result;
     if (offHeapMemorySize == 0 || Boolean.getBoolean(InternalLocator.FORCE_LOCATOR_DM_TYPE)) {
       // Checking the FORCE_LOCATOR_DM_TYPE is a quick hack to keep our locator from allocating off heap memory.

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorImpl.java
index f16253e..dfd05c6 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorImpl.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorImpl.java
@@ -70,6 +70,8 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
    * Sizes are always rounded up to the next multiple of this constant
    * so internal fragmentation will be limited to TINY_MULTIPLE-1 bytes per allocation
    * and on average will be TINY_MULTIPLE/2 given a random distribution of size requests.
+   * This does not account for the additional internal fragmentation caused by the off-heap header
+   * which currently is always 8 bytes.
    */
   public final static int TINY_MULTIPLE = Integer.getInteger("gemfire.OFF_HEAP_ALIGNMENT", 8);
   /**
@@ -77,6 +79,9 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
    */
   public final static int TINY_FREE_LIST_COUNT = Integer.getInteger("gemfire.OFF_HEAP_FREE_LIST_COUNT", 16384);
   public final static int MAX_TINY = TINY_MULTIPLE*TINY_FREE_LIST_COUNT;
+  /**
+   * How many unused bytes are allowed in a huge memory allocation.
+   */
   public final static int HUGE_MULTIPLE = 256;
   
   volatile OffHeapMemoryStats stats;
@@ -95,7 +100,7 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
   private volatile MemoryUsageListener[] memoryUsageListeners = new MemoryUsageListener[0];
   
   private static SimpleMemoryAllocatorImpl singleton = null;
-  private static final AtomicReference<Thread> asyncCleanupThread = new AtomicReference<Thread>();
+  private static final AtomicReference<Thread> asyncCleanupThread = new AtomicReference<>();
   final ChunkFactory chunkFactory;
   
   public static SimpleMemoryAllocatorImpl getAllocator() {
@@ -106,69 +111,116 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
     return result;
   }
 
-  private static final boolean PRETOUCH = Boolean.getBoolean("gemfire.OFF_HEAP_PRETOUCH_PAGES");
-  static final int OFF_HEAP_PAGE_SIZE = Integer.getInteger("gemfire.OFF_HEAP_PAGE_SIZE", UnsafeMemoryChunk.getPageSize());
-  private static final boolean DO_EXPENSIVE_VALIDATION = Boolean.getBoolean("gemfire.OFF_HEAP_DO_EXPENSIVE_VALIDATION");;
-  
-  public static MemoryAllocator create(OutOfOffHeapMemoryListener ooohml, OffHeapMemoryStats stats, LogWriter lw, int slabCount, long offHeapMemorySize, long maxSlabSize) {
+  private static final boolean DO_EXPENSIVE_VALIDATION = Boolean.getBoolean("gemfire.OFF_HEAP_DO_EXPENSIVE_VALIDATION");
+  
+  public static MemoryAllocator create(OutOfOffHeapMemoryListener ooohml, OffHeapMemoryStats stats, LogWriter lw, 
+      int slabCount, long offHeapMemorySize, long maxSlabSize) {
+    return create(ooohml, stats, lw, slabCount, offHeapMemorySize, maxSlabSize,
+        null, TINY_MULTIPLE, BATCH_SIZE, TINY_FREE_LIST_COUNT, HUGE_MULTIPLE, 
+        new UnsafeMemoryChunk.Factory() {
+      @Override
+      public UnsafeMemoryChunk create(int size) {
+        return new UnsafeMemoryChunk(size);
+      }
+    });
+  }
+
+  private static SimpleMemoryAllocatorImpl create(OutOfOffHeapMemoryListener ooohml, OffHeapMemoryStats stats, LogWriter lw, 
+      int slabCount, long offHeapMemorySize, long maxSlabSize, 
+      UnsafeMemoryChunk[] slabs, int tinyMultiple, int batchSize, int tinyFreeListCount, int hugeMultiple,
+      UnsafeMemoryChunk.Factory memChunkFactory) {
     SimpleMemoryAllocatorImpl result = singleton;
     boolean created = false;
     try {
     if (result != null) {
-      result.reuse(ooohml, lw, stats, offHeapMemorySize);
-      lw.config("Reusing " + result.getTotalMemory() + " bytes of off-heap memory. The maximum size of a single off-heap object is " + result.largestSlab + " bytes.");
+      result.reuse(ooohml, lw, stats, offHeapMemorySize, slabs);
+      if (lw != null) {
+        lw.config("Reusing " + result.getTotalMemory() + " bytes of off-heap memory. The maximum size of a single off-heap object is " + result.largestSlab + " bytes.");
+      }
       created = true;
       LifecycleListener.invokeAfterReuse(result);
     } else {
-      // allocate memory chunks
-      //SimpleMemoryAllocatorImpl.cleanupPreviousAllocator();
-      lw.config("Allocating " + offHeapMemorySize + " bytes of off-heap memory. The maximum size of a single off-heap object is " + maxSlabSize + " bytes.");
-      UnsafeMemoryChunk[] slabs = new UnsafeMemoryChunk[slabCount];
-      long uncreatedMemory = offHeapMemorySize;
-      for (int i=0; i < slabCount; i++) {
-        try {
-        if (uncreatedMemory >= maxSlabSize) {
-          slabs[i] = new UnsafeMemoryChunk((int) maxSlabSize);
-          uncreatedMemory -= maxSlabSize;
-        } else {
-          // the last slab can be smaller then maxSlabSize
-          slabs[i] = new UnsafeMemoryChunk((int) uncreatedMemory);
+      if (slabs == null) {
+        // allocate memory chunks
+        //SimpleMemoryAllocatorImpl.cleanupPreviousAllocator();
+        if (lw != null) {
+          lw.config("Allocating " + offHeapMemorySize + " bytes of off-heap memory. The maximum size of a single off-heap object is " + maxSlabSize + " bytes.");
         }
-        } catch (OutOfMemoryError err) {
-          if (i > 0) {
-            lw.severe("Off-heap memory creation failed after successfully allocating " + (i*maxSlabSize) + " bytes of off-heap memory.");
-          }
-          for (int j=0; j < i; j++) {
-            if (slabs[j] != null) {
-              slabs[j].release();
+        slabs = new UnsafeMemoryChunk[slabCount];
+        long uncreatedMemory = offHeapMemorySize;
+        for (int i=0; i < slabCount; i++) {
+          try {
+            if (uncreatedMemory >= maxSlabSize) {
+              slabs[i] = memChunkFactory.create((int) maxSlabSize);
+              uncreatedMemory -= maxSlabSize;
+            } else {
+              // the last slab can be smaller then maxSlabSize
+              slabs[i] = memChunkFactory.create((int) uncreatedMemory);
+            }
+          } catch (OutOfMemoryError err) {
+            if (i > 0) {
+              if (lw != null) {
+                lw.severe("Off-heap memory creation failed after successfully allocating " + (i*maxSlabSize) + " bytes of off-heap memory.");
+              }
             }
+            for (int j=0; j < i; j++) {
+              if (slabs[j] != null) {
+                slabs[j].release();
+              }
+            }
+            throw err;
           }
-          throw err;
         }
       }
 
-      result = new SimpleMemoryAllocatorImpl(ooohml, stats, slabs);
-      created = true;
+      result = new SimpleMemoryAllocatorImpl(ooohml, stats, slabs, tinyMultiple, batchSize, tinyFreeListCount, hugeMultiple);
       singleton = result;
       LifecycleListener.invokeAfterCreate(result);
+      created = true;
     }
     } finally {
       if (!created) {
-        stats.close();
-        ooohml.close();
+        if (stats != null) {
+          stats.close();
+        }
+        if (ooohml != null) {
+          ooohml.close();
+        }
       }
     }
     return result;
   }
   // for unit tests
+  static SimpleMemoryAllocatorImpl create(OutOfOffHeapMemoryListener ooohml, OffHeapMemoryStats stats, LogWriter lw, 
+      int slabCount, long offHeapMemorySize, long maxSlabSize, UnsafeMemoryChunk.Factory memChunkFactory) {
+    return create(ooohml, stats, lw, slabCount, offHeapMemorySize, maxSlabSize, 
+        null, TINY_MULTIPLE, BATCH_SIZE, TINY_FREE_LIST_COUNT, HUGE_MULTIPLE, memChunkFactory);
+  }
+  // for unit tests
   public static SimpleMemoryAllocatorImpl create(OutOfOffHeapMemoryListener oooml, OffHeapMemoryStats stats, UnsafeMemoryChunk[] slabs) {
-    SimpleMemoryAllocatorImpl result = new SimpleMemoryAllocatorImpl(oooml, stats, slabs);
-    singleton = result;
-    LifecycleListener.invokeAfterCreate(result);
-    return result;
+    return create(oooml, stats, slabs, TINY_MULTIPLE, BATCH_SIZE, TINY_FREE_LIST_COUNT, HUGE_MULTIPLE);
   }
+  // for unit tests
+  static SimpleMemoryAllocatorImpl create(OutOfOffHeapMemoryListener oooml, OffHeapMemoryStats stats, UnsafeMemoryChunk[] slabs,
+      int tinyMultiple, int batchSize, int tinyFreeListCount, int hugeMultiple) {
+    int slabCount = 0;
+    long offHeapMemorySize = 0;
+    long maxSlabSize = 0;
+    if (slabs != null) {
+      slabCount = slabs.length;
+      for (int i=0; i < slabCount; i++) {
+        int slabSize = slabs[i].getSize();
+        offHeapMemorySize += slabSize;
+        if (slabSize > maxSlabSize) {
+          maxSlabSize = slabSize;
+        }
+      }
+    }
+    return create(oooml, stats, null, slabCount, offHeapMemorySize, maxSlabSize, slabs, tinyMultiple, batchSize, tinyFreeListCount, hugeMultiple, null);
+  }
+  
   
-  private void reuse(OutOfOffHeapMemoryListener oooml, LogWriter lw, OffHeapMemoryStats newStats, long offHeapMemorySize) {
+  private void reuse(OutOfOffHeapMemoryListener oooml, LogWriter lw, OffHeapMemoryStats newStats, long offHeapMemorySize, UnsafeMemoryChunk[] slabs) {
     if (isClosed()) {
       throw new IllegalStateException("Can not reuse a closed off-heap memory manager.");
     }
@@ -176,100 +228,55 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
       throw new IllegalArgumentException("OutOfOffHeapMemoryListener is null");
     }
     if (getTotalMemory() != offHeapMemorySize) {
-      lw.warning("Using " + getTotalMemory() + " bytes of existing off-heap memory instead of the requested " + offHeapMemorySize);
+      if (lw != null) {
+        lw.warning("Using " + getTotalMemory() + " bytes of existing off-heap memory instead of the requested " + offHeapMemorySize);
+      }
+    }
+    if (slabs != null) {
+      // this will only happen in unit tests
+      if (slabs != this.slabs) {
+        // If the unit test gave us a different array
+        // of slabs then something is wrong because we
+        // are trying to reuse the old already allocated
+        // array which means that the new one will never
+        // be used. Note that this code does not bother
+        // comparing the contents of the arrays.
+        throw new IllegalStateException("attempted to reuse existing off-heap memory even though new off-heap memory was allocated");
+      }
     }
     this.ooohml = oooml;
     newStats.initialize(this.stats);
     this.stats = newStats;
   }
 
-  public static void cleanupPreviousAllocator() {
-    Thread t = asyncCleanupThread.getAndSet(null);
-    if (t != null) {
-//      try {
-//        // HACK to see if a delay fixes bug 47883
-//        Thread.sleep(3000);
-//      } catch (InterruptedException ignore) {
-//      }
-      t.interrupt();
-      try {
-        t.join(FREE_PAUSE_MILLIS);
-      } catch (InterruptedException ignore) {
-        Thread.currentThread().interrupt();
-      }
-    }
-  }
-  
-  private SimpleMemoryAllocatorImpl(final OutOfOffHeapMemoryListener oooml, final OffHeapMemoryStats stats, final UnsafeMemoryChunk[] slabs) {
+  private SimpleMemoryAllocatorImpl(final OutOfOffHeapMemoryListener oooml, final OffHeapMemoryStats stats, final UnsafeMemoryChunk[] slabs,
+      int tinyMultiple, int batchSize, int tinyFreeListCount, int hugeMultiple) {
     if (oooml == null) {
       throw new IllegalArgumentException("OutOfOffHeapMemoryListener is null");
     }
-    if (TINY_MULTIPLE <= 0 || (TINY_MULTIPLE & 3) != 0) {
+    if (tinyMultiple <= 0 || (tinyMultiple & 3) != 0) {
       throw new IllegalStateException("gemfire.OFF_HEAP_ALIGNMENT must be a multiple of 8.");
     }
-    if (TINY_MULTIPLE > 256) {
+    if (tinyMultiple > 256) {
       // this restriction exists because of the dataSize field in the object header.
       throw new IllegalStateException("gemfire.OFF_HEAP_ALIGNMENT must be <= 256 and a multiple of 8.");
     }
-    if (BATCH_SIZE <= 0) {
+    if (batchSize <= 0) {
       throw new IllegalStateException("gemfire.OFF_HEAP_BATCH_ALLOCATION_SIZE must be >= 1.");
     }
-    if (TINY_FREE_LIST_COUNT <= 0) {
+    if (tinyFreeListCount <= 0) {
       throw new IllegalStateException("gemfire.OFF_HEAP_FREE_LIST_COUNT must be >= 1.");
     }
-    assert HUGE_MULTIPLE <= 256;
+    if (hugeMultiple > 256 || hugeMultiple < 0) {
+      // this restriction exists because of the dataSize field in the object header.
+      throw new IllegalStateException("HUGE_MULTIPLE must be >= 0 and <= 256 but it was " + hugeMultiple);
+    }
     
     this.ooohml = oooml;
     this.stats = stats;
     this.slabs = slabs;
-    if(GemFireCacheImpl.sqlfSystem()) {
-      throw new IllegalStateException("offheap sqlf not supported");
-//       String provider = GemFireCacheImpl.SQLF_FACTORY_PROVIDER;
-//       try {
-//         Class<?> factoryProvider = Class.forName(provider);
-//         Method method = factoryProvider.getDeclaredMethod("getChunkFactory");        
-//         this.chunkFactory  = (ChunkFactory)method.invoke(null, (Object [])null);
-//       }catch (Exception e) {
-//         throw new IllegalStateException("Exception in obtaining ChunkFactory class",  e);
-//       }
-
-    }else {
-      
-      this.chunkFactory = new GemFireChunkFactory();
-    }
+    this.chunkFactory = new GemFireChunkFactory();
     
-    if (PRETOUCH) {
-      final int tc;
-      if (Runtime.getRuntime().availableProcessors() > 1) {
-        tc = Runtime.getRuntime().availableProcessors() / 2;
-      } else {
-        tc = 1;
-      }
-      Thread[] threads = new Thread[tc];
-      for (int i=0; i < tc; i++) {
-        final int threadId = i;
-        threads[i] = new Thread(new Runnable() {
-          @Override
-          public void run() {
-            for (int slabId=threadId; slabId < slabs.length; slabId+=tc) {
-              final int slabSize = slabs[slabId].getSize();
-              for (int pageId=0; pageId < slabSize; pageId+=OFF_HEAP_PAGE_SIZE) {
-                slabs[slabId].writeByte(pageId, (byte) 0);
-              }
-            }
-          }
-        });
-        threads[i].start();
-      }
-      for (int i=0; i < tc; i++) {
-        try {
-          threads[i].join();
-        } catch (InterruptedException e) {
-          Thread.currentThread().interrupt();
-          break;
-        }
-      }
-    }
     //OSProcess.printStacks(0, InternalDistributedSystem.getAnyInstance().getLogWriter(), false);
     this.stats.setFragments(slabs.length);
     largestSlab = slabs[0].getSize();
@@ -437,7 +444,7 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
   private void realClose() {
     // Removing this memory immediately can lead to a SEGV. See 47885.
     if (setClosed()) {
-      freeSlabsAsync(this.slabs);
+      freeSlabs(this.slabs);
       this.stats.close();
       singleton = null;
     }
@@ -456,41 +463,11 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
   }
   
 
-  private static final int FREE_PAUSE_MILLIS = Integer.getInteger("gemfire.OFF_HEAP_FREE_PAUSE_MILLIS", 90000);
-
-  
-  
-  private static void freeSlabsAsync(final UnsafeMemoryChunk[] slabs) {
-    //debugLog("called freeSlabsAsync", false);
-    // since we no longer free off-heap memory on every cache close
-    // and production code does not free it but instead reuses it
-    // we should be able to free it sync.
-    // If it turns out that it does need to be async then we need
-    // to make sure we call cleanupPreviousAllocator.
+  private static void freeSlabs(final UnsafeMemoryChunk[] slabs) {
+    //debugLog("called freeSlabs", false);
     for (int i=0; i < slabs.length; i++) {
       slabs[i].release();
     }
-//    Thread t = new Thread(new Runnable() {
-//      @Override
-//      public void run() {
-//        // pause this many millis before freeing the slabs.
-//        try {
-//          Thread.sleep(FREE_PAUSE_MILLIS);
-//        } catch (InterruptedException ignore) {
-//          // If we are interrupted we should wakeup
-//          // and free our slabs.
-//        }
-//        //debugLog("returning offheap memory to OS", false);
-//        for (int i=0; i < slabs.length; i++) {
-//          slabs[i].free();
-//        }
-//        //debugLog("returned offheap memory to OS", false);
-//        asyncCleanupThread.compareAndSet(Thread.currentThread(), null);
-//      }
-//    }, "asyncSlabDeallocator");
-//    t.setDaemon(true);
-//    t.start();
-//    asyncCleanupThread.set(t);    
   }
   
   void freeChunk(long addr) {
@@ -504,7 +481,7 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
   /**
    * Return the slabId of the slab that contains the given addr.
    */
-  protected int findSlab(long addr) {
+  int findSlab(long addr) {
     for (int i=0; i < this.slabs.length; i++) {
       UnsafeMemoryChunk slab = this.slabs[i];
       long slabAddr = slab.getMemoryAddress();
@@ -591,11 +568,11 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
     if (addr >= 0 && addr < 1024) {
       throw new IllegalStateException("addr was smaller than expected 0x" + addr);
     }
-    validateAddressAndSizeWithinSlab(addr, size);
+    validateAddressAndSizeWithinSlab(addr, size, DO_EXPENSIVE_VALIDATION);
   }
 
-  static void validateAddressAndSizeWithinSlab(long addr, int size) {
-    if (DO_EXPENSIVE_VALIDATION) {
+  static void validateAddressAndSizeWithinSlab(long addr, int size, boolean doExpensiveValidation) {
+    if (doExpensiveValidation) {
       SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.singleton;
       if (ma != null) {
         for (int i=0; i < ma.slabs.length; i++) {
@@ -686,21 +663,6 @@ public final class SimpleMemoryAllocatorImpl implements MemoryAllocator, MemoryI
   }
 
   @Override
-  public List<MemoryBlock> getDeallocatedBlocks() {
-    return null;
-  }
-
-  @Override
-  public List<MemoryBlock> getUnusedBlocks() {
-    return null;
-  }
-  
-  @Override
-  public MemoryBlock getBlockContaining(long memoryAddress) {
-    return null;
-  }
-  
-  @Override
   public MemoryBlock getBlockAfter(MemoryBlock block) {
     if (block == null) {
       return null;

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/UnsafeMemoryChunk.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/UnsafeMemoryChunk.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/UnsafeMemoryChunk.java
index 06fee7b..4f0e86d 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/UnsafeMemoryChunk.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/UnsafeMemoryChunk.java
@@ -265,4 +265,14 @@ public class UnsafeMemoryChunk implements MemoryChunk {
     sb.append("}");
     return sb.toString();
   }
+  
+  /**
+   * Used to create UnsafeMemoryChunk instances.
+   */
+  public interface Factory {
+    /** Create and return an UnsafeMemoryChunk.
+     * @throws OutOfMemoryError if the create fails
+     */
+    public UnsafeMemoryChunk create(int size);
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOffHeapMemoryStats.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOffHeapMemoryStats.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOffHeapMemoryStats.java
index 7c668f1..88bab77 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOffHeapMemoryStats.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOffHeapMemoryStats.java
@@ -24,6 +24,7 @@ import com.gemstone.gemfire.Statistics;
  * @author Kirk Lund
  */
 public class NullOffHeapMemoryStats implements OffHeapMemoryStats {
+  private boolean isClosed;
 
   public void incFreeMemory(long value) {
   }
@@ -100,9 +101,14 @@ public class NullOffHeapMemoryStats implements OffHeapMemoryStats {
   }
   @Override
   public void close() {
+    this.isClosed = true;
   }
   @Override
   public void initialize(OffHeapMemoryStats stats) {
     stats.close();
   }     
+  
+  public boolean isClosed() {
+    return this.isClosed;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOutOfOffHeapMemoryListener.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOutOfOffHeapMemoryListener.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOutOfOffHeapMemoryListener.java
index caa913a..7d02c9f 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOutOfOffHeapMemoryListener.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/NullOutOfOffHeapMemoryListener.java
@@ -24,10 +24,16 @@ import com.gemstone.gemfire.OutOfOffHeapMemoryException;
  * @author Kirk Lund
  */
 public class NullOutOfOffHeapMemoryListener implements OutOfOffHeapMemoryListener {
+  private boolean isClosed;
   @Override
   public void outOfOffHeapMemory(OutOfOffHeapMemoryException cause) {
   }
   @Override
   public void close() {
+    this.isClosed = true;
+  }
+  
+  public boolean isClosed() {
+    return this.isClosed;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f9744623/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorJUnitTest.java
index 19dfebb..1477764 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/SimpleMemoryAllocatorJUnitTest.java
@@ -16,21 +16,21 @@
  */
 package com.gemstone.gemfire.internal.offheap;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import com.gemstone.gemfire.OutOfOffHeapMemoryException;
+import com.gemstone.gemfire.cache.CacheClosedException;
+import com.gemstone.gemfire.internal.logging.NullLogWriter;
+import com.gemstone.gemfire.internal.offheap.UnsafeMemoryChunk.Factory;
 import com.gemstone.gemfire.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
@@ -40,15 +40,198 @@ public class SimpleMemoryAllocatorJUnitTest {
     return ((v+multiple-1)/multiple)*multiple;
   }
   @Test
+  public void testNullGetAllocator() {
+    try {
+      SimpleMemoryAllocatorImpl.getAllocator();
+      fail("expected CacheClosedException");
+    } catch (CacheClosedException expected) {
+    }
+  }
+  @Test
+  public void testConstructor() {
+    try {
+      SimpleMemoryAllocatorImpl.create(null, null, null);
+      fail("expected IllegalArgumentException");
+    } catch (IllegalArgumentException expected) {
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, -1, 0, 0, 0);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("gemfire.OFF_HEAP_ALIGNMENT must be a multiple of 8"));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 9, 0, 0, 0);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("gemfire.OFF_HEAP_ALIGNMENT must be a multiple of 8"));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 256+8, 0, 0, 0);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("gemfire.OFF_HEAP_ALIGNMENT must be <= 256"));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 8, 0, 0, 0);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("gemfire.OFF_HEAP_BATCH_ALLOCATION_SIZE must be >= 1."));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 8, 1, 0, 0);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("gemfire.OFF_HEAP_FREE_LIST_COUNT must be >= 1."));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 8, 1, 1, -1);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("HUGE_MULTIPLE must be >= 0 and <= 256 but it was -1"));
+    }
+    try {
+      SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), null, null, 8, 1, 1, 257);
+      fail("expected IllegalStateException");
+    } catch (IllegalStateException expected) {
+      assertEquals(true, expected.getMessage().contains("HUGE_MULTIPLE must be >= 0 and <= 256 but it was 257"));
+    }
+     
+  }
+  /**
+   * Logger that remembers the last severe message
+   */
+  private static class LastSevereLogger extends NullLogWriter {
+    private String lastSevereMessage;
+    private Throwable lastSevereThrowable;
+    
+    private void setLastSevere(String msg, Throwable ex) {
+      this.lastSevereMessage = msg;
+      this.lastSevereThrowable = ex;
+    }
+    public String getLastSevereMessage() {
+      return this.lastSevereMessage;
+    }
+    public Throwable getLastSevereThrowable() {
+      return this.lastSevereThrowable;
+    }
+    @Override
+    public void severe(String msg, Throwable ex) {
+      setLastSevere(msg, ex);
+    }
+    @Override
+    public void severe(String msg) {
+      setLastSevere(msg, null);
+    }
+    @Override
+    public void severe(Throwable ex) {
+      setLastSevere(null, ex);
+    }
+  }
+  @Test
+  public void testCreate() {
+    {
+      NullOutOfOffHeapMemoryListener listener = new NullOutOfOffHeapMemoryListener();
+      NullOffHeapMemoryStats stats = new NullOffHeapMemoryStats();
+      LastSevereLogger logger = new LastSevereLogger();
+      try {
+        SimpleMemoryAllocatorImpl.create(listener, stats, logger, 10, 950, 100,
+            new UnsafeMemoryChunk.Factory() {
+          @Override
+          public UnsafeMemoryChunk create(int size) {
+            throw new OutOfMemoryError("expected");
+          }
+        });
+      } catch (OutOfMemoryError expected) {
+      }
+      assertTrue(listener.isClosed());
+      assertTrue(stats.isClosed());
+      assertEquals(null, logger.getLastSevereThrowable());
+      assertEquals(null, logger.getLastSevereMessage());
+     }
+    {
+      NullOutOfOffHeapMemoryListener listener = new NullOutOfOffHeapMemoryListener();
+      NullOffHeapMemoryStats stats = new NullOffHeapMemoryStats();
+      LastSevereLogger logger = new LastSevereLogger();
+      int MAX_SLAB_SIZE = 100;
+      try {
+        Factory factory = new UnsafeMemoryChunk.Factory() {
+          private int createCount = 0;
+          @Override
+          public UnsafeMemoryChunk create(int size) {
+            createCount++;
+            if (createCount == 1) {
+              return new UnsafeMemoryChunk(size);
+            } else {
+              throw new OutOfMemoryError("expected");
+            }
+          }
+        };
+        SimpleMemoryAllocatorImpl.create(listener, stats, logger, 10, 950, MAX_SLAB_SIZE, factory);
+      } catch (OutOfMemoryError expected) {
+      }
+      assertTrue(listener.isClosed());
+      assertTrue(stats.isClosed());
+      assertEquals(null, logger.getLastSevereThrowable());
+      assertEquals("Off-heap memory creation failed after successfully allocating " + MAX_SLAB_SIZE + " bytes of off-heap memory.", logger.getLastSevereMessage());
+    }
+    {
+      NullOutOfOffHeapMemoryListener listener = new NullOutOfOffHeapMemoryListener();
+      NullOffHeapMemoryStats stats = new NullOffHeapMemoryStats();
+      Factory factory = new UnsafeMemoryChunk.Factory() {
+        @Override
+        public UnsafeMemoryChunk create(int size) {
+          return new UnsafeMemoryChunk(size);
+        }
+      };
+      MemoryAllocator ma = 
+        SimpleMemoryAllocatorImpl.create(listener, stats, new NullLogWriter(), 10, 950, 100, factory);
+      try {
+        assertFalse(listener.isClosed());
+        assertFalse(stats.isClosed());
+        ma.close();
+        assertTrue(listener.isClosed());
+        assertFalse(stats.isClosed());
+        listener = new NullOutOfOffHeapMemoryListener();
+        NullOffHeapMemoryStats stats2 = new NullOffHeapMemoryStats();
+        {
+          UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024);
+          try {
+            SimpleMemoryAllocatorImpl.create(listener, stats2, new UnsafeMemoryChunk[]{slab});
+          } catch (IllegalStateException expected) {
+            assertTrue("unexpected message: " + expected.getMessage(), 
+                expected.getMessage().equals("attempted to reuse existing off-heap memory even though new off-heap memory was allocated"));
+          } finally {
+            slab.release();
+          }
+          assertFalse(stats.isClosed());
+          assertTrue(listener.isClosed());
+          assertTrue(stats2.isClosed());
+        }
+        listener = new NullOutOfOffHeapMemoryListener();
+        stats2 = new NullOffHeapMemoryStats();
+        MemoryAllocator ma2 = SimpleMemoryAllocatorImpl.create(listener, stats2, new NullLogWriter(), 10, 950, 100, factory);
+        assertSame(ma, ma2);
+        assertTrue(stats.isClosed());
+        assertFalse(listener.isClosed());
+        assertFalse(stats2.isClosed());
+        stats = stats2;
+      } finally {
+        ma.close();
+        assertTrue(listener.isClosed());
+        assertFalse(stats.isClosed());
+        SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+        assertTrue(stats.isClosed());
+      }
+    }
+  }
+  @Test
   public void testBasics() {
     int BATCH_SIZE = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.BATCH_SIZE;
     int TINY_MULTIPLE = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.TINY_MULTIPLE;
-//    int BIG_MULTIPLE = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.FreeListManager.BIG_MULTIPLE;
     int HUGE_MULTIPLE = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.HUGE_MULTIPLE;
     int perObjectOverhead = com.gemstone.gemfire.internal.offheap.Chunk.OFF_HEAP_HEADER_SIZE;
     int maxTiny = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.MAX_TINY-perObjectOverhead;
-//    int MIN_BIG_SIZE = round(BIG_MULTIPLE, maxTiny+perObjectOverhead+1)-perObjectOverhead;
-//    int maxBig = com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.FreeListManager.MAX_BIG-perObjectOverhead;
     int minHuge = maxTiny+1;
     int TOTAL_MEM = (maxTiny+perObjectOverhead)*BATCH_SIZE /*+ (maxBig+perObjectOverhead)*BATCH_SIZE*/ + round(TINY_MULTIPLE, minHuge+1+perObjectOverhead)*BATCH_SIZE + (TINY_MULTIPLE+perObjectOverhead)*BATCH_SIZE /*+ (MIN_BIG_SIZE+perObjectOverhead)*BATCH_SIZE*/ + round(TINY_MULTIPLE, minHuge+perObjectOverhead+1);
     UnsafeMemoryChunk slab = new UnsafeMemoryChunk(TOTAL_MEM);
@@ -57,14 +240,10 @@ public class SimpleMemoryAllocatorJUnitTest {
       assertEquals(TOTAL_MEM, ma.getFreeMemory());
       assertEquals(TOTAL_MEM, ma.freeList.getFreeFragmentMemory());
       assertEquals(0, ma.freeList.getFreeTinyMemory());
-//      assertEquals(0, ma.freeList.getFreeBigMemory());
       assertEquals(0, ma.freeList.getFreeHugeMemory());
       MemoryChunk tinymc = ma.allocate(maxTiny, null);
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       assertEquals(round(TINY_MULTIPLE, maxTiny+perObjectOverhead)*(BATCH_SIZE-1), ma.freeList.getFreeTinyMemory());
-//      MemoryChunk bigmc = ma.allocate(maxBig);
-//      assertEquals(TOTAL_MEM-round(BIG_MULTIPLE, maxBig+perObjectOverhead)-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
-//      assertEquals(round(BIG_MULTIPLE, maxBig+perObjectOverhead)*(BATCH_SIZE-1), ma.getFreeList().getFreeBigMemory());
       MemoryChunk hugemc = ma.allocate(minHuge, null);
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, minHuge+perObjectOverhead)/*-round(BIG_MULTIPLE, maxBig+perObjectOverhead)*/-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       long freeSlab = ma.freeList.getFreeFragmentMemory();
@@ -73,9 +252,6 @@ public class SimpleMemoryAllocatorJUnitTest {
       hugemc.release();
       assertEquals(round(TINY_MULTIPLE, minHuge+perObjectOverhead), ma.freeList.getFreeHugeMemory()-oldFreeHugeMemory);
       assertEquals(TOTAL_MEM/*-round(BIG_MULTIPLE, maxBig+perObjectOverhead)*/-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
-//      long oldFreeBigMemory = ma.freeList.getFreeBigMemory();
-//      bigmc.free();
-//      assertEquals(round(BIG_MULTIPLE, maxBig+perObjectOverhead), ma.freeList.getFreeBigMemory()-oldFreeBigMemory);
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       long oldFreeTinyMemory = ma.freeList.getFreeTinyMemory();
       tinymc.release();
@@ -85,17 +261,12 @@ public class SimpleMemoryAllocatorJUnitTest {
       tinymc = ma.allocate(maxTiny, null);
       assertEquals(oldFreeTinyMemory, ma.freeList.getFreeTinyMemory());
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
-//      bigmc = ma.allocate(maxBig);
-//      assertEquals(oldFreeBigMemory, ma.freeList.getFreeBigMemory());
-//      assertEquals(TOTAL_MEM-round(BIG_MULTIPLE, maxBig+perObjectOverhead)-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       hugemc = ma.allocate(minHuge, null);
       assertEquals(oldFreeHugeMemory, ma.freeList.getFreeHugeMemory());
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, minHuge+perObjectOverhead)/*-round(BIG_MULTIPLE, maxBig+perObjectOverhead)*/-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       hugemc.release();
       assertEquals(round(TINY_MULTIPLE, minHuge+perObjectOverhead), ma.freeList.getFreeHugeMemory()-oldFreeHugeMemory);
       assertEquals(TOTAL_MEM/*-round(BIG_MULTIPLE, maxBig+perObjectOverhead)*/-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
-//      bigmc.free();
-//      assertEquals(round(BIG_MULTIPLE, maxBig+perObjectOverhead), ma.freeList.getFreeBigMemory()-oldFreeBigMemory);
       assertEquals(TOTAL_MEM-round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.getFreeMemory());
       tinymc.release();
       assertEquals(round(TINY_MULTIPLE, maxTiny+perObjectOverhead), ma.freeList.getFreeTinyMemory()-oldFreeTinyMemory);
@@ -108,9 +279,6 @@ public class SimpleMemoryAllocatorJUnitTest {
       freeSlab = ma.freeList.getFreeFragmentMemory();
       tinymc.release();
       assertEquals(round(TINY_MULTIPLE, maxTiny+perObjectOverhead)+(round(TINY_MULTIPLE, 1+perObjectOverhead)*BATCH_SIZE), ma.freeList.getFreeTinyMemory()-oldFreeTinyMemory);
-//      bigmc = ma.allocate(MIN_BIG_SIZE);
-//      assertEquals(MIN_BIG_SIZE+perObjectOverhead, bigmc.getSize());
-//      assertEquals(freeSlab-((MIN_BIG_SIZE+perObjectOverhead)*BATCH_SIZE), ma.freeList.getFreeFragmentMemory());
       
       hugemc = ma.allocate(minHuge+1, null);
       assertEquals(round(TINY_MULTIPLE, minHuge+1+perObjectOverhead), hugemc.getSize());
@@ -129,13 +297,6 @@ public class SimpleMemoryAllocatorJUnitTest {
       assertEquals(round(TINY_MULTIPLE, minHuge+perObjectOverhead)*BATCH_SIZE, ma.freeList.getFreeHugeMemory());
       // now that we do compaction the following allocate works.
       hugemc = ma.allocate(minHuge + HUGE_MULTIPLE + HUGE_MULTIPLE-1, null);
-
-      //      assertEquals(minHuge+minHuge+1, ma.freeList.getFreeHugeMemory());
-//      hugemc.free();
-//      assertEquals(minHuge+minHuge+1+minHuge + HUGE_MULTIPLE + HUGE_MULTIPLE-1, ma.freeList.getFreeHugeMemory());
-//      hugemc = ma.allocate(minHuge + HUGE_MULTIPLE);
-//      assertEquals(minHuge + HUGE_MULTIPLE + HUGE_MULTIPLE-1, hugemc.getSize());
-//      assertEquals(minHuge+minHuge+1, ma.freeList.getFreeHugeMemory());
     } finally {
       SimpleMemoryAllocatorImpl.freeOffHeapMemory();
     }
@@ -165,6 +326,144 @@ public class SimpleMemoryAllocatorJUnitTest {
   }
   
   @Test
+  public void testDebugLog() {
+    SimpleMemoryAllocatorImpl.debugLog("test debug log", false);
+    SimpleMemoryAllocatorImpl.debugLog("test debug log", true);
+  }
+  @Test
+  public void testGetLostChunks() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024*1024);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new UnsafeMemoryChunk[]{slab});
+      assertEquals(Collections.emptyList(), ma.getLostChunks());
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+  @Test
+  public void testFindSlab() {
+    final int SLAB_SIZE = 1024*1024;
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(SLAB_SIZE);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new UnsafeMemoryChunk[]{slab});
+      assertEquals(0, ma.findSlab(slab.getMemoryAddress()));
+      assertEquals(0, ma.findSlab(slab.getMemoryAddress()+SLAB_SIZE-1));
+      try {
+        ma.findSlab(slab.getMemoryAddress()-1);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+      }
+      try {
+        ma.findSlab(slab.getMemoryAddress()+SLAB_SIZE);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+      }
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+  @Test
+  public void testValidateAddressAndSize() {
+    final int SLAB_SIZE = 1024*1024;
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(SLAB_SIZE);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new UnsafeMemoryChunk[]{slab});
+      try {
+        SimpleMemoryAllocatorImpl.validateAddress(0L);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+        assertEquals("Unexpected exception message: " + expected.getMessage(), true, expected.getMessage().contains("addr was smaller than expected"));
+      }
+      try {
+        SimpleMemoryAllocatorImpl.validateAddress(1L);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+        assertEquals("Unexpected exception message: " + expected.getMessage(), true, expected.getMessage().contains("Valid addresses must be in one of the following ranges:"));
+      }
+      SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(slab.getMemoryAddress(), SLAB_SIZE, false);
+      SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(slab.getMemoryAddress(), SLAB_SIZE, true);
+      SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(slab.getMemoryAddress(), -1, true);
+      try {
+        SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(slab.getMemoryAddress()-1, SLAB_SIZE, true);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+        assertEquals("Unexpected exception message: " + expected.getMessage(), true, expected.getMessage().equals(" address 0x" + Long.toString(slab.getMemoryAddress()-1, 16) + " does not address the original slab memory"));
+      }
+      try {
+        SimpleMemoryAllocatorImpl.validateAddressAndSizeWithinSlab(slab.getMemoryAddress(), SLAB_SIZE+1, true);
+        fail("expected IllegalStateException");
+      } catch (IllegalStateException expected) {
+        assertEquals("Unexpected exception message: " + expected.getMessage(), true, expected.getMessage().equals(" address 0x" + Long.toString(slab.getMemoryAddress()+SLAB_SIZE, 16) + " does not address the original slab memory"));
+      }
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+  @Test
+  public void testMemoryInspection() {
+    final int SLAB_SIZE = 1024*1024;
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(SLAB_SIZE);
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), new UnsafeMemoryChunk[]{slab});
+      MemoryInspector inspector = ma.getMemoryInspector();
+      assertNotNull(inspector);
+      assertEquals(null, inspector.getFirstBlock());
+      assertEquals(Collections.emptyList(), ma.getInspectionSnapshot());
+      assertEquals(Collections.emptyList(), ma.getAllocatedBlocks());
+      assertEquals(null, ma.getBlockAfter(null));
+      inspector.createInspectionSnapshot();
+      // call this twice for code coverage
+      inspector.createInspectionSnapshot();
+      try {
+        assertEquals(ma.getAllBlocks(), ma.getInspectionSnapshot());
+        MemoryBlock firstBlock = inspector.getFirstBlock();
+        assertNotNull(firstBlock);
+        assertEquals(1024*1024, 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());
+        assertEquals(null, ma.getBlockAfter(firstBlock));
+      } finally {
+        inspector.clearInspectionSnapshot();
+      }
+    } finally {
+      SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+    }
+  }
+
+  @Test
+  public void testClose() {
+    UnsafeMemoryChunk slab = new UnsafeMemoryChunk(1024*1024);
+    boolean freeSlab = true;
+    UnsafeMemoryChunk[] slabs = new UnsafeMemoryChunk[]{slab};
+    try {
+      SimpleMemoryAllocatorImpl ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), slabs);
+      ma.close();
+      ma.close();
+      System.setProperty(SimpleMemoryAllocatorImpl.FREE_OFF_HEAP_MEMORY_PROPERTY, "true");
+      try {
+        ma = SimpleMemoryAllocatorImpl.create(new NullOutOfOffHeapMemoryListener(), new NullOffHeapMemoryStats(), slabs);
+        ma.close();
+        freeSlab = false;
+        ma.close();
+      } finally {
+        System.clearProperty(SimpleMemoryAllocatorImpl.FREE_OFF_HEAP_MEMORY_PROPERTY);
+      }
+    } finally {
+      if (freeSlab) {
+        SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+      }
+    }
+    
+  }
+  
+  @Test
   public void testCompaction() {
     final int perObjectOverhead = com.gemstone.gemfire.internal.offheap.Chunk.OFF_HEAP_HEADER_SIZE;
     final int BIG_ALLOC_SIZE = 150000;
@@ -306,8 +605,18 @@ public class SimpleMemoryAllocatorJUnitTest {
       smc = ma.allocate(SMALL_ALLOC_SIZE-perObjectOverhead, null);
       assertEquals(true, this.memoryUsageEventReceived);
       
+      MemoryUsageListener unaddedListener = new MemoryUsageListener() {
+        @Override
+        public void updateMemoryUsed(final long bytesUsed) {
+          throw new IllegalStateException("Should never be called");
+        }
+      };
+      ma.removeMemoryUsageListener(unaddedListener);
+      
       ma.removeMemoryUsageListener(listener);
       
+      ma.removeMemoryUsageListener(unaddedListener);
+
       this.expectedMemoryUsage = SMALL_ALLOC_SIZE * 2;
       this.memoryUsageEventReceived = false;
       smc = ma.allocate(SMALL_ALLOC_SIZE-perObjectOverhead, null);


Mime
View raw message