mirror of
https://github.com/qdrant/qdrant.git
synced 2026-09-21 13:37:46 -05:00
Replace cgroups-rs with direct cgroup memory file reads (#10295)
* Replace cgroups-rs with direct cgroup memory file reads We used cgroups-rs in exactly one place, to read the memory limit and usage of our own cgroup, so read those files directly instead. Drops 34 crates from the lockfile, including the zbus stack that carries RUSTSEC-2026-0221. Also fixes two latent cgroup v1 bugs (the LONG_MAX unlimited sentinel reported ~9 EB of total memory, an unreadable limit file reported 0 bytes) and the hierarchy mix-up on hybrid hosts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Decline cgroup memory reporting when the usage read fails Reporting a usage of 0 made available_memory_bytes claim the whole cgroup limit as free. Fall back to sysinfo when the usage file cannot be read at init, and keep the last known value on a failed refresh. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep the last known memory limit when its read fails A transient read failure cleared the cached limit and silently fell back to host memory while the process was still capped, the same direction of over-reporting as the usage read. Both now keep their last known value, and a limit lifted at runtime still clears. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Treat a malformed memory limit as an error, not as unlimited Parse failures returned Ok(None), so garbage in the limit file cleared a valid cached limit on refresh and read as unlimited at init. Reserve Ok(None) for "max" and the v1 sentinel, and report anything else as InvalidData so the last known limit survives. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2067eb3398
commit
5b338115f2
Generated
-424
@@ -612,126 +612,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.4",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-signal",
|
||||
"async-task",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"atomic-waker",
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.4",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.92"
|
||||
@@ -923,12 +803,6 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222fb4925a15bea6a68075021910e03d6aa2d04951d71ff1d956190a551d738f"
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -1039,19 +913,6 @@ dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bm25"
|
||||
version = "0.1.0"
|
||||
@@ -1253,20 +1114,6 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "cgroups-rs"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25ae79ba89081d30804e3312bb1163ab82cc8dca0a1b16275e55fb19fce4e89b"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
"libc",
|
||||
"log",
|
||||
"nix 0.25.1",
|
||||
"thiserror 1.0.69",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.10.0"
|
||||
@@ -1557,15 +1404,6 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.15.25"
|
||||
@@ -2347,33 +2185,6 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
||||
dependencies = [
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "2.0.0"
|
||||
@@ -2463,27 +2274,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "faccess"
|
||||
version = "0.2.4"
|
||||
@@ -2872,19 +2662,6 @@ version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.34"
|
||||
@@ -4550,18 +4327,6 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
@@ -4916,16 +4681,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p256"
|
||||
version = "0.13.2"
|
||||
@@ -4960,12 +4715,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -5199,17 +4948,6 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
@@ -5271,20 +5009,6 @@ dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
@@ -5419,15 +5143,6 @@ dependencies = [
|
||||
"elliptic-curve",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr3"
|
||||
version = "3.0.2"
|
||||
@@ -7019,7 +6734,6 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"cc",
|
||||
"cgroups-rs",
|
||||
"charabia",
|
||||
"chrono",
|
||||
"clap",
|
||||
@@ -7223,17 +6937,6 @@ dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.1"
|
||||
@@ -8214,18 +7917,6 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.10+spec-1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow 0.7.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.9+spec-1.1.0"
|
||||
@@ -8569,17 +8260,6 @@ version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uio-grpc-client"
|
||||
version = "0.1.0"
|
||||
@@ -9465,9 +9145,6 @@ name = "winnow"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
@@ -9640,67 +9317,6 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "5.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"async-recursion",
|
||||
"async-task",
|
||||
"async-trait",
|
||||
"blocking",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-lite",
|
||||
"hex",
|
||||
"libc",
|
||||
"ordered-stream",
|
||||
"rustix 1.1.4",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"uuid",
|
||||
"windows-sys 0.61.2",
|
||||
"winnow 0.7.15",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "5.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"winnow 0.7.15",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.56"
|
||||
@@ -9828,43 +9444,3 @@ dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b"
|
||||
dependencies = [
|
||||
"endi",
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"winnow 0.7.15",
|
||||
"zvariant_derive",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "5.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.119",
|
||||
"winnow 0.7.15",
|
||||
]
|
||||
|
||||
@@ -124,7 +124,6 @@ roaring = { workspace = true }
|
||||
duplicate = "2.0.1"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
cgroups-rs = "0.5"
|
||||
procfs = { version = "0.18", default-features = false }
|
||||
|
||||
[[bench]]
|
||||
|
||||
+250
-35
@@ -75,20 +75,31 @@ impl Mem {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod cgroups_mem {
|
||||
use cgroups_rs::fs::{Cgroup, hierarchies, memory};
|
||||
use procfs::process::Process;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fs_err as fs;
|
||||
use procfs::process::{MountInfos, Process};
|
||||
|
||||
/// Mount point of the unified (v2) hierarchy.
|
||||
const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup";
|
||||
|
||||
/// With no limit set, `memory.limit_in_bytes` (v1) reads back as `LONG_MAX` rounded down to the
|
||||
/// page size. Treat anything that large as "no limit", rather than a ~9 EB total memory.
|
||||
const V1_UNLIMITED_THRESHOLD: u64 = i64::MAX as u64 - (1 << 20);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CgroupsMem {
|
||||
mem_controller: memory::MemController,
|
||||
limit_path: PathBuf,
|
||||
usage_path: PathBuf,
|
||||
memory_limit_bytes: Option<u64>,
|
||||
used_memory_bytes: u64,
|
||||
}
|
||||
|
||||
impl CgroupsMem {
|
||||
pub fn new() -> Option<Self> {
|
||||
let memory_cgroup_path = match get_current_process_memory_cgroup_path() {
|
||||
Ok(memory_cgroup_path) => memory_cgroup_path?,
|
||||
let (dir, is_v2) = match memory_cgroup_dir() {
|
||||
Ok(dir) => dir?,
|
||||
Err(err) => {
|
||||
log::error!(
|
||||
"Failed to query current process info \
|
||||
@@ -99,26 +110,55 @@ mod cgroups_mem {
|
||||
}
|
||||
};
|
||||
|
||||
let cgroup = Cgroup::load(
|
||||
hierarchies::auto(),
|
||||
memory_cgroup_path.trim_start_matches('/'),
|
||||
);
|
||||
|
||||
let mut mem = Self {
|
||||
mem_controller: cgroup.controller_of::<memory::MemController>()?.clone(),
|
||||
memory_limit_bytes: None,
|
||||
used_memory_bytes: 0,
|
||||
let (limit_file, usage_file) = if is_v2 {
|
||||
("memory.max", "memory.current")
|
||||
} else {
|
||||
("memory.limit_in_bytes", "memory.usage_in_bytes")
|
||||
};
|
||||
|
||||
mem.refresh();
|
||||
let limit_path = dir.join(limit_file);
|
||||
|
||||
Some(mem)
|
||||
let memory_limit_bytes = match read_memory_limit(&limit_path) {
|
||||
Ok(memory_limit_bytes) => memory_limit_bytes,
|
||||
// The memory controller is not available in this cgroup
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return None,
|
||||
Err(err) => {
|
||||
log::error!("Failed to read memory limit while initializing CgroupsMem: {err}");
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let usage_path = dir.join(usage_file);
|
||||
|
||||
let used_memory_bytes = match read_memory_usage(&usage_path) {
|
||||
Ok(used_memory_bytes) => used_memory_bytes,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return None,
|
||||
Err(err) => {
|
||||
log::error!("Failed to read memory usage while initializing CgroupsMem: {err}");
|
||||
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
limit_path,
|
||||
usage_path,
|
||||
memory_limit_bytes,
|
||||
used_memory_bytes,
|
||||
})
|
||||
}
|
||||
|
||||
/// Failed reads keep the last known value: dropping the limit would silently fall back to
|
||||
/// host memory, and zeroing the usage would report the whole limit as free.
|
||||
pub fn refresh(&mut self) {
|
||||
let stat = self.mem_controller.memory_stat();
|
||||
self.memory_limit_bytes = stat.limit_in_bytes.try_into().ok();
|
||||
self.used_memory_bytes = stat.usage_in_bytes;
|
||||
if let Ok(memory_limit_bytes) = read_memory_limit(&self.limit_path) {
|
||||
self.memory_limit_bytes = memory_limit_bytes;
|
||||
}
|
||||
|
||||
if let Ok(used_memory_bytes) = read_memory_usage(&self.usage_path) {
|
||||
self.used_memory_bytes = used_memory_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memory_limit_bytes(&self) -> Option<u64> {
|
||||
@@ -130,30 +170,205 @@ mod cgroups_mem {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_process_memory_cgroup_path() -> procfs::ProcResult<Option<String>> {
|
||||
/// Directory holding the memory controller files of the current process, and whether it belongs
|
||||
/// to the unified (v2) hierarchy.
|
||||
fn memory_cgroup_dir() -> procfs::ProcResult<Option<(PathBuf, bool)>> {
|
||||
let process = Process::myself()?;
|
||||
let cgroups = process.cgroups()?;
|
||||
|
||||
for cgroup in cgroups {
|
||||
if is_cgroup2_unified_mode() {
|
||||
// TODO: Can a process belong to multiple v2 cgroups!?
|
||||
let is_v2_cgroup = cgroup.controllers.is_empty()
|
||||
|| cgroup
|
||||
.controllers
|
||||
.iter()
|
||||
.all(|controller| controller.is_empty());
|
||||
let dir = process
|
||||
.cgroups()?
|
||||
.into_iter()
|
||||
// The v2 entry is the one with hierarchy ID 0
|
||||
.find(|cgroup| cgroup.hierarchy == 0)
|
||||
.map(|cgroup| join_cgroup_path(Path::new(UNIFIED_MOUNTPOINT), &cgroup.pathname));
|
||||
|
||||
// TODO: Can a process belong to multiple v1 cgroups, with some of these cgroups having the same controllers (e.g., memory)!?
|
||||
let is_v1_memory_cgroup = cgroup
|
||||
.controllers
|
||||
.iter()
|
||||
.any(|controller| controller == "memory");
|
||||
return Ok(dir.map(|dir| (dir, true)));
|
||||
}
|
||||
|
||||
if is_v2_cgroup || is_v1_memory_cgroup {
|
||||
return Ok(Some(cgroup.pathname));
|
||||
let Some(mount_point) = v1_memory_mount_point(process.mountinfo()?) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// TODO: Can a process belong to multiple v1 cgroups, with some of these cgroups having the same controllers (e.g., memory)!?
|
||||
let dir = process
|
||||
.cgroups()?
|
||||
.into_iter()
|
||||
.find(|cgroup| cgroup.controllers.iter().any(|c| c == "memory"))
|
||||
.map(|cgroup| join_cgroup_path(&mount_point, &cgroup.pathname));
|
||||
|
||||
Ok(dir.map(|dir| (dir, false)))
|
||||
}
|
||||
|
||||
fn is_cgroup2_unified_mode() -> bool {
|
||||
Path::new(UNIFIED_MOUNTPOINT)
|
||||
.join("cgroup.controllers")
|
||||
.exists()
|
||||
}
|
||||
|
||||
/// Where the v1 memory controller is mounted.
|
||||
fn v1_memory_mount_point(mountinfo: MountInfos) -> Option<PathBuf> {
|
||||
mountinfo
|
||||
.into_iter()
|
||||
.find(|mount| mount.fs_type == "cgroup" && mount.super_options.contains_key("memory"))
|
||||
.map(|mount| mount.mount_point)
|
||||
}
|
||||
|
||||
/// Cgroup pathnames are relative to the mount point of their hierarchy, but start with a `/`.
|
||||
fn join_cgroup_path(mount_point: &Path, pathname: &str) -> PathBuf {
|
||||
mount_point.join(pathname.trim_start_matches('/'))
|
||||
}
|
||||
|
||||
/// `None` if no limit is set, either as v2 `max` or as the v1 `LONG_MAX` sentinel.
|
||||
fn read_memory_limit(path: &Path) -> io::Result<Option<u64>> {
|
||||
let raw = fs::read_to_string(path)?;
|
||||
let raw = raw.trim();
|
||||
|
||||
if raw == "max" {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let memory_limit_bytes = raw
|
||||
.parse::<u64>()
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
|
||||
|
||||
if memory_limit_bytes >= V1_UNLIMITED_THRESHOLD {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(memory_limit_bytes))
|
||||
}
|
||||
|
||||
fn read_memory_usage(path: &Path) -> io::Result<u64> {
|
||||
let raw = fs::read_to_string(path)?;
|
||||
|
||||
raw.trim()
|
||||
.parse()
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn read_limit(contents: &str) -> Option<u64> {
|
||||
let dir = tempfile::Builder::new().tempdir().unwrap();
|
||||
let path = dir.path().join("memory.max");
|
||||
fs::write(&path, contents).unwrap();
|
||||
read_memory_limit(&path).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memory_limit_parsing() {
|
||||
assert_eq!(read_limit("1073741824\n"), Some(1073741824));
|
||||
// v2 reports "max" when unlimited
|
||||
assert_eq!(read_limit("max\n"), None);
|
||||
// v1 reports LONG_MAX rounded down to the page size when unlimited
|
||||
assert_eq!(read_limit("9223372036854771712\n"), None);
|
||||
assert_eq!(read_limit("9223372036854710272\n"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_memory_limit_is_invalid_data() {
|
||||
let dir = tempfile::Builder::new().tempdir().unwrap();
|
||||
let path = dir.path().join("memory.max");
|
||||
fs::write(&path, "garbage").unwrap();
|
||||
|
||||
let err = read_memory_limit(&path).unwrap_err();
|
||||
assert_eq!(err.kind(), io::ErrorKind::InvalidData);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v1_memory_mount_point_is_picked_by_super_option() {
|
||||
let mountinfo = MountInfos(
|
||||
[
|
||||
"30 23 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec - tmpfs tmpfs ro,mode=755",
|
||||
"32 30 0:28 / /sys/fs/cgroup/cpu,cpuacct rw,relatime - cgroup cgroup rw,cpu,cpuacct",
|
||||
"33 30 0:29 / /sys/fs/cgroup/memory rw,relatime - cgroup cgroup rw,memory",
|
||||
]
|
||||
.into_iter()
|
||||
.map(|line| procfs::process::MountInfo::from_line(line).unwrap())
|
||||
.collect(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
v1_memory_mount_point(mountinfo),
|
||||
Some(PathBuf::from("/sys/fs/cgroup/memory")),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cgroup_paths_are_joined_onto_the_mount_point() {
|
||||
let mount_point = Path::new("/sys/fs/cgroup");
|
||||
|
||||
// A container with its own cgroup namespace sees the root
|
||||
assert_eq!(
|
||||
join_cgroup_path(mount_point, "/"),
|
||||
Path::new("/sys/fs/cgroup"),
|
||||
);
|
||||
assert_eq!(
|
||||
join_cgroup_path(mount_point, "/user.slice/session-2.scope"),
|
||||
Path::new("/sys/fs/cgroup/user.slice/session-2.scope"),
|
||||
);
|
||||
}
|
||||
|
||||
fn cgroup_mem(dir: &Path) -> CgroupsMem {
|
||||
let limit_path = dir.join("memory.max");
|
||||
let usage_path = dir.join("memory.current");
|
||||
fs::write(&limit_path, "1073741824").unwrap();
|
||||
fs::write(&usage_path, "1024").unwrap();
|
||||
|
||||
CgroupsMem {
|
||||
limit_path,
|
||||
usage_path,
|
||||
memory_limit_bytes: Some(1073741824),
|
||||
used_memory_bytes: 1024,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
#[test]
|
||||
fn unreadable_memory_usage_keeps_the_last_known_value() {
|
||||
let dir = tempfile::Builder::new().tempdir().unwrap();
|
||||
let mut mem = cgroup_mem(dir.path());
|
||||
|
||||
fs::write(&mem.usage_path, "garbage").unwrap();
|
||||
mem.refresh();
|
||||
|
||||
assert_eq!(mem.used_memory_bytes(), 1024);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unreadable_memory_limit_keeps_the_last_known_value() {
|
||||
let dir = tempfile::Builder::new().tempdir().unwrap();
|
||||
let mut mem = cgroup_mem(dir.path());
|
||||
|
||||
fs::remove_file(&mem.limit_path).unwrap();
|
||||
mem.refresh();
|
||||
|
||||
assert_eq!(mem.memory_limit_bytes(), Some(1073741824));
|
||||
|
||||
fs::write(&mem.limit_path, "garbage").unwrap();
|
||||
mem.refresh();
|
||||
|
||||
assert_eq!(mem.memory_limit_bytes(), Some(1073741824));
|
||||
|
||||
// A limit lifted at runtime still clears
|
||||
fs::write(&mem.limit_path, "max").unwrap();
|
||||
mem.refresh();
|
||||
|
||||
assert_eq!(mem.memory_limit_bytes(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_memory_limit_file_is_not_found() {
|
||||
let dir = tempfile::Builder::new().tempdir().unwrap();
|
||||
let err = read_memory_limit(&dir.path().join("memory.max")).unwrap_err();
|
||||
assert_eq!(err.kind(), io::ErrorKind::NotFound);
|
||||
|
||||
let err = read_memory_usage(&dir.path().join("memory.current")).unwrap_err();
|
||||
assert_eq!(err.kind(), io::ErrorKind::NotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user