// 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. #include "runtime/buffered_tuple_stream.h" #include "runtime/descriptors.h" #include "runtime/tuple_row.h" namespace doris { bool BufferedTupleStream::deep_copy(TupleRow* row, uint8_t** dst) { if (_nullable_tuple) { return deep_copy_internal(row, dst); } else { return deep_copy_internal(row, dst); } } // TODO: this really needs codegen template bool BufferedTupleStream::deep_copy_internal(TupleRow* row, uint8_t** dst) { if (UNLIKELY(_write_block == NULL)) { return false; } DCHECK_GE(_null_indicators_write_block, 0); const uint64_t tuples_per_row = _desc.tuple_descriptors().size(); if (UNLIKELY((_write_block->bytes_remaining() < _fixed_tuple_row_size) || (HasNullableTuple && (_write_tuple_idx + tuples_per_row > _null_indicators_write_block * 8)))) { return false; } // Allocate the maximum possible buffer for the fixed portion of the tuple. uint8_t* tuple_buf = _write_block->allocate(_fixed_tuple_row_size); if (dst != NULL) { *dst = tuple_buf; } // Total bytes allocated in _write_block for this row. Saved so we can roll back // if this row doesn't fit. int bytes_allocated = _fixed_tuple_row_size; // Copy the not NULL fixed len tuples. For the NULL tuples just update the NULL tuple // indicator. if (HasNullableTuple) { DCHECK_GT(_null_indicators_write_block, 0); uint8_t* null_word = NULL; uint32_t null_pos = 0; // Calculate how much space it should return. int to_return = 0; for (int i = 0; i < tuples_per_row; ++i) { null_word = _write_block->buffer() + (_write_tuple_idx >> 3); // / 8 null_pos = _write_tuple_idx & 7; ++_write_tuple_idx; const int tuple_size = _desc.tuple_descriptors()[i]->byte_size(); Tuple* t = row->get_tuple(i); const uint8_t mask = 1 << (7 - null_pos); if (t != NULL) { *null_word &= ~mask; memcpy(tuple_buf, t, tuple_size); tuple_buf += tuple_size; } else { *null_word |= mask; to_return += tuple_size; } } DCHECK_LE(_write_tuple_idx - 1, _null_indicators_write_block * 8); _write_block->return_allocation(to_return); bytes_allocated -= to_return; } else { // If we know that there are no nullable tuples no need to set the nullability flags. DCHECK_EQ(_null_indicators_write_block, 0); for (int i = 0; i < tuples_per_row; ++i) { const int tuple_size = _desc.tuple_descriptors()[i]->byte_size(); Tuple* t = row->get_tuple(i); // TODO: Once IMPALA-1306 (Avoid passing empty tuples of non-materialized slots) // is delivered, the check below should become DCHECK_NOTNULL(t). DCHECK(t != NULL || tuple_size == 0); memcpy(tuple_buf, t, tuple_size); tuple_buf += tuple_size; } } // Copy string slots. Note: we do not need to convert the string ptrs to offsets // on the write path, only on the read. The tuple data is immediately followed // by the string data so only the len information is necessary. for (int i = 0; i < _string_slots.size(); ++i) { Tuple* tuple = row->get_tuple(_string_slots[i].first); if (HasNullableTuple && tuple == NULL) { continue; } for (int j = 0; j < _string_slots[i].second.size(); ++j) { const SlotDescriptor* slot_desc = _string_slots[i].second[j]; if (tuple->is_null(slot_desc->null_indicator_offset())) { continue; } StringValue* sv = tuple->get_string_slot(slot_desc->tuple_offset()); if (LIKELY(sv->len > 0)) { if (UNLIKELY(_write_block->bytes_remaining() < sv->len)) { _write_block->return_allocation(bytes_allocated); return false; } uint8_t* buf = _write_block->allocate(sv->len); bytes_allocated += sv->len; memcpy(buf, sv->ptr, sv->len); } } } _write_block->add_row(); ++_num_rows; return true; } }