Line data Source code
1 : //! An utilization metric which is used to decide on which pageserver to put next tenant.
2 : //!
3 : //! The metric is exposed via `GET /v1/utilization`. Refer and maintain it's openapi spec as the
4 : //! truth.
5 :
6 : use anyhow::Context;
7 : use std::path::Path;
8 :
9 : use pageserver_api::models::PageserverUtilization;
10 :
11 0 : pub(crate) fn regenerate(tenants_path: &Path) -> anyhow::Result<PageserverUtilization> {
12 : // TODO: currently the http api ratelimits this to 1Hz at most, which is probably good enough
13 :
14 0 : let statvfs = nix::sys::statvfs::statvfs(tenants_path)
15 0 : .map_err(std::io::Error::from)
16 0 : .context("statvfs tenants directory")?;
17 :
18 : // https://unix.stackexchange.com/a/703650
19 0 : let blocksz = if statvfs.fragment_size() > 0 {
20 0 : statvfs.fragment_size()
21 : } else {
22 0 : statvfs.block_size()
23 : };
24 :
25 : #[cfg_attr(not(target_os = "macos"), allow(clippy::unnecessary_cast))]
26 0 : let free = statvfs.blocks_available() as u64 * blocksz;
27 0 :
28 0 : #[cfg_attr(not(target_os = "macos"), allow(clippy::unnecessary_cast))]
29 0 : let used = statvfs
30 0 : .blocks()
31 0 : // use blocks_free instead of available here to match df in case someone compares
32 0 : .saturating_sub(statvfs.blocks_free()) as u64
33 0 : * blocksz;
34 0 :
35 0 : let captured_at = std::time::SystemTime::now();
36 0 :
37 0 : let doc = PageserverUtilization {
38 0 : disk_usage_bytes: used,
39 0 : free_space_bytes: free,
40 0 : // lower is better; start with a constant
41 0 : //
42 0 : // note that u64::MAX will be output as i64::MAX as u64, but that should not matter
43 0 : utilization_score: u64::MAX,
44 0 : captured_at: utils::serde_system_time::SystemTime(captured_at),
45 0 : };
46 0 :
47 0 : // TODO: make utilization_score into a metric
48 0 :
49 0 : Ok(doc)
50 0 : }
|