Skip to main content

frontend/instance/
builder.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::sync::Arc;
16use std::sync::atomic::AtomicBool;
17
18use auth::PermissionCheckerRef;
19use cache::{PARTITION_INFO_CACHE_NAME, TABLE_FLOWNODE_SET_CACHE_NAME, TABLE_ROUTE_CACHE_NAME};
20use catalog::CatalogManagerRef;
21use catalog::kvbackend::KvBackendCatalogManager;
22use catalog::process_manager::ProcessManagerRef;
23use catalog::system_schema::semantic_graph::EntityGraphProviderRef;
24use common_base::Plugins;
25use common_datasource::object_store::LocalFileAccess;
26use common_event_recorder::{EventRecorderImpl, EventRecorderRef};
27use common_meta::cache::{LayeredCacheRegistryRef, TableFlownodeSetCacheRef, TableRouteCacheRef};
28use common_meta::cache_invalidator::{CacheInvalidatorRef, DummyCacheInvalidator};
29use common_meta::key::TableMetadataManager;
30use common_meta::key::flow::FlowMetadataManager;
31use common_meta::kv_backend::KvBackendRef;
32use common_meta::node_manager::NodeManagerRef;
33use common_meta::procedure_executor::ProcedureExecutorRef;
34use dashmap::DashMap;
35use operator::batcher::PendingRowsBatcher;
36use operator::delete::Deleter;
37use operator::flow::FlowServiceOperator;
38use operator::insert::Inserter;
39use operator::procedure::ProcedureServiceOperator;
40use operator::request::Requester;
41#[cfg(feature = "enterprise")]
42use operator::statement::CreateDatabaseHandlerRef;
43use operator::statement::{
44    AdminEventRecorderHandle, AdminFunctionRecordingLayer, ExecutorConfigureContext,
45    StatementExecutor, StatementExecutorConfiguratorRef, StatementExecutorRef,
46};
47use operator::table::TableMutationOperator;
48use partition::cache::PartitionInfoCacheRef;
49use partition::manager::PartitionRuleManager;
50use pipeline::pipeline_operator::PipelineOperator;
51use query::QueryEngineFactory;
52use query::region_query::RegionQueryHandlerFactoryRef;
53use servers::batcher::BatchingProtocol;
54use servers::batcher::table::TablePendingRowsBatcher;
55use snafu::{OptionExt, ResultExt};
56
57use crate::error::{self, DataFusionSnafu, ExternalSnafu, Result};
58use crate::events::EventHandlerImpl;
59use crate::frontend::FrontendOptions;
60use crate::heartbeat::frontend_peer_addr;
61use crate::instance::Instance;
62use crate::instance::entity_graph::EntityGraphProviderImpl;
63use crate::instance::region_query::FrontendRegionQueryHandler;
64use crate::service_config::BatcherOptions;
65
66/// The frontend [`Instance`] builder.
67pub struct FrontendBuilder {
68    options: FrontendOptions,
69    kv_backend: KvBackendRef,
70    layered_cache_registry: LayeredCacheRegistryRef,
71    local_cache_invalidator: Option<CacheInvalidatorRef>,
72    catalog_manager: CatalogManagerRef,
73    node_manager: NodeManagerRef,
74    plugins: Option<Plugins>,
75    procedure_executor: ProcedureExecutorRef,
76    process_manager: ProcessManagerRef,
77    local_file_access: LocalFileAccess,
78}
79
80impl FrontendBuilder {
81    #[allow(clippy::too_many_arguments)]
82    pub fn new(
83        options: FrontendOptions,
84        kv_backend: KvBackendRef,
85        layered_cache_registry: LayeredCacheRegistryRef,
86        catalog_manager: CatalogManagerRef,
87        node_manager: NodeManagerRef,
88        procedure_executor: ProcedureExecutorRef,
89        process_manager: ProcessManagerRef,
90    ) -> Self {
91        Self {
92            options,
93            kv_backend,
94            layered_cache_registry,
95            local_cache_invalidator: None,
96            catalog_manager,
97            node_manager,
98            plugins: None,
99            procedure_executor,
100            process_manager,
101            local_file_access: LocalFileAccess::Disabled,
102        }
103    }
104
105    #[cfg(test)]
106    pub(crate) fn new_test(
107        options: &FrontendOptions,
108        meta_client: meta_client::MetaClientRef,
109    ) -> Self {
110        use cache::{build_fundamental_cache_registry, with_default_composite_cache_registry};
111        use common_meta::cache::LayeredCacheRegistryBuilder;
112        use common_meta::kv_backend::memory::MemoryKvBackend;
113
114        let kv_backend = Arc::new(MemoryKvBackend::new());
115
116        // Builds cache registry
117        let layered_cache_builder = LayeredCacheRegistryBuilder::default();
118        let fundamental_cache_registry = build_fundamental_cache_registry(kv_backend.clone());
119        let layered_cache_registry = Arc::new(
120            with_default_composite_cache_registry(
121                layered_cache_builder.add_cache_registry(fundamental_cache_registry),
122            )
123            .unwrap()
124            .build(),
125        );
126
127        Self::new(
128            options.clone(),
129            kv_backend,
130            layered_cache_registry,
131            catalog::memory::MemoryCatalogManager::with_default_setup(),
132            Arc::new(client::client_manager::NodeClients::default()),
133            meta_client,
134            Arc::new(catalog::process_manager::ProcessManager::new(
135                "".to_string(),
136                None,
137            )),
138        )
139    }
140
141    pub fn with_local_cache_invalidator(self, cache_invalidator: CacheInvalidatorRef) -> Self {
142        Self {
143            local_cache_invalidator: Some(cache_invalidator),
144            ..self
145        }
146    }
147
148    pub fn with_local_file_access(mut self, local_file_access: LocalFileAccess) -> Self {
149        self.local_file_access = local_file_access;
150        self
151    }
152
153    pub fn options(&self) -> &FrontendOptions {
154        &self.options
155    }
156
157    pub fn kv_backend(&self) -> &KvBackendRef {
158        &self.kv_backend
159    }
160
161    pub fn layered_cache_registry(&self) -> &LayeredCacheRegistryRef {
162        &self.layered_cache_registry
163    }
164
165    pub fn catalog_manager(&self) -> &CatalogManagerRef {
166        &self.catalog_manager
167    }
168
169    pub fn node_manager(&self) -> &NodeManagerRef {
170        &self.node_manager
171    }
172
173    pub fn procedure_executor(&self) -> &ProcedureExecutorRef {
174        &self.procedure_executor
175    }
176
177    pub fn process_manager(&self) -> &ProcessManagerRef {
178        &self.process_manager
179    }
180
181    pub fn with_plugin(self, plugins: Plugins) -> Self {
182        Self {
183            plugins: Some(plugins),
184            ..self
185        }
186    }
187
188    pub async fn try_build(self) -> Result<Instance> {
189        let kv_backend = self.kv_backend;
190        let node_manager = self.node_manager;
191        let plugins = self.plugins.unwrap_or_default();
192        let process_manager = self.process_manager;
193        let table_route_cache: TableRouteCacheRef =
194            self.layered_cache_registry
195                .get()
196                .context(error::CacheRequiredSnafu {
197                    name: TABLE_ROUTE_CACHE_NAME,
198                })?;
199        let partition_info_cache: PartitionInfoCacheRef = self
200            .layered_cache_registry
201            .get()
202            .context(error::CacheRequiredSnafu {
203                name: PARTITION_INFO_CACHE_NAME,
204            })?;
205        let partition_manager = Arc::new(PartitionRuleManager::new(
206            kv_backend.clone(),
207            table_route_cache.clone(),
208            partition_info_cache.clone(),
209        ));
210
211        let local_cache_invalidator = self
212            .local_cache_invalidator
213            .unwrap_or_else(|| Arc::new(DummyCacheInvalidator));
214
215        let region_query_handler =
216            if let Some(factory) = plugins.get::<RegionQueryHandlerFactoryRef>() {
217                factory.build(partition_manager.clone(), node_manager.clone())
218            } else {
219                FrontendRegionQueryHandler::arc(partition_manager.clone(), node_manager.clone())
220            };
221
222        let table_flownode_cache: TableFlownodeSetCacheRef = self
223            .layered_cache_registry
224            .get()
225            .context(error::CacheRequiredSnafu {
226                name: TABLE_FLOWNODE_SET_CACHE_NAME,
227            })?;
228
229        let create_inserter = || {
230            Inserter::new(
231                self.catalog_manager.clone(),
232                partition_manager.clone(),
233                node_manager.clone(),
234                table_flownode_cache.clone(),
235                self.options.auto_create_table,
236            )
237        };
238        // The execution-only inserter owns no batchers, avoiding an Arc cycle.
239        let bulk_inserter = Arc::new(create_inserter());
240        let build_batcher = |options: &BatcherOptions| -> Option<Arc<dyn PendingRowsBatcher>> {
241            if !options.pending_rows_batching_enabled()
242                || (self.options.prom_store.with_metric_engine
243                    && options
244                        .protocols
245                        .iter()
246                        .all(|protocol| *protocol == BatchingProtocol::Prom))
247            {
248                return None;
249            }
250            TablePendingRowsBatcher::try_new(
251                options.pending_rows_flush_interval,
252                options.max_batch_rows,
253                options.max_concurrent_flushes,
254                options.worker_channel_capacity,
255                options.max_inflight_requests,
256                options.flow_notification_queue_capacity,
257                bulk_inserter.clone(),
258            )
259            .map(|batcher| batcher as Arc<dyn PendingRowsBatcher>)
260        };
261        let inserter = Arc::new(
262            create_inserter()
263                .with_pending_rows_batcher(build_batcher(self.options.table_batcher_options())),
264        );
265        let deleter = Arc::new(Deleter::new(
266            self.catalog_manager.clone(),
267            partition_manager.clone(),
268            node_manager.clone(),
269        ));
270        let requester = Arc::new(Requester::new(
271            self.catalog_manager.clone(),
272            partition_manager.clone(),
273            node_manager.clone(),
274        ));
275        let table_mutation_handler = Arc::new(TableMutationOperator::new(
276            inserter.clone(),
277            deleter.clone(),
278            requester,
279        ));
280
281        let table_metadata_manager = Arc::new(TableMetadataManager::new(kv_backend.clone()));
282        let procedure_service_handler = Arc::new(ProcedureServiceOperator::new(
283            self.procedure_executor.clone(),
284            self.catalog_manager.clone(),
285            table_metadata_manager.clone(),
286        ));
287
288        let flow_metadata_manager: Arc<FlowMetadataManager> =
289            Arc::new(FlowMetadataManager::new(kv_backend.clone()));
290        let flow_service = FlowServiceOperator::new(flow_metadata_manager, node_manager.clone());
291
292        let mut query_options = self.options.query.clone();
293        query_options.enable_per_region_metrics = self.options.logging.enable_per_region_metrics;
294        let query_engine = QueryEngineFactory::try_new_with_plugins(
295            self.catalog_manager.clone(),
296            Some(partition_manager.clone()),
297            Some(region_query_handler.clone()),
298            Some(table_mutation_handler),
299            Some(procedure_service_handler),
300            Some(Arc::new(flow_service)),
301            true,
302            plugins.clone(),
303            query_options,
304        )
305        .context(DataFusionSnafu)?
306        .query_engine();
307
308        // Inject the entity-graph provider now that the query engine exists, so the
309        // computed `greptime_private.semantic_entities` / `semantic_relationships`
310        // tables can derive rows. Late binding here breaks the `catalog -> query`
311        // dependency cycle.
312        if let Some(kv_catalog) = self
313            .catalog_manager
314            .as_any()
315            .downcast_ref::<KvBackendCatalogManager>()
316        {
317            let provider: EntityGraphProviderRef = Arc::new(EntityGraphProviderImpl::new(
318                query_engine.clone(),
319                Arc::downgrade(&self.catalog_manager),
320                plugins.get::<PermissionCheckerRef>(),
321            ));
322            kv_catalog.set_entity_graph_provider(provider);
323        }
324
325        let frontend_peer_addr = frontend_peer_addr(&self.options);
326        let statement_executor = StatementExecutor::new(
327            self.catalog_manager.clone(),
328            query_engine.clone(),
329            self.procedure_executor,
330            kv_backend.clone(),
331            local_cache_invalidator,
332            inserter.clone(),
333            partition_manager,
334            Some(process_manager.clone()),
335            frontend_peer_addr.clone(),
336            self.local_file_access,
337        );
338
339        let statement_executor =
340            if let Some(configurator) = plugins.get::<StatementExecutorConfiguratorRef>() {
341                let ctx = ExecutorConfigureContext {
342                    kv_backend: kv_backend.clone(),
343                };
344                configurator
345                    .configure(statement_executor, ctx)
346                    .await
347                    .context(ExternalSnafu)?
348            } else {
349                statement_executor
350            };
351
352        #[cfg(feature = "enterprise")]
353        let statement_executor = if let Some(handler) = plugins.get::<CreateDatabaseHandlerRef>() {
354            statement_executor.with_create_database_handler(handler)
355        } else {
356            statement_executor
357        };
358
359        let admin_event_recorder = AdminEventRecorderHandle::default();
360        let statement_executor = statement_executor.with_admin_function_layer(Arc::new(
361            AdminFunctionRecordingLayer::new(admin_event_recorder.clone()),
362        ));
363        let statement_executor = Arc::new(statement_executor);
364
365        let pipeline_operator = Arc::new(PipelineOperator::new(
366            inserter.clone(),
367            statement_executor.clone(),
368            self.catalog_manager.clone(),
369            query_engine.clone(),
370            &self.options.pipeline,
371        ));
372
373        plugins.insert::<StatementExecutorRef>(statement_executor.clone());
374
375        let slow_query_recorder = Arc::new(EventRecorderImpl::new(Box::new(
376            EventHandlerImpl::new(statement_executor.clone(), self.options.slow_query.ttl),
377        )));
378        let event_recorder: EventRecorderRef = Arc::new(EventRecorderImpl::with_event_type_filter(
379            Box::new(EventHandlerImpl::new(
380                statement_executor.clone(),
381                self.options.event_recorder.ttl,
382            )),
383            self.options.event_recorder.event_types.clone(),
384            self.options.event_recorder.flush_interval,
385        ));
386        admin_event_recorder.install(&event_recorder);
387
388        Ok(Instance {
389            logical_batcher: Default::default(),
390            frontend_peer_addr,
391            experimental_metric_export: self.options.experimental_metric_export,
392            catalog_manager: self.catalog_manager,
393            pipeline_operator,
394            statement_executor,
395            query_engine,
396            plugins,
397            inserter,
398            deleter,
399            table_metadata_manager,
400            event_recorder,
401            slow_query_recorder,
402            process_manager,
403            otlp_metrics_table_legacy_cache: DashMap::new(),
404            slow_query_options: self.options.slow_query.clone(),
405            influxdb_default_merge_mode: self.options.influxdb.default_merge_mode,
406            trace_ingest_chunk_size: self.options.otlp.trace_ingest_chunk_size,
407            otlp_resource_info: self.options.otlp.experimental_enable_resource_info,
408            suspend: Arc::new(AtomicBool::new(false)),
409        })
410    }
411}