fix(tool): initialize asset isModified state on startup to prevent 2x hot restart slowdown#187488
Conversation
… hot restart slowdown Prior to this fix, the first hot restart would incorrectly detect all assets as modified and sync/recompile all of them. This was because DevFS.updateBundle bypassed the asset loop during the initial application startup, which prevented the stateful isModified getter from being initialized. This fix accesses isModified for each asset in the bundle during startup to initialize the cache, matching the behavior before the asset processing refactor. Fixes flutter#187391
There was a problem hiding this comment.
Code Review
This pull request updates DevFS.updateBundle to initialize the isModified state of assets during the first upload when syncing is skipped, preventing unnecessary recompilation on subsequent hot restarts. A corresponding test was added to verify this behavior. The review feedback suggests simplifying the asset iteration in DevFS.updateBundle by iterating directly over bundle.entries.values instead of bundle.entries.entries since the keys are not used.
harryterkelsen
left a comment
There was a problem hiding this comment.
Let’s just change isModified to be what people would expect instead of doing this partial solution. To me, it seems odd for isModified to not be idempotent.
|
@harryterkelsen PTAL |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors DevFSContent and its subclasses to decouple the isModified check from state mutation by introducing an explicit markClean() method. It also updates DevFS.updateBundle and associated tests to manage this lifecycle. The review feedback identifies two critical issues: a regression in isModifiedAfter that prevents the detection of deleted files, and an unintended state mutation in the size getter due to calling markClean(), which can cause modified files to be skipped during synchronization.
|
I had to do the google3 dance, but I think we're ready @harryterkelsen ! |
DevFSFileContent.isModifiedAfter returned true whenever the cached
_fileStat was null, ignoring the time argument entirely. _fileStat is the
sync baseline written only by markClean(); the entries of a freshly built
AssetBundle are never marked clean, so _fileStat is always null for them
and isModifiedAfter always reported them as modified.
flutter test's _needsRebuild() relies on isModifiedAfter to decide
whether build/unit_test_assets is up to date. With the broken short
circuit it always rebuilt the directory (delete + non-atomic rewrite) on
every invocation. When several flutter test invocations run in the same
project directory, one invocation's delete window overlaps another's
asset reads, surfacing as a transient
Exception: Asset 'shaders/ink_sparkle.frag' not found
that fails an unrelated test.
isModifiedAfter is handed an explicit reference time and must not consult
the sync baseline. Determine modification purely from the file's current
modification time, matching the other DevFSContent implementations.
Regression from flutter#187488, which made the stat accessors pure. Before that
the mutating _stat() populated _fileStat as a side effect of reads during
the asset build, so _needsRebuild happened to work. Fixes
flutter#187725.
DevFSFileContent.isModifiedAfter returned true whenever the cached
_fileStat was null, ignoring the time argument entirely. _fileStat is the
sync baseline written only by markClean(); the entries of a freshly built
AssetBundle are never marked clean, so _fileStat is always null for them
and isModifiedAfter always reported them as modified.
flutter test's _needsRebuild() relies on isModifiedAfter to decide
whether build/unit_test_assets is up to date. With the broken short
circuit it always rebuilt the directory (delete + non-atomic rewrite) on
every invocation. When several flutter test invocations run in the same
project directory, one invocation's delete window overlaps another's
asset reads, surfacing as a transient
Exception: Asset 'shaders/ink_sparkle.frag' not found
that fails an unrelated test.
isModifiedAfter is handed an explicit reference time and must not consult
the sync baseline. Determine modification purely from the file's current
modification time, matching the other DevFSContent implementations.
Regression from flutter#187488, which made the stat accessors pure. Before that
the mutating _stat() populated _fileStat as a side effect of reads during
the asset build, so _needsRebuild happened to work. Fixes
flutter#187725.
flutter/flutter@1bdf4af...66aaa9a 2026-06-08 katelovett@google.com Add docs on bumping Dart (flutter/flutter#187540) 2026-06-08 rmacnak@google.com Rename Dart_LoadELF2 back to Dart_LoadELF. (flutter/flutter#187677) 2026-06-08 1063596+reidbaker@users.noreply.github.com Add bare, reidbaker, and android agents (flutter/flutter#187588) 2026-06-08 engine-flutter-autoroll@skia.org Roll Dart SDK from 73ec2745c49a to 39f1c44e294f (3 revisions) (flutter/flutter#187684) 2026-06-08 bdero@google.com [Flutter GPU] Document the formats.dart enums (flutter/flutter#187628) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from 0ea3dae686e3 to 43f135735152 (3 revisions) (flutter/flutter#187683) 2026-06-08 bdero@google.com [flutter_tools] Fix `flutter create` crash with SDK packages in bin/cache/pkg (flutter/flutter#187653) 2026-06-08 engine-flutter-autoroll@skia.org Roll Packages from 61bdbb4 to 13b49f4 (1 revision) (flutter/flutter#187678) 2026-06-08 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from fAGotRbStYGA0idum... to KNe93cf5wU4xG2d-m... (flutter/flutter#187675) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from d17c51db4ede to 0ea3dae686e3 (1 revision) (flutter/flutter#187674) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from 9659a87f500f to d17c51db4ede (2 revisions) (flutter/flutter#187672) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from a56d5a4e1120 to 9659a87f500f (1 revision) (flutter/flutter#187667) 2026-06-07 engine-flutter-autoroll@skia.org Roll Skia from 101faf7d9d1f to a56d5a4e1120 (1 revision) (flutter/flutter#187665) 2026-06-07 burak.karahan@mail.ru Remove Material import from navigator replacement tests (flutter/flutter#186674) 2026-06-07 burak.karahan@mail.ru Remove Material import from editable text cursor tests (flutter/flutter#186671) 2026-06-07 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from eIU3QDrxaBPAMY9oi... to fAGotRbStYGA0idum... (flutter/flutter#187656) 2026-06-07 engine-flutter-autoroll@skia.org Roll Skia from 294ac0cb2a7d to 101faf7d9d1f (1 revision) (flutter/flutter#187655) 2026-06-06 engine-flutter-autoroll@skia.org Roll Skia from 91ee612cf552 to 294ac0cb2a7d (2 revisions) (flutter/flutter#187651) 2026-06-06 engine-flutter-autoroll@skia.org Roll Skia from a47a9a2c8ae5 to 91ee612cf552 (4 revisions) (flutter/flutter#187642) 2026-06-06 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from N_LiSaBSUsE2LDZgG... to eIU3QDrxaBPAMY9oi... (flutter/flutter#187641) 2026-06-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 05243f181c21 to 73ec2745c49a (2 revisions) (flutter/flutter#187640) 2026-06-06 engine-flutter-autoroll@skia.org Roll Fuchsia GN SDK from oOAcFhkoE2_-Sy67z... to a87CbQSWEjkPUK1ZY... (flutter/flutter#187632) 2026-06-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 6a9a0efe66eb to 05243f181c21 (1 revision) (flutter/flutter#187634) 2026-06-05 bdero@google.com [Flutter GPU] Add instanced draw support (flutter/flutter#187359) 2026-06-05 30870216+gaaclarke@users.noreply.github.com clears out the android context after the frame on mediatek devices (flutter/flutter#187404) 2026-06-05 kevmoo@users.noreply.github.com fix(tool): initialize asset isModified state on startup to prevent 2x hot restart slowdown (flutter/flutter#187488) 2026-06-05 magder@google.com Remove reference to 'good first issue' in the docs (flutter/flutter#187615) 2026-06-05 stuartmorgan@google.com Remove references to 'good first issue' (flutter/flutter#187617) 2026-06-05 154381524+flutteractionsbot@users.noreply.github.com Revert "Add support for stylus buttons" (flutter/flutter#187581) 2026-06-05 6655696+guidezpl@users.noreply.github.com Always run coverage upload step, even if a single test fails (flutter/flutter#187614) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC louisehsu@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…r#11876) flutter/flutter@1bdf4af...66aaa9a 2026-06-08 katelovett@google.com Add docs on bumping Dart (flutter/flutter#187540) 2026-06-08 rmacnak@google.com Rename Dart_LoadELF2 back to Dart_LoadELF. (flutter/flutter#187677) 2026-06-08 1063596+reidbaker@users.noreply.github.com Add bare, reidbaker, and android agents (flutter/flutter#187588) 2026-06-08 engine-flutter-autoroll@skia.org Roll Dart SDK from 73ec2745c49a to 39f1c44e294f (3 revisions) (flutter/flutter#187684) 2026-06-08 bdero@google.com [Flutter GPU] Document the formats.dart enums (flutter/flutter#187628) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from 0ea3dae686e3 to 43f135735152 (3 revisions) (flutter/flutter#187683) 2026-06-08 bdero@google.com [flutter_tools] Fix `flutter create` crash with SDK packages in bin/cache/pkg (flutter/flutter#187653) 2026-06-08 engine-flutter-autoroll@skia.org Roll Packages from 61bdbb4 to 13b49f4 (1 revision) (flutter/flutter#187678) 2026-06-08 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from fAGotRbStYGA0idum... to KNe93cf5wU4xG2d-m... (flutter/flutter#187675) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from d17c51db4ede to 0ea3dae686e3 (1 revision) (flutter/flutter#187674) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from 9659a87f500f to d17c51db4ede (2 revisions) (flutter/flutter#187672) 2026-06-08 engine-flutter-autoroll@skia.org Roll Skia from a56d5a4e1120 to 9659a87f500f (1 revision) (flutter/flutter#187667) 2026-06-07 engine-flutter-autoroll@skia.org Roll Skia from 101faf7d9d1f to a56d5a4e1120 (1 revision) (flutter/flutter#187665) 2026-06-07 burak.karahan@mail.ru Remove Material import from navigator replacement tests (flutter/flutter#186674) 2026-06-07 burak.karahan@mail.ru Remove Material import from editable text cursor tests (flutter/flutter#186671) 2026-06-07 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from eIU3QDrxaBPAMY9oi... to fAGotRbStYGA0idum... (flutter/flutter#187656) 2026-06-07 engine-flutter-autoroll@skia.org Roll Skia from 294ac0cb2a7d to 101faf7d9d1f (1 revision) (flutter/flutter#187655) 2026-06-06 engine-flutter-autoroll@skia.org Roll Skia from 91ee612cf552 to 294ac0cb2a7d (2 revisions) (flutter/flutter#187651) 2026-06-06 engine-flutter-autoroll@skia.org Roll Skia from a47a9a2c8ae5 to 91ee612cf552 (4 revisions) (flutter/flutter#187642) 2026-06-06 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from N_LiSaBSUsE2LDZgG... to eIU3QDrxaBPAMY9oi... (flutter/flutter#187641) 2026-06-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 05243f181c21 to 73ec2745c49a (2 revisions) (flutter/flutter#187640) 2026-06-06 engine-flutter-autoroll@skia.org Roll Fuchsia GN SDK from oOAcFhkoE2_-Sy67z... to a87CbQSWEjkPUK1ZY... (flutter/flutter#187632) 2026-06-06 engine-flutter-autoroll@skia.org Roll Dart SDK from 6a9a0efe66eb to 05243f181c21 (1 revision) (flutter/flutter#187634) 2026-06-05 bdero@google.com [Flutter GPU] Add instanced draw support (flutter/flutter#187359) 2026-06-05 30870216+gaaclarke@users.noreply.github.com clears out the android context after the frame on mediatek devices (flutter/flutter#187404) 2026-06-05 kevmoo@users.noreply.github.com fix(tool): initialize asset isModified state on startup to prevent 2x hot restart slowdown (flutter/flutter#187488) 2026-06-05 magder@google.com Remove reference to 'good first issue' in the docs (flutter/flutter#187615) 2026-06-05 stuartmorgan@google.com Remove references to 'good first issue' (flutter/flutter#187617) 2026-06-05 154381524+flutteractionsbot@users.noreply.github.com Revert "Add support for stylus buttons" (flutter/flutter#187581) 2026-06-05 6655696+guidezpl@users.noreply.github.com Always run coverage upload step, even if a single test fails (flutter/flutter#187614) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC louisehsu@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Fixes flutter#187725, regression was introduced in flutter#187488 `DevFSFileContent.isModifiedAfter` returned `true` whenever the cached `_fileStat` was `null`, ignoring the time argument entirely. `_fileStat` is the sync baseline written only by `markClean()` the entries of a freshly built `AssetBundle` are never marked clean, so `_fileStat` is always `null` for them and `isModifiedAfter` always reported them as modified. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md Co-authored-by: Kevin Moore <kevmoo@users.noreply.github.com>
… hot restart slowdown (flutter#187488) Prior to this fix, the first hot restart would incorrectly detect all assets as modified and sync/recompile all of them. This was because DevFS.updateBundle bypassed the asset loop during the initial application startup, which prevented the stateful isModified getter from being initialized. This fix accesses isModified for each asset in the bundle during startup to initialize the cache, matching the behavior before the asset processing refactor. Fixes flutter#187391
Fixes flutter#187725, regression was introduced in flutter#187488 `DevFSFileContent.isModifiedAfter` returned `true` whenever the cached `_fileStat` was `null`, ignoring the time argument entirely. `_fileStat` is the sync baseline written only by `markClean()` the entries of a freshly built `AssetBundle` are never marked clean, so `_fileStat` is always `null` for them and `isModifiedAfter` always reported them as modified. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md Co-authored-by: Kevin Moore <kevmoo@users.noreply.github.com>
Prior to this fix, the first hot restart would incorrectly detect all assets as modified and sync/recompile all of them. This was because DevFS.updateBundle bypassed the asset loop during the initial application startup, which prevented the stateful isModified getter from being initialized.
This fix accesses isModified for each asset in the bundle during startup to initialize the cache, matching the behavior before the asset processing refactor.
Fixes #187391