blob: 696a34b73a3319f35905026569e4d42b9de94437 [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.ignite.internal.binary;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjectBuilder;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryType;
import org.apache.ignite.internal.binary.builder.BinaryObjectBuilderImpl;
import org.apache.ignite.internal.binary.streams.BinaryOffheapInputStream;
import org.apache.ignite.internal.processors.cache.CacheObject;
import org.apache.ignite.internal.processors.cache.CacheObjectContext;
import org.apache.ignite.internal.util.GridUnsafe;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.util.Date;
import java.util.UUID;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Binary object implementation over offheap memory
*/
public class BinaryObjectOffheapImpl extends BinaryObjectExImpl implements Externalizable, CacheObject {
/** */
private static final long serialVersionUID = 0L;
/** */
private static final Unsafe UNSAFE = GridUnsafe.unsafe();
/** */
private final BinaryContext ctx;
/** */
private final long ptr;
/** */
private final int start;
/** */
private final int size;
/**
* For {@link Externalizable} (not supported).
*/
public BinaryObjectOffheapImpl() {
throw new UnsupportedOperationException();
}
/**
* @param ctx Context.
* @param ptr Memory address.
* @param start Object start.
* @param size Memory size.
*/
public BinaryObjectOffheapImpl(BinaryContext ctx, long ptr, int start, int size) {
this.ctx = ctx;
this.ptr = ptr;
this.start = start;
this.size = size;
}
/**
* @return Heap-based copy.
*/
public BinaryObject heapCopy() {
return new BinaryObjectImpl(ctx, U.copyMemory(ptr, size), start);
}
/** {@inheritDoc} */
@Override public int typeId() {
return UNSAFE.getInt(ptr + start + GridBinaryMarshaller.TYPE_ID_POS);
}
/** {@inheritDoc} */
@Override public int length() {
return UNSAFE.getInt(ptr + start + GridBinaryMarshaller.TOTAL_LEN_POS);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return UNSAFE.getInt(ptr + start + GridBinaryMarshaller.HASH_CODE_POS);
}
/** {@inheritDoc} */
@Override protected int schemaId() {
return UNSAFE.getInt(ptr + start + GridBinaryMarshaller.SCHEMA_ID_POS);
}
/** {@inheritDoc} */
@Override protected BinarySchema createSchema() {
return reader(null).getOrCreateSchema();
}
/** {@inheritDoc} */
@Override public int start() {
return start;
}
/** {@inheritDoc} */
@Override public byte[] array() {
return null;
}
/** {@inheritDoc} */
@Override public long offheapAddress() {
return ptr;
}
/** {@inheritDoc} */
@Override protected boolean hasArray() {
return false;
}
/** {@inheritDoc} */
@Nullable @Override public BinaryType type() throws BinaryObjectException {
if (ctx == null)
throw new BinaryObjectException("BinaryContext is not set for the object.");
return ctx.metadata(typeId());
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override public <F> F field(String fieldName) throws BinaryObjectException {
return (F) reader(null).unmarshalField(fieldName);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override public <F> F field(int fieldId) throws BinaryObjectException {
return (F) reader(null).unmarshalField(fieldId);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override protected <F> F fieldByOrder(int order) {
Object val;
// Calculate field position.
int schemaOffset = BinaryPrimitives.readInt(ptr, start + GridBinaryMarshaller.SCHEMA_OR_RAW_OFF_POS);
short flags = BinaryPrimitives.readShort(ptr, start + GridBinaryMarshaller.FLAGS_POS);
int fieldIdLen = BinaryUtils.isCompactFooter(flags) ? 0 : BinaryUtils.FIELD_ID_LEN;
int fieldOffsetLen = BinaryUtils.fieldOffsetLength(flags);
int fieldOffsetPos = start + schemaOffset + order * (fieldIdLen + fieldOffsetLen) + fieldIdLen;
int fieldPos;
if (fieldOffsetLen == BinaryUtils.OFFSET_1)
fieldPos = start + ((int)BinaryPrimitives.readByte(ptr, fieldOffsetPos) & 0xFF);
else if (fieldOffsetLen == BinaryUtils.OFFSET_2)
fieldPos = start + ((int)BinaryPrimitives.readShort(ptr, fieldOffsetPos) & 0xFFFF);
else
fieldPos = start + BinaryPrimitives.readInt(ptr, fieldOffsetPos);
// Read header and try performing fast lookup for well-known types (the most common types go first).
byte hdr = BinaryPrimitives.readByte(ptr, fieldPos);
switch (hdr) {
case GridBinaryMarshaller.INT:
val = BinaryPrimitives.readInt(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.LONG:
val = BinaryPrimitives.readLong(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.BOOLEAN:
val = BinaryPrimitives.readBoolean(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.SHORT:
val = BinaryPrimitives.readShort(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.BYTE:
val = BinaryPrimitives.readByte(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.CHAR:
val = BinaryPrimitives.readChar(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.FLOAT:
val = BinaryPrimitives.readFloat(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.DOUBLE:
val = BinaryPrimitives.readDouble(ptr, fieldPos + 1);
break;
case GridBinaryMarshaller.STRING: {
int dataLen = BinaryPrimitives.readInt(ptr, fieldPos + 1);
byte[] data = BinaryPrimitives.readByteArray(ptr, fieldPos + 5, dataLen);
val = new String(data, UTF_8);
break;
}
case GridBinaryMarshaller.DATE: {
long time = BinaryPrimitives.readLong(ptr, fieldPos + 1);
val = new Date(time);
break;
}
case GridBinaryMarshaller.TIMESTAMP: {
long time = BinaryPrimitives.readLong(ptr, fieldPos + 1);
int nanos = BinaryPrimitives.readInt(ptr, fieldPos + 1 + 8);
Timestamp ts = new Timestamp(time);
ts.setNanos(ts.getNanos() + nanos);
val = ts;
break;
}
case GridBinaryMarshaller.UUID: {
long most = BinaryPrimitives.readLong(ptr, fieldPos + 1);
long least = BinaryPrimitives.readLong(ptr, fieldPos + 1 + 8);
val = new UUID(most, least);
break;
}
case GridBinaryMarshaller.DECIMAL: {
int scale = BinaryPrimitives.readInt(ptr, fieldPos + 1);
int dataLen = BinaryPrimitives.readInt(ptr, fieldPos + 5);
byte[] data = BinaryPrimitives.readByteArray(ptr, fieldPos + 9, dataLen);
BigInteger intVal = new BigInteger(data);
if (scale < 0) {
scale &= 0x7FFFFFFF;
intVal = intVal.negate();
}
val = new BigDecimal(intVal, scale);
break;
}
case GridBinaryMarshaller.NULL:
val = null;
break;
default:
BinaryOffheapInputStream stream = new BinaryOffheapInputStream(ptr, size, false);
stream.position(fieldPos);
val = BinaryUtils.unmarshal(stream, ctx, null);
break;
}
return (F)val;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override protected <F> F field(BinaryReaderHandles rCtx, String fieldName) {
return (F)reader(rCtx).unmarshalField(fieldName);
}
/** {@inheritDoc} */
@Override public boolean hasField(String fieldName) {
return reader(null).findFieldByName(fieldName);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override public <T> T deserialize() throws BinaryObjectException {
return (T)deserializeValue();
}
/** {@inheritDoc} */
@SuppressWarnings("CloneDoesntCallSuperClone")
@Override public BinaryObject clone() throws CloneNotSupportedException {
return heapCopy();
}
/** {@inheritDoc} */
@Override public BinaryObjectBuilder toBuilder() throws BinaryObjectException {
return BinaryObjectBuilderImpl.wrap(heapCopy());
}
/** {@inheritDoc} */
@Override public byte cacheObjectType() {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public boolean isPlatformType() {
return false;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override public <T> T value(CacheObjectContext ctx, boolean cpy) {
return (T)deserializeValue();
}
/** {@inheritDoc} */
@Override public byte[] valueBytes(CacheObjectContext ctx) throws IgniteCheckedException {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public CacheObject prepareForCache(CacheObjectContext ctx) {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public byte directType() {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public byte fieldsCount() {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
throw new UnsupportedOperationException(); // To make sure it is not marshalled.
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
throw new UnsupportedOperationException(); // To make sure it is not marshalled.
}
/**
* @return Deserialized value.
*/
private Object deserializeValue() {
return reader(null).deserialize();
}
/**
* Create new reader for this object.
*
* @param rCtx Reader context.
* @return Reader.
*/
private BinaryReaderExImpl reader(@Nullable BinaryReaderHandles rCtx) {
BinaryOffheapInputStream stream = new BinaryOffheapInputStream(ptr, size, false);
stream.position(start);
return new BinaryReaderExImpl(ctx,
stream,
ctx.configuration().getClassLoader(),
rCtx);
}
}