metric_engine/engine/
drop.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
15//! Drop a metric region
16
17use common_telemetry::{debug, info};
18use snafu::ResultExt;
19use store_api::region_engine::RegionEngine;
20use store_api::region_request::{AffectedRows, RegionDropRequest, RegionRequest};
21use store_api::storage::RegionId;
22
23use crate::engine::MetricEngineInner;
24use crate::error::{
25    CloseMitoRegionSnafu, LogicalRegionNotFoundSnafu, PhysicalRegionBusySnafu, Result,
26};
27use crate::metrics::PHYSICAL_REGION_COUNT;
28use crate::utils;
29
30impl MetricEngineInner {
31    pub async fn drop_region(
32        &self,
33        region_id: RegionId,
34        req: RegionDropRequest,
35    ) -> Result<AffectedRows> {
36        let data_region_id = utils::to_data_region_id(region_id);
37        let fast_path = req.fast_path;
38        let force = req.force;
39
40        // enclose the guard in a block to prevent the guard from polluting the async context
41        let (is_physical_region, is_physical_region_busy) = {
42            if let Some(state) = self
43                .state
44                .read()
45                .unwrap()
46                .physical_region_states()
47                .get(&data_region_id)
48            {
49                debug!(
50                    "Physical region {} is busy, there are still some logical regions: {:?}",
51                    data_region_id,
52                    state
53                        .logical_regions()
54                        .iter()
55                        .map(|id| id.to_string())
56                        .collect::<Vec<_>>()
57                );
58                (true, !state.logical_regions().is_empty())
59            } else {
60                // the second argument is not used, just pass in a dummy value
61                (false, true)
62            }
63        };
64
65        if is_physical_region {
66            // check if there is no logical region relates to this physical region
67            if is_physical_region_busy && !force {
68                // reject if there is any present logical region
69                return Err(PhysicalRegionBusySnafu {
70                    region_id: data_region_id,
71                }
72                .build());
73            }
74            if is_physical_region_busy && force {
75                info!("Dropping physical region {} with force", data_region_id);
76            }
77            return self.drop_physical_region(data_region_id).await;
78        }
79
80        if fast_path {
81            // for fast path, we don't delete the metadata in the metadata region.
82            // it only remove the logical region from the engine state.
83            //
84            // The drop database procedure will ensure the metadata region and data region are dropped eventually.
85            self.state
86                .write()
87                .unwrap()
88                .remove_logical_region(region_id)?;
89
90            Ok(0)
91        } else {
92            let metadata_region_id = self
93                .state
94                .read()
95                .unwrap()
96                .logical_regions()
97                .get(&region_id)
98                .copied();
99            if let Some(metadata_region_id) = metadata_region_id {
100                self.drop_logical_region(region_id, metadata_region_id)
101                    .await
102            } else {
103                Err(LogicalRegionNotFoundSnafu { region_id }.build())
104            }
105        }
106    }
107
108    async fn drop_physical_region(&self, region_id: RegionId) -> Result<AffectedRows> {
109        let data_region_id = utils::to_data_region_id(region_id);
110        let metadata_region_id = utils::to_metadata_region_id(region_id);
111
112        // Drop mito regions.
113        // Since the physical regions are going to be dropped, we don't need to
114        // update the contents in metadata region.
115        self.mito
116            .handle_request(
117                data_region_id,
118                RegionRequest::Drop(RegionDropRequest {
119                    fast_path: false,
120                    force: false,
121                }),
122            )
123            .await
124            .with_context(|_| CloseMitoRegionSnafu { region_id })?;
125        self.mito
126            .handle_request(
127                metadata_region_id,
128                RegionRequest::Drop(RegionDropRequest {
129                    fast_path: false,
130                    force: false,
131                }),
132            )
133            .await
134            .with_context(|_| CloseMitoRegionSnafu { region_id })?;
135
136        PHYSICAL_REGION_COUNT.dec();
137
138        // Update engine state
139        self.state
140            .write()
141            .unwrap()
142            .remove_physical_region(data_region_id)?;
143
144        Ok(0)
145    }
146
147    async fn drop_logical_region(
148        &self,
149        logical_region_id: RegionId,
150        physical_region_id: RegionId,
151    ) -> Result<AffectedRows> {
152        // Update metadata
153        self.metadata_region
154            .remove_logical_region(physical_region_id, logical_region_id)
155            .await?;
156
157        // Update engine state
158        self.state
159            .write()
160            .unwrap()
161            .remove_logical_region(logical_region_id)?;
162
163        Ok(0)
164    }
165}