mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
feat(fuse,core,cli): report what the daemon is doing, for the next hang
On 2026-09-18 the daemon hung: 43 minutes of CPU over 20 hours, 5.2 GiB resident, silent from 17:10 until a manual restart the next day, and no panic. Nothing in the journal said what it had been waiting on, and nothing in the daemon could be asked. - The worker pool publishes per-thread state: whether the thread is busy, how long it has been in that state, and the label of the job in hand. Every FUSE handler that hands work to the pool now names its job (`read`, `lookup`, `rename`), so a stuck worker is named rather than merely counted. Queue depths and per-lane completion counts are mirrored outside the queue lock. - `Request::Diagnostics` / `pdfs diagnostics` reports those, plus resident size, the control handler count against its limit, the in-flight control requests with their ages, and the pending-op count. - Built to answer while the daemon is wedged: atomics and `try_lock` only, and the one field that needs the database reads it on a throwaway thread with a 500 ms deadline.
This commit is contained in:
1 parent
f78f663740
commit
f24ac8a429
8 files changed
+593
-51
No files matched your search
@@ -281,6 +281,10 @@ enum Command {
|
||||
},
|
||||
/// Show the daemon's in-flight transfers (active uploads/downloads).
|
||||
Transfers,
|
||||
/// Show what the daemon is doing right now: worker threads, queue depths,
|
||||
/// in-flight control requests and memory. For a daemon that has stopped
|
||||
/// answering rather than one that is merely busy.
|
||||
Diagnostics,
|
||||
/// List what is in the account's trash, with the uids the restore and
|
||||
/// delete-forever commands take.
|
||||
Trash,
|
||||
@@ -674,6 +678,7 @@ fn main() -> Result<()> {
|
||||
Command::Mkdir { parent, name } => cmd_mkdir(parent, name),
|
||||
Command::Upload { sources, parent } => cmd_upload(sources, parent),
|
||||
Command::Transfers => cmd_transfers(),
|
||||
Command::Diagnostics => cmd_diagnostics(),
|
||||
Command::Trash => cmd_trash(),
|
||||
Command::Restore { uids } => cmd_restore(uids),
|
||||
Command::DeleteForever { uids } => cmd_delete_forever(uids),
|
||||
@@ -2153,6 +2158,67 @@ fn cmd_rm(path: PathBuf) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Seconds as something a human reads at a glance: the ages here run from
|
||||
/// "still starting" to "wedged since yesterday".
|
||||
fn human_secs(secs: u64) -> String {
|
||||
match secs {
|
||||
s if s < 60 => format!("{s}s"),
|
||||
s if s < 3600 => format!("{}m{}s", s / 60, s % 60),
|
||||
s if s < 86400 => format!("{}h{}m", s / 3600, (s % 3600) / 60),
|
||||
s => format!("{}d{}h", s / 86400, (s % 86400) / 3600),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_diagnostics() -> Result<()> {
|
||||
let response = control_request(CtlRequest::Diagnostics)?;
|
||||
if emit_json(&response)? {
|
||||
return Ok(());
|
||||
}
|
||||
match response {
|
||||
CtlResponse::Diagnostics { diagnostics: d } => {
|
||||
println!(
|
||||
"uptime {} rss {} pending ops {}",
|
||||
human_secs(d.uptime_secs),
|
||||
human_bytes(d.rss_bytes),
|
||||
d.pending_ops,
|
||||
);
|
||||
println!(
|
||||
"control handlers {}/{}",
|
||||
d.control_handlers, d.control_handler_limit,
|
||||
);
|
||||
println!(
|
||||
"queued: meta {} (done {}), transfer {} (done {})",
|
||||
d.meta_queued, d.meta_completed, d.transfer_queued, d.transfer_completed,
|
||||
);
|
||||
println!("workers:");
|
||||
for worker in &d.workers {
|
||||
let what = if worker.busy {
|
||||
worker.label.as_str()
|
||||
} else {
|
||||
"idle"
|
||||
};
|
||||
println!(
|
||||
" {:<20} {:<12} {}",
|
||||
worker.name,
|
||||
what,
|
||||
human_secs(worker.age_secs)
|
||||
);
|
||||
}
|
||||
if d.inflight.is_empty() {
|
||||
println!("in-flight requests: none");
|
||||
} else {
|
||||
println!("in-flight requests (oldest first):");
|
||||
for request in &d.inflight {
|
||||
println!(" {:<20} {}", request.kind, human_secs(request.age_secs));
|
||||
}
|
||||
}
|
||||
}
|
||||
CtlResponse::Error { message, kind } => bail!("{}", cli_error(kind, &message)),
|
||||
other => bail!("unexpected response: {other:?}"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cmd_trash() -> Result<()> {
|
||||
match control_request(CtlRequest::ListTrash)? {
|
||||
CtlResponse::Entries { entries } if entries.is_empty() => println!("(trash is empty)"),
|
||||
|
||||
Reference in new issue
Block a user