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

[WIP] FSEvent backend for 5.0 #144

Closed
wants to merge 7 commits into from
Closed

Conversation

cmyr
Copy link
Contributor

@cmyr cmyr commented Jan 2, 2018

Very much a rough sketch/first-pass right now (I have no idea if this runs/works, as I'm writing this), but wanted to see if I could get CI running. Will tighten this up in coming days.

progress towards #139

@cmyr cmyr force-pushed the fsevent-next branch 2 times, most recently from 893e474 to e80fa74 Compare January 2, 2018 04:25
vec![
Capability::FollowSymlinks,
Capability::WatchEntireFilesystem,
Capability::WatchFiles,
Copy link
Member

Choose a reason for hiding this comment

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

I've only given a cursory look to the FSEvent documentation, but it is my understanding that it cannot do that, i.e. FSEvent only watches directories (and Apple recommends using kqueue for single files instead).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the FileEvents flag available from 10.7, if I create an FSEventStream with a single path, to a file, I will receive only events for that specific file, not events in the parent directory.

My impression is that a lot of Apple's documentation on the matter was written for the initial release, and hasn't been updated.

Copy link
Member

Choose a reason for hiding this comment

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

Oh cool :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea, I was pleasantly surprised, because all the docs suggested this wasn't the case. :)

@cmyr
Copy link
Contributor Author

cmyr commented Jan 6, 2018

@passcod FSEvents will hold back on sending modify events while the modifying process has an open file descriptor. This means that the current tests checking for modification events will fail consistently.

More than that: closing the fd does not guarantee that events are flushed; even when you ask the stream not to buffer events, some buffering occurs. To receive multiple events for multiple writes, I have to both close the fd and wait 500ms between them.

More generally, on the filesystem-dev mailing list there's a very clear statement from a developer relations person that FSEvent is not a log of file system activity:

FSEvents is designed to notify you about events in the file system so that you can then go look in the file system to find the current state of things and sync based on that. It's not designed to feed you a stream of events with sufficient fidelity to reconstruct how the file system go into its current state."

filesystem-dev

So this particular case is not something FSEvent will give us.

It's not totally clear to me how I should handle this. Maybe we want a new capability like "EmitImmediately"? Curious to hear your thoughts.

@passcod
Copy link
Member

passcod commented Jan 7, 2018

Actually, that's only a problem for the compliance tests, right? It doesn't make a different for usage in Notify or beyond. It's just that this backend will not behave how the compliance tests expect the backends to work.

Instead of adding a capability just to cover this particularity of this backend, we can make an exception to the rule "all backends must pass compliance tests" and write those same tests for FSEvent. In essence, this backend will still "pass compliance tests", it's just that it won't use the centralised backend macro for it.

So: copy the relevant tests from backend/src/compliance.rs, remove the capability checking, and rewrite them to test this backend with its particularities. When we add more compliance tests we'll need to also add them here, so that's a little more work, but it should work.

@cmyr
Copy link
Contributor Author

cmyr commented Jan 7, 2018

Okay that works for me; If you don't think that having the definition of compliance be variable between different backends will be a problem then I am happy to defer to you! I'll have some time tomorrow to work on this, so should at least get the tests done then.

@passcod
Copy link
Member

passcod commented Jan 7, 2018

Yeah, I'll have to write this up somewhere, but basically: the tests themselves as written are not super rigorous and they're not normative. "Compliance" is better defined with words, i.e. a spec (which isn't quite written yet), and the documentation for each Capability (which could be more precise, I'll work on that). That doesn't change. The test_compliance!() macro is a developer convenience to avoid duplication, not the actual definition of compliance.

@passcod
Copy link
Member

passcod commented Jan 25, 2018

@cmyr Hey, have you gotten any further on this? I have my Macbook back now, so I could work on this a bit, but I'd rather not duplicate efforts if you're on it :)

@cmyr
Copy link
Contributor Author

cmyr commented Jan 26, 2018

@passcod Sorry I've been travelling a little bit so this fell off my list, but I'll have time early next week at the latest (and probably a few hours later today)

@passcod
Copy link
Member

passcod commented Jan 27, 2018

No problem!

This is very much a wip, although it compiles and has a first stab at
the flag parsing logic. It doesn't actually run, though.
This patch is a very rough initial pass at handling some of the weird
behaviour around FSEvent. In particular, we now track previous events,
and use the existence of a previous event to determine how to interpret
a new event.
@cmyr
Copy link
Contributor Author

cmyr commented Feb 1, 2018

Okay, I've updated this with a very very basic implementation. We keep track of previously received events; when we receive a new event, we check if there has been a recent event at the same path; if there has we send events for any flags that are in the new event but not the previous; and we also send the Any event, to indicate that there may be other changes. This means that if you modify a file twice within, say, 5 seconds, you will receive a Modify event followed by an Any event; if you create an event and then modify it 5 seconds later, you'll receive a Create event, followed by Modify and Any events.

This doesn't feel great to me, but it's a reasonable starting place?

Pardon the delay, I've been having trouble getting my head back into this.

@passcod
Copy link
Member

passcod commented Feb 1, 2018

Good work! I like this usage of Any. I'll read through more in depth to digest things.

Regarding delay: don't worry :) This isn't blocking anything at the moment — I still have a bunch of work to do on the core interfaces and dayjob has been picking up so I haven't had as much time to work on notify recently. I'm very grateful of any time you do put in this!

Though: if you know — at any point — you're not going to have time for a while (weeks, not days), could you chime in here? That way I can know that I could pick it if I have some time.

@cmyr
Copy link
Contributor Author

cmyr commented Feb 1, 2018

My feeling right now is that refining this implementation should probably happen in concert with other work, when you'll be developing a better sense of how you're going to be unifying the various backends, and what would be most helpful for you to that end.

So maybe give this a read when you have time, see if it makes approximate sense, and then it can be something to iterate from. If it looks like it will make sense, I'm happy to add some more documentation.

@passcod
Copy link
Member

passcod commented Feb 2, 2018

Okay, sounds good. I'll do that.

@passcod
Copy link
Member

passcod commented Apr 24, 2018

I'll merge this in soonish to work on it in-tree more closely, and bring it up to the newest interface.

@passcod
Copy link
Member

passcod commented Oct 6, 2018

I looked some more at FSEvent and had a think and changed the plan... rather dramatically. The low down is this: FSEvent is so radically different that it I think it breaks user expectations of what a filesystem notifier should do. This is also supported by the prose in the Apple documentation. Their recommendation for the kind of semantics we're looking for is kqueue.

The plan becomes this:

  • FSEvent will become an external notify backend. It might be in this repo, it might not. It won't be included in the "default" notify distribution, and won't be loaded by default. To use it, people will have to require the notify-backend-fsevent crate.
  • Actual implementation of this backend is pushed back to after Notify beta is out. That is, I remove the dependence on wrangling FSEvent from shipping Notify.
  • macOS will be covered with a new kqueue backend, along with BSDs.

That makes the default macOS experience more in line with expectations, at the cost of efficiency (i.e. might see higher CPU usage) when watching large trees. People with requirements where FSEvent fits will be able to opt-in.

I'm closing this PR, but be sure that this work is not wasted by any means! There's a merge-fsevent branch in the repo and that will form the basis for the backend, later on.

@passcod passcod closed this Oct 6, 2018
@cmyr
Copy link
Contributor Author

cmyr commented Oct 6, 2018

I agree that kqueue is likely the correct API for us on macOS. Looking forward to the new work!

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