1use std::time::Instant;
2
3use clap::Parser;
4use miette::IntoDiagnostic;
5use naming::{GetFlags, dynamic_naming_factory};
6use tracing::Level;
7use twizzler::object::{MapFlags, ObjID};
8
9#[derive(clap::Args, Clone, Debug)]
10struct TrailingArgs {
11 #[arg(
12 help("List of names or object IDs"),
13 trailing_var_arg = true,
14 allow_hyphen_values = true
15 )]
16 args: Vec<String>,
17}
18
19#[derive(clap::Subcommand, Clone, Debug)]
20enum Command {
21 #[clap(about = "Hold an object.")]
22 Hold(TrailingArgs),
23 #[clap(about = "Drop holds on an object.")]
24 Drop(TrailingArgs),
25 #[clap(about = "Preload an object.")]
26 Preload(TrailingArgs),
27 #[clap(about = "Print stats about an object.")]
28 Stat(TrailingArgs),
29 #[clap(about = "List held objects.")]
30 List,
31}
32
33#[derive(clap::Parser, Clone)]
34struct Args {
35 #[clap(subcommand)]
36 cmd: Command,
37}
38
39fn do_hold(id: ObjID) -> twizzler::Result<()> {
40 tracing::info!("do hold: {}", id);
41 cache_srv::hold(id, MapFlags::READ)?;
42 cache_srv::hold(id, MapFlags::READ | MapFlags::WRITE)?;
43 cache_srv::hold(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
44 Ok(())
45}
46
47fn do_drop(id: ObjID) -> twizzler::Result<()> {
48 tracing::info!("do drop: {}", id);
49 cache_srv::drop(id, MapFlags::READ)?;
50 cache_srv::drop(id, MapFlags::READ | MapFlags::WRITE)?;
51 cache_srv::drop(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
52 Ok(())
53}
54
55fn do_preload(id: ObjID) -> twizzler::Result<()> {
56 tracing::info!("do preload: {}", id);
57 cache_srv::preload(id)
58}
59
60fn do_stat(id: ObjID) -> twizzler::Result<()> {
61 tracing::info!("do stat: {}", id);
62 cache_srv::stat(id)
63}
64
65fn per_arg(arg: &str, cb: fn(ObjID) -> twizzler::Result<()>) -> twizzler::Result<()> {
66 if let Ok(id) = u128::from_str_radix(arg, 16) {
67 match cb(id.into()) {
68 Ok(_) => return twizzler::Result::Ok(()),
69 Err(e) => tracing::debug!(
70 "failed to operate on parsed object ID {} ({}), trying again with name",
71 e,
72 id
73 ),
74 }
75 }
76 match dynamic_naming_factory()
77 .unwrap()
78 .get(arg, GetFlags::FOLLOW_SYMLINK)
79 {
80 Err(e) => {
81 tracing::warn!("could not resolve {}: {}", arg, e);
82 }
83 Ok(ns) => match ns.kind {
84 naming::NsNodeKind::Namespace => {
85 tracing::debug!("enumerating directory {}", arg);
86 match dynamic_naming_factory()
87 .unwrap()
88 .enumerate_names_nsid(ns.id)
89 {
90 Ok(nodes) => {
91 for node in nodes {
92 if let Ok(name) = node.name() {
93 if name != "." && name != ".." {
94 let name = format!("{}/{}", arg, name);
95 let _ = per_arg(name.as_str(), cb);
96 }
97 }
99 }
100 }
101 Err(e) => {
102 tracing::warn!("could not enumerate directory {}: {}", arg, e);
103 }
104 }
105 }
106 naming::NsNodeKind::Object => {
107 if let Err(e) = cb(ns.id) {
108 tracing::warn!("could not operate on {}: {}", arg, e);
109 }
110 }
111 naming::NsNodeKind::SymLink => {
112 tracing::warn!("cannot hold / preload symlinks")
113 }
114 },
115 }
116 Ok(())
117}
118
119fn main() -> miette::Result<()> {
120 tracing::subscriber::set_global_default(
121 tracing_subscriber::fmt()
122 .with_max_level(Level::DEBUG)
123 .without_time()
124 .finish(),
125 )
126 .unwrap();
127
128 let args = Args::try_parse().into_diagnostic()?;
129
130 let mut errs = false;
131 match args.cmd {
132 Command::Hold(args) => {
133 for arg in args.args {
134 if per_arg(&arg, do_hold).is_err() {
135 errs = true;
136 }
137 }
138 }
139 Command::Drop(args) => {
140 for arg in args.args {
141 if per_arg(&arg, do_drop).is_err() {
142 errs = true;
143 }
144 }
145 }
146 Command::Preload(args) => {
147 for arg in args.args {
148 if per_arg(&arg, do_preload).is_err() {
149 errs = true;
150 }
151 }
152 }
153 Command::Stat(args) => {
154 for arg in args.args {
155 if per_arg(&arg, do_stat).is_err() {
156 errs = true;
157 }
158 }
159 }
160 Command::List => {
161 let mut i = 0;
162 while let Some(info) = cache_srv::list_nth(i).into_diagnostic()? {
163 println!(
164 "{} {:?} {} seconds old",
165 info.id,
166 info.flags,
167 (Instant::now() - info.start).as_secs_f32()
168 );
169 i += 1;
170 }
171 }
172 }
173
174 if errs {
175 miette::bail!("errors occurred")
176 }
177 Ok(())
178}