Skip to content

Fix refresh() not clearing cached state when file was never attached#758

Open
ilang wants to merge 1 commit intoapache:masterfrom
new-proimage:VFS-refresh-not-clearing-cached-state
Open

Fix refresh() not clearing cached state when file was never attached#758
ilang wants to merge 1 commit intoapache:masterfrom
new-proimage:VFS-refresh-not-clearing-cached-state

Conversation

@ilang
Copy link
Copy Markdown

@ilang ilang commented Mar 31, 2026

Summary

AbstractFileObject.detach() guards both doDetach() and cache clearing (setFileType(null), parent = null, removeChildrenCache()) with if (attached). This prevents clearing cached state on objects that were never attached.

However, provider-specific cached fields like FtpFileObject.childMap can be populated without going through attach() (e.g. via getChildFile()doGetChildren()). When refresh() calls detach() on such an object, the stale cached data is silently preserved, causing exists() to return incorrect results.

Fix

Move cache clearing (setFileType, parent, removeChildrenCache) outside the if (attached) guard so it always runs. The doDetach() call to the provider remains guarded, since providers should not be detached if they were never attached.

Root cause

The if (attached) guard was introduced in the original detach() implementation (2005) when childMap was only populated during attach()doGetType(). Over the years, code paths were added that populate cached fields without attach() (like getChildFile()doGetChildren()), making the guard incorrect.

Test plan

  • Full VFS2 test suite passes (3203 tests, 0 failures)
  • Verified with debugger that childMap is correctly cleared after refresh() on unattached objects

Copy link
Copy Markdown
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

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

-1: This PR is missing a unit test. A future change could undo this behavior without detection.

…ached

AbstractFileObject.detach() guards both doDetach() and cache clearing
with 'if (attached)'. This prevents clearing cached state (type, parent,
children) on objects that were never attached. However, provider-specific
cached fields can be populated without going through attach():
- FtpFileObject.childMap via getChildFile() -> doGetChildren()
- SftpFileObject.attrs via setStat() in doListChildrenResolved()

When refresh() calls detach() on such an object, the stale cached data
is silently preserved, causing exists() to return incorrect results.

Fix:
- FtpFileObject.refresh(): clear childMap explicitly, since doDetach()
  is guarded by attached and may not run.
- SftpFileObject.refresh(): override to clear attrs explicitly, same
  reason.
- AbstractFileObject.detach(): move base-class cache clearing
  (setFileType, parent, removeChildrenCache) outside the 'if (attached)'
  guard as a defensive measure. Currently these fields are only populated
  via code paths that call attach(), but this ensures correctness if
  future changes introduce paths that bypass attach().

Tests:
- FtpRefreshCachedStateTest: verifies exists() returns false after a
  file is deleted and parent is refreshed (FTP childMap scenario).
- SftpRefreshCachedStateTest: verifies exists() returns false after a
  file is deleted and refreshed (SFTP attrs scenario).
@ilang ilang force-pushed the VFS-refresh-not-clearing-cached-state branch from 93d09ad to 2b2f45a Compare March 31, 2026 13:48
@ilang ilang requested a review from garydgregory March 31, 2026 21:56
@ilang ilang marked this pull request as draft March 31, 2026 22:34
@ilang ilang marked this pull request as ready for review April 1, 2026 09: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