FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

string_decoder: make write after end to reset by thefourtheye · Pull Request #16594 · nodejs/node · GitHub

/ node Public

string_decoder: make write after end to reset - #16594

Closed
thefourtheye wants to merge 4 commits into
nodejs:masterfrom
thefourtheye:string-decoder-fix
Closed

string_decoder: make write after end to reset#16594
thefourtheye wants to merge 4 commits into
nodejs:masterfrom
thefourtheye:string-decoder-fix

Conversation

Copy link
Copy Markdown
Contributor

Fixes: #16564

When StringDecoder's end is called, it is no longer supposed to wait
for the data. If a write call is made after end, then the decoder
has to be flushed and treated as a brand new write request.

This patch also introduces a new StringDecoder#reset method, which
simply resets all the internal data.

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
Affected core subsystem(s)

Fixes: nodejs#16564

When StringDecoder's `end` is called, it is no longer supposed to wait
for the data. If a `write` call is made after `end`, then the decoder
has to be flushed and treated as a brand new write request.

This patch also introduces a new StringDecoder#reset method, which
simply resets all the internal data.
nodejs-github-bot added the string_decoder Issues and PRs related to the string_decoder subsystem. label Oct 29, 2017
Comment thread doc/api/string_decoder.md Outdated
internal buffer for the next call to `stringDecoder.write()` or
`stringDecoder.end()`.

### stringDecoder.reset([encoding])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A nit: it seems this should go before the stringDecoder.write(), ABC-wise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Done!

Comment thread lib/string_decoder.js Outdated
StringDecoder.prototype.reset = StringDecoder;

StringDecoder.prototype.write = function(buf) {
if (this._closed === true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

=== true is unnecessary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

If we explicitly compare strictly against the value, the performance would be better right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Not with TurboFan, no. I asked about this in another PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

For reference, I think this is the previous discussion in question: #16397 (comment)

jasnell added the semver-minor PRs that contain new features and should be released in the next minor version. label Oct 30, 2017

mscdex commented Oct 30, 2017

Copy link
Copy Markdown
Contributor

What if we do something simpler, like overwrite at least .write() (and possibly .end()) in .end(). Perhaps that would have less overhead? .write() is going to be called more times than .end() in general.

Copy link
Copy Markdown
Contributor Author

@mscdex In that case, users would have to create a new StringDecoder object every time end is called, right? They cannot reuse it. Also, that would break a lot of buggy code which is already out there I think.

mscdex commented Oct 30, 2017

Copy link
Copy Markdown
Contributor

@thefourtheye The basic concern still stands though, .write() is hotter than .end(), so if we can come up with some way to avoid adding stuff to .write() that would be ideal (unless benchmarks show that the current solution does not cause a performance regression).

Comment thread doc/api/string_decoder.md
If the `buffer` argument is provided, one final call to `stringDecoder.write()`
is performed before returning the remaining input.

### stringDecoder.reset([encoding])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I believe this is an implementation detail users don't have to know about.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

As it is, there is no way for the users to reset the string decoder, right? They have to create a new instance if needed. This will enable reusability.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A new way to reset the state each time was not requested as far as I read the issue. So I also prefer not to expose the reset function. If I am correct the following should work.

const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');

decoder.write(Buffer.from([0xE2, 0x82])); // => ''
decoder.end(); // => '�'
decoder.write(Buffer.of(0x61)); // => 'a'

Comment thread lib/string_decoder.js Outdated

StringDecoder.prototype.write = function(buf) {
if (this._closed === true)
this.reset();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can this logic be in StringDecoder.prototype.end instead? Make the per-encoding this.end switching in the constructor actually set to an internal symbol-named property, and use a shared StringDecoder.prototype.end that calls that internal encoding-specific function and clean up after itself. Would probably help with write performance too if StringDecoders of different encodings (e.g. UTF-8 which does not have an own property end and UTF-16LE that does) are used simultaneously.

jridgewell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This seems all very complicated. Why isn't StringDecoder#end just doing:

this.lastNeed = 0;
this.lastTotal = 0;

The buffer is already "unsafe" and access to it is guarded, so we don't need to sanitize it. And reusing a constructor as a call seems fraught.

mscdex commented Oct 31, 2017
edited
Loading

Copy link
Copy Markdown
Contributor

This seems all very complicated. Why isn't StringDecoder#end just doing:

One reason is backwards compatibility.

Copy link
Copy Markdown
Member

Ping @thefourtheye

Copy link
Copy Markdown
Contributor Author

I have updated the PR to make sure that write doesn't have much any changes. PTAL.

Comment thread lib/string_decoder.js Outdated
function end(buf) {
let result = '';

if (this.encoding === 'utf16le')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Might consider using a switch here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ack.

Comment thread lib/string_decoder.js Outdated
let result = '';

if (this.encoding === 'utf16le')
result = utf16End.call(this, buf);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

If we're the only ones calling these methods directly, then we should be able to avoid the overhead of .call() and just pass an instance as another argument.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ack.

Comment thread lib/string_decoder.js Outdated
else
result = simpleEnd.call(this, buf);

this.reset();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Would it be better to use this.reset(this.encoding) to avoid the switch in the constructor?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We still cannot get rid of the switch in the constructor, right?

mscdex Dec 5, 2017
edited
Loading

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Correct, but this.reset(this.encoding) would only hit that first if in the constructor, which might be better.

Comment thread lib/string_decoder.js
]);

function end(buf) {
const result = (endMappings.get(this.encoding) || simpleEnd)(this, buf);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This looks "elegant" but using a switch case for the encoding and calling the function directly is probably faster.

Comment thread doc/api/string_decoder.md
If the `buffer` argument is provided, one final call to `stringDecoder.write()`
is performed before returning the remaining input.

### stringDecoder.reset([encoding])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A new way to reset the state each time was not requested as far as I read the issue. So I also prefer not to expose the reset function. If I am correct the following should work.

const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');

decoder.write(Buffer.from([0xE2, 0x82])); // => ''
decoder.end(); // => '�'
decoder.write(Buffer.of(0x61)); // => 'a'

targos commented Jan 15, 2018

Copy link
Copy Markdown
Member

ping @thefourtheye

Copy link
Copy Markdown
Member

Ping again @thefourtheye

jridgewell added a commit to jridgewell/node that referenced this pull request Feb 1, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

Refs: nodejs#16594
Fixes: nodejs#16564
thefourtheye deleted the string-decoder-fix branch February 1, 2018 09:05
addaleax pushed a commit that referenced this pull request Feb 2, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 20, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Mar 20, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Mar 28, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Mar 30, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: #18494
Fixes: #16564
Refs: #16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
This resets the StringDecoder's state after calling `#end`. Further
writes to the decoder will act as if it were a brand new instance,
allowing simple reuse.

PR-URL: nodejs#18494
Fixes: nodejs#16564
Refs: nodejs#16594
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver-minor PRs that contain new features and should be released in the next minor version. string_decoder Issues and PRs related to the string_decoder subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StringDecoder#end doesn't flush state

10 participants


Back | FazBrowse Home | New Git URL