150 lines
5.0 KiB
C++
150 lines
5.0 KiB
C++
// 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 "exec/pl_task_root.h"
|
|
|
|
namespace doris {
|
|
|
|
ExchangeNode::ExchangeNode(
|
|
ObjectPool* pool,
|
|
const TPlanNode& tnode,
|
|
const DescriptorTbl& descs) :
|
|
ExecNode(pool, tnode, descs),
|
|
_num_senders(0),
|
|
_stream_recvr(NULL),
|
|
_next_row_idx(0) {
|
|
}
|
|
|
|
ExchangeNode::~ExchangeNode() {
|
|
}
|
|
|
|
Status ExchangeNode::init(const TPlanNode& tnode, RuntimeState* state) {
|
|
return ExecNode::init(tnode, state);
|
|
}
|
|
|
|
Status ExchangeNode::prepare(RuntimeState* state) {
|
|
RETURN_IF_ERROR(ExecNode::prepare(state));
|
|
|
|
_convert_row_batch_timer = ADD_TIMER(runtime_profile(), "ConvertRowBatchTime");
|
|
|
|
// TODO: figure out appropriate buffer size
|
|
DCHECK_GT(_num_senders, 0);
|
|
_stream_recvr = state->create_recvr(_row_descriptor, _id, _num_senders,
|
|
config::exchg_node_buffer_size_bytes, runtime_profile());
|
|
return Status::OK();
|
|
}
|
|
|
|
Status ExchangeNode::open(RuntimeState* state) {
|
|
SCOPED_TIMER(_runtime_profile->total_time_counter());
|
|
RETURN_IF_ERROR(ExecNode::open(state));
|
|
return Status::OK();
|
|
}
|
|
|
|
Status ExchangeNode::close(RuntimeState* state) {
|
|
if (is_closed()) {
|
|
return Status::OK();
|
|
}
|
|
return ExecNode::close(state);
|
|
}
|
|
|
|
Status ExchangeNode::get_next(RuntimeState* state, RowBatch* output_batch, bool* eos) {
|
|
RETURN_IF_ERROR(exec_debug_action(TExecNodePhase::GETNEXT));
|
|
SCOPED_TIMER(_runtime_profile->total_time_counter());
|
|
|
|
if (reached_limit()) {
|
|
*eos = true;
|
|
return Status::OK();
|
|
}
|
|
|
|
ExprContext* const* ctxs = &_conjunct_ctxs[0];
|
|
int num_ctxs = _conjunct_ctxs.size();
|
|
|
|
while (true) {
|
|
{
|
|
SCOPED_TIMER(_convert_row_batch_timer);
|
|
|
|
// copy rows until we hit the limit/capacity or until we exhaust _input_batch
|
|
while (!reached_limit() && !output_batch->is_full()
|
|
&& _input_batch.get() != NULL && _next_row_idx < _input_batch->capacity()) {
|
|
TupleRow* src = _input_batch->get_row(_next_row_idx);
|
|
|
|
if (ExecNode::eval_conjuncts(ctxs, num_ctxs, src)) {
|
|
int j = output_batch->add_row();
|
|
TupleRow* dest = output_batch->get_row(j);
|
|
// if the input row is shorter than the output row, make sure not to leave
|
|
// uninitialized Tuple* around
|
|
output_batch->clear_row(dest);
|
|
// this works as expected if rows from input_batch form a prefix of
|
|
// rows in output_batch
|
|
_input_batch->copy_row(src, dest);
|
|
output_batch->commit_last_row();
|
|
++_num_rows_returned;
|
|
}
|
|
|
|
++_next_row_idx;
|
|
}
|
|
|
|
COUNTER_SET(_rows_returned_counter, _num_rows_returned);
|
|
|
|
if (reached_limit()) {
|
|
*eos = true;
|
|
return Status::OK();
|
|
}
|
|
|
|
if (output_batch->is_full()) {
|
|
*eos = false;
|
|
return Status::OK();
|
|
}
|
|
}
|
|
|
|
// we need more rows
|
|
if (_input_batch.get() != NULL) {
|
|
_input_batch->transfer_resource_ownership(output_batch);
|
|
}
|
|
|
|
bool is_cancelled = true;
|
|
_input_batch.reset(_stream_recvr->get_batch(&is_cancelled));
|
|
VLOG_FILE << "exch: has batch=" << (_input_batch.get() == NULL ? "false" : "true")
|
|
<< " #rows=" << (_input_batch.get() != NULL ? _input_batch->num_rows() : 0)
|
|
<< " is_cancelled=" << (is_cancelled ? "true" : "false")
|
|
<< " instance_id=" << state->fragment_instance_id();
|
|
|
|
if (is_cancelled) {
|
|
return Status::Cancelled("Cancelled");
|
|
}
|
|
|
|
*eos = (_input_batch.get() == NULL);
|
|
|
|
if (*eos) {
|
|
return Status::OK();
|
|
}
|
|
|
|
_next_row_idx = 0;
|
|
DCHECK(_input_batch->row_desc().is_prefix_of(output_batch->row_desc()));
|
|
}
|
|
}
|
|
|
|
void ExchangeNode::debug_string(int indentation_level, std::stringstream* out) const {
|
|
*out << string(indentation_level * 2, ' ');
|
|
*out << "ExchangeNode(#senders=" << _num_senders;
|
|
ExecNode::debug_string(indentation_level, out);
|
|
*out << ")";
|
|
}
|
|
|
|
}
|
|
|