public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
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







  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
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal