blob: 5706a3260196c51e09c16007f7fc2ca2f9f1f724 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#![allow(clippy::future_not_send)]
mod args;
use args::Args;
use clap::Parser;
use configs::server::ServerConfig;
use server::boot::{apply_default_root_credentials, bootstrap, load_config, prepare_runtime_dirs};
use server::server_error::ServerError;
use server_common::log::Logging;
use system_stats::capture_allowed_cpus;
use tracing::{error, info};
fn main() -> Result<(), ServerError> {
// This prelude must stay ahead of the first thread the process ever
// spawns: `--with-default-root-credentials` writes to the environment,
// and `set_var` is only sound while single-threaded. `early_init` just
// installs the tracing registry (buffered until `late_init`) and starts
// no worker of its own, so it can run here and make the warnings below
// visible. `create_shard_executor` also reads its capacity knob from the
// environment, which is why the `.env` load has to precede it.
let args = Args::parse();
// `logging` owns the tracing appender worker guards; it must outlive the
// shard threads or every log line after bootstrap is silently dropped.
let mut logging = Logging::new(server::VERSION);
logging.early_init();
server_common::print_build_info!(server::VERSION);
#[cfg(all(feature = "mimalloc", not(feature = "disable-mimalloc")))]
info!("Using mimalloc allocator");
#[cfg(not(all(feature = "mimalloc", not(feature = "disable-mimalloc"))))]
tracing::warn!("Using the default system allocator");
if let Ok(env_path) = std::env::var("IGGY_ENV_PATH") {
let _ = dotenvy::from_path(&env_path);
} else {
let _ = dotenvy::dotenv();
}
// SAFETY: no thread has been spawned yet, see the comment above.
unsafe { apply_default_root_credentials(args.with_default_root_credentials) };
// Before shard threads pin themselves: a pinned capture sees one core.
capture_allowed_cpus();
let bootstrap_runtime = match server_common::create_shard_executor() {
Ok(rt) => rt,
Err(e) => {
let e = server_common::diagnostics::enrich_runtime_create_error(e);
panic!("Cannot create server bootstrap executor: {e}");
}
};
// Bootstrap on a temporary runtime: load config, prepare the data
// directory, init the memory pool. Then drop the runtime and spawn the
// per-shard runtimes - each shard thread builds its OWN
// `compio::runtime::Runtime` via `create_shard_executor`, pinned to
// its CPU.
let bootstrap_result: Result<ServerConfig, ServerError> = bootstrap_runtime.block_on(async {
let config = load_config().await?;
prepare_runtime_dirs(&config, &mut logging, args.fresh).await?;
let memory_pool_settings =
server_common::MemoryPoolSettings::from(&config.system.memory_pool);
server_common::MemoryPool::init_pool(&memory_pool_settings);
Ok(config)
});
let config = bootstrap_result?;
drop(bootstrap_runtime);
let shards = bootstrap(config, args.replica_id)?;
if let Err(error) = shards.install_ctrlc_handler() {
// Without a working SIGINT handler the server has no way to
// observe an operator Ctrl-C and the shutdown flag would never
// flip, leaving shard threads parked indefinitely. Fail fast
// rather than boot into an un-killable state.
error!(error = %error, "failed to install Ctrl-C handler; aborting boot");
std::process::exit(1);
}
info!("server running; waiting on shard threads");
let joined = shards.join_all();
#[cfg(feature = "systemd")]
if let Err(error) = &joined {
server::boot::systemd::notify_shutdown_failure(error);
}
joined?;
info!("server shutdown complete");
Ok(())
}