Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8a49735

Browse filesBrowse files
authored
fs: add flush option to createWriteStream()
This commit adds a 'flush' option to the createWriteStream() family of functions. Refs: #49886 PR-URL: #50093 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
1 parent f23a935 commit 8a49735
Copy full SHA for 8a49735

File tree

Expand file treeCollapse file tree

5 files changed

+118
-4
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+118
-4
lines changed
Open diff view settings
Collapse file

‎doc/api/fs.md‎

Copy file name to clipboardExpand all lines: doc/api/fs.md
+11Lines changed: 11 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ fd.createReadStream({ start: 90, end: 99 });
318318
319319
<!-- YAML
320320
added: v16.11.0
321+
changes:
322+
- version: REPLACEME
323+
pr-url: https://github.com/nodejs/node/pull/50093
324+
description: The `flush` option is now supported.
321325
-->
322326
323327
* `options` {Object}
@@ -326,6 +330,8 @@ added: v16.11.0
326330
* `emitClose` {boolean} **Default:** `true`
327331
* `start` {integer}
328332
* `highWaterMark` {number} **Default:** `16384`
333+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
334+
prior to closing it. **Default:** `false`.
329335
* Returns: {fs.WriteStream}
330336
331337
`options` may also include a `start` option to allow writing data at some
@@ -2540,6 +2546,9 @@ If `options` is a string, then it specifies the encoding.
25402546
<!-- YAML
25412547
added: v0.1.31
25422548
changes:
2549+
- version: REPLACEME
2550+
pr-url: https://github.com/nodejs/node/pull/50093
2551+
description: The `flush` option is now supported.
25432552
- version: v16.10.0
25442553
pr-url: https://github.com/nodejs/node/pull/40013
25452554
description: The `fs` option does not need `open` method if an `fd` was provided.
@@ -2593,6 +2602,8 @@ changes:
25932602
* `fs` {Object|null} **Default:** `null`
25942603
* `signal` {AbortSignal|null} **Default:** `null`
25952604
* `highWaterMark` {number} **Default:** `16384`
2605+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
2606+
prior to closing it. **Default:** `false`.
25962607
* Returns: {fs.WriteStream}
25972608
25982609
`options` may also include a `start` option to allow writing data at some
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,6 +3108,7 @@ function createReadStream(path, options) {
31083108
* emitClose?: boolean;
31093109
* start: number;
31103110
* fs?: object | null;
3111+
* flush?: boolean;
31113112
* }} [options]
31123113
* @returns {WriteStream}
31133114
*/
Collapse file

‎lib/internal/fs/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ class FileHandle extends EventEmitter {
350350
* autoClose?: boolean;
351351
* emitClose?: boolean;
352352
* start: number;
353+
* flush?: boolean;
353354
* }} [options]
354355
* @returns {WriteStream}
355356
*/
Collapse file

‎lib/internal/fs/streams.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/streams.js
+24-4Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
kEmptyObject,
2424
} = require('internal/util');
2525
const {
26+
validateBoolean,
2627
validateFunction,
2728
validateInteger,
2829
} = require('internal/validators');
@@ -92,6 +93,9 @@ const FileHandleOperations = (handle) => {
9293
PromisePrototypeThen(handle.close(),
9394
() => cb(), cb);
9495
},
96+
fsync: (fd, cb) => {
97+
PromisePrototypeThen(handle.sync(), () => cb(), cb);
98+
},
9599
read: (fd, buf, offset, length, pos, cb) => {
96100
PromisePrototypeThen(handle.read(buf, offset, length, pos),
97101
(r) => cb(null, r.bytesRead, r.buffer),
@@ -113,14 +117,22 @@ const FileHandleOperations = (handle) => {
113117
function close(stream, err, cb) {
114118
if (!stream.fd) {
115119
cb(err);
116-
} else {
117-
stream[kFs].close(stream.fd, (er) => {
118-
cb(er || err);
120+
} else if (stream.flush) {
121+
stream[kFs].fsync(stream.fd, (flushErr) => {
122+
_close(stream, err || flushErr, cb);
119123
});
120-
stream.fd = null;
124+
} else {
125+
_close(stream, err, cb);
121126
}
122127
}
123128

129+
function _close(stream, err, cb) {
130+
stream[kFs].close(stream.fd, (er) => {
131+
cb(er || err);
132+
});
133+
stream.fd = null;
134+
}
135+
124136
function importFd(stream, options) {
125137
if (typeof options.fd === 'number') {
126138
// When fd is a raw descriptor, we must keep our fingers crossed
@@ -350,6 +362,14 @@ function WriteStream(path, options) {
350362
validateFunction(this[kFs].close, 'options.fs.close');
351363
}
352364

365+
this.flush = options.flush;
366+
if (this.flush == null) {
367+
this.flush = false;
368+
} else {
369+
validateBoolean(this.flush, 'options.flush');
370+
validateFunction(this[kFs].fsync, 'options.fs.fsync');
371+
}
372+
353373
// It's enough to override either, in which case only one will be used.
354374
if (!this[kFs].write) {
355375
this._write = null;
Collapse file
+81Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
'use strict';
2+
const common = require('../common');
3+
const tmpdir = require('../common/tmpdir');
4+
const assert = require('node:assert');
5+
const fs = require('node:fs');
6+
const fsp = require('node:fs/promises');
7+
const test = require('node:test');
8+
const data = 'foo';
9+
let cnt = 0;
10+
11+
function nextFile() {
12+
return tmpdir.resolve(`${cnt++}.out`);
13+
}
14+
15+
tmpdir.refresh();
16+
17+
test('validation', () => {
18+
for (const flush of ['true', '', 0, 1, [], {}, Symbol()]) {
19+
assert.throws(() => {
20+
fs.createWriteStream(nextFile(), { flush });
21+
}, { code: 'ERR_INVALID_ARG_TYPE' });
22+
}
23+
});
24+
25+
test('performs flush', (t, done) => {
26+
const spy = t.mock.method(fs, 'fsync');
27+
const file = nextFile();
28+
const stream = fs.createWriteStream(file, { flush: true });
29+
30+
stream.write(data, common.mustSucceed(() => {
31+
stream.close(common.mustSucceed(() => {
32+
const calls = spy.mock.calls;
33+
assert.strictEqual(calls.length, 1);
34+
assert.strictEqual(calls[0].result, undefined);
35+
assert.strictEqual(calls[0].error, undefined);
36+
assert.strictEqual(calls[0].arguments.length, 2);
37+
assert.strictEqual(typeof calls[0].arguments[0], 'number');
38+
assert.strictEqual(typeof calls[0].arguments[1], 'function');
39+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
40+
done();
41+
}));
42+
}));
43+
});
44+
45+
test('does not perform flush', (t, done) => {
46+
const values = [undefined, null, false];
47+
const spy = t.mock.method(fs, 'fsync');
48+
let cnt = 0;
49+
50+
for (const flush of values) {
51+
const file = nextFile();
52+
const stream = fs.createWriteStream(file, { flush });
53+
54+
stream.write(data, common.mustSucceed(() => {
55+
stream.close(common.mustSucceed(() => {
56+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
57+
cnt++;
58+
59+
if (cnt === values.length) {
60+
assert.strictEqual(spy.mock.calls.length, 0);
61+
done();
62+
}
63+
}));
64+
}));
65+
}
66+
});
67+
68+
test('works with file handles', async () => {
69+
const file = nextFile();
70+
const handle = await fsp.open(file, 'w');
71+
const stream = handle.createWriteStream({ flush: true });
72+
73+
return new Promise((resolve) => {
74+
stream.write(data, common.mustSucceed(() => {
75+
stream.close(common.mustSucceed(() => {
76+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
77+
resolve();
78+
}));
79+
}));
80+
});
81+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.