blob: 255bff20abf395b9069fc504f5c2078083527e02 [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 java.nio.ByteBuffer;
import java.util.Arrays;
import org.apache.geode.cache.Region;
import org.apache.geode.internal.cache.BytesAndBitsForCompactor;
import org.apache.geode.internal.cache.EntryBits;
import org.apache.geode.internal.cache.EntryEventImpl;
import org.apache.geode.internal.cache.RegionEntry;
import org.apache.geode.internal.cache.RegionEntryContext;
/**
* Used to represent stored objects that can be stored in the address field. The RegionEntry for an
* off-heap region uses a primitive long to store the off-heap address of the entry's value. If the
* value can be encoded as a long (i.e. its serialized representation will fit in the 8 bytes of a
* long without looking like an actual off-heap address) then these tiny values on an off-heap
* regions are actually stored on the heap in the primitive long field. When these values are
* "objectified" they will be an instance of this class. Instances of this class have a very short
* lifetime.
*/
public class TinyStoredObject extends AbstractStoredObject {
private final long address;
public TinyStoredObject(long addr) {
this.address = addr;
}
@Override
public long getAddress() {
return this.address;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof TinyStoredObject) {
return getAddress() == ((TinyStoredObject) o).getAddress();
}
return false;
}
@Override
public int hashCode() {
long value = getAddress();
return (int) (value ^ (value >>> 32));
}
@Override
public int getSizeInBytes() {
return 0;
}
public byte[] getDecompressedBytes(RegionEntryContext r) {
if (isCompressed()) {
byte[] bytes = OffHeapRegionEntryHelper.decodeAddressToRawBytes(getAddress());
long time = r.getCachePerfStats().startDecompression();
bytes = r.getCompressor().decompress(bytes);
r.getCachePerfStats().endDecompression(time);
return bytes;
}
return getRawBytes();
}
/**
* If we contain a byte[] return it. Otherwise return the serialize bytes in us in a byte array.
*/
public byte[] getRawBytes() {
return OffHeapRegionEntryHelper.decodeUncompressedAddressToBytes(getAddress());
}
@Override
public byte[] getSerializedValue() {
byte[] value = getRawBytes();
if (!isSerialized()) {
value = EntryEventImpl.serialize(value);
}
return value;
}
@Override
public Object getDeserializedValue(Region r, RegionEntry re) {
return OffHeapRegionEntryHelper.decodeAddressToObject(this.address);
}
@Override
public void fillSerializedValue(BytesAndBitsForCompactor wrapper, byte userBits) {
byte[] value;
if (isSerialized()) {
value = getSerializedValue();
userBits = EntryBits.setSerialized(userBits, true);
} else {
value = (byte[]) getDeserializedForReading();
}
wrapper.setData(value, userBits, value.length, true);
}
@Override
public int getValueSizeInBytes() {
return 0;
}
@Override
public boolean isSerialized() {
return OffHeapRegionEntryHelper.isSerialized(this.address);
}
@Override
public boolean isCompressed() {
return OffHeapRegionEntryHelper.isCompressed(this.address);
}
@Override
public void release() {
// nothing needed
}
@Override
public boolean retain() {
return true;
}
@Override
public int getRefCount() {
return -1;
}
@Override
public int getSize() {
return Long.BYTES;
}
@Override
public int getDataSize() {
return OffHeapRegionEntryHelper.decodeAddressToDataSize(this.address);
}
@Override
public byte readDataByte(int offset) {
return getRawBytes()[offset];
}
@Override
public void writeDataByte(int offset, byte value) {
throw new UnsupportedOperationException(
"ObjectStoredAsAddress does not support modifying the data bytes");
}
@Override
public void readDataBytes(int offset, byte[] bytes) {
readDataBytes(offset, bytes, 0, bytes.length);
}
@Override
public void writeDataBytes(int offset, byte[] bytes) {
writeDataBytes(offset, bytes, 0, bytes.length);
}
@Override
public void readDataBytes(int offset, byte[] bytes, int bytesOffset, int size) {
byte[] src = getRawBytes();
int dstIdx = bytesOffset;
for (int i = offset; i < offset + size; i++) {
bytes[dstIdx++] = src[i];
}
}
@Override
public void writeDataBytes(int offset, byte[] bytes, int bytesOffset, int size) {
throw new UnsupportedOperationException(
"ObjectStoredAsAddress does not support modifying the data bytes");
}
@Override
public ByteBuffer createDirectByteBuffer() {
return null;
}
@Override
public boolean hasRefCount() {
return false;
}
@Override
public boolean checkDataEquals(StoredObject so) {
return equals(so);
}
@Override
public boolean checkDataEquals(byte[] serializedObj) {
byte[] myBytes = getSerializedValue();
return Arrays.equals(myBytes, serializedObj);
}
@Override
public long getAddressForReadingData(int offset, int size) {
throw new UnsupportedOperationException(
"ObjectStoredAsAddress does not support reading at an address");
}
@Override
public StoredObject slice(int offset, int limit) {
throw new UnsupportedOperationException("ObjectStoredAsAddress does not support slice");
}
}