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

fs: WriteStream should handle partial writes #22740

Closed
wants to merge 1 commit into from

Conversation

kyliau
Copy link

@kyliau kyliau commented Sep 6, 2018

Given a buffer of length l, fs.write() will not necessarily write the
entire buffer to the file. This can occur if, for example, there is
insufficient space on the underlying physical medium.

WriteStream did not handle this case, and when partial write occurs,
it will errorneously report that the write is successful.

This commit changes the _write() behavior to continue the write
operation, picking up from where the last operation left off.

More information about the write() system call is available at
http://man7.org/linux/man-pages/man2/write.2.html

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added the fs Issues and PRs related to the fs subsystem / file system. label Sep 6, 2018
Copy link
Contributor

@ofrobots ofrobots left a comment

Choose a reason for hiding this comment

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

Thanks for contributing a fix for this bug @kyliau ! I left a comment, but otherwise this is looking great. Please take a look.

if (er) {
if (this.autoClose) {
this.destroy();
}
return cb(er);
}
this.bytesWritten += bytes;
cb();
});
pos += bytes;
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that pos may be undefined if this.pos was undefined. It would be better to pass undefined to fs.write rather than NaN in this case.

@ofrobots
Copy link
Contributor

@ofrobots
Copy link
Contributor

/cc @nodejs/fs

@ronkorving
Copy link
Contributor

Thanks for addressing this issue! Makes you wonder... what happens with _writev?

addaleax
addaleax previously approved these changes Sep 14, 2018
test/parallel/test-fs-write-stream-partial-write.js Outdated Show resolved Hide resolved
@addaleax addaleax added the needs-ci PRs that need a full CI run. label Sep 14, 2018
@addaleax
Copy link
Member

@kyliau Can you look into @ronkorving’s comment? I think _writev might be having the same issue. Maybe it would be better to address this in libuv? Also, the example you mentioned in the PR description is a full disk – it doesn’t sound to me like trying to continue to write would make sense in that scenario?

CI: https://ci.nodejs.org/job/node-test-pull-request/17214/

@addaleax addaleax removed the needs-ci PRs that need a full CI run. label Sep 16, 2018
@addaleax
Copy link
Member

Also, how does libuv/libuv#1742 fit into this? I haven’t dug much but from the sound of it it seems like it would fix the same issue on the libuv level?

@kyliau
Copy link
Author

kyliau commented Sep 20, 2018

@ronkorving I briefly looked at _writev. It also does not check the return value of bytes written. However in this case it doesn't seem like it's a good choice to reimplement the logic to determine the remaining buffers in JS since similar logic already exists in https://github.com/nodejs/node/blob/master/src/stream_wrap.cc#L290.

@addaleax It's true that if the underlying medium is a HDD and it's full then we shouldn't continue writing. The case where I encountered this bug is in a Unix pipe, where partial write occurred when the payload is much larger than the pipe buffer, but it's ok to resume writing once the pipe is drained.

In either case, the user has no way of knowing that a partial write occurred. Would it be better to pass along the written bytes to the callback so user is aware and can take appropriate steps?

Given a buffer of length l, fs.write() will not necessarily write the
entire buffer to the file. This can occur if, for example, there is
insufficient space on the underlying physical medium.

WriteStream did not handle this case, and when partial write occurs,
it will errorneously report that the write is successful.

This commit changes the _write() behavior to continue the write
operation, picking up from where the last operation left off.

More information about the write() system call is available at
http://man7.org/linux/man-pages/man2/write.2.html
@kyliau
Copy link
Author

kyliau commented Sep 20, 2018

@gireeshpunathil reported similar issue with an example here

@santigimeno
Copy link
Member

FYI: libuv/libuv#1742 has just landed.

@kyliau kyliau closed this Oct 22, 2018
@kyliau kyliau deleted the writestream branch October 22, 2018 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fs Issues and PRs related to the fs subsystem / file system.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants