1#![recursion_limit = "256"]
16#![doc = include_str!("../../../../README.md")]
17
18use clap::{Parser, Subcommand};
19use cmd::datanode::builder::InstanceBuilder;
20#[cfg(unix)]
21use cmd::error::DaemonizeSnafu;
22use cmd::error::{InitTlsProviderSnafu, Result};
23use cmd::options::GlobalOptions;
24use cmd::{App, cli, datanode, flownode, frontend, metasrv, standalone, user};
25use common_base::Plugins;
26use common_version::{product_name, verbose_version, version};
27use servers::install_default_crypto_provider;
28
29#[derive(Parser)]
30#[command(name = product_name(), author, version, long_version = verbose_version(), about)]
31#[command(propagate_version = true)]
32pub(crate) struct Command {
33 #[clap(subcommand)]
34 pub(crate) subcmd: SubCommand,
35
36 #[clap(flatten)]
37 pub(crate) global_options: GlobalOptions,
38}
39
40#[derive(Subcommand)]
41enum SubCommand {
42 #[clap(name = "datanode")]
44 Datanode(datanode::Command),
45
46 #[clap(name = "flownode")]
48 Flownode(flownode::Command),
49
50 #[clap(name = "frontend")]
52 Frontend(frontend::Command),
53
54 #[clap(name = "metasrv")]
56 Metasrv(metasrv::Command),
57
58 #[clap(name = "standalone")]
60 Standalone(standalone::Command),
61
62 #[clap(name = "cli")]
64 Cli(cli::Command),
65
66 #[clap(name = "user")]
68 User(user::Command),
69}
70
71#[cfg(not(windows))]
72#[global_allocator]
73static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
74
75#[cfg(debug_assertions)]
76fn main() -> Result<()> {
77 use snafu::ResultExt;
78
79 let cli = Command::parse();
80 maybe_daemonize(&cli)?;
81
82 std::thread::Builder::new()
86 .name("main_spawn".to_string())
87 .stack_size(8 * 1024 * 1024)
88 .spawn(move || {
89 {
90 tokio::runtime::Builder::new_multi_thread()
91 .thread_stack_size(8 * 1024 * 1024)
92 .enable_all()
93 .build()
94 .expect("Failed building the Runtime")
95 .block_on(main_body(cli))
96 }
97 })
98 .context(cmd::error::SpawnThreadSnafu)?
99 .join()
100 .expect("Couldn't join on the associated thread")
101}
102
103#[cfg(not(debug_assertions))]
104fn main() -> Result<()> {
105 let cli = Command::parse();
106 maybe_daemonize(&cli)?;
107
108 tokio::runtime::Builder::new_multi_thread()
109 .enable_all()
110 .build()
111 .expect("Failed building the Runtime")
112 .block_on(main_body(cli))
113}
114
115async fn main_body(cli: Command) -> Result<()> {
116 setup_human_panic();
117 install_default_crypto_provider().map_err(|msg| InitTlsProviderSnafu { msg }.build())?;
118 start(cli).await
119}
120
121fn maybe_daemonize(cli: &Command) -> Result<()> {
125 let daemon = matches!(&cli.subcmd, SubCommand::Standalone(cmd) if cmd.is_daemon());
126 if !daemon {
127 return Ok(());
128 }
129
130 #[cfg(unix)]
131 {
132 let cwd = std::env::current_dir().map_err(|e| {
133 DaemonizeSnafu {
134 msg: format!("failed to read current working directory: {e}"),
135 }
136 .build()
137 })?;
138
139 daemonize::Daemonize::new()
140 .working_directory(cwd)
141 .start()
142 .map_err(|e| {
143 DaemonizeSnafu {
144 msg: format!("failed to daemonize: {e}"),
145 }
146 .build()
147 })?;
148 }
149
150 Ok(())
151}
152
153async fn start(cli: Command) -> Result<()> {
154 match cli.subcmd {
155 SubCommand::Datanode(cmd) => match cmd.subcmd {
156 datanode::SubCommand::Start(ref start) => {
157 let opts = start.load_options(&cli.global_options)?;
158 let plugins = Plugins::new();
159 let builder = InstanceBuilder::try_new_with_init(opts, plugins).await?;
160 cmd.build_with(builder).await?.run().await
161 }
162 datanode::SubCommand::Objbench(ref bench) => bench.run().await,
163 datanode::SubCommand::Scanbench(ref bench) => bench.run().await,
164 datanode::SubCommand::Parquetbench(ref bench) => bench.run().await,
165 #[cfg(feature = "dev-tools")]
166 datanode::SubCommand::ParquetMeta(ref cmd) => cmd.run().await,
167 #[cfg(feature = "dev-tools")]
168 datanode::SubCommand::ParquetRewrite(ref cmd) => cmd.run().await,
169 #[cfg(feature = "dev-tools")]
170 datanode::SubCommand::SstReplace(ref cmd) => cmd.run().await,
171 },
172 SubCommand::Flownode(cmd) => {
173 cmd.build(cmd.load_options(&cli.global_options)?)
174 .await?
175 .run()
176 .await
177 }
178 SubCommand::Frontend(cmd) => {
179 cmd.build(cmd.load_options(&cli.global_options)?)
180 .await?
181 .run()
182 .await
183 }
184 SubCommand::Metasrv(cmd) => {
185 cmd.build(cmd.load_options(&cli.global_options)?)
186 .await?
187 .run()
188 .await
189 }
190 SubCommand::Standalone(cmd) => {
191 cmd.build(cmd.load_options(&cli.global_options)?)
192 .await?
193 .run()
194 .await
195 }
196 SubCommand::Cli(cmd) => {
197 cmd.build(cmd.load_options(&cli.global_options)?)
198 .await?
199 .run()
200 .await
201 }
202 SubCommand::User(cmd) => cmd.run(),
203 }
204}
205
206fn setup_human_panic() {
207 human_panic::setup_panic!(
208 human_panic::Metadata::new(product_name(), version())
209 .homepage("https://github.com/GreptimeTeam/greptimedb/discussions")
210 );
211
212 common_telemetry::set_panic_hook();
213}