Skip to content

fix: wait for cached files to be removed before deleting their cache info - #541

Open
junsworth wants to merge 1 commit into
Baseflow:mainfrom
junsworth:fix/await-file-removal-before-cache-info
Open

junsworth wants to merge 1 commit into
Baseflow:mainfrom
junsworth:fix/await-file-removal-before-cache-info

Conversation

@junsworth

Copy link
Copy Markdown

✨ What kind of change does this PR introduce? (Bug fix, feature, docs update...)

Bug fix.

⤵️ What is the current behavior?

CacheStore._cleanupCache starts removing the cached files without waiting for them, and then deletes the cache info rows (provider.deleteAll). So the rows can be gone while the files are still on disk. If the app is killed in that gap, the file is left behind with no row pointing at it, and nothing cleans it up afterwards. A row without a file is dropped on the next read, but a file without a row is never looked at again.

emptyCache already waits for the removals before deleting the rows, _cleanupCache doesn't.

To make the gap easy to hit I added a 20 second pause before the file deletes in a local copy of 3.4.5. Killing the app during cleanup then left 300 files (12.1 MB) in the cache folder with no row. The pause only makes it reproducible, I haven't measured how often this happens without it.

This doesn't cover files left behind by a download that is killed before its row is written, that is a separate case.

🆕 What is the new behavior (if this is a feature change)?

The cleanup waits for the file removals and then deletes the rows. If the app is killed in between, there is a row without a file, which the store already handles.

If a file can't be removed, its row is kept so the next cleanup retries it. The other rows are still deleted, and the error is still thrown like before.

💥 Does this PR introduce a breaking change?

No.

🐛 Recommendations for testing

Two new tests in cache_store_test.dart:

  • Store should not remove cache info before the cached file is removed: getting to the file is delayed, and deleteAll must not be called until the file is gone.
  • Store should keep cache info of a file that cannot be removed.

Both fail on current main (deleteAll([1]) is called while the file is still there, and deleteAll([1, 2]) includes the file that couldn't be removed) and pass with this change.

On Flutter 3.47.4, flutter test, dart format --set-exit-if-changed . and flutter analyze all pass.

📝 Links to relevant issues/docs

Related: #540 also changes cache_store.dart (_removeCachedFile, different lines). Both PRs bump to 3.4.6, so whichever lands second needs to move to 3.4.7.

🤔 Checklist before submitting

  • All projects build
  • Follows style guide lines (code style guide)
  • Relevant documentation was updated
  • Rebased onto current main
  • Version bumped and dated CHANGELOG entry added

I haven't built the example apps locally (CI does), the change only touches cache_store.dart.

…info

The cleanup started removing files without waiting and then deleted the
cache info right away, so the cache info could be gone while the files
were still on disk. If the app was killed in between, those files were
left with nothing referencing them.

The cleanup now waits for the file removals first. The cache info of a
file that could not be removed is kept, so the next cleanup retries it.
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.

1 participant