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: work with any TypedArrays instead of only Uint8Arrays #22150

Closed
wants to merge 16 commits into from

Conversation

SirR4T
Copy link
Contributor

@SirR4T SirR4T commented Aug 6, 2018

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

Partially fixing #1826

Haven't added tests yet, since I'm not sure what behaviour to expect. Current tests are not breaking, though, so yay!
Tests have been added since.

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

SirR4T commented Aug 6, 2018

cc: @TimothyGu

So, i'm not 100% sure what behaviour should be expected, when writing and reading to and from files, using TypedArrays. For instance, test/parallel/test-fs-write-file-uint8array.js fails if I replace the Uint8Array in the line

const input = Uint8Array.from(Buffer.from(s, 'utf8'));

with any other TypedArray. Why is that so? Due to this, I suspect a lot many tests should be added, to ensure read and write work correctly when using other TypedArrays.

@SirR4T SirR4T force-pushed the fix1826-ArrayBuffersInFs branch from a53af6e to 5204651 Compare August 6, 2018 12:04
jasnell
jasnell previously approved these changes Aug 6, 2018
@targos
Copy link
Member

targos commented Aug 6, 2018

We need tests to make sure it's handled correctly on the C++ side

Copy link
Member

@benjamingr benjamingr left a comment

Choose a reason for hiding this comment

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

Actually, reading this again tests are missing - if we officially support those types we need to make sure we have tests making sure we don't break that.

@benjamingr
Copy link
Member

If you haven't wrote tests for PRs before and want help with writing the tests or aren't sure what/where to do let me know and I'll elaborate on how that works.

@SirR4T
Copy link
Contributor Author

SirR4T commented Aug 7, 2018

@benjamingr I'm happy to write tests, but I'm not sure what the behaviour should be, when writing to files via TypedArrays or reading from them. Hence the hesitation. Maybe I could make copies of test/parallel/test-fs-write-file-uint8array.js with other typed arrays, and reviewers can take it from there?

@benjamingr
Copy link
Member

@SirR4T basically, to check that you can perform each FS operations that supports other types of arrays and that it returns the value you expect - test-fs-write-file-uint8array.js is a good start though I'm not sure I'd create a file for every view type.

@SirR4T SirR4T force-pushed the fix1826-ArrayBuffersInFs branch from 5204651 to ae2d513 Compare August 7, 2018 09:36
@TimothyGu
Copy link
Member

test/parallel/test-fs-write-file-uint8array.js fails if I replace the Uint8Array in the line

const input = Uint8Array.from(Buffer.from(s, 'utf8'));

with any other TypedArray. Why is that so?

That is because .from() for TypedArray objects copy the data to conform to a new layout. E.g.

const a = new Uint8Array([1, 2, 3])
// In memory: 0x01 0x02 0x03

const b = Uint16Array.from(a);
// In memory 0x0001 0x0002 0x0003

However, if the test doesn't work with Int8Array, then there's a problem.

For testing, you could use getArrayBufferViews() to help simplify testing for many types of ArrayBufferViews. However, you need to make sure the buffer you pass in have a size that's a multiple of 8 bytes to make sure it works with all ArrayBufferViews (BigInt64Array and BigUint64Array have 8 bytes per element).

@TimothyGu
Copy link
Member

Also, I'd be fine if you modify existing tests rather than creating new ones.

@TimothyGu TimothyGu self-requested a review August 7, 2018 22:02
@SirR4T SirR4T force-pushed the fix1826-ArrayBuffersInFs branch from ae2d513 to bcaacaa Compare August 8, 2018 05:19
Copy link
Contributor Author

@SirR4T SirR4T left a comment

Choose a reason for hiding this comment

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

@benjamingr : going ahead with @TimothyGu 's suggestion, modifying the existing test case.

for (const type of types) {
const expect = convertToType(type, expectBuf);
fs.writeFileSync(filename, expect);
assert.strictEqual(convertToType(type, readInput(filename)), expect);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@benjamingr this test is currently failing with

assert.js:84
  throw new AssertionError(obj);
  ^

AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
+ actual - expected ... Lines skipped

  Int8Array [
+   45,
+   50,
+   55,
+   44,
+   45,
+   49,
+   49,
+   53,
+   44,
+   45,
...
-   -27,
-   -115,
-   -105,
-   -24,
-   -74,
-   -118,
-   -27,
-   -101,
-   -67,
-   -26,
...

What am i doing wrong?

@SirR4T
Copy link
Contributor Author

SirR4T commented Aug 8, 2018

@TimothyGu makes sense, going ahead with the current test case. Will modify the test case name too.

Currently, it is failing with

AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
+ actual - expected ... Lines skipped

+ '-27,-115,-105,-24,-74,-118,-27,-101,-67,-26,-104,-81,-27,-119,-115,50,48,51,-27,-71,-76,-24,-121,-77,-27,-119,-115,49,49,49,-27,-71,-76,-27,-83,-104,-27,-100,-88,-28,-70,-114,
... many more entries

...
- Int8Array [
-   -27,
-   -115,
-   -105,
-   -24,
-   -74,
-   -118,
-   -27,
-   -101,
-   -67,
-   -26,
-   -104,
-   -81,
-   -27,
-   -119,
-   -115,
-   50,
-   48,
-   51,
-   -27,
...
    at Object.<anonymous> (/Users/saratchandra/Play/Github/nodejs/node/test/parallel/test-fs-write-file-uint8array.js:24:10)

I notice that:

  1. the expected value is a raw Buffer a string of raw buffer values concatenated 😲, whereas, I'm trying to match with a TypedArray (Int8Array here).
  2. the actual entries for both are matching (the values in the raw buffer, i presume).

Can't shake the feeling i'm doing something terribly wrong here.
How do I do exact matches between raw buffers and typed arrays fix this?

@SirR4T SirR4T force-pushed the fix1826-ArrayBuffersInFs branch from bcaacaa to bc3b58e Compare August 8, 2018 06:04
@SirR4T
Copy link
Contributor Author

SirR4T commented Aug 10, 2018

@TimothyGu @benjamingr : The file contents are a string of numbers (positive and negative), concatenated by ,, when writing via TypedArrays (for eg., Int8Array). Is that expected behaviour?

@jasnell jasnell dismissed their stale review August 10, 2018 13:48

outstanding issues

Copy link
Member

@TimothyGu TimothyGu left a comment

Choose a reason for hiding this comment

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

Hope this answers your question.

assert.strictEqual(fs.readFileSync(filename, 'utf8'), s);
for (const expectView of common.getArrayBufferViews(inputBuffer)) {
fs.writeFileSync(filename, expectView);
assert.strictEqual(fs.readFileSync(filename, 'utf8'), expectView);
Copy link
Member

Choose a reason for hiding this comment

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

fs.readFileSync(..., 'utf8') returns a string, so the assertion should compare with s.repeat(8) instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah! indeed. so that will work for reads that are string based, that is, for utf8 strings, Buffers, Uint8Arrays. How should I test for the other typed arrays and data views?

For instance, when encoding is not specified fs.readFileSync() returns a Buffer. How do i match this with Int8Arrays or other typed arrays?

Copy link
Member

Choose a reason for hiding this comment

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

You don't. The test is testing if writeFile supports non-Buffer TypedArrays. It's not testing readFileSync, and you should always compare the result of readFileSync to the string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aha! things are much more clearer now, thanks for the explanation 😄

}));
fs.readFile(filename, 'utf8', common.mustCall((err, data) => {
assert.ifError(err);
assert.strictEqual(data, expectView);
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

@@ -17,13 +17,18 @@ const s = '南越国是前203年至前111年存在于岭南地区的一个国家
'历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' +
'它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n';

const input = Uint8Array.from(Buffer.from(s, 'utf8'));
const inputBuffer = Buffer.from(s.repeat(8), 'utf8');
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a comment explaining why .repeat(8) is necessary? Specifically, that getArrayBufferViews expects it.

@TimothyGu
Copy link
Member

Could you please rebase this branch on master?

@SirR4T
Copy link
Contributor Author

SirR4T commented Aug 17, 2018

@benjamingr tests added, and now passing.

@TimothyGu I can see that this diff of my feature branch against upstream/master is showing the correct files changed, but this PR is showing many more commits. How do I fix this? Should I close this and raise a different PR? This is after rebasing against latest upstream master.

@TimothyGu
Copy link
Member

@SirR4T I see that your branch has this merge commit: SirR4T@590d218 You would need to get rid of that merge commit for things to work. I think just doing a git rebase with the upstream's master branch as base should be enough.

@SirR4T SirR4T force-pushed the fix1826-ArrayBuffersInFs branch from 590d218 to 0b78626 Compare August 17, 2018 15:21
@benjamingr benjamingr dismissed their stale review August 17, 2018 17:19

comments addressed

lib/fs.js Outdated
@@ -525,7 +524,7 @@ function write(fd, buffer, offset, length, position, callback) {
const req = new FSReqCallback();
req.oncomplete = wrapper;

if (isUint8Array(buffer)) {
if (ArrayBuffer.isView(buffer)) {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good idea, will do that.

fs.writeFileSync(filename, input);
assert.strictEqual(fs.readFileSync(filename, 'utf8'), s);
for (const expectView of common.getArrayBufferViews(inputBuffer)) {
debuglog('Running test for: ', expectView[Symbol.toStringTag]);
Copy link
Member

Choose a reason for hiding this comment

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

I think we just use console.log in tests, don't we?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh... I'm not sure what the current convention is, but following the discussion at #9314, I had assumed debug log was the consensus. Lemme know if I should change to console.log.

If I understand correctly, console.log statements are not printed when tests are run, but debuglog statements are printed atleast when tests fail.

Copy link
Member

@TimothyGu TimothyGu left a comment

Choose a reason for hiding this comment

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

LGTM once @lundibundi's comments are addressed.

@TimothyGu
Copy link
Member

@TimothyGu
Copy link
Member

@SirR4T seems like the CI is failing on the new test. Could you take a look?

@addaleax
Copy link
Member

Should this be backported to v10.x-staging? If yes please follow the guide and raise a backport PR, if not let me know or add the dont-land-on label.

@targos
Copy link
Member

targos commented Aug 28, 2018

The conflict is trivial. I have a good version of this change locally. Currently compiling/running tests.

targos pushed a commit that referenced this pull request Aug 28, 2018
PR-URL: #22150
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@targos targos removed author ready PRs that have at least one approval, no pending requests for changes, and a CI started. backport-requested-v10.x labels Aug 28, 2018
addaleax added a commit to addaleax/node that referenced this pull request Sep 2, 2018
Using the same filename for different async tests could lead
to race conditions.

Example failure: https://travis-ci.com/nodejs/node/jobs/143351655

Refs: nodejs#22150
addaleax added a commit that referenced this pull request Sep 3, 2018
Using the same filename for different async tests could lead
to race conditions.

Example failure: https://travis-ci.com/nodejs/node/jobs/143351655

Refs: #22150

PR-URL: #22659
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
targos pushed a commit that referenced this pull request Sep 3, 2018
PR-URL: #22150
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this pull request Sep 3, 2018
Using the same filename for different async tests could lead
to race conditions.

Example failure: https://travis-ci.com/nodejs/node/jobs/143351655

Refs: #22150

PR-URL: #22659
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
targos added a commit that referenced this pull request Sep 5, 2018
Notable changes:

* child_process:
  * `TypedArray` and `DataView` values are now accepted as input by
    `execFileSync` and `spawnSync`. #22409
* coverage:
  * Native V8 code coverage information can now be output to disk by setting the
    environment variable `NODE_V8_COVERAGE` to a directory. #22527
* deps:
  * The bundled npm was upgraded to version 6.4.1. #22591
    * Changelogs:
      [6.3.0-next.0](https://github.com/npm/cli/releases/tag/v6.3.0-next.0)
      [6.3.0](https://github.com/npm/cli/releases/tag/v6.3.0)
      [6.4.0](https://github.com/npm/cli/releases/tag/v6.4.0)
      [6.4.1](https://github.com/npm/cli/releases/tag/v6.4.1)
* fs:
  * The methods `fs.read`, `fs.readSync`, `fs.write`, `fs.writeSync`,
    `fs.writeFile` and `fs.writeFileSync` now all accept `TypedArray` and
    `DataView` objects. #22150
  * A new boolean option, `withFileTypes`, can be passed to to `fs.readdir` and
    `fs.readdirSync`. If set to true, the methods return an array of directory
    entries. These are objects that can be used to determine the type of each
    entry and filter them based on that without calling `fs.stat`. #22020
* http2:
  * The `http2` module is no longer experimental. #22466
* os:
  * Added two new methods: `os.getPriority` and `os.setPriority`, allowing to
    manipulate the scheduling priority of processes. #22394
* process:
  * Added `process.allowedNodeEnvironmentFlags`. This object can be used to
    programmatically validate and list flags that are allowed in the
    `NODE_OPTIONS` environment variable. #19335
* src:
  * Deprecated option variables in public C++ API. #22392
  * Refactored options parsing. #22392
* vm:
  * Added `vm.compileFunction`, a method to create new JavaScript functions from
    a source body, with options similar to those of the other `vm` methods. #21571
* Added new collaborators:
  * [lundibundi](https://github.com/lundibundi) - Denys Otrishko

PR-URL: #22716
targos pushed a commit that referenced this pull request Sep 6, 2018
PR-URL: #22150
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this pull request Sep 6, 2018
Using the same filename for different async tests could lead
to race conditions.

Example failure: https://travis-ci.com/nodejs/node/jobs/143351655

Refs: #22150

PR-URL: #22659
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
targos added a commit that referenced this pull request Sep 6, 2018
Notable changes:

* child_process:
  * `TypedArray` and `DataView` values are now accepted as input by
    `execFileSync` and `spawnSync`. #22409
* coverage:
  * Native V8 code coverage information can now be output to disk by setting the
    environment variable `NODE_V8_COVERAGE` to a directory. #22527
* deps:
  * The bundled npm was upgraded to version 6.4.1. #22591
    * Changelogs:
      [6.3.0-next.0](https://github.com/npm/cli/releases/tag/v6.3.0-next.0)
      [6.3.0](https://github.com/npm/cli/releases/tag/v6.3.0)
      [6.4.0](https://github.com/npm/cli/releases/tag/v6.4.0)
      [6.4.1](https://github.com/npm/cli/releases/tag/v6.4.1)
* fs:
  * The methods `fs.read`, `fs.readSync`, `fs.write`, `fs.writeSync`,
    `fs.writeFile` and `fs.writeFileSync` now all accept `TypedArray` and
    `DataView` objects. #22150
  * A new boolean option, `withFileTypes`, can be passed to to `fs.readdir` and
    `fs.readdirSync`. If set to true, the methods return an array of directory
    entries. These are objects that can be used to determine the type of each
    entry and filter them based on that without calling `fs.stat`. #22020
* http2:
  * The `http2` module is no longer experimental. #22466
* os:
  * Added two new methods: `os.getPriority` and `os.setPriority`, allowing to
    manipulate the scheduling priority of processes. #22407
* process:
  * Added `process.allowedNodeEnvironmentFlags`. This object can be used to
    programmatically validate and list flags that are allowed in the
    `NODE_OPTIONS` environment variable. #19335
* src:
  * Deprecated option variables in public C++ API. #22515
  * Refactored options parsing. #22392
* vm:
  * Added `vm.compileFunction`, a method to create new JavaScript functions from
    a source body, with options similar to those of the other `vm` methods. #21571
* Added new collaborators:
  * [lundibundi](https://github.com/lundibundi) - Denys Otrishko

PR-URL: #22716
targos added a commit that referenced this pull request Sep 6, 2018
Notable changes:

* child_process:
  * `TypedArray` and `DataView` values are now accepted as input by
    `execFileSync` and `spawnSync`. #22409
* coverage:
  * Native V8 code coverage information can now be output to disk by setting the
    environment variable `NODE_V8_COVERAGE` to a directory. #22527
* deps:
  * The bundled npm was upgraded to version 6.4.1. #22591
    * Changelogs:
      [6.3.0-next.0](https://github.com/npm/cli/releases/tag/v6.3.0-next.0)
      [6.3.0](https://github.com/npm/cli/releases/tag/v6.3.0)
      [6.4.0](https://github.com/npm/cli/releases/tag/v6.4.0)
      [6.4.1](https://github.com/npm/cli/releases/tag/v6.4.1)
* fs:
  * The methods `fs.read`, `fs.readSync`, `fs.write`, `fs.writeSync`,
    `fs.writeFile` and `fs.writeFileSync` now all accept `TypedArray` and
    `DataView` objects. #22150
  * A new boolean option, `withFileTypes`, can be passed to to `fs.readdir` and
    `fs.readdirSync`. If set to true, the methods return an array of directory
    entries. These are objects that can be used to determine the type of each
    entry and filter them based on that without calling `fs.stat`. #22020
* http2:
  * The `http2` module is no longer experimental. #22466
* os:
  * Added two new methods: `os.getPriority` and `os.setPriority`, allowing to
    manipulate the scheduling priority of processes. #22407
* process:
  * Added `process.allowedNodeEnvironmentFlags`. This object can be used to
    programmatically validate and list flags that are allowed in the
    `NODE_OPTIONS` environment variable. #19335
* src:
  * Deprecated option variables in public C++ API. #22515
  * Refactored options parsing. #22392
* vm:
  * Added `vm.compileFunction`, a method to create new JavaScript functions from
    a source body, with options similar to those of the other `vm` methods. #21571
* Added new collaborators:
  * [lundibundi](https://github.com/lundibundi) - Denys Otrishko

PR-URL: #22716
targos added a commit that referenced this pull request Sep 6, 2018
Notable changes:

* child_process:
  * `TypedArray` and `DataView` values are now accepted as input by
    `execFileSync` and `spawnSync`. #22409
* coverage:
  * Native V8 code coverage information can now be output to disk by setting the
    environment variable `NODE_V8_COVERAGE` to a directory. #22527
* deps:
  * The bundled npm was upgraded to version 6.4.1. #22591
    * Changelogs:
      [6.3.0-next.0](https://github.com/npm/cli/releases/tag/v6.3.0-next.0)
      [6.3.0](https://github.com/npm/cli/releases/tag/v6.3.0)
      [6.4.0](https://github.com/npm/cli/releases/tag/v6.4.0)
      [6.4.1](https://github.com/npm/cli/releases/tag/v6.4.1)
* fs:
  * The methods `fs.read`, `fs.readSync`, `fs.write`, `fs.writeSync`,
    `fs.writeFile` and `fs.writeFileSync` now all accept `TypedArray` and
    `DataView` objects. #22150
  * A new boolean option, `withFileTypes`, can be passed to to `fs.readdir` and
    `fs.readdirSync`. If set to true, the methods return an array of directory
    entries. These are objects that can be used to determine the type of each
    entry and filter them based on that without calling `fs.stat`. #22020
* http2:
  * The `http2` module is no longer experimental. #22466
* os:
  * Added two new methods: `os.getPriority` and `os.setPriority`, allowing to
    manipulate the scheduling priority of processes. #22407
* process:
  * Added `process.allowedNodeEnvironmentFlags`. This object can be used to
    programmatically validate and list flags that are allowed in the
    `NODE_OPTIONS` environment variable. #19335
* src:
  * Deprecated option variables in public C++ API. #22515
  * Refactored options parsing. #22392
* vm:
  * Added `vm.compileFunction`, a method to create new JavaScript functions from
    a source body, with options similar to those of the other `vm` methods. #21571
* Added new collaborators:
  * [lundibundi](https://github.com/lundibundi) - Denys Otrishko

PR-URL: #22716
@SimonSchick
Copy link
Contributor

Does this also affect appendFile and the likes?

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. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants