1use 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;
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 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 operator::write_dispatcher::WriteDispatcher;
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::instance::Instance;
62use crate::instance::entity_graph::EntityGraphProviderImpl;
63use crate::instance::otlp::TraceAuxCache;
64use crate::instance::region_query::FrontendRegionQueryHandler;
65use crate::service_config::BatcherOptions;
66
67pub struct FrontendBuilder {
69 options: FrontendOptions,
70 kv_backend: KvBackendRef,
71 layered_cache_registry: LayeredCacheRegistryRef,
72 local_cache_invalidator: CacheInvalidatorRef,
73 catalog_manager: CatalogManagerRef,
74 node_manager: NodeManagerRef,
75 plugins: Option<Plugins>,
76 procedure_executor: ProcedureExecutorRef,
77 process_manager: ProcessManagerRef,
78 local_file_access: LocalFileAccess,
79}
80
81impl FrontendBuilder {
82 #[allow(clippy::too_many_arguments)]
86 pub fn new(
87 options: FrontendOptions,
88 kv_backend: KvBackendRef,
89 layered_cache_registry: LayeredCacheRegistryRef,
90 catalog_manager: CatalogManagerRef,
91 node_manager: NodeManagerRef,
92 procedure_executor: ProcedureExecutorRef,
93 process_manager: ProcessManagerRef,
94 ) -> Self {
95 Self {
96 options,
97 kv_backend,
98 local_cache_invalidator: layered_cache_registry.clone(),
99 layered_cache_registry,
100 catalog_manager,
101 node_manager,
102 plugins: None,
103 procedure_executor,
104 process_manager,
105 local_file_access: LocalFileAccess::Disabled,
106 }
107 }
108
109 #[cfg(test)]
110 pub(crate) fn new_test(
111 options: &FrontendOptions,
112 meta_client: meta_client::MetaClientRef,
113 ) -> Self {
114 use cache::{build_fundamental_cache_registry, with_default_composite_cache_registry};
115 use common_meta::cache::LayeredCacheRegistryBuilder;
116 use common_meta::kv_backend::memory::MemoryKvBackend;
117
118 let kv_backend = Arc::new(MemoryKvBackend::new());
119
120 let layered_cache_builder = LayeredCacheRegistryBuilder::default();
122 let fundamental_cache_registry = build_fundamental_cache_registry(kv_backend.clone());
123 let layered_cache_registry = Arc::new(
124 with_default_composite_cache_registry(
125 layered_cache_builder.add_cache_registry(fundamental_cache_registry),
126 )
127 .unwrap()
128 .build(),
129 );
130
131 Self::new(
132 options.clone(),
133 kv_backend,
134 layered_cache_registry,
135 catalog::memory::MemoryCatalogManager::with_default_setup(),
136 Arc::new(client::client_manager::NodeClients::default()),
137 meta_client,
138 Arc::new(catalog::process_manager::ProcessManager::new(
139 "".to_string(),
140 None,
141 )),
142 )
143 }
144
145 pub fn with_local_cache_invalidator(self, cache_invalidator: CacheInvalidatorRef) -> Self {
147 Self {
148 local_cache_invalidator: cache_invalidator,
149 ..self
150 }
151 }
152
153 pub fn with_local_file_access(mut self, local_file_access: LocalFileAccess) -> Self {
154 self.local_file_access = local_file_access;
155 self
156 }
157
158 pub fn options(&self) -> &FrontendOptions {
159 &self.options
160 }
161
162 pub fn kv_backend(&self) -> &KvBackendRef {
163 &self.kv_backend
164 }
165
166 pub fn layered_cache_registry(&self) -> &LayeredCacheRegistryRef {
167 &self.layered_cache_registry
168 }
169
170 pub fn catalog_manager(&self) -> &CatalogManagerRef {
171 &self.catalog_manager
172 }
173
174 pub fn node_manager(&self) -> &NodeManagerRef {
175 &self.node_manager
176 }
177
178 pub fn procedure_executor(&self) -> &ProcedureExecutorRef {
179 &self.procedure_executor
180 }
181
182 pub fn process_manager(&self) -> &ProcessManagerRef {
183 &self.process_manager
184 }
185
186 pub fn with_plugin(self, plugins: Plugins) -> Self {
187 Self {
188 plugins: Some(plugins),
189 ..self
190 }
191 }
192
193 pub async fn try_build(self) -> Result<Instance> {
195 if let Err(reason) = self.options.write_retry.validate() {
196 return error::InvalidWriteRetryConfigSnafu { reason }.fail();
197 }
198 let kv_backend = self.kv_backend;
199 let node_manager = self.node_manager;
200 let plugins = self.plugins.unwrap_or_default();
201 let process_manager = self.process_manager;
202 let table_route_cache: TableRouteCacheRef =
203 self.layered_cache_registry
204 .get()
205 .context(error::CacheRequiredSnafu {
206 name: TABLE_ROUTE_CACHE_NAME,
207 })?;
208 let partition_info_cache: PartitionInfoCacheRef = self
209 .layered_cache_registry
210 .get()
211 .context(error::CacheRequiredSnafu {
212 name: PARTITION_INFO_CACHE_NAME,
213 })?;
214 let partition_manager = Arc::new(PartitionRuleManager::new(
215 kv_backend.clone(),
216 table_route_cache.clone(),
217 partition_info_cache.clone(),
218 ));
219
220 let local_cache_invalidator = self.local_cache_invalidator;
221
222 let mut write_dispatcher =
223 WriteDispatcher::new(node_manager.clone(), partition_manager.clone());
224 if self.options.write_retry.max_retries > 0 {
225 write_dispatcher = write_dispatcher.with_retry(
226 self.options.write_retry.clone(),
227 self.catalog_manager.clone(),
228 local_cache_invalidator.clone(),
229 );
230 }
231 let write_dispatcher = Arc::new(write_dispatcher);
232
233 let region_query_handler =
234 if let Some(factory) = plugins.get::<RegionQueryHandlerFactoryRef>() {
235 factory.build(partition_manager.clone(), node_manager.clone())
236 } else {
237 FrontendRegionQueryHandler::arc(partition_manager.clone(), node_manager.clone())
238 };
239
240 let table_flownode_cache: TableFlownodeSetCacheRef = self
241 .layered_cache_registry
242 .get()
243 .context(error::CacheRequiredSnafu {
244 name: TABLE_FLOWNODE_SET_CACHE_NAME,
245 })?;
246
247 let create_inserter = || {
248 Inserter::new(
249 self.catalog_manager.clone(),
250 partition_manager.clone(),
251 node_manager.clone(),
252 table_flownode_cache.clone(),
253 self.options.auto_create_table,
254 )
255 .with_write_dispatcher(write_dispatcher.clone())
256 };
257 let bulk_inserter = Arc::new(create_inserter());
259 let build_batcher = |options: &BatcherOptions| -> Option<Arc<dyn PendingRowsBatcher>> {
260 if !options.pending_rows_batching_enabled()
261 || (self.options.prom_store.with_metric_engine
262 && options
263 .protocols
264 .iter()
265 .all(|protocol| *protocol == BatchingProtocol::Prom))
266 {
267 return None;
268 }
269 TablePendingRowsBatcher::try_new(
270 options.pending_rows_flush_interval,
271 options.max_batch_rows,
272 options.max_concurrent_flushes,
273 options.worker_channel_capacity,
274 options.max_inflight_requests,
275 options.flow_notification_queue_capacity,
276 bulk_inserter.clone(),
277 )
278 .map(|batcher| batcher as Arc<dyn PendingRowsBatcher>)
279 };
280 let inserter = Arc::new(
281 create_inserter()
282 .with_pending_rows_batcher(build_batcher(self.options.table_batcher_options())),
283 );
284 let deleter = Arc::new(
285 Deleter::new(
286 self.catalog_manager.clone(),
287 partition_manager.clone(),
288 node_manager.clone(),
289 )
290 .with_write_dispatcher(write_dispatcher),
291 );
292 let requester = Arc::new(Requester::new(
293 self.catalog_manager.clone(),
294 partition_manager.clone(),
295 node_manager.clone(),
296 ));
297 let table_mutation_handler = Arc::new(TableMutationOperator::new(
298 inserter.clone(),
299 deleter.clone(),
300 requester,
301 ));
302
303 let table_metadata_manager = Arc::new(TableMetadataManager::new(kv_backend.clone()));
304 let procedure_service_handler = Arc::new(ProcedureServiceOperator::new(
305 self.procedure_executor.clone(),
306 self.catalog_manager.clone(),
307 table_metadata_manager.clone(),
308 ));
309
310 let flow_metadata_manager: Arc<FlowMetadataManager> =
311 Arc::new(FlowMetadataManager::new(kv_backend.clone()));
312 let flow_service = FlowServiceOperator::new(flow_metadata_manager, node_manager.clone());
313
314 let mut query_options = self.options.query.clone();
315 query_options.enable_per_region_metrics = self.options.logging.enable_per_region_metrics;
316 let query_engine = QueryEngineFactory::try_new_with_plugins(
317 self.catalog_manager.clone(),
318 Some(partition_manager.clone()),
319 Some(region_query_handler.clone()),
320 Some(table_mutation_handler),
321 Some(procedure_service_handler),
322 Some(Arc::new(flow_service)),
323 true,
324 plugins.clone(),
325 query_options,
326 )
327 .context(DataFusionSnafu)?
328 .query_engine();
329
330 if let Some(kv_catalog) = self
335 .catalog_manager
336 .as_any()
337 .downcast_ref::<KvBackendCatalogManager>()
338 {
339 let provider: EntityGraphProviderRef = Arc::new(EntityGraphProviderImpl::new(
340 query_engine.clone(),
341 Arc::downgrade(&self.catalog_manager),
342 plugins.get::<PermissionCheckerRef>(),
343 ));
344 kv_catalog.set_entity_graph_provider(provider);
345 }
346
347 let frontend_peer_addr = self.options.peer_addr();
348 let statement_executor = StatementExecutor::new(
349 self.catalog_manager.clone(),
350 query_engine.clone(),
351 self.procedure_executor,
352 kv_backend.clone(),
353 local_cache_invalidator,
354 inserter.clone(),
355 partition_manager,
356 Some(process_manager.clone()),
357 frontend_peer_addr.clone(),
358 self.local_file_access,
359 );
360
361 let statement_executor =
362 if let Some(configurator) = plugins.get::<StatementExecutorConfiguratorRef>() {
363 let ctx = ExecutorConfigureContext {
364 kv_backend: kv_backend.clone(),
365 };
366 configurator
367 .configure(statement_executor, ctx)
368 .await
369 .context(ExternalSnafu)?
370 } else {
371 statement_executor
372 };
373
374 #[cfg(feature = "enterprise")]
375 let statement_executor = if let Some(handler) = plugins.get::<CreateDatabaseHandlerRef>() {
376 statement_executor.with_create_database_handler(handler)
377 } else {
378 statement_executor
379 };
380
381 let admin_event_recorder = AdminEventRecorderHandle::default();
382 let statement_executor = statement_executor.with_admin_function_layer(Arc::new(
383 AdminFunctionRecordingLayer::new(admin_event_recorder.clone()),
384 ));
385 let statement_executor = Arc::new(statement_executor);
386
387 let pipeline_operator = Arc::new(PipelineOperator::new(
388 inserter.clone(),
389 statement_executor.clone(),
390 self.catalog_manager.clone(),
391 query_engine.clone(),
392 &self.options.pipeline,
393 ));
394
395 plugins.insert::<StatementExecutorRef>(statement_executor.clone());
396
397 let slow_query_recorder = Arc::new(EventRecorderImpl::new(Box::new(
398 EventHandlerImpl::new(statement_executor.clone(), self.options.slow_query.ttl),
399 )));
400 let event_recorder: EventRecorderRef = Arc::new(EventRecorderImpl::with_event_type_filter(
401 Box::new(EventHandlerImpl::new(
402 statement_executor.clone(),
403 self.options.event_recorder.ttl,
404 )),
405 self.options.event_recorder.event_types.clone(),
406 self.options.event_recorder.flush_interval,
407 ));
408 admin_event_recorder.install(&event_recorder);
409
410 let batcher_options = self.options.table_batcher_options();
411 let trace_aux_limiter = if batcher_options.pending_rows_batching_enabled()
412 && !pending_rows_batch_sync_enabled()
413 {
414 RequestLimiter::try_new(batcher_options.max_inflight_requests)
415 } else {
416 None
417 };
418
419 Ok(Instance {
420 logical_batcher: Default::default(),
421 frontend_peer_addr,
422 catalog_manager: self.catalog_manager,
423 pipeline_operator,
424 statement_executor,
425 query_engine,
426 plugins,
427 inserter,
428 deleter,
429 table_metadata_manager,
430 event_recorder,
431 slow_query_recorder,
432 process_manager,
433 slow_query_options: self.options.slow_query.clone(),
434 influxdb_default_merge_mode: self.options.influxdb.default_merge_mode,
435 trace_ingest_chunk_size: self.options.otlp.trace_ingest_chunk_size,
436 trace_aux_cache: TraceAuxCache::new(self.options.otlp.trace_aux_cache_size.as_bytes()),
437 trace_aux_limiter,
438 otlp_resource_info: self.options.otlp.experimental_enable_resource_info,
439 suspend: Arc::new(AtomicBool::new(false)),
440 })
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use api::v1::meta::Role;
447 use common_meta::cache_invalidator::{Context, DummyCacheInvalidator};
448 use common_meta::instruction::CacheIdent;
449 use common_meta::key::table_route::{TableRouteKey, TableRouteValue};
450 use common_meta::key::{MetadataKey, MetadataValue};
451 use common_meta::rpc::router::{Region, RegionRoute};
452 use common_meta::rpc::store::PutRequest;
453 use meta_client::client::MetaClientBuilder;
454 use store_api::storage::RegionId;
455
456 use super::*;
457
458 #[tokio::test]
459 async fn test_local_cache_invalidator() {
460 for custom_invalidator in [false, true] {
461 let mut builder = FrontendBuilder::new_test(
462 &FrontendOptions::default(),
463 Arc::new(MetaClientBuilder::new(0, Role::Frontend).build()),
464 );
465 if custom_invalidator {
466 builder = builder.with_local_cache_invalidator(Arc::new(DummyCacheInvalidator));
467 }
468 let backend = builder.kv_backend.clone();
469 let routes: TableRouteCacheRef = builder.layered_cache_registry.get().unwrap();
470 let partitions: PartitionInfoCacheRef = builder.layered_cache_registry.get().unwrap();
471 let instance = builder.try_build().await.unwrap();
472 let table_id = 1024;
473 for region_number in [1, 2] {
474 let route = TableRouteValue::physical(vec![RegionRoute {
475 region: Region {
476 id: RegionId::new(table_id, region_number),
477 ..Default::default()
478 },
479 ..Default::default()
480 }]);
481 backend
482 .put(
483 PutRequest::new()
484 .with_key(TableRouteKey::new(table_id).to_bytes())
485 .with_value(route.try_as_raw_value().unwrap()),
486 )
487 .await
488 .unwrap();
489 if region_number == 1 {
490 routes.get(table_id).await.unwrap().unwrap();
491 partitions.get(table_id).await.unwrap().unwrap();
492 }
493 }
494 assert!(routes.contains_key(&table_id));
495 assert!(partitions.contains_key(&table_id));
496
497 instance
498 .cache_invalidator()
499 .invalidate(&Context::default(), &[CacheIdent::TableId(table_id)])
500 .await
501 .unwrap();
502
503 assert_eq!(custom_invalidator, routes.contains_key(&table_id));
504 assert_eq!(custom_invalidator, partitions.contains_key(&table_id));
505 let route = routes.get(table_id).await.unwrap().unwrap();
506 let region = route.as_physical_table_route_ref().unwrap().region_routes[0]
507 .region
508 .id;
509 assert_eq!(
510 if custom_invalidator { 1 } else { 2 },
511 region.region_number()
512 );
513 }
514 }
515}