blob: 3245616b1fe36c8dc36a6aa13c51dea171d4128c [file]
// 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/partitioner/writer_assigner.h"
#include "exec/connector/skewed_partition_rebalancer.h"
namespace doris {
namespace {
Status validate_assignment_input(const std::vector<uint32_t>& partition_ids,
const std::vector<uint8_t>* mask, size_t rows) {
if (partition_ids.size() < rows) {
return Status::InvalidArgument("Writer assignment has {} partition ids for {} rows",
partition_ids.size(), rows);
}
if (mask != nullptr && mask->size() < rows) {
return Status::InvalidArgument("Writer assignment mask has {} entries for {} rows",
mask->size(), rows);
}
return Status::OK();
}
} // namespace
Status IdentityWriterAssigner::assign(const std::vector<uint32_t>& partition_ids,
const std::vector<uint8_t>* mask, size_t rows,
size_t /*block_bytes*/, std::vector<uint32_t>& writer_ids) {
RETURN_IF_ERROR(validate_assignment_input(partition_ids, mask, rows));
if (writer_ids.size() != rows && &writer_ids != &partition_ids) {
writer_ids.resize(rows);
}
for (size_t row = 0; row < rows; ++row) {
if (mask != nullptr && (*mask)[row] == 0) {
continue;
}
if (partition_ids[row] >= _writer_count) {
return Status::InvalidArgument("Logical partition {} exceeds writer count {}",
partition_ids[row], _writer_count);
}
writer_ids[row] = partition_ids[row];
}
return Status::OK();
}
SkewedWriterAssigner::SkewedWriterAssigner(int partition_count, int task_count,
int task_bucket_count,
long min_partition_data_processed_rebalance_threshold,
long min_data_processed_rebalance_threshold)
: _rebalancer(std::make_unique<SkewedPartitionRebalancer>(
partition_count, task_count, task_bucket_count,
min_partition_data_processed_rebalance_threshold,
min_data_processed_rebalance_threshold)),
_writer_count(task_count),
_partition_row_counts(partition_count, 0),
_partition_writer_ids(partition_count, -1),
_partition_writer_indexes(partition_count, 0) {}
SkewedWriterAssigner::~SkewedWriterAssigner() = default;
Status SkewedWriterAssigner::assign(const std::vector<uint32_t>& partition_ids,
const std::vector<uint8_t>* mask, size_t rows,
size_t block_bytes, std::vector<uint32_t>& writer_ids) {
RETURN_IF_ERROR(validate_assignment_input(partition_ids, mask, rows));
if (rows == 0) {
return Status::OK();
}
if (_partition_row_counts.empty()) {
return Status::InvalidArgument("Skewed writer assignment has no logical partitions");
}
if (writer_ids.size() != rows && &writer_ids != &partition_ids) {
writer_ids.resize(rows);
}
std::fill(_partition_row_counts.begin(), _partition_row_counts.end(), 0);
std::fill(_partition_writer_ids.begin(), _partition_writer_ids.end(), -1);
_rebalancer->rebalance();
const size_t partition_count = _partition_row_counts.size();
for (size_t row = 0; row < rows; ++row) {
if (mask != nullptr && (*mask)[row] == 0) {
continue;
}
const uint32_t partition_id = partition_ids[row];
if (partition_id >= partition_count) {
return Status::InvalidArgument("Logical partition {} exceeds partition count {}",
partition_id, partition_count);
}
_partition_row_counts[partition_id] += 1;
int writer_id = _partition_writer_ids[partition_id];
if (writer_id == -1) {
writer_id = _get_next_writer_id(partition_id);
if (writer_id < 0 || writer_id >= _writer_count) {
return Status::InternalError("Skewed writer assignment returned invalid writer {}",
writer_id);
}
_partition_writer_ids[partition_id] = writer_id;
}
writer_ids[row] = static_cast<uint32_t>(writer_id);
}
for (size_t partition_id = 0; partition_id < partition_count; ++partition_id) {
if (_partition_row_counts[partition_id] > 0) {
_rebalancer->add_partition_row_count(static_cast<int>(partition_id),
_partition_row_counts[partition_id]);
}
}
_rebalancer->add_data_processed(static_cast<long>(block_bytes));
return Status::OK();
}
int SkewedWriterAssigner::_get_next_writer_id(uint32_t partition_id) {
return _rebalancer->get_task_id(partition_id, _partition_writer_indexes[partition_id]++);
}
int64_t scale_writer_threshold_by_task(int64_t value, int task_num) {
if (task_num <= 0) {
return value;
}
int64_t scaled = value / task_num;
return scaled == 0 ? value : scaled;
}
} // namespace doris