Skip to content

Add an experimental opt in tar based implementation of the local cache#1065

Open
christiango wants to merge 9 commits intomainfrom
christiango/tar-based-cache
Open

Add an experimental opt in tar based implementation of the local cache#1065
christiango wants to merge 9 commits intomainfrom
christiango/tar-based-cache

Conversation

@christiango
Copy link
Member

@christiango christiango commented Mar 23, 2026

We're seeing that for operations that are fast (such as transpiling with SWC) lage caching overhead is extremely high from copying the files over to the cache. This implements a local cache that uses tar for storing the cache. Here is the performance delta for this implementation from an internal repo

Platform Cold cache on branch (avg) Cold cache before change (avg) Speedup
Windows (ReFS) 19.31s 34.78s 1.8x
**M1 Mac ** 17.53s 42.07s 2.4x
Codespaces (Linux) 14.0s 20.4s 1.5x
WSL 13.49s 15.60s 1.2x

And for reference here is the overhead before and after compared to lage --no-cache on that same repo

Platform No cache (avg) Cold cache on branch (avg) Cold cache before change (avg) Tar vs no-cache Before change vs no-cache
Windows (ReFS) 14.25s 19.31s 34.78s 1.4x slower 2.4x slower
M1 Mac 14.41s 17.53s 42.07s 1.2x slower 2.9x slower
Codespaces (Linux) 13.2s 14.0s 20.4s 1.1x slower 1.5x slower
WSL 12.34s 13.49s 15.60s 1.1x slower 1.3x slower

Key takeaway: Master's file-copy cache adds 1.3x–2.9x overhead vs no cache at all. The tar cache reduces that overhead to just 1.1x–1.4x, making cold-cache builds nearly as fast as uncached builds.

Comment on lines +12 to +14
const rm = promisify(fs.rm);
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
Copy link
Member

Choose a reason for hiding this comment

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

This is outdated--you can import these directly from fs/promises now (that's usually also preferable to fs.promises since it's easier to mock if needed)

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, I missed that

// Read all output files in parallel, then build and write the tar
// in one shot. This is dramatically faster than tar.create() which
// processes each file sequentially through Minipass streams.
const fileEntries: TarFileEntry[] = await Promise.all(
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure firing off an unbounded number of parallel read or write requests is a good idea? (same in other places)

Copy link
Member Author

Choose a reason for hiding this comment

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

So locally in our repo it's been faster than what we currently do with the local cache provider. Do we have some examples of limits in other cache implementations I can apply here?

}

interface TarFileEntry {
path: string;
Copy link
Member

Choose a reason for hiding this comment

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

Can you add a comment about whether this is relative or absolute?

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding jsdoc comments to all interfaces

}

/**
* Build a tar buffer from in-memory file entries.
Copy link
Member

Choose a reason for hiding this comment

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

I assume Claude wrote this but is there some documentation for this format?

? undefined
const useLocalTarCache = cacheOptions?.useLocalTarCache === true;

const localCacheProvider =
Copy link
Member

Choose a reason for hiding this comment

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

Especially now that we have backfill in the same repo, I think it would be better if the tar caching option and implementation could be added to the backfill side.

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