/* * 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.collect.Lists; import com.google.common.primitives.*; import org.apache.tajo.common.TajoDataTypes; import org.apache.tajo.datum.IntervalDatum; import org.apache.tajo.datum.ProtobufDatum; import org.apache.tajo.exception.TajoRuntimeException; import org.apache.tajo.exception.UnsupportedException; import org.apache.tajo.exception.ValueOutOfRangeException; import org.apache.tajo.storage.Tuple; import org.apache.tajo.tuple.RowBlockReader; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class OffHeapRowBlockUtils { private static TupleConverter tupleConverter; static { tupleConverter = new TupleConverter(); } public static List<Tuple> sort(MemoryRowBlock rowBlock, Comparator<Tuple> comparator) { List<Tuple> tupleList = Lists.newArrayList(); ZeroCopyTuple zcTuple; if(rowBlock.getMemory().hasAddress()) { zcTuple = new UnSafeTuple(); } else { zcTuple = new HeapTuple(); } RowBlockReader reader = rowBlock.getReader(); while(reader.next(zcTuple)) { tupleList.add(zcTuple); if(rowBlock.getMemory().hasAddress()) { zcTuple = new UnSafeTuple(); } else { zcTuple = new HeapTuple(); } } Collections.sort(tupleList, comparator); return tupleList; } public static List<UnSafeTuple> sort(UnSafeTupleList list, Comparator<UnSafeTuple> comparator) { Collections.sort(list, comparator); return list; } public static Tuple[] sortToArray(MemoryRowBlock rowBlock, Comparator<Tuple> comparator) { Tuple[] tuples = new Tuple[rowBlock.rows()]; ZeroCopyTuple zcTuple; if(rowBlock.getMemory().hasAddress()) { zcTuple = new UnSafeTuple(); } else { zcTuple = new HeapTuple(); } RowBlockReader reader = rowBlock.getReader(); for (int i = 0; i < rowBlock.rows() && reader.next(zcTuple); i++) { tuples[i] = zcTuple; if(rowBlock.getMemory().hasAddress()) { zcTuple = new UnSafeTuple(); } else { zcTuple = new HeapTuple(); } } Arrays.sort(tuples, comparator); return tuples; } public static final int compareColumn(UnSafeTuple tuple1, UnSafeTuple tuple2, int index, TajoDataTypes.Type type, boolean ascending, boolean nullFirst) { final boolean n1 = tuple1.isBlankOrNull(index); final boolean n2 = tuple2.isBlankOrNull(index); if (n1 && n2) { return 0; } if (n1 ^ n2) { return nullFirst ? (n1 ? -1 : 1) : (n1 ? 1 : -1); } int compare; switch (type) { case BOOLEAN: compare = Booleans.compare(tuple1.getBool(index), tuple2.getBool(index)); break; case BIT: compare = tuple1.getByte(index) - tuple2.getByte(index); break; case INT1: case INT2: compare = Shorts.compare(tuple1.getInt2(index), tuple2.getInt2(index)); break; case DATE: case INT4: compare = Ints.compare(tuple1.getInt4(index), tuple2.getInt4(index)); break; case TIME: case TIMESTAMP: case INT8: compare = Longs.compare(tuple1.getInt8(index), tuple2.getInt8(index)); break; case FLOAT4: compare = Floats.compare(tuple1.getFloat4(index), tuple2.getFloat4(index)); break; case FLOAT8: compare = Doubles.compare(tuple1.getFloat8(index), tuple2.getFloat8(index)); break; case CHAR: case TEXT: case BLOB: compare = UnSafeTupleBytesComparator.compare(tuple1.getFieldAddr(index), tuple2.getFieldAddr(index)); break; default: throw new TajoRuntimeException( new UnsupportedException("unknown data type '" + type.name() + "'")); } return ascending ? compare : -compare; } /** * This class is tuple converter to the RowBlock */ public static class TupleConverter { public void convert(Tuple tuple, RowWriter writer) { try { writer.startRow(); for (int i = 0; i < writer.dataTypes().length; i++) { writeField(i, tuple, writer); } } catch (ValueOutOfRangeException e) { writer.cancelRow(); throw e; } writer.endRow(); } protected void writeField(int colIdx, Tuple tuple, RowWriter writer) { if (tuple.isBlankOrNull(colIdx)) { writer.skipField(); } else { switch (writer.dataTypes()[colIdx].getType()) { case BOOLEAN: writer.putBool(tuple.getBool(colIdx)); break; case BIT: writer.putByte(tuple.getByte(colIdx)); break; case INT1: case INT2: writer.putInt2(tuple.getInt2(colIdx)); break; case INT4: writer.putInt4(tuple.getInt4(colIdx)); break; case DATE: writer.putDate(tuple.getInt4(colIdx)); break; case INT8: writer.putInt8(tuple.getInt8(colIdx)); break; case TIMESTAMP: writer.putTimestamp(tuple.getInt8(colIdx)); break; case TIME: writer.putTime(tuple.getInt8(colIdx)); break; case FLOAT4: writer.putFloat4(tuple.getFloat4(colIdx)); break; case FLOAT8: writer.putFloat8(tuple.getFloat8(colIdx)); break; case CHAR: case TEXT: writer.putText(tuple.getBytes(colIdx)); break; case BLOB: writer.putBlob(tuple.getBytes(colIdx)); break; case INTERVAL: writer.putInterval((IntervalDatum) tuple.getInterval(colIdx)); break; case PROTOBUF: writer.putProtoDatum((ProtobufDatum) tuple.getProtobufDatum(colIdx)); break; case NULL_TYPE: writer.skipField(); break; default: throw new TajoRuntimeException( new UnsupportedException("unknown data type '" + writer.dataTypes()[colIdx].getType().name() + "'")); } } } } public static void convert(Tuple tuple, RowWriter writer) { tupleConverter.convert(tuple, writer); } }