Skip to content

feat: add V2/INVALIDATE_PATH socket message for cache invalidation - #48

Open
flash7777 wants to merge 2 commits into
opencloud-eu:mainfrom
flash7777:feature/invalidate-entry
Open

feat: add V2/INVALIDATE_PATH socket message for cache invalidation#48
flash7777 wants to merge 2 commits into
opencloud-eu:mainfrom
flash7777:feature/invalidate-entry

Conversation

@flash7777

Copy link
Copy Markdown

Summary

When a sync daemon creates new placeholder files in the underlying filesystem after the FUSE mount is active, the kernel may cache negative lookups. New files don't appear in directory listings until the user navigates away and back.

This adds a new socket message that the sync daemon can send to invalidate a path in the FUSE kernel cache:

V2/INVALIDATE_PATH:{"arguments":{"path":"/subdir"}}

On receiving this message, openvfs calls fuse_invalidate_path() which clears the kernel's cached entries for that path. The next readdir or lookup will see the new files.

Use case

Headless sync daemons like cloudd periodically sync remote directory listings and create local placeholder files. Without cache invalidation, Nautilus and other file managers don't show new files until manual refresh.

Changes

  • openvfsfuse.cpp: store fuse * pointer during init, add openvfsfuse_invalidate_path()
  • openvfsfuse.h: declare openvfsfuse_invalidate_path()
  • socketthread.cpp: handle V2/INVALIDATE_PATH message, call invalidate

3 files, +37 lines.

Test plan

  • Builds clean
  • Existing socket protocol (VERSION, V2/HYDRATE_FILE) unaffected
  • Integration test: create file in underlying FS, send INVALIDATE_PATH, verify ls shows it

When a sync daemon (e.g. cloudd) creates new placeholder files in the
underlying filesystem after the FUSE mount is active, the kernel may
cache negative lookups and not show the new files until the user
navigates away and back.

This adds a new socket message that the sync daemon can send to
invalidate a path in the FUSE kernel cache:

    V2/INVALIDATE_PATH:{"arguments":{"path":"/subdir"}}

On receiving this message, openvfs calls fuse_invalidate_path() which
clears the kernel's cached entries for that path. The next readdir
or lookup will see the new files.

The fuse instance pointer is captured during init and stored globally
for use by the socket thread.

@dragotin dragotin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Interesting feature. When I investigated with the help of a machine, it suggested to use file_invalidate_path also from within the codebase, when the SocketThread received info about the hydrated file. Maybe that would fix the problem?

Here are some remarks.

// Store fuse instance for invalidation from socket thread
auto *ctx = fuse_get_context();
if (ctx) {
_fuseInstance = ctx->fuse;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can't you completely get rid of the _fuseInstance var by calling fuse_get_context()->fuse ?

Comment thread src/openvfsfuse/openvfsfuse.cpp Outdated
std::string fusePath = path;
if (!fusePath.empty() && fusePath[0] != '/') {
fusePath = "/" + fusePath;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you can use const auto fusePath = getInternalPath(path);

Comment thread src/openvfsfuse/socketthread.cpp Outdated
try {
const auto j = json::parse(msgAttr);
const auto path = j["arguments"]["path"].get<string>();
cout << "Invalidating path: " << path << endl;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please use openvfsfuse_log

Comment thread src/openvfsfuse/socketthread.cpp Outdated
cout << "Invalidating path: " << path << endl;
openvfsfuse_invalidate_path(path);
} catch (json::exception &e) {
std::cerr << "Invalid INVALIDATE_PATH message: " << msgAttr << e.what() << std::endl;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same

Per review by @dragotin:
- Replace _fuseInstance global with fuse_get_context()->fuse
- Use getInternalPath() for path normalization in invalidate
- Replace cout/cerr with openvfsfuse_log for consistent logging

Note: invalidating after hydration completion would require adding
the file path to HydJob struct — left as follow-up since HydJob
currently only stores state.

@dragotin dragotin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One more comment. Thanks.

Btw, I think the cache clearing could happen in openVFSfuse_open() after the hydration is finished. There we are in the right thread and have the path available. It is still the same that came in to the function. (I haven't tried...)

return;
}
const auto fusePath = getInternalPath(path);
std::string fuseStr = "/" + fusePath.string();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you please put that behind a function getFusePath() similar to the other two? That way we can properly document the difference between the three pathes.

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