cache/
main.rs

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::EXEC)?;
43    cache_srv::hold(id, MapFlags::READ | MapFlags::NO_NULLPAGE)?;
44    cache_srv::hold(id, MapFlags::READ | MapFlags::WRITE)?;
45    cache_srv::hold(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
46    Ok(())
47}
48
49fn do_drop(id: ObjID) -> twizzler::Result<()> {
50    tracing::info!("do drop: {}", id);
51    cache_srv::drop(id, MapFlags::READ)?;
52    cache_srv::drop(id, MapFlags::READ | MapFlags::EXEC)?;
53    cache_srv::drop(id, MapFlags::READ | MapFlags::NO_NULLPAGE)?;
54    cache_srv::drop(id, MapFlags::READ | MapFlags::WRITE)?;
55    cache_srv::drop(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
56    Ok(())
57}
58
59fn do_preload(id: ObjID) -> twizzler::Result<()> {
60    tracing::info!("do preload: {}", id);
61    cache_srv::preload(id)
62}
63
64fn do_stat(id: ObjID) -> twizzler::Result<()> {
65    tracing::info!("do stat: {}", id);
66    cache_srv::stat(id)
67}
68
69fn per_arg(arg: &str, cb: fn(ObjID) -> twizzler::Result<()>) -> twizzler::Result<()> {
70    if let Ok(id) = u128::from_str_radix(arg, 16) {
71        match cb(id.into()) {
72            Ok(_) => return twizzler::Result::Ok(()),
73            Err(e) => tracing::debug!(
74                "failed to operate on parsed object ID {} ({}), trying again with name",
75                e,
76                id
77            ),
78        }
79    }
80    match dynamic_naming_factory()
81        .unwrap()
82        .get(arg, GetFlags::FOLLOW_SYMLINK)
83    {
84        Err(e) => {
85            tracing::warn!("could not resolve {}: {}", arg, e);
86        }
87        Ok(ns) => match ns.kind {
88            naming::NsNodeKind::Namespace => {
89                tracing::debug!("enumerating directory {}", arg);
90                match dynamic_naming_factory()
91                    .unwrap()
92                    .enumerate_names_nsid(ns.id)
93                {
94                    Ok(nodes) => {
95                        for node in nodes {
96                            if let Ok(name) = node.name() {
97                                if name != "." && name != ".." {
98                                    let name = format!("{}/{}", arg, name);
99                                    let _ = per_arg(name.as_str(), cb);
100                                }
101                                // TODO: track error for ret val
102                            }
103                        }
104                    }
105                    Err(e) => {
106                        tracing::warn!("could not enumerate directory {}: {}", arg, e);
107                    }
108                }
109            }
110            naming::NsNodeKind::Object => {
111                if let Err(e) = cb(ns.id) {
112                    tracing::warn!("could not operate on {}: {}", arg, e);
113                }
114            }
115            naming::NsNodeKind::SymLink => {
116                tracing::warn!("cannot hold / preload symlinks")
117            }
118        },
119    }
120    Ok(())
121}
122
123fn main() -> miette::Result<()> {
124    tracing::subscriber::set_global_default(
125        tracing_subscriber::fmt()
126            .with_max_level(Level::DEBUG)
127            .without_time()
128            .finish(),
129    )
130    .unwrap();
131
132    let args = Args::try_parse().into_diagnostic()?;
133
134    let mut errs = false;
135    match args.cmd {
136        Command::Hold(args) => {
137            for arg in args.args {
138                if per_arg(&arg, do_hold).is_err() {
139                    errs = true;
140                }
141            }
142        }
143        Command::Drop(args) => {
144            for arg in args.args {
145                if per_arg(&arg, do_drop).is_err() {
146                    errs = true;
147                }
148            }
149        }
150        Command::Preload(args) => {
151            for arg in args.args {
152                if per_arg(&arg, do_preload).is_err() {
153                    errs = true;
154                }
155            }
156        }
157        Command::Stat(args) => {
158            for arg in args.args {
159                if per_arg(&arg, do_stat).is_err() {
160                    errs = true;
161                }
162            }
163        }
164        Command::List => {
165            let mut i = 0;
166            while let Some(info) = cache_srv::list_nth(i).into_diagnostic()? {
167                println!(
168                    "{} {:?} {:x} {} seconds old",
169                    info.id,
170                    info.flags,
171                    info.addr,
172                    (Instant::now() - info.start).as_secs_f32()
173                );
174                i += 1;
175            }
176        }
177    }
178
179    if errs {
180        miette::bail!("errors occurred")
181    }
182    Ok(())
183}