VFS cache: pin / warm / cold controls per file (prototype patch)

My home server has ~500 GB; Google Drive is cheap bulk storage but not private. So I keep everything in Drive behind rclone crypt and serve it through Nextcloud, using the server's disk as a local cache. I want to choose which files stay local (hot) and which live only in the cloud (cold).

With --vfs-cache-mode full, eviction is age/size LRU only. For a Nextcloud-over-rclone setup I wanted per-file control:

  • pin: keep a file or folder local permanently
  • warm: download a whole file now
  • cold: drop a file's cached data now

I prototyped this as a patch on v1.75.1:

  • Pins/jobs persisted in a JSON policy file next to vfsMeta
  • Background worker that warms/evicts files one at a time
  • New rc command workspace/control
  • Cache cleaner skips pinned and in-progress files
  • Upstream changes are small (5 files, +41 lines); the rest is new files with tests

Nextcloud view -

Nextcloud Files on top of the patched rclone: :snowflake: = not fully cached, :fire: = fully local, :pushpin: = pinned

Per-file status overlaps with rclone issue 8779 (vfs/dir-status); I'd align with that rather than duplicate it. The part I haven't seen proposed is the control side. Earlier asks on this forum: "Pinned persistent cache?" (t/25520) and "rc cache/fetch for vfs?" (t/45468).

The idea and design are mine; I used Codex to quickly prototype it and see if it was feasible. I'm now reviewing the code line by line. I'm a young dev doing this partly to learn rclone's internals, so any pointers on the code are welcome too.

Questions:

  1. Is this approach sane, or is there a better way to get pin/warm/cold without modifying rclone (existing flags, rc commands, or a wrapper around the stock cache)?
  2. If it does need rclone changes, would pin/warm/cold make sense as rc commands next to vfs/dir-status?

Update: after reviewing the code I ended up changing quite a lot, so the patch at the same link is now mostly rewritten.

How it works now:

Pins are saved in a small JSON file next to vfsMeta. Pinning a folder covers everything inside it, and the most specific entry wins, so I can pin a folder and then unpin individual files inside it. Pins follow renames and get removed when the file is deleted.

Warming just reads the file through the VFS so the full cache keeps it. The cleaner skips pinned files in removeNotInUse and purgeClean.

Cold is now an action instead of a mode. It removes eligible cached copies immediately. If a file is open, still uploading, or in the handle-caching grace period, the normal cleaner removes it once it's free.

New pin and retry requests are checked against --vfs-cache-max-size. The size check and accounting happen together under the cache lock, so concurrent requests can't reserve the same free space. Failed downloads keep their space accounted for until unpinned.

New rc commands:

  • vfs/pin: accepts path or paths, with mode pinned or unpinned
  • vfs/evict: unpins and releases cached copies
  • vfs/retry: retries warming a pinned path
  • vfs/status: lists a directory's entries with pin/cache status, failure and pending-eviction flags, mixed folder policies, and how much pin space is left

The changes to existing rclone files are small: about 65 added lines across dir.go, file.go, vfs.go and vfscache/cache.go, plus the new rc commands in vfs/rc.go. Everything else is in new files, around 560 lines of code and 440 lines of tests.

Questions:

  1. Would something like this be welcome upstream? Do separate rc commands make sense for pin/evict/retry? For status reporting, should I align with the proposal in issue 8779?
  2. To warm a file I just read it fully through the VFS so the cache keeps it. Is there a better way to pull a whole file into the cache?