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