Combining fs_event and fs_poll

135 views
Skip to first unread message

Saúl Ibarra Corretgé

unread,
Sep 3, 2012, 7:28:00 AM9/3/12
to li...@googlegroups.com
Hi all,

fsevent and fspoll seem to provide the same functionality, but IIRC Ben
told me that fsevent won't work in all cases, for example if the file is
in a NFS mount point.

I wrapped them both on pyuv, but for a higher level application I was
thinking on making a thin layer on top of both and have them as
'backends'. It would be ideal to know which one to use on the fly,
however :-) Is there a way to know this? Some hint on the stat result
perhaps?


Thanks,

--
Sa�l Ibarra Corretg�
http://saghul.net/blog | http://about.me/saghul

Ben Noordhuis

unread,
Sep 3, 2012, 10:20:32 AM9/3/12
to li...@googlegroups.com
On Mon, Sep 3, 2012 at 1:28 PM, Saúl Ibarra Corretgé <sag...@gmail.com> wrote:
> Hi all,
>
> fsevent and fspoll seem to provide the same functionality, but IIRC Ben told
> me that fsevent won't work in all cases, for example if the file is in a NFS
> mount point.
>
> I wrapped them both on pyuv, but for a higher level application I was
> thinking on making a thin layer on top of both and have them as 'backends'.
> It would be ideal to know which one to use on the fly, however :-) Is there
> a way to know this? Some hint on the stat result perhaps?

There is no easy way to detect that, unfortunately, otherwise I would
have added it to libuv by now. :-)

For example, on Linux you could check /etc/mtab and maybe
/proc/filesystems to find out on what mount type the watched file
resides, and, if it's a file system like NFS, fall back to polling for
changes. However, that opens up a race window: another process can
remount the file system in the time between reading /etc/mtab and
creating the watcher.

Knowing what file systems will and won't report events is another hard
problem. Some won't work at all, others only partially or unreliably.
I would take a conservative approach here and use a whitelist (ext3,
ext4, xfs, jfs) and fall back to polling for everything else. That
approach won't work for file systems like /proc however, because the
inode changes on every stat. (inotify on the other hand doesn't work
at all on procfs...)

And that's just Linux. Other platforms have similar (or completely
different) issues. :-)

Saúl Ibarra Corretgé

unread,
Sep 3, 2012, 11:17:33 AM9/3/12
to li...@googlegroups.com
Ben Noordhuis wrote:
Thanks a lot for such detailed information Ben!

Bert Belder

unread,
Sep 3, 2012, 12:05:22 PM9/3/12
to li...@googlegroups.com
> For example, on Linux you could check /etc/mtab and maybe
> /proc/filesystems to find out on what mount type the watched file resides,
> and, if it's a file system like NFS, fall back to polling for changes.
However,
> that opens up a race window: another process can remount the file system
in
> the time between reading /etc/mtab and creating the watcher.

You could use fstatfs() the file it to find out without racing. Obviously
the user can still remount after inotify has been set up; I don't know what
will happen then.

> Knowing what file systems will and won't report events is another hard
> problem. Some won't work at all, others only partially or unreliably.
> I would take a conservative approach here and use a whitelist (ext3, ext4,
> xfs, jfs) and fall back to polling for everything else. That approach
won't work
> for file systems like /proc however, because the inode changes on every
> stat. (inotify on the other hand doesn't work at all on procfs...)

Libev also uses a whitelist approach:

```c
struct statfs sfs;

/* now local changes will be tracked by inotify, but remote changes
won't */
/* unless the filesystem is known to be local, we therefore still poll
*/
/* also do poll on <2.6.25, but with normal frequency */

if (!fs_2625)
w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL;
else if (!statfs (w->path, &sfs)
&& (sfs.f_type == 0x1373 /* devfs */
|| sfs.f_type == 0xEF53 /* ext2/3 */
|| sfs.f_type == 0x3153464a /* jfs */
|| sfs.f_type == 0x52654973 /* reiser3 */
|| sfs.f_type == 0x01021994 /* tempfs */
|| sfs.f_type == 0x58465342 /* xfs */))
w->timer.repeat = 0.; /* filesystem is local, kernel new enough */
else
w->timer.repeat = w->interval ? w->interval : NFS_STAT_INTERVAL; /*
remote, use reduced frequency */
```

> And that's just Linux. Other platforms have similar (or completely
> different) issues. :-)

You should define clearly what is supposed to happen. For example, if the
user renames a file, do we follow it or do we keep watching/polling the old
filename?

Also, we'd need to think about if and how we could monitor directories.

- Bert

Saúl Ibarra Corretgé

unread,
Sep 3, 2012, 3:40:06 PM9/3/12
to li...@googlegroups.com
Oh, I didn't know liev did it like that. Thanks for the pointer Bert!

Ben Noordhuis

unread,
Sep 3, 2012, 4:46:37 PM9/3/12
to li...@googlegroups.com
On Mon, Sep 3, 2012 at 6:05 PM, Bert Belder <bertb...@gmail.com> wrote:
> You could use fstatfs() the file it to find out without racing. Obviously
> the user can still remount after inotify has been set up; I don't know what
> will happen then.

That's a better solution but it's not race free either, there's still
a window between statfs() or fstatfs() and inotify_add_watch().

> You should define clearly what is supposed to happen. For example, if the
> user renames a file, do we follow it or do we keep watching/polling the old
> filename?

Lowest common denominator says we'll have to track the new file.
kqueue watches file descriptors, not file paths, and it won't
(always?) emit an event after a rename().

Maybe it's better to use polling file watchers on the BSDs and OS X.
kqueue file watching is broken on each platform in some way and often
subtly different from how it's broken on other platforms...

Bert Belder

unread,
Sep 3, 2012, 5:19:28 PM9/3/12
to li...@googlegroups.com
On Monday, September 3, 2012 10:46:38 PM UTC+2, Ben Noordhuis wrote:
On Mon, Sep 3, 2012 at 6:05 PM, Bert Belder <bertb...@gmail.com> wrote:
> You could use fstatfs() the file it to find out without racing. Obviously
> the user can still remount after inotify has been set up; I don't know what
> will happen then.

That's a better solution but it's not race free either, there's still
a window between statfs() or fstatfs() and inotify_add_watch().
 
It would be interesting to test what inotify does when the user unmounts and remounts the directory before we start finding a race-free solution for this problem.

> You should define clearly what is supposed to happen. For example, if the
> user renames a file, do we follow it or do we keep watching/polling the old
> filename?

Lowest common denominator says we'll have to track the new file.
kqueue watches file descriptors, not file paths, and it won't
(always?) emit an event after a rename().

This could probably be made to work on windows but it's not how it works atm. I believe it's also hard to do this with polling watchers.
 
Maybe it's better to use polling file watchers on the BSDs and OS X.
kqueue file watching is broken on each platform in some way and often
subtly different from how it's broken on other platforms...

This is only a problem when watching directories afact. Also, I believe Fedor has been working on a patch to support fsevents on OS X.

- Bert

Ben Noordhuis

unread,
Sep 3, 2012, 6:11:50 PM9/3/12
to li...@googlegroups.com
On Mon, Sep 3, 2012 at 11:19 PM, Bert Belder <bertb...@gmail.com> wrote:
> On Monday, September 3, 2012 10:46:38 PM UTC+2, Ben Noordhuis wrote:
>> That's a better solution but it's not race free either, there's still
>> a window between statfs() or fstatfs() and inotify_add_watch().
>
> It would be interesting to test what inotify does when the user unmounts and
> remounts the directory before we start finding a race-free solution for this
> problem.

You mean when you're watching /foo/bar and the user unmounts /foo? You
get an IN_ACCESS event and the kernel silently disarms the watcher.
That's on Linux though, I don't know how (or if) other Unices handle
that.

But the race condition I had in mind is this:

1. Alice calls statfs(/foo/bar), fs type is ext3
2. Bob unmounts /foo
3. Bob remounts /foo as fat16
4. Alice calls inotify_add_watch(/foo/bar)

> This is only a problem when watching directories afact. Also, I believe
> Fedor has been working on a patch to support fsevents on OS X.

Yes, but that won't help on FreeBSD. Poor file watcher support will
make me and the other FreeBSD user very upset.
Reply all
Reply to author
Forward
0 new messages