You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2015/12/02 20:38:38 UTC
incubator-geode git commit: GEODE-607: improve
SimpleMemoryAllocatorImpl unit test coverage
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 <ds...@pivotal.io>
Authored: Wed Nov 25 11:43:15 2015 -0800
Committer: Darrel Schneider <ds...@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);