-
Notifications
You must be signed in to change notification settings - Fork 7.6k
improvements to file system events processing for search #12885
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some comments.
@@ -657,8 +665,8 @@ define(function (require, exports, module) { | |||
* Inform node that the list of files has changed. | |||
* @param {array} fileList The list of files that changed. | |||
*/ | |||
function filesChanged(fileList) { | |||
if (FindUtils.isNodeSearchDisabled() || fileList.length === 0) { | |||
function filesChanged(fileList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some trailing whitespace here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
function filesChanged(fileList) { | ||
if (FindUtils.isNodeSearchDisabled() || fileList.length === 0) { | ||
function filesChanged(fileList) { | ||
if (FindUtils.isNodeSearchDisabled() || !fileList || fileList.length === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!fileList
covers fileList.length === 0
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no it doesn't
var emptyArray = []; var a = !emptyArray; var b = emptyArray.length === 0; [a,b];
[false, true]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, sorry about that @zaggino, I automatically assumed that fileList
would never be an empty array just undefined. Again, sorry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving it as is, it's a very cheap check and better be safe than sorry :)
// node search : inform node that the file is removed | ||
fullPaths.push(fullPath); | ||
if (findOrReplaceInProgress) { | ||
searchModel.removeResults(fullPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be called once with a large array too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removeResults
is a classic sync method, so it wouldn't do any benefit here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zaggino@ Bro how are you today? Please Bro help us we want CoffeeScript in Brakets and also
Babel , and many's other please
resultsChanged = true; | ||
function _removeSearchResultsForEntries(entries) { | ||
var fullPaths = []; | ||
entries.forEach(function (entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth checking out if couple of Array.prototype.map
s would be faster than nested forEach
s and a push
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fullPaths.push(fullPath);
is inside an if
so if map would be used, we'd need to filter it out for nulls afterwards
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid point 👍
Should avoid doing code reviews when I am tired 😴 👍 Nice work @zaggino |
clearSearch; | ||
|
||
/* Waits for FS changes to stack up until processing them (scripts like npm install can do a lot of movements on the disk) */ | ||
var FILE_SYSTEM_EVENT_DEBOUNCE_TIME = 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be something like 100ms instead? Or is too low?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right here, re-tested this set to 100ms with my script and it's fine. So setting it to 100ms.
addedFiles.push(child); | ||
addedFilePaths.push(child.fullPath); | ||
function _addSearchResultsForEntries(entries) { | ||
var fullPaths = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a rough idea of the memory usage here? If we store a lot of path could cause some trouble?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, this array is not being persisted besides the function execution lifetime and I wouldn't expect there to be a problem even if you have thousands of entries in it. On the other hand, without it, trying to send thousands of messages to a node process will definitely crash it (or socket server). In other words, I don't think memory usage is something to worry about.
}, FILE_SYSTEM_EVENT_DEBOUNCE_TIME); | ||
|
||
_debouncedFileSystemChangeHandler = function (event, entry, added, removed) { | ||
_cachedFileSystemEvents.push([ event, entry, added, removed ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you push an object instead of an array? So I will not feel so dumb when reading the reduce function above...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, can do.
👍 |
_.forEach(_cachedFileSystemEvents, function (obj) { | ||
_fileSystemChangeHandler(obj.event, obj.entry, obj.added, obj.removed); | ||
}); | ||
_cachedFileSystemEvents = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are accessing the same global, and this function is called with a delay, don't we risk here to delete the events that have been added in the bouncedFileSystemChangeHandler
function while waiting this to run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How exactly? There's a _.forEach
above this that launches _fileSystemChangeHandler
for every object in the array, before deleting it. The function is completely synchronous - if an fs event is emitted while this is running, it'll be added to the empty array once this function finishes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably I was overthinking, but I was wondering if there could be some races between _debouncedFileSystemChangeHandler
and _processCachedFileSystemEvents
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, races certainly can't happen in this case. They are both completely sync functions - no promises or async-await there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The debounce and relative timout are threwing me off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
debounce
just wraps a function and keeps postponing its execution until the wrapper stops to be called for the timeout time. But once the wrapped function is executed, all happens totally sync so the code is safe. I've used this pattern a few times before.
_processCachedFileSystemEvents = _.debounce(function () { | ||
// we need to reduce _cachedFileSystemEvents not to contain duplicates! | ||
_cachedFileSystemEvents = _cachedFileSystemEvents.reduce(function (result, obj) { | ||
var fullPath = obj.entry ? obj.entry.fullPath : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If fullPath
is null maybe return immediately?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deeper in the code there's a handle for this case (doing a full refresh I think) so it didn't want to stop it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the assignment below is safe: result[fullPath] = obj;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it actuall assigns result[null] = obj;
which is a bit weird but valid so I left it like that.
@petetnt anything else? if not it should be good to merge |
@zaggino LGTM, I'll run this in production use for today and merge it in if nothing pops up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Used it all day without any issues and Brackets did feel snappier. Great job once again @zaggino! |
Hi guys, I've reported elsewhere that my db dump script crashes both brackets (white-screen) and also brackets-electron. This is the work done to fix that (and I can confirm that with this fix there's no crash when running my script anymore) - it's not final and I'd like to have it reviewed before working on little things as docs and similar.
There're two main things, first aggregate duplicate events and debounce for a short while before processing. My script quickly deletes and creates back a lot of stuff, before this change some of the directories were removed and added back to search multiple times. With debouncing it's only once after script is done.
Second, no less important thing is fixing calls to
filesChanged
andfilesRemoved
functions. In case of my script these two were called about 1000 times with an array of size 1 which cause a lot of trouble for IPC connection in electron and socket connection in regular brackets. With the fix these are now properly called.Marking this as high-priority because it fixes brackets completely crashing in some cases.