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