1use crate::stores::Registry;
2use clap::ValueHint::FilePath;
3use clap::{Args, Parser, Subcommand};
4use log::debug;
5use std::fs::read_to_string;
6use std::sync::mpsc::channel;
7
8#[derive(Args, Debug)]
9struct BenchArgs {
10 #[arg(short = 's')]
11 #[arg(value_hint = FilePath)]
12 #[arg(help = "Path to the key-value store's TOML config file")]
13 store_config: String,
14
15 #[arg(short = 'b')]
16 #[arg(value_hint = FilePath)]
17 #[arg(help = "Path to the benchmark's TOML config file")]
18 benchmark_config: String,
19}
20
21#[derive(Args, Debug)]
22struct ServerArgs {
23 #[arg(short = 'a', default_value = "0.0.0.0")]
24 #[arg(help = "Bind address")]
25 host: String,
26
27 #[arg(short = 'p', default_value = "9000")]
28 #[arg(help = "Bind port")]
29 port: String,
30
31 #[arg(short = 's')]
32 #[arg(value_hint = FilePath)]
33 #[arg(help = "Path to the key-value store's TOML config file")]
34 store_config: String,
35
36 #[arg(short = 'n', default_value_t = 1)]
37 #[arg(help = "Number of worker threads")]
38 workers: usize,
39}
40
41#[derive(Parser, Debug)]
42#[command(version, about)]
43struct Cli {
44 #[command(subcommand)]
45 command: Commands,
46}
47
48#[derive(Subcommand, Debug)]
49enum Commands {
50 #[command(about = "Run a benchmark")]
51 Bench(BenchArgs),
52 #[command(about = "Start a key-value server")]
53 Server(ServerArgs),
54 #[command(about = "List all registered key-value stores")]
55 List,
56}
57
58fn bench_cli(args: &BenchArgs) {
59 let opt: String = {
60 let s = args.store_config.clone();
61 let b = args.benchmark_config.clone();
62 read_to_string(s.as_str()).unwrap() + "\n" + &read_to_string(b.as_str()).unwrap()
63 };
64
65 let (map, phases) = crate::bench::init(&opt);
66 map.bench(&phases);
67}
68
69fn server_cli(args: &ServerArgs) {
70 let host = &args.host;
71 let port = &args.port;
72 let nr_workers = args.workers;
73
74 let opt: String = read_to_string(args.store_config.as_str()).unwrap();
75 let map = crate::server::init(&opt);
76
77 let (stop_tx, stop_rx) = channel();
78 let (grace_tx, grace_rx) = channel();
79
80 ctrlc::set_handler(move || {
81 assert!(stop_tx.send(()).is_ok());
82 debug!("SIGINT received and stop message sent to server");
83 })
84 .expect("Error setting Ctrl-C handler for server");
85
86 map.server(&host, &port, nr_workers, stop_rx, grace_tx);
87
88 assert!(grace_rx.recv().is_ok());
89 debug!("All server threads have been shut down gracefully, exit");
90}
91
92fn list_cli() {
93 for r in inventory::iter::<Registry> {
94 println!("Registered map: {}", r.name);
95 }
96}
97
98pub fn cmdline() {
149 env_logger::init();
150 let cli = Cli::parse();
151 debug!("Starting kvbench with args: {:?}", cli);
152 match cli.command {
153 Commands::Bench(args) => bench_cli(&args),
154 Commands::Server(args) => server_cli(&args),
155 Commands::List => list_cli(),
156 }
157}