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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.