Skip to main content

tests_integration/
standalone.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::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    /// Storage engine for assertions across protocol and storage boundaries.
64    pub mito_engine: mito2::engine::MitoEngine,
65    /// Owns the region server and the log store, so a test can shut them down.
66    pub datanode: Datanode,
67    pub frontend: Arc<Frontend>,
68    pub opts: StandaloneOptions,
69    pub guard: TestGuard,
70    // Used in rebuild.
71    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            // Enable slow query log with 1s threshold by default for integration tests.
106            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    /// Overrides the Mito configuration for this test instance.
121    #[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    /// Enables experimental Metric export for the standalone test instance.
128    #[must_use]
129    pub fn with_experimental_metric_export(mut self) -> Self {
130        self.experimental_metric_export = true;
131        self
132    }
133
134    /// Configures ordinary-table batching for protocol integration tests.
135    #[must_use]
136    pub fn with_table_batcher(mut self, options: BatcherOptions) -> Self {
137        self.table_batcher = options;
138        self
139    }
140
141    /// Configures logical-table batching for integration tests.
142    #[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    /// Sets the event recorder options for the standalone instance.
155    #[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        // set the frontend client for flownode
338        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            // Tests cover the descriptor, so they run with it enabled.
407            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}