Skip to main content

mito2/worker/
handle_create.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//! Handling create request.
16
17use common_telemetry::info;
18use store_api::logstore::LogStore;
19use store_api::metadata::RegionMetadataBuilder;
20use store_api::region_request::{AffectedRows, RegionCreateRequest};
21use store_api::storage::RegionId;
22
23use crate::error::Result;
24use crate::region::opener::{RegionOpener, check_recovered_region};
25#[cfg(feature = "hdfs-object-store")]
26use crate::temp_file_sweeper;
27use crate::worker::RegionWorkerLoop;
28
29impl<S: LogStore> RegionWorkerLoop<S> {
30    pub(crate) async fn handle_create_request(
31        &mut self,
32        region_id: RegionId,
33        request: RegionCreateRequest,
34    ) -> Result<AffectedRows> {
35        // Checks whether the table exists.
36        if let Some(region) = self.regions.get_region(region_id) {
37            // Region already exists.
38            check_recovered_region(
39                &region.metadata(),
40                region_id,
41                &request.column_metadatas,
42                &request.primary_key,
43            )?;
44
45            return Ok(0);
46        }
47
48        // Convert the request into a RegionMetadata and validate it.
49        let mut builder = RegionMetadataBuilder::new(region_id);
50        for column in request.column_metadatas {
51            builder.push_column_metadata(column);
52        }
53        builder.primary_key(request.primary_key);
54        if let Some(expr_json) = request.partition_expr_json.as_ref() {
55            builder.partition_expr_json(Some(expr_json.clone()));
56        }
57
58        // Create a MitoRegion from the RegionMetadata.
59        let requirements = request.requirements;
60        let opener = RegionOpener::new(
61            region_id,
62            &request.table_dir,
63            request.path_type,
64            self.node_lease.clone(),
65            self.memtable_builder_provider.clone(),
66            self.object_store_manager.clone(),
67            self.purge_scheduler.clone(),
68            self.puffin_manager_factory.clone(),
69            self.intermediate_manager.clone(),
70            self.time_provider.clone(),
71            self.file_ref_manager.clone(),
72            self.partition_expr_fetcher.clone(),
73        )
74        .metadata_builder(builder)
75        .parse_options(request.options)?
76        .cache(Some(self.cache_manager.clone()))
77        .series_index_store(self.series_index_store.clone())
78        .series_index_purger(self.series_index_purger.clone())
79        .hook(self.plugins.get());
80
81        opener.ensure_region_requirements(requirements)?;
82
83        let region = opener.create_or_open(&self.config, &self.wal).await?;
84
85        // A Create retried after a crash opens an existing region as a leader
86        // without a role-state change, so sweep here as well.
87        #[cfg(feature = "hdfs-object-store")]
88        temp_file_sweeper::spawn_region_sweep(
89            region.access_layer(),
90            region_id,
91            self.config.gc.unknown_file_lingering_time,
92            self.sweep_limiter.clone(),
93        );
94
95        info!(
96            "A new region created with requirement {:?}, worker: {}, region: {:?}",
97            requirements,
98            self.id,
99            region.metadata()
100        );
101
102        self.region_count.inc();
103
104        // Notify the region hook that the region has been opened (created).
105        // Fires before registration; allocates nothing when no hook is registered.
106        if let Some(hook) = region.manifest_ctx.hook() {
107            hook.on_region_opened(region_id, &region.metadata()).await;
108        }
109
110        // The region takes writes under the node lease until its first Leader grant.
111        self.node_lease.seed(&region.manifest_ctx.leader_deadline);
112        // Insert the MitoRegion into the RegionMap.
113        self.register_region(region);
114        if let Some(state) = &self.series_index_task_state {
115            state.wake();
116        }
117
118        Ok(0)
119    }
120}