Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-10-29 17:15:36 +0300
committerAnna Henningsen <anna@addaleax.net>2019-11-06 01:07:04 +0300
commit973f324463a91721cc8a1158a5ab10ad0dd69019 (patch)
treea7664cbcc50c0fe7eced11fb20e49dc255abfe1e /lib/internal/child_process.js
parentf17e414dc4b5d80dd5b5c7ee7107659ec5ebeb1a (diff)
child_process,cluster: allow using V8 serialization API
Add an `serialization` option that allows child process IPC to use the (typically more powerful) V8 serialization API. Fixes: https://github.com/nodejs/node/issues/10965 PR-URL: https://github.com/nodejs/node/pull/30162 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Diffstat (limited to 'lib/internal/child_process.js')
-rw-r--r--lib/internal/child_process.js59
1 files changed, 27 insertions, 32 deletions
diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js
index 22f7da92ce8..9e13650fa3d 100644
--- a/lib/internal/child_process.js
+++ b/lib/internal/child_process.js
@@ -1,6 +1,6 @@
'use strict';
-const { JSON, Object } = primordials;
+const { Object } = primordials;
const {
errnoException,
@@ -55,8 +55,6 @@ const {
const { SocketListSend, SocketListReceive } = SocketList;
-// Lazy loaded for startup performance.
-let StringDecoder;
// Lazy loaded for startup performance and to allow monkey patching of
// internalBinding('http_parser').HTTPParser.
let freeParser;
@@ -343,6 +341,15 @@ ChildProcess.prototype.spawn = function(options) {
const ipcFd = stdio.ipcFd;
stdio = options.stdio = stdio.stdio;
+ if (options.serialization !== undefined &&
+ options.serialization !== 'json' &&
+ options.serialization !== 'advanced') {
+ throw new ERR_INVALID_OPT_VALUE('options.serialization',
+ options.serialization);
+ }
+
+ const serialization = options.serialization || 'json';
+
if (ipc !== undefined) {
// Let child process know about opened IPC channel
if (options.envPairs === undefined)
@@ -353,7 +360,8 @@ ChildProcess.prototype.spawn = function(options) {
options.envPairs);
}
- options.envPairs.push('NODE_CHANNEL_FD=' + ipcFd);
+ options.envPairs.push(`NODE_CHANNEL_FD=${ipcFd}`);
+ options.envPairs.push(`NODE_CHANNEL_SERIALIZATION_MODE=${serialization}`);
}
validateString(options.file, 'options.file');
@@ -446,7 +454,7 @@ ChildProcess.prototype.spawn = function(options) {
this.stdio.push(stdio[i].socket === undefined ? null : stdio[i].socket);
// Add .send() method and start listening for IPC data
- if (ipc !== undefined) setupChannel(this, ipc);
+ if (ipc !== undefined) setupChannel(this, ipc, serialization);
return err;
};
@@ -516,7 +524,8 @@ class Control extends EventEmitter {
const channelDeprecationMsg = '_channel is deprecated. ' +
'Use ChildProcess.channel instead.';
-function setupChannel(target, channel) {
+let serialization;
+function setupChannel(target, channel, serializationMode) {
target.channel = channel;
Object.defineProperty(target, '_channel', {
@@ -535,12 +544,16 @@ function setupChannel(target, channel) {
const control = new Control(channel);
- if (StringDecoder === undefined)
- StringDecoder = require('string_decoder').StringDecoder;
- const decoder = new StringDecoder('utf8');
- var jsonBuffer = '';
- var pendingHandle = null;
- channel.buffering = false;
+ if (serialization === undefined)
+ serialization = require('internal/child_process/serialization');
+ const {
+ initMessageChannel,
+ parseChannelMessages,
+ writeChannelMessage
+ } = serialization[serializationMode];
+
+ let pendingHandle = null;
+ initMessageChannel(channel);
channel.pendingHandle = null;
channel.onread = function(arrayBuffer) {
const recvHandle = channel.pendingHandle;
@@ -552,21 +565,7 @@ function setupChannel(target, channel) {
if (recvHandle)
pendingHandle = recvHandle;
- // Linebreak is used as a message end sign
- var chunks = decoder.write(pool).split('\n');
- var numCompleteChunks = chunks.length - 1;
- // Last line does not have trailing linebreak
- var incompleteChunk = chunks[numCompleteChunks];
- if (numCompleteChunks === 0) {
- jsonBuffer += incompleteChunk;
- this.buffering = jsonBuffer.length !== 0;
- return;
- }
- chunks[0] = jsonBuffer + chunks[0];
-
- for (var i = 0; i < numCompleteChunks; i++) {
- var message = JSON.parse(chunks[i]);
-
+ for (const message of parseChannelMessages(channel, pool)) {
// There will be at most one NODE_HANDLE message in every chunk we
// read because SCM_RIGHTS messages don't get coalesced. Make sure
// that we deliver the handle with the right message however.
@@ -581,9 +580,6 @@ function setupChannel(target, channel) {
handleMessage(message, undefined, false);
}
}
- jsonBuffer = incompleteChunk;
- this.buffering = jsonBuffer.length !== 0;
-
} else {
this.buffering = false;
target.disconnect();
@@ -782,8 +778,7 @@ function setupChannel(target, channel) {
const req = new WriteWrap();
- const string = JSON.stringify(message) + '\n';
- const err = channel.writeUtf8String(req, string, handle);
+ const err = writeChannelMessage(channel, req, message, handle);
const wasAsyncWrite = streamBaseState[kLastWriteWasAsync];
if (err === 0) {