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::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                                // TODO: track error for ret val
98                            }
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}