ClickHouse/dbms/src/Processors/ResizeProcessor.cpp

384 lines
9.9 KiB
C++
Raw Normal View History

#include <Processors/ResizeProcessor.h>
namespace DB
{
ResizeProcessor::Status ResizeProcessor::prepare()
{
bool is_first_output = true;
auto output_end = current_output;
2019-02-07 18:51:53 +00:00
bool all_outs_full_or_unneeded = true;
bool all_outs_finished = true;
bool is_first_input = true;
auto input_end = current_input;
bool all_inputs_finished = true;
auto is_end_input = [&]() { return !is_first_input && current_input == input_end; };
auto is_end_output = [&]() { return !is_first_output && current_output == output_end; };
auto inc_current_input = [&]()
{
is_first_input = false;
++current_input;
if (current_input == inputs.end())
current_input = inputs.begin();
};
auto inc_current_output = [&]()
{
is_first_output = false;
++current_output;
if (current_output == outputs.end())
current_output = outputs.begin();
};
2019-02-07 18:51:53 +00:00
/// Find next output where can push.
auto get_next_out = [&, this]() -> OutputPorts::iterator
{
while (!is_end_output())
{
if (!current_output->isFinished())
2019-02-07 18:51:53 +00:00
{
all_outs_finished = false;
if (current_output->canPush())
2019-02-07 18:51:53 +00:00
{
all_outs_full_or_unneeded = false;
auto res_output = current_output;
inc_current_output();
return res_output;
2019-02-07 18:51:53 +00:00
}
}
inc_current_output();
}
return outputs.end();
2019-02-07 18:51:53 +00:00
};
2019-02-07 18:51:53 +00:00
/// Find next input from where can pull.
auto get_next_input = [&, this]() -> InputPorts::iterator
{
while (!is_end_input())
{
if (!current_input->isFinished())
2019-02-07 18:51:53 +00:00
{
all_inputs_finished = false;
current_input->setNeeded();
if (current_input->hasData())
2019-02-07 18:51:53 +00:00
{
auto res_input = current_input;
inc_current_input();
return res_input;
2019-02-07 18:51:53 +00:00
}
}
inc_current_input();
}
return inputs.end();
2019-02-07 18:51:53 +00:00
};
2019-02-07 18:51:53 +00:00
auto get_status_if_no_outputs = [&]() -> Status
{
if (all_outs_finished)
{
2019-02-07 18:51:53 +00:00
for (auto & in : inputs)
in.close();
2019-02-07 18:51:53 +00:00
return Status::Finished;
}
2019-02-07 18:51:53 +00:00
if (all_outs_full_or_unneeded)
{
2019-02-07 18:51:53 +00:00
for (auto & in : inputs)
in.setNotNeeded();
return Status::PortFull;
}
2019-02-07 18:51:53 +00:00
/// Now, we pushed to output, and it must be full.
return Status::PortFull;
};
auto get_status_if_no_inputs = [&]() -> Status
{
if (all_inputs_finished)
{
2019-02-07 18:51:53 +00:00
for (auto & out : outputs)
out.finish();
return Status::Finished;
}
2019-02-07 18:51:53 +00:00
return Status::NeedData;
};
/// Set all inputs needed in order to evenly process them.
/// Otherwise, in case num_outputs < num_inputs and chunks are consumed faster than produced,
/// some inputs can be skipped.
// auto set_all_unprocessed_inputs_needed = [&]()
// {
// for (; cur_input != inputs.end(); ++cur_input)
// if (!cur_input->isFinished())
// cur_input->setNeeded();
// };
while (!is_end_input() && !is_end_output())
2019-02-07 18:51:53 +00:00
{
auto output = get_next_out();
2019-07-09 17:47:13 +00:00
auto input = get_next_input();
2019-02-07 18:51:53 +00:00
if (output == outputs.end())
return get_status_if_no_outputs();
2019-07-09 17:47:13 +00:00
2019-02-07 18:51:53 +00:00
if (input == inputs.end())
return get_status_if_no_inputs();
output->push(input->pull());
}
2019-02-07 18:51:53 +00:00
if (is_end_input())
2019-02-07 18:51:53 +00:00
return get_status_if_no_outputs();
/// cur_input == inputs_end()
return get_status_if_no_inputs();
}
IProcessor::Status ResizeProcessor::prepare(const PortNumbers & updated_inputs, const PortNumbers & updated_outputs)
{
if (!initialized)
{
initialized = true;
2020-01-13 12:04:02 +00:00
for (auto & input : inputs)
{
input.setNeeded();
input_ports.push_back({.port = &input, .status = InputStatus::NotActive});
}
for (auto & output : outputs)
output_ports.push_back({.port = &output, .status = OutputStatus::NotActive});
}
for (auto & output_number : updated_outputs)
{
auto & output = output_ports[output_number];
if (output.port->isFinished())
{
if (output.status != OutputStatus::Finished)
{
++num_finished_outputs;
output.status = OutputStatus::Finished;
}
continue;
}
if (output.port->canPush())
{
if (output.status != OutputStatus::NeedData)
{
output.status = OutputStatus::NeedData;
waiting_outputs.push(output_number);
}
}
}
if (num_finished_outputs == outputs.size())
{
for (auto & input : inputs)
input.close();
return Status::Finished;
}
for (auto & input_number : updated_inputs)
{
auto & input = input_ports[input_number];
if (input.port->isFinished())
{
if (input.status != InputStatus::Finished)
{
input.status = InputStatus::Finished;
++num_finished_inputs;
}
continue;
}
if (input.port->hasData())
{
if (input.status != InputStatus::HasData)
{
input.status = InputStatus::HasData;
inputs_with_data.push(input_number);
}
}
}
while (!waiting_outputs.empty() && !inputs_with_data.empty())
{
auto & waiting_output = output_ports[waiting_outputs.front()];
waiting_outputs.pop();
auto & input_with_data = input_ports[inputs_with_data.front()];
inputs_with_data.pop();
waiting_output.port->pushData(input_with_data.port->pullData());
input_with_data.status = InputStatus::NotActive;
waiting_output.status = OutputStatus::NotActive;
if (input_with_data.port->isFinished())
{
input_with_data.status = InputStatus::Finished;
++num_finished_inputs;
}
}
if (num_finished_inputs == inputs.size())
{
for (auto & output : outputs)
output.finish();
return Status::Finished;
}
if (!waiting_outputs.empty())
return Status::NeedData;
return Status::PortFull;
}
IProcessor::Status StrictResizeProcessor::prepare(const PortNumbers & updated_inputs, const PortNumbers & updated_outputs)
{
if (!initialized)
{
initialized = true;
for (auto & input : inputs)
input_ports.push_back({.port = &input, .status = InputStatus::NotActive});
2020-01-13 10:32:55 +00:00
for (UInt64 i = 0; i < input_ports.size(); ++i)
disabled_input_ports.push(i);
for (auto & output : outputs)
output_ports.push_back({.port = &output, .status = OutputStatus::NotActive});
}
for (auto & output_number : updated_outputs)
{
auto & output = output_ports[output_number];
if (output.port->isFinished())
{
if (output.status != OutputStatus::Finished)
{
++num_finished_outputs;
output.status = OutputStatus::Finished;
}
continue;
}
if (output.port->canPush())
{
if (output.status != OutputStatus::NeedData)
{
output.status = OutputStatus::NeedData;
waiting_outputs.push(output_number);
}
}
}
if (num_finished_outputs == outputs.size())
{
for (auto & input : inputs)
input.close();
return Status::Finished;
}
2020-01-13 10:32:55 +00:00
std::queue<UInt64> inputs_with_data;
for (auto & input_number : updated_inputs)
{
auto & input = input_ports[input_number];
if (input.port->isFinished())
{
if (input.status != InputStatus::Finished)
{
input.status = InputStatus::Finished;
++num_finished_inputs;
}
continue;
}
if (input.port->hasData())
{
2020-01-13 10:32:55 +00:00
if (input.status != InputStatus::NotActive)
{
2020-01-13 10:32:55 +00:00
input.status = InputStatus::NotActive;
inputs_with_data.push(input_number);
}
}
}
while (!waiting_outputs.empty() && !inputs_with_data.empty())
{
auto & waiting_output = output_ports[waiting_outputs.front()];
waiting_outputs.pop();
2020-01-13 10:32:55 +00:00
auto input_number = inputs_with_data.front();
auto & input_with_data = input_ports[input_number];
inputs_with_data.pop();
2020-01-13 10:32:55 +00:00
waiting_output.port->pushData(input_with_data.port->pullData(/* set_not_deeded = */ true));
waiting_output.status = OutputStatus::NotActive;
if (input_with_data.port->isFinished())
{
2019-12-03 12:08:59 +00:00
input_with_data.status = InputStatus::Finished;
++num_finished_inputs;
}
2020-01-13 10:32:55 +00:00
else
disabled_input_ports.push(input_number);
}
if (!inputs_with_data.empty())
throw Exception("Has input with data, but no outputs which need data were found.", ErrorCodes::LOGICAL_ERROR);
2020-01-13 10:47:07 +00:00
if (num_finished_inputs == inputs.size())
{
for (auto & output : outputs)
output.finish();
return Status::Finished;
}
2020-01-13 10:32:55 +00:00
/// Enable more inputs if needed.
while (!disabled_input_ports.empty()
2020-01-13 12:04:02 +00:00
&& (inputs.size() - num_finished_inputs - disabled_input_ports.size()) < waiting_outputs.size())
2020-01-13 10:32:55 +00:00
{
auto & input = input_ports[disabled_input_ports.front()];
disabled_input_ports.pop();
input.port->setNeeded();
input.status = InputStatus::NeedData;
}
2020-01-13 10:47:07 +00:00
if (waiting_outputs.empty())
return Status::PortFull;
2020-01-13 10:47:07 +00:00
return Status::NeedData;
}
}