From: "Lukas Wagner" <l.wagner@proxmox.com>
To: "Wolfgang Bumiller" <w.bumiller@proxmox.com>,
"Lukas Wagner" <l.wagner@proxmox.com>
Cc: pdm-devel@lists.proxmox.com
Subject: Re: [PATCH datacenter-manager 1/4] add persistent, generic, namespaced key-value cache implementation
Date: Wed, 13 May 2026 10:45:38 +0200 [thread overview]
Message-ID: <DIHF1AAK95G0.205WA10D3G983@proxmox.com> (raw)
In-Reply-To: <3b7fegzovd2vvukjsctqba73qtdhize7s2xchoko7dq5xngzp6@2x7dunsotkik>
On Tue May 12, 2026 at 2:29 PM CEST, Wolfgang Bumiller wrote:
>> +
>> +impl<T> CacheEntry<T> {
>> + fn is_expired(&self, now: i64, max_age: i64) -> bool {
>> + if max_age == 0 {
>> + return true;
>> + }
>> +
>> + let diff = now - self.timestamp;
>> + diff >= max_age || diff < 0
>> + }
>> +}
>> +
>> +pub struct NamespacedCache {
>> + base_path: PathBuf,
>> + file_options: CreateOptions,
>> + dir_options: CreateOptions,
>> +}
>> +
>> +impl NamespacedCache {
>> + /// Create a new cache instance.
>> + pub fn new<P: AsRef<Path>>(
>
> Consider `Into<PathBuf>` - since you force a clone on `PathBuf` now.
>
Done, thanks!
>> + base_path: P,
>> + dir_options: CreateOptions,
>> + file_options: CreateOptions,
>> + ) -> Self {
>> + Self {
>> + base_path: base_path.as_ref().into(),
>> + dir_options,
>> + file_options,
>> + }
>> + }
>> +
[...]
>> +
>> +fn get_impl<T: Serialize + DeserializeOwned>(
>> + base: &Path,
>> + namespace: &str,
>> + key: &str,
>> + max_age: Option<i64>,
>> +) -> Result<Option<T>, CacheError> {
>> + let path = get_path(base, namespace, key);
>> + let content = proxmox_sys::fs::file_read_optional_string(path)?;
>> +
>> + if let Some(content) = content {
>> + let val = serde_json::from_str::<CacheEntry<T>>(&content)?;
>> +
>> + if let Some(max_age) = max_age {
>> + if val.is_expired(proxmox_time::epoch_i64(), max_age) {
>> + return Ok(None);
>> + }
>> + }
>> + return Ok(Some(val.value));
>> + }
>> +
>> + return Ok(None);
>> +}
>> +
>> +fn get_path(base: &Path, namespace: &str, key: &str) -> PathBuf {
>> + let mut path = base.join(namespace).join(key);
>> + path.set_extension("json");
>
> ^ I'd rather join base with `format!("{key}.json")`, otherwise if a
> `key` contains dots, it'll lose its final component.
Did that for the next revision, thanks!
>
> Alternatively we could just skip the extension altogether.
>
> Ah and I think we might want to `panic` (or fail) if
> `namespace.starts_with('/')`, that would cause discard `base` to be
> discarded! (I'm leaning towards panicking since this isn't something
> that should ever come from the outside (I hope…), at least currently
> it's all `const`s…)
Added, thanks!
I went with a failure, since I added some basic checks on keys and
namespaces anyway (e.g. prohibiting '../'). I added new error variants
InvalidNamespace and InvalidKey for this.
>
>> + path
>> +}
>> +
>> +fn get_lockfile(base: &Path, namespace: &str) -> PathBuf {
>> + let path = base.join(format!(".{namespace}.lock"));
>> + path
>> +}
>> +
>> +#[cfg(test)]
>> +mod tests {
>> + use tempfile::TempDir;
>> +
>> + use super::*;
>> +
>> + fn make_cache() -> (TempDir, NamespacedCache) {
>> + let dir = tempfile::tempdir().unwrap();
>
> (I wonder if we should use `tempdir_in` and pass `$OUT_DIR` or some
> other dir cargo provides via env vars for these things?)
Unfortunately, cargo does not seem to set OUT_DIR when `cargo test` is
used. According to [1], there is CARGO_TARGET_TMPDIR, but that one is
only set for *integration* tests, not *unit* tests.
Once we put this cache impl into a shared crate, I'd likely promote the
test cases to be integration tests anyway, then we can consider
switching the directory. For now, I'll just keep on using `tmpdir`.
[1] https://doc.rust-lang.org/cargo/reference/environment-variables.html
next prev parent reply other threads:[~2026-05-13 8:45 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-08 15:03 [RFC datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Lukas Wagner
2026-05-08 15:03 ` [PATCH datacenter-manager 1/4] add persistent, generic, namespaced key-value cache implementation Lukas Wagner
2026-05-12 12:29 ` Wolfgang Bumiller
2026-05-13 8:45 ` Lukas Wagner [this message]
2026-05-08 15:03 ` [PATCH datacenter-manager 2/4] add pdm_cache cache as a specialized wrapper around the namespaced cache Lukas Wagner
2026-05-08 15:03 ` [PATCH datacenter-manager 3/4] api: resources: subscriptions: switch over to pdm_cache Lukas Wagner
2026-05-08 15:03 ` [PATCH datacenter-manager 4/4] remote-updates: " Lukas Wagner
2026-05-11 12:37 ` [RFC datacenter-manager 0/4] add generic, per-remote (and global) cache for remote API responses Dominik Csapak
2026-05-12 8:39 ` Lukas Wagner
2026-05-13 13:56 ` superseded: " Lukas Wagner
-- strict thread matches above, loose matches on Subject: below --
2026-05-13 13:54 [PATCH " Lukas Wagner
2026-05-13 13:54 ` [PATCH datacenter-manager 1/4] add persistent, generic, namespaced key-value cache implementation Lukas Wagner
2026-05-15 9:06 ` Thomas Lamprecht
2026-05-15 9:19 ` Lukas Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DIHF1AAK95G0.205WA10D3G983@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
--cc=w.bumiller@proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox