1use std::sync::Arc;
16use std::time::Duration;
17
18use cache::{
19 build_datanode_layered_cache_registry, build_fundamental_cache_registry,
20 with_default_composite_cache_registry,
21};
22use catalog::information_schema::NoopInformationExtension;
23use catalog::kvbackend::KvBackendCatalogManagerBuilder;
24use catalog::process_manager::ProcessManager;
25use common_base::Plugins;
26use common_catalog::consts::{MIN_USER_FLOW_ID, MIN_USER_TABLE_ID};
27use common_config::KvBackendConfig;
28use common_datasource::object_store::LocalFileAccess;
29use common_event_recorder::EventRecorderOptions;
30use common_meta::cache::LayeredCacheRegistryBuilder;
31use common_meta::ddl::flow_meta::FlowMetadataAllocator;
32use common_meta::ddl::table_meta::TableMetadataAllocator;
33use common_meta::ddl::{DdlContext, NoopRegionFailureDetectorControl};
34use common_meta::ddl_manager::DdlManager;
35use common_meta::key::TableMetadataManager;
36use common_meta::key::flow::FlowMetadataManager;
37use common_meta::kv_backend::KvBackendRef;
38use common_meta::procedure_executor::LocalProcedureExecutor;
39use common_meta::region_keeper::MemoryRegionKeeper;
40use common_meta::region_registry::LeaderRegionRegistry;
41use common_meta::sequence::SequenceBuilder;
42use common_procedure::ProcedureManagerRef;
43use common_procedure::local::EventRecorderHandle;
44use common_procedure::options::ProcedureConfig;
45use common_telemetry::logging::SlowQueryOptions;
46use common_test_util::find_workspace_path;
47use common_wal::config::DatanodeWalConfig;
48use datanode::datanode::{Datanode, DatanodeBuilder};
49use flow::{FlownodeBuilder, FrontendClient, GrpcQueryHandlerWithBoxedError};
50use frontend::frontend::Frontend;
51use frontend::instance::Instance;
52use frontend::instance::builder::FrontendBuilder;
53use frontend::server::Services;
54use frontend::service_config::{BatcherOptions, PendingRowsBatcherOptions};
55use meta_srv::metasrv::{FLOW_ID_SEQ, TABLE_ID_SEQ};
56use servers::grpc::GrpcOptions;
57use standalone::options::StandaloneOptions;
58use standalone::{StandaloneDatanodeManager, StandaloneRepartitionProcedureFactory};
59
60use crate::test_util::{self, StorageType, TestGuard, create_tmp_dir_and_datanode_opts};
61
62pub struct GreptimeDbStandalone {
63 pub mito_engine: mito2::engine::MitoEngine,
65 pub datanode: Datanode,
67 pub frontend: Arc<Frontend>,
68 pub opts: StandaloneOptions,
69 pub guard: TestGuard,
70 pub kv_backend: KvBackendRef,
72 pub procedure_manager: ProcedureManagerRef,
73 pub event_recorder_handle: EventRecorderHandle,
74}
75
76impl GreptimeDbStandalone {
77 pub fn fe_instance(&self) -> &Arc<Instance> {
78 &self.frontend.instance
79 }
80}
81
82pub struct GreptimeDbStandaloneBuilder {
83 instance_name: String,
84 datanode_wal_config: DatanodeWalConfig,
85 store_providers: Option<Vec<StorageType>>,
86 default_store: Option<StorageType>,
87 plugin: Option<Plugins>,
88 slow_query_options: SlowQueryOptions,
89 event_recorder_options: EventRecorderOptions,
90 auto_create_table: bool,
91 experimental_metric_export: bool,
92 logical_batcher: Option<BatcherOptions>,
93 table_batcher: BatcherOptions,
94 mito_config: Option<mito2::config::MitoConfig>,
95}
96
97impl GreptimeDbStandaloneBuilder {
98 pub fn new(instance_name: &str) -> Self {
99 Self {
100 instance_name: instance_name.to_string(),
101 store_providers: None,
102 plugin: None,
103 default_store: None,
104 datanode_wal_config: DatanodeWalConfig::default(),
105 slow_query_options: SlowQueryOptions {
107 enable: true,
108 threshold: Duration::from_secs(1),
109 ..Default::default()
110 },
111 event_recorder_options: EventRecorderOptions::default(),
112 auto_create_table: true,
113 experimental_metric_export: false,
114 logical_batcher: None,
115 table_batcher: BatcherOptions::default(),
116 mito_config: None,
117 }
118 }
119
120 #[must_use]
122 pub fn with_mito_config(mut self, config: mito2::config::MitoConfig) -> Self {
123 self.mito_config = Some(config);
124 self
125 }
126
127 #[must_use]
129 pub fn with_experimental_metric_export(mut self) -> Self {
130 self.experimental_metric_export = true;
131 self
132 }
133
134 #[must_use]
136 pub fn with_table_batcher(mut self, options: BatcherOptions) -> Self {
137 self.table_batcher = options;
138 self
139 }
140
141 #[must_use]
143 pub fn with_logical_batcher(mut self, options: BatcherOptions) -> Self {
144 self.logical_batcher = Some(options);
145 self
146 }
147
148 #[must_use]
149 pub fn with_auto_create_table(mut self, auto_create_table: bool) -> Self {
150 self.auto_create_table = auto_create_table;
151 self
152 }
153
154 #[must_use]
156 pub fn with_event_recorder_options(
157 mut self,
158 event_recorder_options: EventRecorderOptions,
159 ) -> Self {
160 self.event_recorder_options = event_recorder_options;
161 self
162 }
163
164 #[must_use]
165 pub fn with_default_store_type(self, store_type: StorageType) -> Self {
166 Self {
167 default_store: Some(store_type),
168 ..self
169 }
170 }
171
172 #[cfg(test)]
173 #[must_use]
174 pub fn with_store_providers(self, store_providers: Vec<StorageType>) -> Self {
175 Self {
176 store_providers: Some(store_providers),
177 ..self
178 }
179 }
180
181 #[must_use]
182 pub fn with_plugin(self, plugin: Plugins) -> Self {
183 Self {
184 plugin: Some(plugin),
185 ..self
186 }
187 }
188
189 #[must_use]
190 pub fn with_slow_query_threshold(mut self, threshold: Duration) -> Self {
191 self.slow_query_options.threshold = threshold;
192 self
193 }
194
195 #[must_use]
196 pub fn with_datanode_wal_config(mut self, datanode_wal_config: DatanodeWalConfig) -> Self {
197 self.datanode_wal_config = datanode_wal_config;
198 self
199 }
200
201 pub async fn build_with(
202 &self,
203 kv_backend: KvBackendRef,
204 guard: TestGuard,
205 opts: StandaloneOptions,
206 procedure_manager: ProcedureManagerRef,
207 event_recorder_handle: EventRecorderHandle,
208 register_procedure_loaders: bool,
209 ) -> GreptimeDbStandalone {
210 let plugins = self.plugin.clone().unwrap_or_default();
211
212 let layered_cache_registry =
213 Arc::new(build_datanode_layered_cache_registry(kv_backend.clone()));
214
215 let mut builder =
216 DatanodeBuilder::new(opts.datanode_options(), plugins.clone(), kv_backend.clone());
217 let local_file_access = LocalFileAccess::sandboxed(find_workspace_path(".")).unwrap();
218 builder.with_cache_registry(layered_cache_registry);
219 builder.with_local_file_access(local_file_access.clone());
220 let datanode = builder.build().await.unwrap();
221
222 let table_metadata_manager = Arc::new(TableMetadataManager::new(kv_backend.clone()));
223 table_metadata_manager.init().await.unwrap();
224
225 let flow_metadata_manager = Arc::new(FlowMetadataManager::new(kv_backend.clone()));
226
227 let layered_cache_builder = LayeredCacheRegistryBuilder::default();
228 let fundamental_cache_registry = build_fundamental_cache_registry(kv_backend.clone());
229 let cache_registry = Arc::new(
230 with_default_composite_cache_registry(
231 layered_cache_builder.add_cache_registry(fundamental_cache_registry),
232 )
233 .unwrap()
234 .build(),
235 );
236
237 let catalog_manager = KvBackendCatalogManagerBuilder::new(
238 Arc::new(NoopInformationExtension),
239 kv_backend.clone(),
240 cache_registry.clone(),
241 )
242 .with_procedure_manager(procedure_manager.clone())
243 .build();
244
245 let (frontend_client, frontend_instance_handler) =
246 FrontendClient::from_empty_grpc_handler(opts.query.clone());
247 let flow_builder = FlownodeBuilder::new(
248 Default::default(),
249 plugins.clone(),
250 table_metadata_manager.clone(),
251 catalog_manager.clone(),
252 flow_metadata_manager.clone(),
253 Arc::new(frontend_client),
254 );
255 let flownode = Arc::new(flow_builder.build().await.unwrap());
256
257 let node_manager = Arc::new(StandaloneDatanodeManager {
258 region_server: datanode.region_server(),
259 flow_server: flownode.flow_engine(),
260 });
261
262 let table_id_allocator = Arc::new(
263 SequenceBuilder::new(TABLE_ID_SEQ, kv_backend.clone())
264 .initial(MIN_USER_TABLE_ID as u64)
265 .step(10)
266 .build(),
267 );
268 let flow_id_sequence = Arc::new(
269 SequenceBuilder::new(FLOW_ID_SEQ, kv_backend.clone())
270 .initial(MIN_USER_FLOW_ID as u64)
271 .step(10)
272 .build(),
273 );
274 let wal_provider = cmd::standalone::build_standalone_wal_provider(
275 &opts.wal,
276 opts.datanode_options().node_id,
277 kv_backend.clone(),
278 )
279 .await
280 .unwrap();
281 let wal_provider = Arc::new(wal_provider);
282 let table_metadata_allocator = Arc::new(TableMetadataAllocator::new(
283 table_id_allocator,
284 wal_provider.clone(),
285 ));
286 let flow_metadata_allocator = Arc::new(FlowMetadataAllocator::with_noop_peer_allocator(
287 flow_id_sequence,
288 ));
289
290 let repartition_procedure_factory = Arc::new(StandaloneRepartitionProcedureFactory);
291 let ddl_manager = Arc::new(DdlManager::new(
292 DdlContext {
293 node_manager: node_manager.clone(),
294 cache_invalidator: cache_registry.clone(),
295 memory_region_keeper: Arc::new(MemoryRegionKeeper::default()),
296 leader_region_registry: Arc::new(LeaderRegionRegistry::default()),
297 table_metadata_manager,
298 table_metadata_allocator,
299 flow_metadata_manager,
300 flow_metadata_allocator,
301 region_failure_detector_controller: Arc::new(NoopRegionFailureDetectorControl),
302 soft_drop_enabled: false,
303 soft_drop_retention: None,
304 create_database_metadata_committer: None,
305 },
306 procedure_manager.clone(),
307 repartition_procedure_factory,
308 ));
309 if register_procedure_loaders {
310 ddl_manager.register_loaders().unwrap();
311 }
312 let procedure_executor = Arc::new(LocalProcedureExecutor::new(
313 ddl_manager,
314 procedure_manager.clone(),
315 ));
316
317 let server_addr = opts.frontend_options().grpc.server_addr.clone();
318
319 let instance = FrontendBuilder::new(
320 opts.frontend_options(),
321 kv_backend.clone(),
322 cache_registry.clone(),
323 catalog_manager.clone(),
324 node_manager.clone(),
325 procedure_executor.clone(),
326 Arc::new(ProcessManager::new(server_addr, None)),
327 )
328 .with_local_file_access(local_file_access)
329 .with_plugin(plugins.clone())
330 .try_build()
331 .await
332 .unwrap();
333 let instance = Arc::new(instance);
334
335 event_recorder_handle.install(instance.event_recorder());
336
337 let grpc_handler = instance.clone() as Arc<dyn GrpcQueryHandlerWithBoxedError>;
339 let weak_grpc_handler = Arc::downgrade(&grpc_handler);
340 frontend_instance_handler
341 .set_handler(weak_grpc_handler)
342 .await;
343 procedure_manager.start().await.unwrap();
344 wal_provider.start().await.unwrap();
345
346 test_util::prepare_another_catalog_and_schema(&instance).await;
347
348 let servers = Services::new(opts.clone(), instance.clone(), plugins)
349 .build()
350 .unwrap();
351 let frontend = Frontend {
352 instance,
353 servers,
354 heartbeat_task: None,
355 };
356
357 GreptimeDbStandalone {
358 mito_engine: datanode.region_server().mito_engine().unwrap(),
359 datanode,
360 frontend: Arc::new(frontend),
361 opts,
362 guard,
363 kv_backend,
364 procedure_manager,
365 event_recorder_handle,
366 }
367 }
368
369 pub async fn build(&self) -> GreptimeDbStandalone {
370 let default_store_type = self.default_store.unwrap_or(StorageType::File);
371 let store_types = self.store_providers.clone().unwrap_or_default();
372
373 let (opts, guard) = create_tmp_dir_and_datanode_opts(
374 default_store_type,
375 store_types,
376 &self.instance_name,
377 self.datanode_wal_config.clone(),
378 Default::default(),
379 );
380
381 let kv_backend_config = KvBackendConfig::default();
382 let procedure_config = ProcedureConfig::default();
383
384 let kv_backend = standalone::build_metadata_kvbackend(
385 format!("{}/kv", opts.storage.data_home),
386 kv_backend_config,
387 )
388 .unwrap();
389 let (procedure_manager, event_recorder_handle) =
390 standalone::build_procedure_manager(kv_backend.clone(), procedure_config);
391
392 let mut standalone_opts = StandaloneOptions {
393 storage: opts.storage,
394 procedure: procedure_config,
395 metadata_store: kv_backend_config,
396 wal: opts.wal,
397 grpc: GrpcOptions::default().with_server_addr("127.0.0.1:4001"),
398 slow_query: self.slow_query_options.clone(),
399 event_recorder: self.event_recorder_options.clone(),
400 auto_create_table: self.auto_create_table,
401 experimental_metric_export: self.experimental_metric_export,
402 pending_rows_batcher: PendingRowsBatcherOptions {
403 logical_table: self.logical_batcher.clone(),
404 table: self.table_batcher.clone(),
405 },
406 otlp: frontend::service_config::OtlpOptions {
408 experimental_enable_resource_info: true,
409 ..Default::default()
410 },
411 ..StandaloneOptions::default()
412 };
413
414 if let Some(config) = &self.mito_config {
415 for engine in &mut standalone_opts.region_engine {
416 if let datanode::config::RegionEngineConfig::Mito(mito) = engine {
417 *mito = config.clone();
418 }
419 }
420 }
421
422 self.build_with(
423 kv_backend,
424 guard,
425 standalone_opts,
426 procedure_manager,
427 event_recorder_handle,
428 true,
429 )
430 .await
431 }
432}