meta_srv/procedure/repartition/group/
utils.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::HashMap;
16
17use common_meta::peer::Peer;
18use common_meta::rpc::router::RegionRoute;
19use store_api::storage::RegionId;
20
21use crate::error::{Error, Result};
22
23/// Groups the region routes by the leader peer.
24///
25/// # Panics
26///
27/// Panics if the leader peer is not set for any of the region routes.
28pub(crate) fn group_region_routes_by_peer(
29    region_routes: &[RegionRoute],
30) -> HashMap<&Peer, Vec<RegionId>> {
31    let mut map: HashMap<&Peer, Vec<RegionId>> = HashMap::new();
32    for region_route in region_routes {
33        map.entry(region_route.leader_peer.as_ref().unwrap())
34            .or_default()
35            .push(region_route.region.id);
36    }
37    map
38}
39
40/// Returns `true` if all results are successful.
41fn all_successful(results: &[Result<()>]) -> bool {
42    results.iter().all(Result::is_ok)
43}
44
45pub enum HandleMultipleResult<'a> {
46    AllSuccessful,
47    AllRetryable(Vec<(usize, &'a Error)>),
48    PartialRetryable {
49        retryable_errors: Vec<(usize, &'a Error)>,
50        non_retryable_errors: Vec<(usize, &'a Error)>,
51    },
52    AllNonRetryable(Vec<(usize, &'a Error)>),
53}
54
55/// Evaluates results from multiple operations and categorizes errors by retryability.
56///
57/// If all operations succeed, returns `AllSuccessful`.
58/// If all errors are retryable, returns `AllRetryable`.
59/// If all errors are non-retryable, returns `AllNonRetryable`.
60/// Otherwise, returns `PartialRetryable` with separate collections for retryable and non-retryable errors.
61pub(crate) fn handle_multiple_results<'a>(results: &'a [Result<()>]) -> HandleMultipleResult<'a> {
62    if all_successful(results) {
63        return HandleMultipleResult::AllSuccessful;
64    }
65
66    let mut retryable_errors = Vec::new();
67    let mut non_retryable_errors = Vec::new();
68    for (index, result) in results.iter().enumerate() {
69        if let Err(error) = result {
70            if error.is_retryable() {
71                retryable_errors.push((index, error));
72            } else {
73                non_retryable_errors.push((index, error));
74            }
75        }
76    }
77
78    match (retryable_errors.is_empty(), non_retryable_errors.is_empty()) {
79        (true, false) => HandleMultipleResult::AllNonRetryable(non_retryable_errors),
80        (false, true) => HandleMultipleResult::AllRetryable(retryable_errors),
81        (false, false) => HandleMultipleResult::PartialRetryable {
82            retryable_errors,
83            non_retryable_errors,
84        },
85        // Should not happen, but include for completeness
86        (true, true) => HandleMultipleResult::AllSuccessful,
87    }
88}