Skip to content

Share halide-cache entries through a server - #10

Merged
RMPR merged 6 commits into
masterfrom
halide-server
Oct 6, 2026
Merged

RMPR merged 6 commits into
masterfrom
halide-server

Conversation

@RMPR

@RMPR RMPR commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

This is the meat, best reviewed commit by commit. We introduce a new halide-cache-server binary and the corresponding --remote flag on the client.

@RMPR
RMPR added this pull request to stack #11 October 5, 2026 09:55
@RMPR
RMPR requested a review from johningve October 5, 2026 09:59
Base automatically changed from halide-cache-cleanup to master October 5, 2026 11:03
Comment thread lager/src/lager.rs Outdated

pub fn retrieve(&self, address: &Address, destination: &Path) -> Result<()> {
let mut source = self.root.join(shard_path(address, 2));
pub fn store_raw<R: Read>(&self, address: &Address, mut blob: R) -> Result<bool> {

@johningve johningve Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not add a second method that stores data into the lager. In this case we can easily generalize lager to make it fit both. You already have most of it: the write_entry method. IMO this is the shape that lager's API should have.

The concept of a lager in my mind is a space into which you store things. The important things the lager does for you is to keep track of where you stored the things, and in this case also keep track of which inventory has been sitting in the lager for the longest.

It does not have to include the concept of what form the inventory is stored into, and how to extract the inventory from the lager, which it currently does, and this PR adds a second way via the raw methods.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you suggest?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not add a second method that stores data into the lager. In this case we can easily generalize lager to make it fit both. You already have most of it: the write_entry method. IMO this is the shape that lager's API should have.

imho that is only valid if lager is meant to be an external crate because this just pushes the work to the client. This is just something I extended from what already existed. I did the change you requested (thanks LLMs) but it should have been a nitpick.

Comment thread lager/src/lager.rs Outdated
pub fn store_at(
&self,
address: &Address,
write: impl FnOnce(&mut File) -> std::io::Result<()>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can be more generic: &mut dyn std::io::Write instead of File.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johningve johningve left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't looked too closely at the server, but LGTM

RMPR added 6 commits October 6, 2026 09:19
The lager keeps track of where entries are and which have gone unused the
longest. What an entry holds, and how it is packed, is now the caller's
business:

- store_at(address, write) writes an entry through a closure, atomically,
  and reports whether it is new
- retrieve(address) opens an entry for reading and refreshes its LRU time

Entries no longer have an extension. The scan removes entries left in an
older format, which the new key scheme never hits anyway.

halide-cache packs the files of an entry into a deterministic
zstd-compressed tar archive, in a fixed order, and unpacks them by position.

Prework for the server, which stores and serves entries as they are.
The object and header are always produced together, so this commit
changes how halide-cache stores, restores and later: fetches, uploads
and evicts them together with the same address in lager.
Entries are about to be shared, so the key must drop what differs
between machines and include what makes an object valid elsewhere:

- strip the base directory wherever it occurs in an argument and
  normalise path separators
- prefix a key scheme version, and include the host OS and architecture
- hash the builder executable, the Python interpreter, resolved through
  PATH. Ask it where it imports halide from and hash that package's
  native libraries. A missing or unusable halide is an error rather than
  a weaker key.
- reject non-UTF-8 output paths instead of hashing a lossy conversion
Make local cache cleanup best effort, since Windows refuses to delete an
entry another parallel build has open and the outputs are already in
place. Run the client's tests on Windows in CI.
An HTTP server sharing cache entries between machines, storing them
through lager in the same layout as the local cache.

  GET/PUT /v1/blobs/{address}

Ships a systemd unit, and static musl binaries for x86_64 and aarch64 in
CI and releases to be self-contained and independent of the Glibc
version of the host.
Look locally, then on the server, then build and upload. A remote hit is
stored locally and triggers the local LRU cleanup. The remote is
fail-open: connection errors, failed uploads and entries that do not
decompress are warnings, and the build proceeds locally.

The end-to-end tests start the server and cover hits across machines, a
server that is down, corrupt entries, oversized uploads, and concurrent
clients racing on one entry under constant eviction. They run on Unix
only, since the server is deployed on Linux.
@RMPR
RMPR merged commit 01eab75 into master Oct 6, 2026
18 checks passed
@RMPR
RMPR deleted the halide-server branch October 6, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants