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 logical_batcher: Option<BatcherOptions>,
92 table_batcher: BatcherOptions,
93 mito_config: Option<mito2::config::MitoConfig>,
94}
95
96impl GreptimeDbStandaloneBuilder {
97 pub fn new(instance_name: &str) -> Self {
98 Self {
99 instance_name: instance_name.to_string(),
100 store_providers: None,
101 plugin: None,
102 default_store: None,
103 datanode_wal_config: DatanodeWalConfig::default(),
104 slow_query_options: SlowQueryOptions {
106 enable: true,
107 threshold: Duration::from_secs(1),
108 ..Default::default()
109 },
110 event_recorder_options: EventRecorderOptions::default(),
111 auto_create_table: true,
112 logical_batcher: None,
113 table_batcher: BatcherOptions::default(),
114 mito_config: None,
115 }
116 }
117
118 #[must_use]
120 pub fn with_mito_config(mut self, config: mito2::config::MitoConfig) -> Self {
121 self.mito_config = Some(config);
122 self
123 }
124
125 #[must_use]
127 pub fn with_table_batcher(mut self, options: BatcherOptions) -> Self {
128 self.table_batcher = options;
129 self
130 }
131
132 #[must_use]
134 pub fn with_logical_batcher(mut self, options: BatcherOptions) -> Self {
135 self.logical_batcher = Some(options);
136 self
137 }
138
139 #[must_use]
140 pub fn with_auto_create_table(mut self, auto_create_table: bool) -> Self {
141 self.auto_create_table = auto_create_table;
142 self
143 }
144
145 #[must_use]
147 pub fn with_event_recorder_options(
148 mut self,
149 event_recorder_options: EventRecorderOptions,
150 ) -> Self {
151 self.event_recorder_options = event_recorder_options;
152 self
153 }
154
155 #[must_use]
156 pub fn with_default_store_type(self, store_type: StorageType) -> Self {
157 Self {
158 default_store: Some(store_type),
159 ..self
160 }
161 }
162
163 #[cfg(test)]
164 #[must_use]
165 pub fn with_store_providers(self, store_providers: Vec<StorageType>) -> Self {
166 Self {
167 store_providers: Some(store_providers),
168 ..self
169 }
170 }
171
172 #[must_use]
173 pub fn with_plugin(self, plugin: Plugins) -> Self {
174 Self {
175 plugin: Some(plugin),
176 ..self
177 }
178 }
179
180 #[must_use]
181 pub fn with_slow_query_threshold(mut self, threshold: Duration) -> Self {
182 self.slow_query_options.threshold = threshold;
183 self
184 }
185
186 #[must_use]
187 pub fn with_datanode_wal_config(mut self, datanode_wal_config: DatanodeWalConfig) -> Self {
188 self.datanode_wal_config = datanode_wal_config;
189 self
190 }
191
192 pub async fn build_with(
193 &self,
194 kv_backend: KvBackendRef,
195 guard: TestGuard,
196 opts: StandaloneOptions,
197 procedure_manager: ProcedureManagerRef,
198 event_recorder_handle: EventRecorderHandle,
199 register_procedure_loaders: bool,
200 ) -> GreptimeDbStandalone {
201 let plugins = self.plugin.clone().unwrap_or_default();
202
203 let layered_cache_registry =
204 Arc::new(build_datanode_layered_cache_registry(kv_backend.clone()));
205
206 let mut builder =
207 DatanodeBuilder::new(opts.datanode_options(), plugins.clone(), kv_backend.clone());
208 let local_file_access = LocalFileAccess::sandboxed(find_workspace_path(".")).unwrap();
209 builder.with_cache_registry(layered_cache_registry);
210 builder.with_local_file_access(local_file_access.clone());
211 let datanode = builder.build().await.unwrap();
212
213 let table_metadata_manager = Arc::new(TableMetadataManager::new(kv_backend.clone()));
214 table_metadata_manager.init().await.unwrap();
215
216 let flow_metadata_manager = Arc::new(FlowMetadataManager::new(kv_backend.clone()));
217
218 let layered_cache_builder = LayeredCacheRegistryBuilder::default();
219 let fundamental_cache_registry = build_fundamental_cache_registry(kv_backend.clone());
220 let cache_registry = Arc::new(
221 with_default_composite_cache_registry(
222 layered_cache_builder.add_cache_registry(fundamental_cache_registry),
223 )
224 .unwrap()
225 .build(),
226 );
227
228 let catalog_manager = KvBackendCatalogManagerBuilder::new(
229 Arc::new(NoopInformationExtension),
230 kv_backend.clone(),
231 cache_registry.clone(),
232 )
233 .with_procedure_manager(procedure_manager.clone())
234 .build();
235
236 let (frontend_client, frontend_instance_handler) =
237 FrontendClient::from_empty_grpc_handler(opts.query.clone());
238 let flow_builder = FlownodeBuilder::new(
239 Default::default(),
240 plugins.clone(),
241 table_metadata_manager.clone(),
242 catalog_manager.clone(),
243 flow_metadata_manager.clone(),
244 Arc::new(frontend_client),
245 );
246 let flownode = Arc::new(flow_builder.build().await.unwrap());
247
248 let node_manager = Arc::new(StandaloneDatanodeManager {
249 region_server: datanode.region_server(),
250 flow_server: flownode.flow_engine(),
251 });
252
253 let table_id_allocator = Arc::new(
254 SequenceBuilder::new(TABLE_ID_SEQ, kv_backend.clone())
255 .initial(MIN_USER_TABLE_ID as u64)
256 .step(10)
257 .build(),
258 );
259 let flow_id_sequence = Arc::new(
260 SequenceBuilder::new(FLOW_ID_SEQ, kv_backend.clone())
261 .initial(MIN_USER_FLOW_ID as u64)
262 .step(10)
263 .build(),
264 );
265 let wal_provider = cmd::standalone::build_standalone_wal_provider(
266 &opts.wal,
267 opts.datanode_options().node_id,
268 kv_backend.clone(),
269 )
270 .await
271 .unwrap();
272 let wal_provider = Arc::new(wal_provider);
273 let table_metadata_allocator = Arc::new(TableMetadataAllocator::new(
274 table_id_allocator,
275 wal_provider.clone(),
276 ));
277 let flow_metadata_allocator = Arc::new(FlowMetadataAllocator::with_noop_peer_allocator(
278 flow_id_sequence,
279 ));
280
281 let repartition_procedure_factory = Arc::new(StandaloneRepartitionProcedureFactory);
282 let ddl_manager = Arc::new(DdlManager::new(
283 DdlContext {
284 node_manager: node_manager.clone(),
285 cache_invalidator: cache_registry.clone(),
286 memory_region_keeper: Arc::new(MemoryRegionKeeper::default()),
287 leader_region_registry: Arc::new(LeaderRegionRegistry::default()),
288 table_metadata_manager,
289 table_metadata_allocator,
290 flow_metadata_manager,
291 flow_metadata_allocator,
292 region_failure_detector_controller: Arc::new(NoopRegionFailureDetectorControl),
293 soft_drop_enabled: false,
294 soft_drop_retention: None,
295 create_database_metadata_committer: None,
296 },
297 procedure_manager.clone(),
298 repartition_procedure_factory,
299 ));
300 if register_procedure_loaders {
301 ddl_manager.register_loaders().unwrap();
302 }
303 let procedure_executor = Arc::new(LocalProcedureExecutor::new(
304 ddl_manager,
305 procedure_manager.clone(),
306 ));
307
308 let server_addr = opts.frontend_options().grpc.server_addr.clone();
309
310 let instance = FrontendBuilder::new(
311 opts.frontend_options(),
312 kv_backend.clone(),
313 cache_registry.clone(),
314 catalog_manager.clone(),
315 node_manager.clone(),
316 procedure_executor.clone(),
317 Arc::new(ProcessManager::new(server_addr, None)),
318 )
319 .with_local_file_access(local_file_access)
320 .with_plugin(plugins.clone())
321 .try_build()
322 .await
323 .unwrap();
324 let instance = Arc::new(instance);
325
326 event_recorder_handle.install(instance.event_recorder());
327
328 let grpc_handler = instance.clone() as Arc<dyn GrpcQueryHandlerWithBoxedError>;
330 let weak_grpc_handler = Arc::downgrade(&grpc_handler);
331 frontend_instance_handler
332 .set_handler(weak_grpc_handler)
333 .await;
334 procedure_manager.start().await.unwrap();
335 wal_provider.start().await.unwrap();
336
337 test_util::prepare_another_catalog_and_schema(&instance).await;
338
339 let servers = Services::new(opts.clone(), instance.clone(), plugins)
340 .build()
341 .unwrap();
342 let frontend = Frontend {
343 instance,
344 servers,
345 heartbeat_task: None,
346 };
347
348 GreptimeDbStandalone {
349 mito_engine: datanode.region_server().mito_engine().unwrap(),
350 datanode,
351 frontend: Arc::new(frontend),
352 opts,
353 guard,
354 kv_backend,
355 procedure_manager,
356 event_recorder_handle,
357 }
358 }
359
360 pub async fn build(&self) -> GreptimeDbStandalone {
361 let default_store_type = self.default_store.unwrap_or(StorageType::File);
362 let store_types = self.store_providers.clone().unwrap_or_default();
363
364 let (opts, guard) = create_tmp_dir_and_datanode_opts(
365 default_store_type,
366 store_types,
367 &self.instance_name,
368 self.datanode_wal_config.clone(),
369 Default::default(),
370 );
371
372 let kv_backend_config = KvBackendConfig::default();
373 let procedure_config = ProcedureConfig::default();
374
375 let kv_backend = standalone::build_metadata_kvbackend(
376 format!("{}/kv", opts.storage.data_home),
377 kv_backend_config,
378 )
379 .unwrap();
380 let (procedure_manager, event_recorder_handle) =
381 standalone::build_procedure_manager(kv_backend.clone(), procedure_config);
382
383 let mut standalone_opts = StandaloneOptions {
384 storage: opts.storage,
385 procedure: procedure_config,
386 metadata_store: kv_backend_config,
387 wal: opts.wal,
388 grpc: GrpcOptions::default().with_server_addr("127.0.0.1:4001"),
389 slow_query: self.slow_query_options.clone(),
390 event_recorder: self.event_recorder_options.clone(),
391 auto_create_table: self.auto_create_table,
392 pending_rows_batcher: PendingRowsBatcherOptions {
393 logical_table: self.logical_batcher.clone(),
394 table: self.table_batcher.clone(),
395 },
396 otlp: frontend::service_config::OtlpOptions {
398 experimental_enable_resource_info: true,
399 ..Default::default()
400 },
401 ..StandaloneOptions::default()
402 };
403
404 if let Some(config) = &self.mito_config {
405 for engine in &mut standalone_opts.region_engine {
406 if let datanode::config::RegionEngineConfig::Mito(mito) = engine {
407 *mito = config.clone();
408 }
409 }
410 }
411
412 self.build_with(
413 kv_backend,
414 guard,
415 standalone_opts,
416 procedure_manager,
417 event_recorder_handle,
418 true,
419 )
420 .await
421 }
422}