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

[CLOSED] [File Watchers] Can not externally rename a directory with subfolders on Windows #5955

Open
core-ai-bot opened this issue Aug 30, 2021 · 18 comments

Comments

@core-ai-bot
Copy link
Member

Issue by jasonsanjose
Thursday Jan 16, 2014 at 04:37 GMT
Originally opened as adobe/brackets#6551


UPDATE: I don't remember seeing this earlier, but now if I load a simple tree 2 levels deep...

ProjectRoot
----folder
--------subfolder
------------file.txt

...and I try to rename folder externally, I get the "folder in use" dialog.

Old Description:

While debugging #6537, I found the following...

If, external to brackets, I copy in a folder with a subfolder into my project, then externally try to rename the folder that I pasted, windows prevents me from doing so with this warning:

Folder In Use
The action can't be completed because the folder or a file in it is open in another program. Close the folder or file and try again.

Note that this only happens for externally added folders that include a subfolder. Pasting in a folder with no subfolders doesn't reproduce the issue. I assume that the file watcher for the subfolder is what is holding a file lock.

This may be a sprint 36 blocker.

cc@iwehrman@peterflynn@gruehle

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Thursday Jan 16, 2014 at 04:42 GMT


@peterflynn made a good point, why doesn't this happen for all watched folders? Indeed it doesn't...

@core-ai-bot
Copy link
Member Author

Comment by iwehrman
Thursday Jan 16, 2014 at 18:10 GMT


So Windows doesn't like the rename? Is the hypothesis that the Node watcher is somehow locking the directory? I have no idea how Windows filesystem locking works.@peterflynn?

@core-ai-bot
Copy link
Member Author

Comment by dangoor
Thursday Jan 16, 2014 at 19:26 GMT


I ran Process Explorer and it confirmed that brackets-node has a handle on the directory that I moved.

@core-ai-bot
Copy link
Member Author

Comment by peterflynn
Thursday Jan 16, 2014 at 21:57 GMT


@jasonsanjose@iwehrman I have a theory that the stuck handle is actually a result of the watcher notification from the directory getting added while its parent was already watched. That would explain why it only occurs for added directories and not all directories. Does anything in the Node-side code fit into that picture? Or could there be a bug in the Node watcher impl itself...?

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Friday Jan 17, 2014 at 05:43 GMT


Not exactly sure what you mean about the notification. Can you clarify?

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Friday Jan 17, 2014 at 18:59 GMT


I don't remember seeing this earlier, but now if I load a simple tree 2 levels deep...

ProjectRoot
----folder
--------subfolder
------------file.txt

...and I try to rename folder externally, I get the "folder in use" dialog.

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Friday Jan 17, 2014 at 19:40 GMT


@iwehrman found the node bug, it looks like an FOL nodejs/node-v0.x-archive#3963.

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Friday Jan 17, 2014 at 19:50 GMT


Tested with Node 0.11.10 and the problem still exists.

@core-ai-bot
Copy link
Member Author

Comment by iwehrman
Friday Jan 17, 2014 at 19:59 GMT


The available options are unpalatable:

  1. Live with the bug on Windows;
  2. Disable watchers on Windows, patching up the caching infrastructure to always cache directory contents, and to invalidate directory contents on window focus if unwatched; or
  3. Use Node's slower, more expensive fs.watchFile operation (or one of its many wrapper libraries) for file-change notifications.

The best option in my opinion is 2. The downside is that it will require some additional code. The upside is that it will probably leave the filesystem code in a better state overall, since there's no particular reason why we shouldn't have the proposed caching policy already for unwatched directories except for the added complexity.

Side note: although the aforementioned Node issue would indicate that this is impossible on Windows, I frankly don't believe that. I bet it works in Sublime somehow or another. It would be nice to know how.

CC@gruehle

@core-ai-bot
Copy link
Member Author

Comment by peterflynn
Friday Jan 17, 2014 at 20:15 GMT


This is confusing. If I have Sublime open, it lets me rename folders with folder children, yet it still detects the rename instantly.

Windows Explorer itself it obviously also able to do this. So it seems like there's some Windows API that has the behavior we want...

Could they really both be doing the super inefficient one-watcher-per-file thing??

@core-ai-bot
Copy link
Member Author

Comment by iwehrman
Friday Jan 17, 2014 at 20:30 GMT


Because Explorer can do it efficiently, it seems very likely that the answer is that there exists an API that libuv doesn't use. Also, if they're spinning up a watcher-per-visible-file, they still need a way to watch for new files...

@core-ai-bot
Copy link
Member Author

Comment by peterflynn
Friday Jan 17, 2014 at 21:08 GMT


We've identified at least four promising-sounding options that might allow efficient watching without locking most (or any) folders... It does seem like there's a good chance libuv is simply 'doing it wrong' -- Windows isn't really a top-priority platform for Node, and the main native watching API is apparently pretty complicated to use effectively:

E.g., from http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html

The biggest challenge to using ReadDirectoryChangesW is that there are several hundred possibilities for combinations of I/O mode, handle signaling, waiting methods, and threading models. Unless you're an expert on Win32 I/O, it's extremely unlikely that you'll get it right, even in the simplest of scenarios.

So at this point we just need to proove out which alternative is going to work well, and then start thinking about how that fits into our desire to ship a Brackets update relatively soon...

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Monday Jan 20, 2014 at 18:15 GMT


FYI this was also tested on Mac and Linux...both are unaffected.

@core-ai-bot
Copy link
Member Author

Comment by bchintx
Wednesday Jan 29, 2014 at 02:31 GMT


Pull requests #6673 and #412 should fix this issue. Per@peterflynn 's note,@JeffryBooher@ingorichter and I have implemented a native node add-on for Windows, called 'fsevents_win'.

This new node-module replaces Brackets' previous use of node's fs.watch() with a Windows-native implementation of the same ReadDirectoryChangesW() function, but leveraging the 'recursive' flag. So, on Windows, we now only have to set a single watcher at the project root level, rather than having to iterate thru and set individual fs.watch() watchers for each subfolder within the project. As a result, the observed "in-use" issues disappear.

Per@jasonsanjose 's last comment, the reason why this didn't occur on Mac was because@iwehrman had already integrated a similar 3rd-party node-module that provided this same native functionality on the Mac.

FYI... one side benefit of only setting a watcher on the project's root folder is that we now also lock that folder so that it can't be deleted or renamed out from under us while it's open within Brackets. :-)

@core-ai-bot
Copy link
Member Author

Comment by ackalker
Thursday Jan 30, 2014 at 04:54 GMT


Does anyone have some smart comments on http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html ?
Especially the part following the use of the ReadDirectoryChanges API marked "Update:" which suggests that renaming a watched directory should be possible (i.e. without the 'watch the parent' trick).

@core-ai-bot
Copy link
Member Author

Comment by bchintx
Friday Jan 31, 2014 at 18:59 GMT


@ackalker Good observation. The comment referred to in that link points to how using FILE_SHARE_DELETE in the CreateFile() call will keep the code from locking the folder that you're wanting to watch with ReadDirectoryChangesW(). However, even if you use that flag, the parent folder of the watched folder will be locked by the ReadDirectoryChangesW() call.

So, in this implementation, we've chosen to not use this flag, and so Brackets will be locking the root of the project folder (and its parent folder). However, since we are now able to recursively watch all subfolders with a single-watcher, we've fixed the problem of not being able to externally rename/delete folders within the project itself.

(IMHO, it's actually a positive that we're now locking the root of the project folder so that it won't be moved/deleted out from underneath us as easily.)

@core-ai-bot
Copy link
Member Author

Comment by bchintx
Friday Jan 31, 2014 at 19:00 GMT


The Pull Requests have been merged into the release and master branches now, so marking this as FBNC back to@jasonsanjose

@core-ai-bot
Copy link
Member Author

Comment by jasonsanjose
Friday Jan 31, 2014 at 19:43 GMT


Confirmed fix on release build 0.37.0-11591 (build number to be fixed soon right?)

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

No branches or pull requests

1 participant