You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by sb...@apache.org on 2016/02/02 00:32:56 UTC
incubator-geode git commit: GEODE-646: OffHeapRegionEntryHelper needs
unit test
Repository: incubator-geode
Updated Branches:
refs/heads/develop 4dde1af52 -> 6d6f62606
GEODE-646: OffHeapRegionEntryHelper needs unit test
Added unit tests to cover OffHeapRegionEntryHelper.
closes #83
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/6d6f6260
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/6d6f6260
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/6d6f6260
Branch: refs/heads/develop
Commit: 6d6f626069d2f64f98a8a31c5b0500de15f32bc2
Parents: 4dde1af
Author: Sai Boorlagadda <sb...@pivotal.io>
Authored: Wed Jan 27 16:21:53 2016 -0800
Committer: Swapnil Bawaskar <sb...@pivotal.io>
Committed: Mon Feb 1 15:29:07 2016 -0800
----------------------------------------------------------------------
.../gemfire/internal/offheap/DataAsAddress.java | 7 +-
.../offheap/OffHeapRegionEntryHelper.java | 44 +-
.../OffHeapRegionEntryHelperJUnitTest.java | 870 +++++++++++++++++++
3 files changed, 892 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6d6f6260/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 dff1d8f..96957ac 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
@@ -19,6 +19,7 @@ package com.gemstone.gemfire.internal.offheap;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.internal.cache.BytesAndBitsForCompactor;
import com.gemstone.gemfire.internal.cache.EntryBits;
+import com.gemstone.gemfire.internal.cache.EntryEventImpl;
import com.gemstone.gemfire.internal.cache.RegionEntry;
import com.gemstone.gemfire.internal.cache.RegionEntryContext;
@@ -78,7 +79,11 @@ public class DataAsAddress extends AbstractStoredObject {
@Override
public byte[] getSerializedValue() {
- return OffHeapRegionEntryHelper.decodeAddressToBytes(this.address);
+ byte[] value = OffHeapRegionEntryHelper.decodeAddressToBytes(this.address, true, false);
+ if (!isSerialized()) {
+ value = EntryEventImpl.serialize(value);
+ }
+ return value;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6d6f6260/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelper.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelper.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelper.java
index 1731b01..84e4218 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelper.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelper.java
@@ -39,15 +39,15 @@ import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
*/
public class OffHeapRegionEntryHelper {
- private static final long NULL_ADDRESS = 0L<<1;
- private static final long INVALID_ADDRESS = 1L<<1;
- private static final long LOCAL_INVALID_ADDRESS = 2L<<1;
- private static final long DESTROYED_ADDRESS = 3L<<1;
- public static final long REMOVED_PHASE1_ADDRESS = 4L<<1;
- private static final long REMOVED_PHASE2_ADDRESS = 5L<<1;
- private static final long END_OF_STREAM_ADDRESS = 6L<<1;
- private static final long NOT_AVAILABLE_ADDRESS = 7L<<1;
- private static final long TOMBSTONE_ADDRESS = 8L<<1;
+ protected static final long NULL_ADDRESS = 0L<<1;
+ protected static final long INVALID_ADDRESS = 1L<<1;
+ protected static final long LOCAL_INVALID_ADDRESS = 2L<<1;
+ protected static final long DESTROYED_ADDRESS = 3L<<1;
+ protected static final long REMOVED_PHASE1_ADDRESS = 4L<<1;
+ protected static final long REMOVED_PHASE2_ADDRESS = 5L<<1;
+ protected static final long END_OF_STREAM_ADDRESS = 6L<<1;
+ protected static final long NOT_AVAILABLE_ADDRESS = 7L<<1;
+ protected static final long TOMBSTONE_ADDRESS = 8L<<1;
public static final int MAX_LENGTH_FOR_DATA_AS_ADDRESS = 8;
/* private static final ChunkFactory chunkFactory ;
static {
@@ -88,12 +88,6 @@ public class OffHeapRegionEntryHelper {
throw new IllegalStateException("Can not convert " + v + " to an off heap address.");
}
- //TODO:Asif:Check if this is a valid equality conditions
- public static boolean isAddressInvalidOrRemoved(long address) {
- return address == INVALID_ADDRESS || address == LOCAL_INVALID_ADDRESS
- || address == REMOVED_PHASE2_ADDRESS || address == NULL_ADDRESS;
- }
-
/**
* This method may release the object stored at ohAddress if the result
* needs to be decompressed and the decompress parameter is true.
@@ -164,7 +158,10 @@ public class OffHeapRegionEntryHelper {
}
}
-
+ /*
+ * This method is optimized for cases where if the caller wants to convert address to a Token
+ * compared to addressToObject which would deserialize the value.
+ */
private static Token addressToToken(long ohAddress) {
if (isOffHeap(ohAddress) || (ohAddress & ENCODED_BIT) != 0) {
return Token.NOT_A_TOKEN;
@@ -218,11 +215,11 @@ public class OffHeapRegionEntryHelper {
/**
* This bit is set to indicate that the encoded data is serialized.
*/
- private static long SERIALIZED_BIT = 2L;
+ static long SERIALIZED_BIT = 2L;
/**
* This bit is set to indicate that the encoded data is compressed.
*/
- private static long COMPRESSED_BIT = 4L;
+ static long COMPRESSED_BIT = 4L;
/**
* This bit is set to indicate that the encoded data is a long whose value fits in 7 bytes.
*/
@@ -288,15 +285,6 @@ public class OffHeapRegionEntryHelper {
}
}
- static byte[] decodeAddressToBytes(long addr) {
- byte[] result = decodeAddressToBytes(addr, true, false);
- boolean isSerialized = (addr & SERIALIZED_BIT) != 0;
- if (!isSerialized) {
- result = EntryEventImpl.serialize(result);
- }
- return result;
- }
-
static byte[] decodeAddressToBytes(long addr, boolean decompress, boolean compressedOk) {
assert (addr & ENCODED_BIT) != 0;
boolean isCompressed = (addr & COMPRESSED_BIT) != 0;
@@ -359,7 +347,7 @@ public class OffHeapRegionEntryHelper {
public static boolean isOffHeap(long addr) {
if ((addr & ENCODED_BIT) != 0) return false;
if (addr < 0) return true;
- addr >>= 1; // shift left 1 to convert to array index;
+ addr >>= 1; // shift right 1 to convert to array index;
return addr >= addrToObj.length;
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6d6f6260/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelperJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelperJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelperJUnitTest.java
new file mode 100644
index 0000000..b800977
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OffHeapRegionEntryHelperJUnitTest.java
@@ -0,0 +1,870 @@
+/*
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.nio.ByteBuffer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.compression.Compressor;
+import com.gemstone.gemfire.internal.DSCODE;
+import com.gemstone.gemfire.internal.cache.CachePerfStats;
+import com.gemstone.gemfire.internal.cache.DiskEntry;
+import com.gemstone.gemfire.internal.cache.DiskId;
+import com.gemstone.gemfire.internal.cache.EntryEventImpl;
+import com.gemstone.gemfire.internal.cache.OffHeapRegionEntry;
+import com.gemstone.gemfire.internal.cache.RegionEntryContext;
+import com.gemstone.gemfire.internal.cache.Token;
+import com.gemstone.gemfire.internal.cache.VMCachedDeserializable;
+import com.gemstone.gemfire.internal.cache.VersionedStatsDiskRegionEntryOffHeap;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+@RunWith(PowerMockRunner.class)
+@PowerMockIgnore("*.UnitTest")
+@PrepareForTest({ Chunk.class, OffHeapRegionEntryHelper.class })
+public class OffHeapRegionEntryHelperJUnitTest {
+
+ private static final Long VALUE_IS_NOT_ENCODABLE = 0L;
+
+ private MemoryAllocator ma;
+
+ @Before
+ public void setUp() {
+ OutOfOffHeapMemoryListener ooohml = mock(OutOfOffHeapMemoryListener.class);
+ OffHeapMemoryStats stats = mock(OffHeapMemoryStats.class);
+ LogWriter lw = mock(LogWriter.class);
+
+ ma = SimpleMemoryAllocatorImpl.create(ooohml, stats, lw, 1, OffHeapStorage.MIN_SLAB_SIZE * 1, OffHeapStorage.MIN_SLAB_SIZE);
+ }
+
+ @After
+ public void tearDown() {
+ SimpleMemoryAllocatorImpl.freeOffHeapMemory();
+ }
+
+ private GemFireChunk createChunk(Object value) {
+ byte[] v = EntryEventImpl.serialize(value);
+
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ GemFireChunk chunk = (GemFireChunk) ma.allocateAndInitialize(v, isSerialized, isCompressed, GemFireChunk.TYPE);
+
+ return chunk;
+ }
+
+ @Test
+ public void encodeDataAsAddressShouldReturnZeroIfValueIsGreaterThanSevenBytes() {
+ Long value = Long.MAX_VALUE;
+
+ byte[] valueInBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(value).array();
+ boolean isSerialized = false;
+ boolean isCompressed = false;
+
+ assertThat(valueInBytes.length).isGreaterThanOrEqualTo(OffHeapRegionEntryHelper.MAX_LENGTH_FOR_DATA_AS_ADDRESS);
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
+ }
+
+ @Test
+ public void encodeDataAsAddressShouldEncodeLongIfItsSerializedAndIfItsNotTooBig() {
+ Long value = 0L;
+ long expectedEncodedAddress = 123L;
+
+ byte[] valueInBytes = EntryEventImpl.serialize(value);
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(expectedEncodedAddress);
+ assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
+ }
+
+ @Test
+ public void encodeDataAsAddressShouldReturnZeroIfValueIsLongAndItIsSerializedAndBig() {
+ Long value = Long.MAX_VALUE;
+
+ byte[] valueInBytes = EntryEventImpl.serialize(value);
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
+ }
+
+ @Test
+ public void encodeDataAsAddressShouldReturnZeroIfValueIsLargerThanEightBytesAndNotLong() {
+ byte[] someValue = new byte[8];
+ someValue[0] = DSCODE.CLASS;
+
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(someValue, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(VALUE_IS_NOT_ENCODABLE);
+ }
+
+ @Test
+ public void encodeDataAsAddressShouldReturnValidAddressIfValueIsLesserThanSevenBytes() {
+ long expectedAddress = 549755813697L;
+
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] valueInBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
+ boolean isSerialized = false;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(expectedAddress);
+ assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
+ }
+
+ @Test
+ public void encodeDataAsAssressShouldSetSerialziedBitIfSerizliaed() {
+ long expectedAddress = 63221918596947L;
+
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] valueInBytes = EntryEventImpl.serialize(value);
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(expectedAddress).isEqualTo(encodedAddress);
+ assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
+ }
+
+ @Test
+ public void encodeDataAsAssressShouldSetSerialziedBitIfCompressed() {
+ long expectedAddress = 549755813701L;
+
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] valueInBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
+ boolean isSerialized = false;
+ boolean isCompressed = true;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(encodedAddress).isEqualTo(expectedAddress);
+ assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
+ }
+
+ @Test
+ public void encodeDataAsAssressShouldSetBothSerialziedAndCompressedBitsIfSerializedAndCompressed() {
+ long expectedAddress = 63221918596951L;
+
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] valueInBytes = EntryEventImpl.serialize(value);
+ boolean isSerialized = true;
+ boolean isCompressed = true;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(valueInBytes, isSerialized, isCompressed);
+
+ assertThat(expectedAddress).isEqualTo(encodedAddress);
+ assertSerializedAndCompressedBits(encodedAddress, isSerialized, isCompressed);
+ }
+
+ private void assertSerializedAndCompressedBits(long encodedAddress, boolean shouldSerializedBitBeSet, boolean shouldCompressedBitBeSet) {
+ boolean isSerializedBitSet = (encodedAddress & OffHeapRegionEntryHelper.SERIALIZED_BIT) == OffHeapRegionEntryHelper.SERIALIZED_BIT ? true : false;
+ boolean isCompressedBitSet = (encodedAddress & OffHeapRegionEntryHelper.COMPRESSED_BIT) == OffHeapRegionEntryHelper.COMPRESSED_BIT ? true : false;
+
+ assertThat(isSerializedBitSet).isEqualTo(shouldSerializedBitBeSet);
+ assertThat(isCompressedBitSet).isEqualTo(shouldCompressedBitBeSet);
+ }
+
+ @Test
+ public void decodeAddressToBytesShouldReturnActualBytes() {
+ long encodedAddress = 549755813697L;
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] actual = OffHeapRegionEntryHelper.decodeAddressToBytes(encodedAddress, false, false);
+ byte[] expectedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
+
+ assertThat(actual).isEqualTo(expectedValue);
+ }
+
+ @Test
+ public void decodeDataAsAddressShouldDecodeLongIfItsSerializedAndIfItsNotTooBig() {
+ Long value = 0L;
+ long encodedAddress = 123L;
+
+ byte[] actual = OffHeapRegionEntryHelper.decodeAddressToBytes(encodedAddress, false, false);
+ byte[] expectedValue = EntryEventImpl.serialize(value);
+
+ assertThat(actual).isEqualTo(expectedValue);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void decodeDataAsAddressShouldThrowExceptionIfDataIsCompressedAndItsNotOkToBeCompressed() {
+ long encodedAddress = 549755813703L;
+ OffHeapRegionEntryHelper.decodeAddressToBytes(encodedAddress, true, false);
+ }
+
+ @Test
+ public void encodedAddressShouldBeDecodableEvenIfValueIsSerialized() {
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] serializedValue = EntryEventImpl.serialize(value);
+ boolean isSerialized = true;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(serializedValue, isSerialized, isCompressed);
+
+ Integer actualValue = (Integer) OffHeapRegionEntryHelper.decodeAddressToObject(encodedAddress);
+
+ assertThat(actualValue).isEqualTo(value);
+ }
+
+ @Test
+ public void encodedAddressShouldBeDecodableEvenIfValueIsUnserialized() {
+ Integer value = Integer.MAX_VALUE;
+
+ byte[] unSerializedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
+ boolean isSerialized = false;
+ boolean isCompressed = false;
+
+ long encodedAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(unSerializedValue, isSerialized, isCompressed);
+
+ byte[] actualValue = (byte[]) OffHeapRegionEntryHelper.decodeAddressToObject(encodedAddress);
+
+ assertThat(actualValue).isEqualTo(unSerializedValue);
+ }
+
+ @Test
+ public void isSerializedShouldReturnTrueIfSerialized() {
+ assertThat(OffHeapRegionEntryHelper.isSerialized(1000010L)).isTrue();
+ }
+
+ @Test
+ public void isSerializedShouldReturnFalseIfNotSerialized() {
+ assertThat(OffHeapRegionEntryHelper.isSerialized(1000000L)).isFalse();
+ }
+
+ @Test
+ public void isCompressedShouldReturnTrueIfCompressed() {
+ assertThat(OffHeapRegionEntryHelper.isCompressed(1000100L)).isTrue();
+ }
+
+ @Test
+ public void isCompressedShouldReturnFalseIfNotCompressed() {
+ assertThat(OffHeapRegionEntryHelper.isCompressed(1000000L)).isFalse();
+ }
+
+ @Test
+ public void isOffHeapShouldReturnTrueIfAddressIsOnOffHeap() {
+ Chunk value = createChunk(Long.MAX_VALUE);
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(value.getMemoryAddress())).isTrue();
+ }
+
+ @Test
+ public void isOffHeapShouldReturnFalseIfAddressIsAnEncodedAddress() {
+ byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt((Integer) Integer.MAX_VALUE).array();
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(address)).isFalse();
+ }
+
+ @Test
+ public void isOffHeapShouldReturnFalseForAnyTokenAddress() {
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.NULL_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.INVALID_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.DESTROYED_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS)).isFalse();
+ assertThat(OffHeapRegionEntryHelper.isOffHeap(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS)).isFalse();
+ }
+
+ @Test
+ public void setValueShouldChangeTheRegionEntryAddressToNewAddress() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ // some old address
+ long oldAddress = 1L;
+
+ // testing when the newValue is a chunk
+ Chunk newValue = createChunk(Long.MAX_VALUE);
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, newValue.getMemoryAddress())).thenReturn(Boolean.TRUE);
+
+ // invoke the method under test
+ OffHeapRegionEntryHelper.setValue(re, newValue);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, newValue.getMemoryAddress());
+ // resetting the spy in-order to re-use
+ reset(re);
+
+ // testing when the newValue is DataAsAddress
+ DataAsAddress newAddress1 = new DataAsAddress(2L);
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, newAddress1.getEncodedAddress())).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, newAddress1);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, newAddress1.getEncodedAddress());
+ reset(re);
+
+ // Testing when newValue is Token Objects
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.NULL_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, null);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.NULL_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.INVALID_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.INVALID);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.INVALID_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.LOCAL_INVALID);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.DESTROYED_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.DESTROYED);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.DESTROYED_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE1);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.END_OF_STREAM);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.NOT_AVAILABLE);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS);
+ reset(re);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS)).thenReturn(Boolean.TRUE);
+ OffHeapRegionEntryHelper.setValue(re, Token.TOMBSTONE);
+
+ // verify oldAddress is replaced with newAddress
+ verify(re, times(1)).setAddress(oldAddress, OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS);
+ reset(re);
+ }
+
+ @Test
+ public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndReleaseOldValueIfItsOnOffHeap() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ Chunk oldValue = createChunk(Long.MAX_VALUE);
+ Chunk newValue = createChunk(Long.MAX_VALUE - 1);
+
+ // mock Chunk static methods - in-order to verify that release is called
+ PowerMockito.spy(Chunk.class);
+ PowerMockito.doNothing().when(Chunk.class);
+ Chunk.release(oldValue.getMemoryAddress(), true);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldValue.getMemoryAddress());
+ when(re.setAddress(oldValue.getMemoryAddress(), newValue.getMemoryAddress())).thenReturn(Boolean.TRUE);
+
+ // invoke the method under test
+ OffHeapRegionEntryHelper.setValue(re, newValue);
+
+ // verify oldAddress is changed to newAddress
+ verify(re, times(1)).setAddress(oldValue.getMemoryAddress(), newValue.getMemoryAddress());
+
+ // verify oldAddress is released
+ PowerMockito.verifyStatic();
+ Chunk.release(oldValue.getMemoryAddress(), true);
+ }
+
+ @Test
+ public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsAnEncodedAddress() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ byte[] oldData = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt((Integer) Integer.MAX_VALUE).array();
+ long oldAddress = OffHeapRegionEntryHelper.encodeDataAsAddress(oldData, false, false);
+
+ byte[] newData = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt((Integer) Integer.MAX_VALUE - 1).array();
+ DataAsAddress newAddress = new DataAsAddress(OffHeapRegionEntryHelper.encodeDataAsAddress(newData, false, false));
+
+ // mock Chunk static methods - in-order to verify that release is never called
+ PowerMockito.spy(Chunk.class);
+ PowerMockito.doNothing().when(Chunk.class);
+ Chunk.release(oldAddress, true);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, newAddress.getEncodedAddress())).thenReturn(Boolean.TRUE);
+
+ // invoke the method under test
+ OffHeapRegionEntryHelper.setValue(re, newAddress);
+
+ // verify oldAddress is changed to newAddress
+ verify(re, times(1)).setAddress(oldAddress, newAddress.getEncodedAddress());
+
+ // verify that release is never called as the old address is not on offheap
+ PowerMockito.verifyStatic(never());
+ Chunk.release(oldAddress, true);
+ }
+
+ @Test
+ public void setValueShouldChangeTheRegionEntryAddressToNewAddressAndDoesNothingIfOldAddressIsATokenAddress() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ long oldAddress = OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS;
+
+ Token newValue = Token.REMOVED_PHASE2;
+ long newAddress = OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS;
+
+ // mock Chunk static methods - in-order to verify that release is never called
+ PowerMockito.spy(Chunk.class);
+ PowerMockito.doNothing().when(Chunk.class);
+ Chunk.release(oldAddress, true);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(oldAddress);
+ when(re.setAddress(oldAddress, newAddress)).thenReturn(Boolean.TRUE);
+
+ // invoke the method under test
+ OffHeapRegionEntryHelper.setValue(re, newValue);
+
+ // verify oldAddress is changed to newAddress
+ verify(re, times(1)).setAddress(oldAddress, newAddress);
+
+ // verify that release is never called as the old address is not on offheap
+ PowerMockito.verifyStatic(never());
+ Chunk.release(oldAddress, true);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void setValueShouldThrowIllegalExceptionIfNewValueCannotBeConvertedToAddress() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(1L);
+
+ // invoke the method under test with some object other than Chunk/DataAsAddress/Token
+ OffHeapRegionEntryHelper.setValue(re, new Object());
+ }
+
+ @Test
+ public void getValueAsTokenShouldReturnNotATokenIfValueIsOnOffHeap() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ Chunk chunk = createChunk(Long.MAX_VALUE);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(chunk.getMemoryAddress());
+ Token token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.NOT_A_TOKEN);
+ }
+
+ @Test
+ public void getValueAsTokenShouldReturnNotATokenIfValueIsEncoded() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(address);
+ Token token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.NOT_A_TOKEN);
+ }
+
+ @Test
+ public void getValueAsTokenShouldReturnAValidToken() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.NULL_ADDRESS);
+ Token token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isNull();
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.INVALID_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.INVALID);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.LOCAL_INVALID);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.DESTROYED_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.DESTROYED);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.REMOVED_PHASE1);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.REMOVED_PHASE2);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.END_OF_STREAM);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.NOT_AVAILABLE);
+
+ // mock region entry methods required for test
+ when(re.getAddress()).thenReturn(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS);
+ token = OffHeapRegionEntryHelper.getValueAsToken(re);
+
+ assertThat(token).isEqualTo(Token.TOMBSTONE);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnValueFromChunk() {
+ Chunk expected = createChunk(Long.MAX_VALUE);
+ Object actual = OffHeapRegionEntryHelper.addressToObject(expected.getMemoryAddress(), false, null);
+
+ assertThat(actual).isInstanceOf(Chunk.class);
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnCachedDeserializableFromChunkIfAskedToDecompress() {
+ byte[] data = EntryEventImpl.serialize(Long.MAX_VALUE);
+ boolean isSerialized = true;
+ boolean isCompressed = true;
+
+ GemFireChunk chunk = (GemFireChunk) ma.allocateAndInitialize(data, isSerialized, isCompressed, GemFireChunk.TYPE);
+
+ // create the mock context
+ RegionEntryContext regionContext = mock(RegionEntryContext.class);
+ CachePerfStats cacheStats = mock(CachePerfStats.class);
+ Compressor compressor = mock(Compressor.class);
+
+ long startTime = 10000L;
+
+ // mock required things
+ when(regionContext.getCompressor()).thenReturn(compressor);
+ when(compressor.decompress(data)).thenReturn(data);
+ when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
+ when(cacheStats.startDecompression()).thenReturn(startTime);
+
+ Object actual = OffHeapRegionEntryHelper.addressToObject(chunk.getMemoryAddress(), true, regionContext);
+
+ assertThat(actual).isInstanceOf(VMCachedDeserializable.class);
+
+ Long actualValue = (Long) ((VMCachedDeserializable) actual).getDeserializedForReading();
+ assertThat(actualValue).isEqualTo(Long.MAX_VALUE);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnDecompressedValueFromChunkIfAskedToDecompress() {
+ byte[] data = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(Long.MAX_VALUE).array();
+ boolean isSerialized = false;
+ boolean isCompressed = true;
+
+ GemFireChunk chunk = (GemFireChunk) ma.allocateAndInitialize(data, isSerialized, isCompressed, GemFireChunk.TYPE);
+
+ // create the mock context
+ RegionEntryContext regionContext = mock(RegionEntryContext.class);
+ CachePerfStats cacheStats = mock(CachePerfStats.class);
+ Compressor compressor = mock(Compressor.class);
+
+ long startTime = 10000L;
+
+ // mock required things
+ when(regionContext.getCompressor()).thenReturn(compressor);
+ when(compressor.decompress(data)).thenReturn(data);
+ when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
+ when(cacheStats.startDecompression()).thenReturn(startTime);
+
+ Object actual = OffHeapRegionEntryHelper.addressToObject(chunk.getMemoryAddress(), true, regionContext);
+
+ assertThat(actual).isInstanceOf(byte[].class);
+ assertThat(actual).isEqualTo(data);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnValueFromDataAsAddress() {
+ byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, false, false);
+
+ DataAsAddress expected = new DataAsAddress(address);
+ Object actual = OffHeapRegionEntryHelper.addressToObject(address, false, null);
+
+ assertThat(actual).isInstanceOf(DataAsAddress.class);
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnCachedDeserializableFromSerializedDataAsAddressIfAskedToDecompress() {
+ byte[] data = EntryEventImpl.serialize(Integer.MAX_VALUE);
+ boolean isSerialized = true;
+ boolean isCompressed = true;
+
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);
+
+ // create the mock context
+ RegionEntryContext regionContext = mock(RegionEntryContext.class);
+ CachePerfStats cacheStats = mock(CachePerfStats.class);
+ Compressor compressor = mock(Compressor.class);
+
+ long startTime = 10000L;
+
+ // mock required things
+ when(regionContext.getCompressor()).thenReturn(compressor);
+ when(compressor.decompress(data)).thenReturn(data);
+ when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
+ when(cacheStats.startDecompression()).thenReturn(startTime);
+
+ Object actual = OffHeapRegionEntryHelper.addressToObject(address, true, regionContext);
+
+ assertThat(actual).isInstanceOf(VMCachedDeserializable.class);
+
+ Integer actualValue = (Integer) ((VMCachedDeserializable) actual).getDeserializedForReading();
+ assertThat(actualValue).isEqualTo(Integer.MAX_VALUE);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnDecompressedValueFromDataAsAddressIfAskedToDecompress() {
+ byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
+ boolean isSerialized = false;
+ boolean isCompressed = true;
+
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);
+
+ // create the mock context
+ RegionEntryContext regionContext = mock(RegionEntryContext.class);
+ CachePerfStats cacheStats = mock(CachePerfStats.class);
+ Compressor compressor = mock(Compressor.class);
+
+ long startTime = 10000L;
+
+ // mock required things
+ when(regionContext.getCompressor()).thenReturn(compressor);
+ when(compressor.decompress(data)).thenReturn(data);
+ when(regionContext.getCachePerfStats()).thenReturn(cacheStats);
+ when(cacheStats.startDecompression()).thenReturn(startTime);
+
+ Object actual = OffHeapRegionEntryHelper.addressToObject(address, true, regionContext);
+
+ assertThat(actual).isInstanceOf(byte[].class);
+ assertThat(actual).isEqualTo(data);
+ }
+
+ @Test
+ public void addressToObjectShouldReturnToken() {
+ Token token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.NULL_ADDRESS, false, null);
+ assertThat(token).isNull();
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.INVALID_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.INVALID);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.LOCAL_INVALID_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.LOCAL_INVALID);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.DESTROYED_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.DESTROYED);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.REMOVED_PHASE1_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.REMOVED_PHASE1);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.REMOVED_PHASE2);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.END_OF_STREAM_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.END_OF_STREAM);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.NOT_AVAILABLE_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.NOT_AVAILABLE);
+
+ token = (Token) OffHeapRegionEntryHelper.addressToObject(OffHeapRegionEntryHelper.TOMBSTONE_ADDRESS, false, null);
+ assertThat(token).isEqualTo(Token.TOMBSTONE);
+ }
+
+ @Test
+ public void getSerializedLengthFromDataAsAddressShouldReturnValidLength() {
+ byte[] data = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(Integer.MAX_VALUE).array();
+ boolean isSerialized = false;
+ boolean isCompressed = true;
+
+ long address = OffHeapRegionEntryHelper.encodeDataAsAddress(data, isSerialized, isCompressed);
+ DataAsAddress daa = new DataAsAddress(address);
+
+ int actualLength = OffHeapRegionEntryHelper.getSerializedLengthFromDataAsAddress(daa);
+
+ assertThat(actualLength).isEqualTo(data.length);
+ }
+
+ @Test
+ public void getSerializedLengthFromDataAsAddressShouldReturnZeroForNonEncodedAddress() {
+ DataAsAddress nonEncodedAddress = new DataAsAddress(100000L);
+ int actualLength = OffHeapRegionEntryHelper.getSerializedLengthFromDataAsAddress(nonEncodedAddress);
+ assertThat(actualLength).isZero();
+ }
+
+ @Test
+ public void releaseEntryShouldSetValueToRemovePhase2() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(OffHeapRegionEntry.class);
+ when(re.getAddress()).thenReturn(1L);
+ when(re.setAddress(1L, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS)).thenReturn(Boolean.TRUE);
+
+ // mock required methods
+ PowerMockito.spy(OffHeapRegionEntryHelper.class);
+ PowerMockito.doNothing().when(OffHeapRegionEntryHelper.class);
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
+
+ OffHeapRegionEntryHelper.releaseEntry(re);
+
+ PowerMockito.verifyStatic();
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
+ }
+
+ @Test
+ public void releaseEntryShouldSetValueToRemovePhase2AndSetsAsyncToFalseForDiskEntry() {
+ // mock region entry
+ OffHeapRegionEntry re = mock(VersionedStatsDiskRegionEntryOffHeap.class);
+ when(re.getAddress()).thenReturn(1L);
+ when(re.setAddress(1L, OffHeapRegionEntryHelper.REMOVED_PHASE2_ADDRESS)).thenReturn(Boolean.TRUE);
+
+ DiskId spy = Mockito.spy(DiskId.class);
+ when(((DiskEntry) re).getDiskId()).thenReturn(spy);
+ when(spy.isPendingAsync()).thenReturn(Boolean.TRUE);
+
+ // mock required methods
+ PowerMockito.spy(OffHeapRegionEntryHelper.class);
+ PowerMockito.doNothing().when(OffHeapRegionEntryHelper.class);
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
+
+ OffHeapRegionEntryHelper.releaseEntry(re);
+
+ verify(spy, times(1)).setPendingAsync(Boolean.FALSE);
+
+ PowerMockito.verifyStatic();
+ OffHeapRegionEntryHelper.setValue(re, Token.REMOVED_PHASE2);
+ }
+
+ @Test
+ public void doWithOffHeapClearShouldSetTheThreadLocalToTrue() {
+ // verify that threadlocal is not set
+ assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isFalse();
+
+ OffHeapRegionEntryHelper.doWithOffHeapClear(new Runnable() {
+ @Override
+ public void run() {
+ // verify that threadlocal is set when offheap is cleared
+ assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isTrue();
+ }
+ });
+
+ // verify that threadlocal is reset after offheap is cleared
+ assertThat(OffHeapRegionEntryHelper.doesClearNeedToCheckForOffHeap()).isFalse();
+ }
+}