Skip to content

Refactor CachingAssetReader to FilesystemCache. #3869

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 21, 2025

Conversation

davidmorgan
Copy link
Contributor

@davidmorgan davidmorgan commented Feb 19, 2025

For #3811.

Move caching out of AssetReader and next to the filesystem.

For now, largely preserves existing functionality, for simplicity. I'll improve these in future PRs as needed:

  • only async methods are cached
  • the caching strategy is the same

But there is one behaviour change:

  • the digest method used to bypass the cache, now it reads from the cache if there is one
  • explicitly call invalidate in places that use digest and expect a fresh result

One other change / cleanup: remove test StubAssetReader, which always returned a fixed digest. Update tests to use InMemoryAssetReaderWriter and write files to it as needed.

Copy link

github-actions bot commented Feb 19, 2025

PR Health

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

@davidmorgan davidmorgan force-pushed the cache-reader branch 14 times, most recently from 3b560cd to 697a096 Compare February 20, 2025 13:10
@davidmorgan
Copy link
Contributor Author

FYI, while working on the next PR it looks like I probably want to keep Filesystem not having a cache, and call the cache from FileBasedAssetReader / InMemoryAssetReaderWriter; which probably do end up being the same class when all this is over.

I think this PR still works as is, just wanted to mention the change in direction coming :) thanks.

Copy link

@jensjoha jensjoha left a comment

Choose a reason for hiding this comment

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

Why are all the copyWiths with a single optional argument, when - unless I missed somewhere - it ultimately just does a whole lot of nothing?


/// Whether the file exists.
///
/// Uses [cache].

Choose a reason for hiding this comment

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

Here - and below - it talks about a specific implementation. Isn't that weird to have as documentation for the interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a bit awkward :) while writing the next PR I realized it makes more sense to leave Filesystem always uncached and do the caching one level up in the reader. So that's the plan.

As the code is I do think it makes sense on the interface, because exactly how the cache is used has visible side effects. Which is also why it makes sense to move it out, it makes this type do too much :)

/// Cached results of [readAsBytes].
final _bytesContentCache = LruCache<AssetId, Uint8List>(
1024 * 1024,
1024 * 1024 * 512,

Choose a reason for hiding this comment

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

Are these numbers copied from somewhere?
Do we have any numbers on "normal" usage of these, because 2 x 0.5 GB seems quite high to me...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's copied.

Added a TODO to look into the caching strategy; I suspect we can do something simpler. It would be surprising if we can't fit one build's worth of input in memory ... particularly given that when running with the analyzer, there is exactly another copy of all the inputs in the in-memory filesystem we give to the analyzer :)

Thanks.

Copy link
Contributor Author

@davidmorgan davidmorgan left a comment

Choose a reason for hiding this comment

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

Why are all the copyWiths with a single optional argument, when - unless I missed somewhere - it ultimately just does a whole lot of nothing?

Good question :) there will be more fields+arguments soon; the plan is that rather than nesting delegating readers you copyWith and set the functionality you want that way, so there is just one instance with a collection of things plugged into it.

So for example AssetPathProvider is currently "set" by wrapping in a BuildCacheReader, that will change to copyWith(assetPathProvider: ...).

Thanks.

/// Cached results of [readAsBytes].
final _bytesContentCache = LruCache<AssetId, Uint8List>(
1024 * 1024,
1024 * 1024 * 512,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's copied.

Added a TODO to look into the caching strategy; I suspect we can do something simpler. It would be surprising if we can't fit one build's worth of input in memory ... particularly given that when running with the analyzer, there is exactly another copy of all the inputs in the in-memory filesystem we give to the analyzer :)

Thanks.


/// Whether the file exists.
///
/// Uses [cache].
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a bit awkward :) while writing the next PR I realized it makes more sense to leave Filesystem always uncached and do the caching one level up in the reader. So that's the plan.

As the code is I do think it makes sense on the interface, because exactly how the cache is used has visible side effects. Which is also why it makes sense to move it out, it makes this type do too much :)

@davidmorgan davidmorgan merged commit 2f2eca0 into dart-lang:master Feb 21, 2025
35 checks passed
@davidmorgan davidmorgan deleted the cache-reader branch February 21, 2025 08:44
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