Skip to content
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

File system watcher #20

Merged
merged 28 commits into from
Jan 6, 2019
Merged

File system watcher #20

merged 28 commits into from
Jan 6, 2019

Conversation

sbusch42
Copy link
Member

@sbusch42 sbusch42 commented Nov 25, 2018

This is our first take on implementing a file system watcher interface. It can be merged as soon as the Windows implementation of LocalFileWatcher has been implemented.

Missing features, nice-to-have:

  • Implement windows/LocalFileWatcher
  • Research and implement macOS backend
  • The linux backend is in the posix directory, but it's not posix, so it should be in a linux directory, use null implementation for other *nix systems

@sbusch42 sbusch42 requested a review from scheibel November 25, 2018 12:20
source/cppfs/include/cppfs/cppfs.h Show resolved Hide resolved
source/cppfs/source/posix/LocalFileWatcher.cpp Outdated Show resolved Hide resolved
source/cppfs/source/FileEventHandler.cpp Outdated Show resolved Hide resolved
@sbusch42
Copy link
Member Author

I guess we should also support some more events like changing file permissions or renaming files

@sbusch42
Copy link
Member Author

ref #3

Copy link
Member Author

@sbusch42 sbusch42 left a comment

Choose a reason for hiding this comment

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

Some questions mainly about the windows backend.

source/cppfs/source/windows/LocalFileWatcher.cpp Outdated Show resolved Hide resolved
if (!hEvent)
throw std::runtime_error("failed creating wait event");

auto lw = std::make_shared<LocalWatcher>();
Copy link
Member Author

Choose a reason for hiding this comment

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

Are the shared pointers here ever shared between several objects, or are they unique? (seems to me that way). Maybe we can use unique_ptr, or even just plain handles?

Copy link
Contributor

Choose a reason for hiding this comment

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

shared_ptr is used because you can specify the delete functions for the object, which in case of Windows HANDLE is the ::CloseHandle function. Out of pure convenience, and to avoid dangling handles.

NULL);
if (ret != 0) {
std::string fname(fileName, fileName + ret);
std::replace(fname.begin(), fname.end(), '\\', '/');
Copy link
Member Author

Choose a reason for hiding this comment

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

No need to convert path delimiters, FilePath already takes care of that


protected:
std::shared_ptr<LocalFileSystem> m_fs; ///< File system that created this watcher
std::shared_ptr<void> m_waitStopEvent; ///< Event to stop watch function
Copy link
Member Author

Choose a reason for hiding this comment

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

These are not shared in any way, so it should be unique_ptr instead of shared_ptr. But also that smart pointer does not do anything, the handle has been released by specific API-functions anyway, so I would suggest to just use void* here.

if (event->mask & IN_CREATE) eventType = FileCreated;
else if (event->mask & IN_DELETE) eventType = FileRemoved;
else if (event->mask & IN_MODIFY) eventType = FileModified;
else if (event->mask & IN_ATTRIB) eventType = FileModified;
Copy link
Member Author

Choose a reason for hiding this comment

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

I think we should add a new type FileAttribChanged instead of implicitly merging them.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea.

uint32_t flags = 0;
if (events & FileCreated) flags |= IN_CREATE;
if (events & FileRemoved) flags |= IN_DELETE;
if (events & FileModified) flags |= (IN_MODIFY | IN_ATTRIB);
Copy link
Member Author

Choose a reason for hiding this comment

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

I think we should add a new type FileAttribChanged instead of implicitly merging them.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

source/examples/cppfs-watch/main.cpp Outdated Show resolved Hide resolved
* This class is used for file systems that do not support
* file system watchers, such as remote file systems.
*/
class CPPFS_API NullFileWatcher : public AbstractFileWatcherBackend
Copy link
Member

Choose a reason for hiding this comment

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

I do like the null object pattern.
However, I have the impression that our remaining code base uses nullptr in similiar cases.
Does using this pattern simplify our code base?

Copy link
Member Author

Choose a reason for hiding this comment

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

I used it in some of my older projects with the private implementation pattern (which we also use here). It makes it simpler because one can just assume that the implementation object is always valid and doesn't have to check it in each function. But you're right, we're checking m_backend in all functions to far, so maybe we should stick to that pattern (use nullptr instead of null-implementation)


AbstractFileWatcherBackend::AbstractFileWatcherBackend(FileWatcher * fileWatcher)
: m_fileWatcher(fileWatcher)
{
Copy link
Member

Choose a reason for hiding this comment

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

The documentation states that m_fileWatcher may never be nullptr.
I suggest to add the corresponding assertion here.

source/cppfs/include/cppfs/FileHandle.h Show resolved Hide resolved
source/cppfs/include/cppfs/fs.h Show resolved Hide resolved
* @brief
* Watcher entry
*/
struct Watcher {
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to reorder the members?
I suggest from large to small.
For this case, this may result in something like this:

struct Watcher {
        std::shared_ptr<void> handle;
        std::shared_ptr<void> platform;
        FileHandle            fileHandle;
        RecursiveMode         recursive;
        unsigned int          events;
}

Copy link
Member

Choose a reason for hiding this comment

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

Rationale: hopefully reduce object size. Probably we should measure this properly. Using the attribute packed may be another option.

source/cppfs/source/FileWatcher.cpp Show resolved Hide resolved
source/cppfs/source/fs.cpp Show resolved Hide resolved
uint32_t flags = 0;
if (events & FileCreated) flags |= IN_CREATE;
if (events & FileRemoved) flags |= IN_DELETE;
if (events & FileModified) flags |= (IN_MODIFY | IN_ATTRIB);
Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

source/cppfs/source/windows/LocalFileWatcher.cpp Outdated Show resolved Hide resolved
@sbusch42 sbusch42 changed the title [WIP] File system watcher File system watcher Jan 6, 2019
@sbusch42 sbusch42 merged commit a5e7840 into master Jan 6, 2019
@sbusch42 sbusch42 deleted the watcher branch January 6, 2019 18:48
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.

3 participants