Conversation
lib/fs.js
Outdated
There was a problem hiding this comment.
This change is necessary because using an async function for stat operations means we have a race condition on the use of statValues when there's just a single TypedArray. So, for the normal callback case, we keep the single shared typed array, but for the promises version, we allocate one TypedArray per Promise. It's a bit more expensive for the promises case, but keeps things status quo for the callback case.
lib/fs.js
Outdated
There was a problem hiding this comment.
there is no place where loop is incremented
There was a problem hiding this comment.
oh, that's a left over... should have removed that.
lib/fs.js
Outdated
lib/fs.js
Outdated
There was a problem hiding this comment.
I'm afraid it's bad for performance to concat for each chunk. Is it possible to push to an array and concat once we are out of the loop?
There was a problem hiding this comment.
yep, whatever works best.
There was a problem hiding this comment.
for await is very slow at the moment
There was a problem hiding this comment.
yep... part of my goal is to make this available then see what @bmeurer and team can do in terms of making it faster.
There was a problem hiding this comment.
@jasnell this would make the promise API prohibitebly expensive to use though.
There was a problem hiding this comment.
While the API is still experimental, performance is not the priority. If we're not able to get the performance optimized adequately, then we can move to a different approach.
lib/fs.js
Outdated
There was a problem hiding this comment.
I’d drop the , position if it isn’t necessary… without it, this should work on un-seekable files (e.g. TTYs, pipes) as well?
There was a problem hiding this comment.
Yeah, had that on my list to work through
lib/fs.js
Outdated
There was a problem hiding this comment.
Can you set fs.access[util.promisify.custom] = fs.promises.access; etc.?
src/node_file.cc
Outdated
There was a problem hiding this comment.
To keep myself from doing silly things until it's a bit more baked.
src/node_file.cc
Outdated
There was a problem hiding this comment.
sidenote, using &req->statbuf will let you get rid of the cast + remove one layer of indirection
src/node_file.h
Outdated
There was a problem hiding this comment.
Can you make this enum class? I think that would be a bit more readable since COPY and MOVE are pretty short identifiers and it’s not obvious what kind of thing they refer to…
lib/fs.js
Outdated
There was a problem hiding this comment.
Using ERR_INVALID_FD might be more suitable for the errors like this.
78ed377 to
21f59ec
Compare
| eof = true; | ||
| yield buffer.slice(0, length); | ||
| } | ||
| } |
There was a problem hiding this comment.
This is going to be very slow. Do we know if there is some improvements in the area from the V8 team?
Can you use the same class approach I used for Async Iterators? It ended up being 2x the async generator function.
There was a problem hiding this comment.
Yes this can use the class approach, but I'm purposefully leaving this in so that folks my @bmeurer can take a look and figure out how to make it faster. I will be switching it to the class approach a bit later.
| length -= written; | ||
| if (position !== null) | ||
| position += written; | ||
| return writeEverything(fd, buffer, offset, length, position); |
There was a problem hiding this comment.
If the buffer is big enough, it could lead to a stack overflow. Can this be done as a loop?
There was a problem hiding this comment.
Given that it returns a Promise, does it overflow the stack? :-)
That said, I'm already planning to rework this function. This was a temporary impl
|
@bmeurer / @fhinkel ... question for you. With this implementation currently... within an async function, I create an instance of It works rather nicely as is, however... it is a bit inefficient because we already know that we are running within an async function, which we know will create it's own Promise. What I would like to be able to do is avoid creating the This would save two additional allocations (one for the Thing is, I don't know if this would be possible within V8 (I know it's not possible now). For instance.... something like: |
|
@jasnell I think that would basically be equivalent to having native async functions, right? I can’t tell you whether V8 wants it or not, but it should certainly be doable…? |
|
Yes, that's exactly it. I want the native code to be able to know that it's running within an |
|
Or, perhaps a different approach... having the ability to explicitly create Async Functions at the native level with an void AsyncThing(const AsyncFunctionCallbackInfo<Value>& args) {
Local<Promise> promise = args.Promise();
// resolve sync or async here... setting the return value like below would resolve sync
args.GetReturnValue().Set(1);
}such that the function itself returns a However it works, I just want to avoid having to allocate the |
|
Oh, exciting to see all this progress! Nice work @jasnell 😄 Async API functions can be supported but I don't see the need here. Looking at methods in A couple of them do use
The double call out to C++ can be avoided by having the binding create and return the promise. This would improve performance greatly. For example: Instead of doing this: we could do: With this change, there's only one call out to C++. |
Yeah, I've been going back and forth on this a bit. One of the key reasons they are async functions now is to simplify the error handling. The
Yeah, as I was digging in to it more I realized that also. It would still be good to have the ability to create an async function at the native layer so that I can do something like: void AsyncThing(const AsyncFunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(123);
}At the C++ level and... const binding = process.binding('foo');
await binding.asyncThing();At the JavaScript level without having to worry about the explicit Promise creation stuff within C++.
Yep, and I that's ultimately where I'm going to go. The reason I've gone with the |
|
How would you model the “resume” strategy in C++? |
TBD, I think. I'm not yet 100% sure. |
|
@caitp C# models them (effectively) with a class (rather than a function) with a state variable and an entry hook. However I simply don't see any benefit to this over using a regular function and doing this yourself. boost coroutines (if were used) could provide a more elegant solution - but let's don't :) |
|
Closing in favor of #18297 |
This is a work in progress continuation of the prototyping work started originally in #15485.
Ping @MylesBorins @addaleax @mcollina
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
fs