blob: 3c219ffae856dbe2f2e4668b50cfb70f34b78b1d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.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.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 org.apache.geode.compression.Compressor;
import org.apache.geode.internal.cache.CachePerfStats;
import org.apache.geode.internal.cache.DiskId;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.RegionEntryContext;
import org.apache.geode.internal.cache.Token;
import org.apache.geode.internal.cache.VMCachedDeserializable;
import org.apache.geode.internal.cache.entries.DiskEntry;
import org.apache.geode.internal.cache.entries.OffHeapRegionEntry;
import org.apache.geode.internal.cache.entries.VersionedStatsDiskRegionEntryOffHeap;
import org.apache.geode.internal.serialization.DSCODE;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("*.UnitTest")
@PrepareForTest({OffHeapStoredObject.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);
ma = MemoryAllocatorImpl.create(ooohml, stats, 1, OffHeapStorage.MIN_SLAB_SIZE * 1,
OffHeapStorage.MIN_SLAB_SIZE);
}
@After
public void tearDown() {
MemoryAllocatorImpl.freeOffHeapMemory();
}
private OffHeapStoredObject createChunk(Object value) {
byte[] v = EntryEventImpl.serialize(value);
boolean isSerialized = true;
boolean isCompressed = false;
OffHeapStoredObject chunk =
(OffHeapStoredObject) ma.allocateAndInitialize(v, isSerialized, isCompressed);
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.toByte();
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 decodeUncompressedAddressToBytesShouldReturnActualBytes() {
long encodedAddress = 549755813697L;
Integer value = Integer.MAX_VALUE;
byte[] actual = OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
byte[] expectedValue = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(value).array();
assertThat(actual).isEqualTo(expectedValue);
}
@Test
public void decodeUncompressedAddressToBytesShouldDecodeLongIfItsSerializedAndIfItsNotTooBig() {
Long value = 0L;
long encodedAddress = 123L;
byte[] actual = OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
byte[] expectedValue = EntryEventImpl.serialize(value);
assertThat(actual).isEqualTo(expectedValue);
}
@Test(expected = AssertionError.class)
public void decodeUncompressedAddressToBytesWithCompressedAddressShouldThrowException() {
long encodedAddress = 549755813703L;
OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(encodedAddress);
}
@Test
public void decodeCompressedDataAsAddressToRawBytes() {
long encodedAddress = 549755813703L;
byte[] expected = new byte[] {127, -1, -1, -1};
byte[] bytes = OffHeapRegionEntryHelper.decodeAddressToRawBytes(encodedAddress);
assertThat(bytes).isEqualTo(expected);
}
@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() {
OffHeapStoredObject value = createChunk(Long.MAX_VALUE);
assertThat(OffHeapRegionEntryHelper.isOffHeap(value.getAddress())).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
OffHeapStoredObject newValue = createChunk(Long.MAX_VALUE);
// mock region entry methods required for test
when(re.getAddress()).thenReturn(oldAddress);
when(re.setAddress(oldAddress, newValue.getAddress())).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.getAddress());
// resetting the spy in-order to re-use
reset(re);
// testing when the newValue is DataAsAddress
TinyStoredObject newAddress1 = new TinyStoredObject(2L);
// mock region entry methods required for test
when(re.getAddress()).thenReturn(oldAddress);
when(re.setAddress(oldAddress, newAddress1.getAddress())).thenReturn(Boolean.TRUE);
OffHeapRegionEntryHelper.setValue(re, newAddress1);
// verify oldAddress is replaced with newAddress
verify(re, times(1)).setAddress(oldAddress, newAddress1.getAddress());
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);
OffHeapStoredObject oldValue = createChunk(Long.MAX_VALUE);
OffHeapStoredObject newValue = createChunk(Long.MAX_VALUE - 1);
// mock Chunk static methods - in-order to verify that release is called
PowerMockito.spy(OffHeapStoredObject.class);
PowerMockito.doNothing().when(OffHeapStoredObject.class);
OffHeapStoredObject.release(oldValue.getAddress());
// mock region entry methods required for test
when(re.getAddress()).thenReturn(oldValue.getAddress());
when(re.setAddress(oldValue.getAddress(), newValue.getAddress())).thenReturn(Boolean.TRUE);
// invoke the method under test
OffHeapRegionEntryHelper.setValue(re, newValue);
// verify oldAddress is changed to newAddress
verify(re, times(1)).setAddress(oldValue.getAddress(), newValue.getAddress());
// verify oldAddress is released
PowerMockito.verifyStatic(OffHeapStoredObject.class);
OffHeapStoredObject.release(oldValue.getAddress());
}
@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();
TinyStoredObject newAddress =
new TinyStoredObject(OffHeapRegionEntryHelper.encodeDataAsAddress(newData, false, false));
// mock Chunk static methods - in-order to verify that release is never called
PowerMockito.spy(OffHeapStoredObject.class);
PowerMockito.doNothing().when(OffHeapStoredObject.class);
OffHeapStoredObject.release(oldAddress);
// mock region entry methods required for test
when(re.getAddress()).thenReturn(oldAddress);
when(re.setAddress(oldAddress, newAddress.getAddress())).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.getAddress());
// verify that release is never called as the old address is not on offheap
PowerMockito.verifyStatic(OffHeapStoredObject.class, never());
OffHeapStoredObject.release(oldAddress);
}
@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(OffHeapStoredObject.class);
PowerMockito.doNothing().when(OffHeapStoredObject.class);
OffHeapStoredObject.release(oldAddress);
// 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(OffHeapStoredObject.class, never());
OffHeapStoredObject.release(oldAddress);
}
@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);
OffHeapStoredObject chunk = createChunk(Long.MAX_VALUE);
// mock region entry methods required for test
when(re.getAddress()).thenReturn(chunk.getAddress());
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() {
OffHeapStoredObject expected = createChunk(Long.MAX_VALUE);
Object actual = OffHeapRegionEntryHelper.addressToObject(expected.getAddress(), false, null);
assertThat(actual).isInstanceOf(OffHeapStoredObject.class);
assertThat(actual).isEqualTo(expected);
}
@Test
public void addressToObjectShouldReturnCachedDeserializableFromChunkIfAskedToDecompress() {
byte[] data = EntryEventImpl.serialize(Long.MAX_VALUE);
boolean isSerialized = true;
boolean isCompressed = true;
OffHeapStoredObject chunk =
(OffHeapStoredObject) ma.allocateAndInitialize(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(chunk.getAddress(), 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;
OffHeapStoredObject chunk =
(OffHeapStoredObject) ma.allocateAndInitialize(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(chunk.getAddress(), 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);
TinyStoredObject expected = new TinyStoredObject(address);
Object actual = OffHeapRegionEntryHelper.addressToObject(address, false, null);
assertThat(actual).isInstanceOf(TinyStoredObject.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);
TinyStoredObject daa = new TinyStoredObject(address);
int actualLength = OffHeapRegionEntryHelper.getSerializedLength(daa);
assertThat(actualLength).isEqualTo(data.length);
}
@Test
public void getSerializedLengthFromDataAsAddressShouldReturnZeroForNonEncodedAddress() {
TinyStoredObject nonEncodedAddress = new TinyStoredObject(100000L);
int actualLength = OffHeapRegionEntryHelper.getSerializedLength(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.class);
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.class);
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();
}
}