@@ -66,6 +66,33 @@ distinct_from(const absl::flat_hash_set<model::node_id>& nodes) {
66
66
return hard_constraint (std::make_unique<impl>(nodes));
67
67
}
68
68
69
+ reallocation_failure_details map_result_to_failure_details (
70
+ change_reason reason, std::error_code ec, model::node_id replica_to_move) {
71
+ reallocation_failure_details details{
72
+ .replica_to_move = replica_to_move,
73
+ .reason = reason,
74
+ .error = details.error = reallocation_error::unknown_error};
75
+ if (ec.category () == cluster::error_category ()) {
76
+ switch (static_cast <cluster::errc>(ec.value ())) {
77
+ case cluster::errc::no_eligible_allocation_nodes:
78
+ details.error = reallocation_error::no_eligible_node_found;
79
+ break ;
80
+ case cluster::errc::topic_invalid_partitions_fd_limit:
81
+ details.error = reallocation_error::over_partition_fd_limit;
82
+ break ;
83
+ case cluster::errc::topic_invalid_partitions_core_limit:
84
+ details.error = reallocation_error::over_partition_core_limit;
85
+ break ;
86
+ case cluster::errc::topic_invalid_partitions_memory_limit:
87
+ details.error = reallocation_error::over_partition_memory_limit;
88
+ break ;
89
+ default :
90
+ break ;
91
+ }
92
+ }
93
+
94
+ return details;
95
+ }
69
96
} // namespace
70
97
71
98
partition_balancer_planner::partition_balancer_planner (
@@ -187,8 +214,8 @@ class partition_balancer_planner::request_context {
187
214
188
215
void increment_missing_size_count () { _partitions_with_missing_size++; }
189
216
190
- void
191
- report_decommission_reallocation_failure (model::node_id, const model::ntp&);
217
+ void report_reallocation_failure (
218
+ const model::ntp&, reallocation_failure_details );
192
219
193
220
node2count_t & get_topic_to_node_count (model::topic_namespace_view tp_ns) {
194
221
auto it = _topic2node_counts.find (tp_ns);
@@ -240,10 +267,9 @@ class partition_balancer_planner::request_context {
240
267
// we track missing partition size info separately as it requires force
241
268
// refresh of health report
242
269
size_t _partitions_with_missing_size = 0 ;
243
- // Tracks ntps with allocation failures grouped by decommissioning node.
244
- static constexpr size_t max_ntps_with_reallocation_falures = 25 ;
245
- absl::flat_hash_map<model::node_id, absl::btree_set<model::ntp>>
246
- _decommission_realloc_failures;
270
+ static constexpr size_t max_reallocation_failures_reported = 25 ;
271
+ chunked_hash_map<model::ntp, reallocation_failure_details>
272
+ _reallocation_failures;
247
273
absl::node_hash_set<model::ntp> _cancellations;
248
274
bool _counts_rebalancing_finished = false ;
249
275
ss::abort_source& _as;
@@ -544,13 +570,13 @@ bool partition_balancer_planner::request_context::increment_failure_count() {
544
570
}
545
571
}
546
572
547
- void partition_balancer_planner::request_context::
548
- report_decommission_reallocation_failure (
549
- model::node_id node, const model::ntp& ntp) {
550
- auto & ntps = _decommission_realloc_failures.try_emplace (node).first ->second ;
551
- if (ntps.size () < max_ntps_with_reallocation_falures) {
552
- ntps.emplace (ntp);
573
+ void partition_balancer_planner::request_context::report_reallocation_failure (
574
+ const model::ntp& ntp, reallocation_failure_details details) {
575
+ if (_reallocation_failures.size () >= max_reallocation_failures_reported) {
576
+ return ;
553
577
}
578
+
579
+ _reallocation_failures.try_emplace (ntp, details);
554
580
}
555
581
556
582
static bool has_quorum (
@@ -821,6 +847,54 @@ class partition_balancer_planner::immutable_partition {
821
847
change_reason);
822
848
}
823
849
850
+ bool contains_replica (model::node_id replica) const {
851
+ return contains_node (_replicas, replica);
852
+ }
853
+
854
+ reallocation_failure_details map_immutability_reason_to_failure_details (
855
+ change_reason reason, model::node_id replica_to_move) {
856
+ reallocation_failure_details details{
857
+ .replica_to_move = replica_to_move,
858
+ .reason = reason,
859
+ .error = details.error = reallocation_error::unknown_error};
860
+
861
+ switch (_reason) {
862
+ case immutability_reason::no_quorum:
863
+ details.error = reallocation_error::no_quorum;
864
+ break ;
865
+ case immutability_reason::no_size_info:
866
+ details.error = reallocation_error::missing_partition_size_info;
867
+ break ;
868
+ case immutability_reason::reconfiguration_state:
869
+ details.error = reallocation_error::reconfiguration_in_progress;
870
+ break ;
871
+ case immutability_reason::disabled:
872
+ details.error = reallocation_error::partition_disabled;
873
+ break ;
874
+ case immutability_reason::batch_full:
875
+ break ;
876
+ }
877
+
878
+ return details;
879
+ }
880
+
881
+ void report_immutable_partition_as_reallocation_failure (
882
+ request_context& ctx,
883
+ const std::vector<model::node_id>& replicas_to_move,
884
+ change_reason reason) {
885
+ if (_reason == immutability_reason::batch_full) {
886
+ return ;
887
+ }
888
+ // report per replica reallocation failures
889
+ for (const auto replica : replicas_to_move) {
890
+ if (contains_replica (replica)) {
891
+ ctx.report_reallocation_failure (
892
+ ntp (),
893
+ map_immutability_reason_to_failure_details (reason, replica));
894
+ }
895
+ }
896
+ }
897
+
824
898
private:
825
899
friend class request_context ;
826
900
@@ -1497,8 +1571,10 @@ ss::future<> partition_balancer_planner::get_node_drain_actions(
1497
1571
ctx.config ().hard_max_disk_usage_ratio ,
1498
1572
reason);
1499
1573
if (!result) {
1500
- ctx.report_decommission_reallocation_failure (
1501
- replica, part.ntp ());
1574
+ ctx.report_reallocation_failure (
1575
+ part.ntp (),
1576
+ map_result_to_failure_details (
1577
+ reason, result.error (), replica));
1502
1578
}
1503
1579
}
1504
1580
}
@@ -1522,7 +1598,11 @@ ss::future<> partition_balancer_planner::get_node_drain_actions(
1522
1598
}
1523
1599
},
1524
1600
[&](force_reassignable_partition&) {},
1525
- [&](immutable_partition& part) { part.report_failure (reason); });
1601
+ [&](immutable_partition& part) {
1602
+ part.report_failure (reason);
1603
+ part.report_immutable_partition_as_reallocation_failure (
1604
+ ctx, to_move, reason);
1605
+ });
1526
1606
1527
1607
return ss::stop_iteration::no;
1528
1608
});
@@ -1589,15 +1669,25 @@ ss::future<> partition_balancer_planner::get_rack_constraint_repair_actions(
1589
1669
if (part.is_original (replica)) {
1590
1670
// only move replicas that haven't been moved for
1591
1671
// other reasons
1592
- ( void ) part.move_replica (
1672
+ auto r = part.move_replica (
1593
1673
replica,
1594
1674
ctx.config ().soft_max_disk_usage_ratio ,
1595
1675
change_reason::rack_constraint_repair);
1676
+ if (r.has_error ()) {
1677
+ ctx.report_reallocation_failure (
1678
+ part.ntp (),
1679
+ map_result_to_failure_details (
1680
+ change_reason::rack_constraint_repair,
1681
+ r.error (),
1682
+ replica));
1683
+ }
1596
1684
}
1597
1685
}
1598
1686
},
1599
- [](immutable_partition& part) {
1687
+ [& ](immutable_partition& part) {
1600
1688
part.report_failure (change_reason::rack_constraint_repair);
1689
+ part.report_immutable_partition_as_reallocation_failure (
1690
+ ctx, to_move, change_reason::rack_constraint_repair);
1601
1691
},
1602
1692
[](moving_partition&) {},
1603
1693
[](force_reassignable_partition&) {});
@@ -1814,12 +1904,23 @@ partition_balancer_planner::get_full_node_actions(request_context& ctx) {
1814
1904
});
1815
1905
1816
1906
for (const auto & replica : full_node_replicas) {
1817
- ( void ) part.move_replica (
1907
+ auto r = part.move_replica (
1818
1908
replica.node_id ,
1819
1909
ctx.config ().soft_max_disk_usage_ratio ,
1820
1910
change_reason::disk_full);
1911
+ if (r.has_error ()) {
1912
+ ctx.report_reallocation_failure (
1913
+ part.ntp (),
1914
+ map_result_to_failure_details (
1915
+ change_reason::disk_full,
1916
+ r.error (),
1917
+ replica.node_id ));
1918
+ }
1821
1919
}
1822
1920
},
1921
+ [&](immutable_partition& part) {
1922
+ part.report_failure (change_reason::disk_full);
1923
+ },
1823
1924
[](auto &) {});
1824
1925
});
1825
1926
}
@@ -1940,6 +2041,12 @@ ss::future<> partition_balancer_planner::get_counts_rebalancing_actions(
1940
2041
ctx.config ().soft_max_disk_usage_ratio ,
1941
2042
change_reason::partition_count_rebalancing);
1942
2043
if (!res) {
2044
+ ctx.report_reallocation_failure (
2045
+ part.ntp (),
2046
+ map_result_to_failure_details (
2047
+ change_reason::partition_count_rebalancing,
2048
+ res.error (),
2049
+ node));
1943
2050
return ;
1944
2051
}
1945
2052
@@ -1959,6 +2066,8 @@ ss::future<> partition_balancer_planner::get_counts_rebalancing_actions(
1959
2066
},
1960
2067
[&](immutable_partition& p) {
1961
2068
p.report_failure (change_reason::partition_count_rebalancing);
2069
+ p.report_immutable_partition_as_reallocation_failure (
2070
+ ctx, {node}, change_reason::partition_count_rebalancing);
1962
2071
should_stop = false ;
1963
2072
},
1964
2073
[](auto &) {});
@@ -2048,8 +2157,7 @@ void partition_balancer_planner::request_context::collect_actions(
2048
2157
2049
2158
result.counts_rebalancing_finished = _counts_rebalancing_finished;
2050
2159
2051
- result.decommission_realloc_failures = std::move (
2052
- _decommission_realloc_failures);
2160
+ result.reallocation_failures = std::move (_reallocation_failures);
2053
2161
2054
2162
if (
2055
2163
!result.cancellations .empty () || !result.reassignments .empty ()
0 commit comments