-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Create less IO errors to improve efficiency of require #8189
Conversation
I added Also - As for the motivation for this change: While profiling the server startup of the application I work on, I have noticed that a lot of time is spent on URIError. All of those errors are then immediately caught in the module.js. This seems like an inefficiency that can be avoided. In my particular case, applying this change make the server startup 30% faster. |
Going to close this for now until the libuv deps change has propagated. Once that's been done ping back and I'll reopen. |
This variable is meant to control whether IO errors are created or not. This enables: nodejs/node-v0.x-archive#8189 The general idea is to throw less errors that are immediately caught.
This variable is meant to control whether IO errors are created or not. This enables: nodejs/node-v0.x-archive#8189 The general idea is to throw less errors that are immediately caught.
OK, I have made the pull request for libuv: joyent/libuv#1428 |
This variable is meant to control whether IO errors are created or not. This enables: nodejs/node-v0.x-archive#8189 The general idea is to throw less errors that are immediately caught.
@trevnorris As it was explained to me in the libuv pull request (joyent/libuv#1428) this change should be node.js internal. Here is the commit errendir@f25c4db. It removes the libuv changes and makes this modification completely independent from libuv. Could you please reopen this PR? |
I'll reopen. Go ahead and force update the commit on this PR to the code you pointed to. This will definitely need revision, and I'm sure @indutny will have something to say. Also the words "especially when coffescript is involved" in the commit message don't exactly help the viability of the commit or why it should land. But more importantly you're changing public API without any doc or test updates. It'll never be merged w/o those. |
OK, I understand. I mentioned coffeescript, but this applies in general to all attempts made by module.js to load a file - tryExtensions might try loading files that don't exist. This is magnified by the use of coffeescript, as it registers its extensions after the standard extensions (.js, .json, .node). This means that each require of a coffeescript file hits three nonexisting files. Each of those attempts triggers creation, throw and catch of an error. As for the tests and docs - I will look into it. |
The tests are added and the documentation is updated. As for the naming conventions - is it a rule to use camel case? Do you have a style guide? |
0a9c02b
to
40ab368
Compare
I appreciate the work you've done here. Also see that you have it based on the v0.10 branch. API changes are only allowed into stable releases if they are to fix critical bugs or security vulnerabilities. Maybe could make it into v0.12. /cc @indutny How do you feel about this? |
There is a way to make this change happen with no API modifications - we can make module.js use the fs binding directly instead of using fs.js. This way the change could be limited only to the binding and module.js and still benefit the efficiency. |
/cc @indutny @tjfontaine Feedback on all this? |
I believe Best if |
@@ -153,12 +153,15 @@ Only available on Mac OS X. | |||
|
|||
Synchronous lchmod(2). | |||
|
|||
## fs.stat(path, callback) | |||
## fs.stat(path, callback, [throw_safe]) |
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.
We can't land this in v0.10, at least not the docs. If everything else looks fine here, we should probably land docs in v0.12 after the merge.
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.
Also, I'd like it if we start properly documenting optional arguments. e.g.:
## fs.stat(path, callback[, throw_safe])
I've been having the urge to go through all the documentation an change this. Drives me nuts.
@errendir I haven't finished the "Code review" yet, but I have a question: could you please paste here a benchmark that demonstrates the performance improvement after your patch? The changes appears to be quite vast, and I'm not sure what exactly do we gain with it. |
@indutny Sorry for the late response. Here is the toy test I wrote to see what kind of improvement we can see:
The results I get are:
Thanks for the code review. I can make this change not modify the public interface of the |
Untrue. Take the following:
The same pertains to |
|
||
Asynchronous stat(2). The callback gets two arguments `(err, stats)` where | ||
`stats` is a [fs.Stats](#fs_class_fs_stats) object. See the [fs.Stats](#fs_class_fs_stats) | ||
section below for more information. | ||
|
||
The throw_safe parameter if set to true prevents the error creation. If the call |
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.
throw_safe => throw_safe
true => 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.
i.e. use backticks.
Ah. Before I continue with the review, mind rebasing this on v0.12 or master? |
@trevnorris I meant asynchronous function pattern as introduced with Node.js. It would be a very first function that breaks that contract, which makes it both a breaking change and dangerous precedence |
@trevnorris to put more light on this: there are many decorators in user land that rely on that contract, and See e.g. |
@medikoo Just curious, then how are those supposed to work with functions like |
@trevnorris |
@medikoo I really couldn't give a rat poop about the concerns of Promises, but I do see what you mean by "node style callbacks". Fair enough. |
@trevnorris Here is the PR into master: #8312 @medikoo I agree that the interface change is not usually a good idea. However the efficiency improvement is significant, so we should find the correct place for this change. I was considering different ways to avoid the interface change:
|
In some environment (especially when coffescript is involved) module.js will spend a lot of time looking up nonexisting files. This is caused by the lengthy error creation. Those errors are then immediately caught. This change makes the lookup much faster, by avoiding the unnecessary error creation. module::statPath now uses the new second parameter of fs.statSync function of the fs.js. There is a similar change for the fs.stat, adding the third parameter. Apply suggestions from libuv pull request Thanks saghul: joyent/libuv#1428 Fix the datastructures for async Documentation update Add tests and simplify Stat function Apply the code review comments
dd15813
to
dbd9afb
Compare
binding.stat(pathModule._makeLong(path), cb); | ||
function cb(err, stats) { | ||
if (callback) callback(err ? false : true); | ||
if (!nullCheck(path, undefined, 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.
Why are you setting cb
as undefined
? fs.exists()
is async, and if the callback isn't passed then it should throw that the callback wasn't passed.
ah wait. nm. i'm going to place all comments on the new PR. |
@trevnorris ... any further thoughts on this? |
Actually... closing this in favor of #8312. Can reopen if necessary. |
In some environment (especially when coffescript is involved) module.js
will spend a lot of time looking up nonexisting files. This is caused by the
lengthy error creation. Those errors are then immediately caught.
This change makes the lookup much faster, by avoiding the unnecessary error
creation.
module::statPath now uses the new second parameter of fs.statSync function of the
fs.js. There is a similar change for the fs.stat, adding the third parameter.