blob: 4e9ecb4034d004b15a8da396a91e231f34d55da4 [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.tajo.tuple.memory;
import com.google.common.base.Preconditions;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import io.netty.util.internal.PlatformDependent;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.*;
import org.apache.tajo.exception.TajoRuntimeException;
import org.apache.tajo.exception.UnsupportedException;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
import org.apache.tajo.util.SizeOf;
import org.apache.tajo.util.StringUtils;
import org.apache.tajo.util.UnsafeUtil;
import org.apache.tajo.util.datetime.TimeMeta;
import sun.misc.Unsafe;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import static org.apache.tajo.common.TajoDataTypes.DataType;
public class UnSafeTuple extends ZeroCopyTuple {
private static final Unsafe UNSAFE = UnsafeUtil.unsafe;
private MemoryBlock memoryBlock;
private DataType[] types;
@Override
public void set(MemoryBlock memoryBlock, int relativePos, DataType[] types) {
Preconditions.checkArgument(memoryBlock.hasAddress());
this.memoryBlock = memoryBlock;
this.types = types;
super.set(relativePos);
}
public void set(UnSafeTuple tuple) {
this.memoryBlock = tuple.memoryBlock;
this.types = tuple.types;
super.set(tuple.getRelativePos());
}
@Override
public int size() {
return types.length;
}
@Override
public int getLength() {
return PlatformDependent.getInt(address());
}
@Override
public TajoDataTypes.Type type(int fieldId) {
return types[fieldId].getType();
}
@Override
public int size(int fieldId) {
return PlatformDependent.getInt(getFieldAddr(fieldId));
}
public void writeTo(ByteBuffer bb) {
if (bb.remaining() < getLength()) {
throw new IndexOutOfBoundsException("remaining length: " + bb.remaining()
+ ", tuple length: " + getLength());
}
if (getLength() > 0) {
if (bb.isDirect()) {
PlatformDependent.copyMemory(address(), PlatformDependent.directBufferAddress(bb) + bb.position(), getLength());
bb.position(bb.position() + getLength());
} else {
PlatformDependent.copyMemory(address(), bb.array(), bb.arrayOffset() + bb.position(), getLength());
bb.position(bb.position() + getLength());
}
}
}
public long address() {
return memoryBlock.address() + getRelativePos();
}
public HeapTuple toHeapTuple() {
HeapTuple heapTuple = new HeapTuple();
byte [] bytes = new byte[getLength()];
PlatformDependent.copyMemory(address(), bytes, 0, getLength());
heapTuple.set(bytes, types);
return heapTuple;
}
private int getFieldOffset(int fieldId) {
return PlatformDependent.getInt(address()+ (long)(SizeOf.SIZE_OF_INT + (fieldId * SizeOf.SIZE_OF_INT)));
}
public long getFieldAddr(int fieldId) {
int fieldOffset = getFieldOffset(fieldId);
if (fieldOffset < 0 || fieldOffset > getLength()) {
throw new RuntimeException("Invalid Access. Field : " + fieldId
+ ", Offset:" + fieldOffset + ", Record length:" + getLength());
}
return address() + fieldOffset;
}
@Override
public boolean contains(int fieldid) {
return getFieldOffset(fieldid) > MemoryRowBlock.NULL_FIELD_OFFSET;
}
@Override
public boolean isBlank(int fieldid) {
return getFieldOffset(fieldid) == MemoryRowBlock.NULL_FIELD_OFFSET;
}
@Override
public boolean isBlankOrNull(int fieldid) {
return getFieldOffset(fieldid) == MemoryRowBlock.NULL_FIELD_OFFSET;
}
@Override
public void clear() {
// nothing to do
}
@Override
public void put(int fieldId, Datum value) {
throw new TajoRuntimeException(new UnsupportedException());
}
@Override
public void insertTuple(int fieldId, Tuple tuple) {
throw new TajoRuntimeException(new UnsupportedException());
}
@Override
public void put(Datum[] values) {
throw new TajoRuntimeException(new UnsupportedException());
}
@Override
public Datum asDatum(int fieldId) {
if (isBlankOrNull(fieldId)) {
return NullDatum.get();
}
switch (types[fieldId].getType()) {
case BOOLEAN:
return DatumFactory.createBool(getBool(fieldId));
case BIT:
return DatumFactory.createBit(getByte(fieldId));
case INT1:
case INT2:
return DatumFactory.createInt2(getInt2(fieldId));
case INT4:
return DatumFactory.createInt4(getInt4(fieldId));
case INT8:
return DatumFactory.createInt8(getInt8(fieldId));
case FLOAT4:
return DatumFactory.createFloat4(getFloat4(fieldId));
case FLOAT8:
return DatumFactory.createFloat8(getFloat8(fieldId));
case CHAR:
return DatumFactory.createChar(getBytes(fieldId));
case TEXT:
return DatumFactory.createText(getBytes(fieldId));
case BLOB:
return DatumFactory.createBlob(getBytes(fieldId));
case TIMESTAMP:
return DatumFactory.createTimestamp(getInt8(fieldId));
case DATE:
return DatumFactory.createDate(getInt4(fieldId));
case TIME:
return DatumFactory.createTime(getInt8(fieldId));
case INTERVAL:
return getInterval(fieldId);
case PROTOBUF:
return getProtobufDatum(fieldId);
case NULL_TYPE:
return NullDatum.get();
default:
throw new TajoRuntimeException(new UnsupportedException("data type '" + types[fieldId] + "'"));
}
}
@Override
public void clearOffset() {
}
@Override
public void setOffset(long offset) {
}
@Override
public long getOffset() {
return 0;
}
@Override
public boolean getBool(int fieldId) {
return PlatformDependent.getByte(getFieldAddr(fieldId)) == 0x01;
}
@Override
public byte getByte(int fieldId) {
return PlatformDependent.getByte(getFieldAddr(fieldId));
}
@Override
public char getChar(int fieldId) {
return UNSAFE.getChar(getFieldAddr(fieldId));
}
@Override
public byte[] getBytes(int fieldId) {
long pos = getFieldAddr(fieldId);
int len = PlatformDependent.getInt(pos);
pos += SizeOf.SIZE_OF_INT;
byte [] bytes = new byte[len];
PlatformDependent.copyMemory(pos, bytes, 0, len);
return bytes;
}
@Override
public byte[] getTextBytes(int fieldId) {
return asDatum(fieldId).asTextBytes();
}
@Override
public short getInt2(int fieldId) {
long addr = getFieldAddr(fieldId);
return PlatformDependent.getShort(addr);
}
@Override
public int getInt4(int fieldId) {
return PlatformDependent.getInt(getFieldAddr(fieldId));
}
@Override
public long getInt8(int fieldId) {
return PlatformDependent.getLong(getFieldAddr(fieldId));
}
@Override
public float getFloat4(int fieldId) {
return Float.intBitsToFloat(PlatformDependent.getInt(getFieldAddr(fieldId)));
}
@Override
public double getFloat8(int fieldId) {
return Double.longBitsToDouble(PlatformDependent.getLong(getFieldAddr(fieldId)));
}
@Override
public String getText(int fieldId) {
return new String(getBytes(fieldId), TextDatum.DEFAULT_CHARSET);
}
@Override
public IntervalDatum getInterval(int fieldId) {
long pos = getFieldAddr(fieldId);
int months = PlatformDependent.getInt(pos);
pos += SizeOf.SIZE_OF_INT;
long millisecs = PlatformDependent.getLong(pos);
return new IntervalDatum(months, millisecs);
}
@Override
public Datum getProtobufDatum(int fieldId) {
byte [] bytes = getBytes(fieldId);
ProtobufDatumFactory factory = ProtobufDatumFactory.get(types[fieldId]);
Message.Builder builder = factory.newBuilder();
try {
builder.mergeFrom(bytes);
} catch (InvalidProtocolBufferException e) {
return NullDatum.get();
}
return new ProtobufDatum(builder.build());
}
@Override
public char[] getUnicodeChars(int fieldId) {
long pos = getFieldAddr(fieldId);
int len = PlatformDependent.getInt(pos);
pos += SizeOf.SIZE_OF_INT;
byte [] bytes = new byte[len];
PlatformDependent.copyMemory(pos, bytes, 0, len);
return StringUtils.convertBytesToChars(bytes, Charset.forName("UTF-8"));
}
@Override
public TimeMeta getTimeDate(int fieldId) {
return asDatum(fieldId).asTimeMeta();
}
@Override
public Tuple clone() throws CloneNotSupportedException {
return toHeapTuple();
}
@Override
public Datum[] getValues() {
Datum [] datums = new Datum[size()];
for (int i = 0; i < size(); i++) {
if (contains(i)) {
datums[i] = asDatum(i);
} else {
datums[i] = NullDatum.get();
}
}
return datums;
}
@Override
public int hashCode() {
return Arrays.hashCode(getValues());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Tuple) {
Tuple other = (Tuple) obj;
return Arrays.equals(getValues(), other.getValues());
}
return false;
}
@Override
public String toString() {
return VTuple.toDisplayString(getValues());
}
public void release() {
}
}