GeezerVison is showing github.com — timers: reuse Timeout objects in setStreamTimeout · nodejs/node@086741d
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/stream_base_commons.js +9-2Lines changed: 9 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -22,7 +22,7 @@ const { | 22 | 22 | const { owner_symbol } = require('internal/async_hooks').symbols; | 23 | 23 | const { | 24 | 24 | kTimeout, | 25 | | - setUnrefTimeout, | | 25 | + reuseOrCreateUnrefTimeout, | 26 | 26 | getTimerDuration, | 27 | 27 | } = require('internal/timers'); | 28 | 28 | const { isUint8Array } = require('internal/util/types'); | @@ -233,6 +233,10 @@ function onStreamRead(arrayBuffer) { | 233 | 233 | } | 234 | 234 | } | 235 | 235 |
| | 236 | +function onStreamTimeout(stream) { | | 237 | + stream._onTimeout(); | | 238 | +} | | 239 | + | 236 | 240 | function setStreamTimeout(msecs, callback) { | 237 | 241 | if (this.destroyed) | 238 | 242 | return this; | @@ -244,6 +248,8 @@ function setStreamTimeout(msecs, callback) { | 244 | 248 |
| 245 | 249 | // Attempt to clear an existing timer in both cases - | 246 | 250 | // even if it will be rescheduled we don't want to leak an existing timer. | | 251 | + // The cleared Timeout stays referenced in this[kTimeout] so that it can be | | 252 | + // reused the next time a timeout is set, e.g. on keep-alive connections. | 247 | 253 | clearTimeout(this[kTimeout]); | 248 | 254 |
| 249 | 255 | if (msecs === 0) { | @@ -252,7 +258,8 @@ function setStreamTimeout(msecs, callback) { | 252 | 258 | this.removeListener('timeout', callback); | 253 | 259 | } | 254 | 260 | } else { | 255 | | - this[kTimeout] = setUnrefTimeout(this._onTimeout.bind(this), msecs); | | 261 | + this[kTimeout] = | | 262 | + reuseOrCreateUnrefTimeout(this[kTimeout], onStreamTimeout, msecs, this); | 256 | 263 | if (this[kSession]) this[kSession][kUpdateTimer](); | 257 | 264 | if (this[kBoundSession]) this[kBoundSession][kUpdateTimer](); | 258 | 265 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/timers.js +31Lines changed: 31 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -417,6 +417,36 @@ function setUnrefTimeout(callback, after) { | 417 | 417 | return timer; | 418 | 418 | } | 419 | 419 |
| | 420 | +// Just like setUnrefTimeout() but reuses `timer` if it is a Timeout that is | | 421 | +// no longer scheduled (fired or cleared), avoiding the allocation of a new | | 422 | +// Timeout on rearm. This is the internal reuse path anticipated by the | | 423 | +// TODO in unenroll() (lib/timers.js), used by hot paths such as the | | 424 | +// keep-alive timeout handling in the HTTP server. `arg` is passed to | | 425 | +// `callback` when the timer fires. | | 426 | +function reuseOrCreateUnrefTimeout(timer, callback, after, arg) { | | 427 | + if (timer !== undefined && timer !== null && | | 428 | + timer._destroyed && timer._repeat === null && !timer[kHasPrimitive]) { | | 429 | + timer._idleTimeout = after; | | 430 | + timer._onTimeout = callback; | | 431 | + const args = timer._timerArgs; | | 432 | + if (args === undefined) { | | 433 | + timer._timerArgs = [arg]; | | 434 | + } else { | | 435 | + args[0] = arg; | | 436 | + } | | 437 | + // Re-inserts the timer and re-initializes its async resource, so | | 438 | + // async_hooks observes the same init/destroy sequence as if a new | | 439 | + // Timeout had been allocated. | | 440 | + unrefActive(timer); | | 441 | + return timer; | | 442 | + } | | 443 | + | | 444 | + timer = new Timeout(callback, after, [arg], false, false); | | 445 | + insert(timer, timer._idleTimeout); | | 446 | + | | 447 | + return timer; | | 448 | +} | | 449 | + | 420 | 450 | // Type checking used by timers.enroll() and Socket#setTimeout() | 421 | 451 | function getTimerDuration(msecs, name) { | 422 | 452 | validateNumber(msecs, name); | @@ -704,6 +734,7 @@ module.exports = { | 704 | 734 | kHasPrimitive, | 705 | 735 | initAsyncResource, | 706 | 736 | setUnrefTimeout, | | 737 | + reuseOrCreateUnrefTimeout, | 707 | 738 | getTimerDuration, | 708 | 739 | immediateQueue, | 709 | 740 | getTimerCallbacks, | |
|