Skip to content

Commit a640834

Browse files
Fishrock123targos
authored andcommitted
timers: move big impl comment to /internal/
To be paired with the commits from #26583 Specifically: 1a6fb71 PR-URL: #26761 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
1 parent 3ec652a commit a640834

File tree

2 files changed

+72
-72
lines changed

2 files changed

+72
-72
lines changed

β€Žlib/internal/timers.js

+72
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,77 @@
11
'use strict';
22

3+
// HOW and WHY the timers implementation works the way it does.
4+
//
5+
// Timers are crucial to Node.js. Internally, any TCP I/O connection creates a
6+
// timer so that we can time out of connections. Additionally, many user
7+
// libraries and applications also use timers. As such there may be a
8+
// significantly large amount of timeouts scheduled at any given time.
9+
// Therefore, it is very important that the timers implementation is performant
10+
// and efficient.
11+
//
12+
// Note: It is suggested you first read through the lib/internal/linkedlist.js
13+
// linked list implementation, since timers depend on it extensively. It can be
14+
// somewhat counter-intuitive at first, as it is not actually a class. Instead,
15+
// it is a set of helpers that operate on an existing object.
16+
//
17+
// In order to be as performant as possible, the architecture and data
18+
// structures are designed so that they are optimized to handle the following
19+
// use cases as efficiently as possible:
20+
21+
// - Adding a new timer. (insert)
22+
// - Removing an existing timer. (remove)
23+
// - Handling a timer timing out. (timeout)
24+
//
25+
// Whenever possible, the implementation tries to make the complexity of these
26+
// operations as close to constant-time as possible.
27+
// (So that performance is not impacted by the number of scheduled timers.)
28+
//
29+
// Object maps are kept which contain linked lists keyed by their duration in
30+
// milliseconds.
31+
//
32+
/* eslint-disable node-core/non-ascii-character */
33+
//
34+
// ╔════ > Object Map
35+
// β•‘
36+
// ╠══
37+
// β•‘ lists: { '40': { }, '320': { etc } } (keys of millisecond duration)
38+
// β•šβ•β• β”Œβ”€β”€β”€β”€β”˜
39+
// β”‚
40+
// ╔══ β”‚
41+
// β•‘ TimersList { _idleNext: { }, _idlePrev: (self) }
42+
// β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
43+
// β•‘ ╔══ β”‚ ^
44+
// β•‘ β•‘ { _idleNext: { }, _idlePrev: { }, _onTimeout: (callback) }
45+
// β•‘ β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
46+
// β•‘ β•‘ β”‚ ^
47+
// β•‘ β•‘ { _idleNext: { etc }, _idlePrev: { }, _onTimeout: (callback) }
48+
// ╠══ ╠══
49+
// β•‘ β•‘
50+
// β•‘ β•šβ•β•β•β• > Actual JavaScript timeouts
51+
// β•‘
52+
// β•šβ•β•β•β• > Linked List
53+
//
54+
/* eslint-enable node-core/non-ascii-character */
55+
//
56+
// With this, virtually constant-time insertion (append), removal, and timeout
57+
// is possible in the JavaScript layer. Any one list of timers is able to be
58+
// sorted by just appending to it because all timers within share the same
59+
// duration. Therefore, any timer added later will always have been scheduled to
60+
// timeout later, thus only needing to be appended.
61+
// Removal from an object-property linked list is also virtually constant-time
62+
// as can be seen in the lib/internal/linkedlist.js implementation.
63+
// Timeouts only need to process any timers currently due to expire, which will
64+
// always be at the beginning of the list for reasons stated above. Any timers
65+
// after the first one encountered that does not yet need to timeout will also
66+
// always be due to timeout at a later time.
67+
//
68+
// Less-than constant time operations are thus contained in two places:
69+
// The PriorityQueue β€” an efficient binary heap implementation that does all
70+
// operations in worst-case O(log n) time β€” which manages the order of expiring
71+
// Timeout lists and the object map lookup of a specific list by the duration of
72+
// timers within (or creation of a new list). However, these operations combined
73+
// have shown to be trivial in comparison to other timers architectures.
74+
375
const {
476
scheduleTimer,
577
toggleTimerRef,

β€Žlib/timers.js

-72
Original file line numberDiff line numberDiff line change
@@ -63,78 +63,6 @@ const {
6363
emitDestroy
6464
} = require('internal/async_hooks');
6565

66-
// HOW and WHY the timers implementation works the way it does.
67-
//
68-
// Timers are crucial to Node.js. Internally, any TCP I/O connection creates a
69-
// timer so that we can time out of connections. Additionally, many user
70-
// libraries and applications also use timers. As such there may be a
71-
// significantly large amount of timeouts scheduled at any given time.
72-
// Therefore, it is very important that the timers implementation is performant
73-
// and efficient.
74-
//
75-
// Note: It is suggested you first read through the lib/internal/linkedlist.js
76-
// linked list implementation, since timers depend on it extensively. It can be
77-
// somewhat counter-intuitive at first, as it is not actually a class. Instead,
78-
// it is a set of helpers that operate on an existing object.
79-
//
80-
// In order to be as performant as possible, the architecture and data
81-
// structures are designed so that they are optimized to handle the following
82-
// use cases as efficiently as possible:
83-
84-
// - Adding a new timer. (insert)
85-
// - Removing an existing timer. (remove)
86-
// - Handling a timer timing out. (timeout)
87-
//
88-
// Whenever possible, the implementation tries to make the complexity of these
89-
// operations as close to constant-time as possible.
90-
// (So that performance is not impacted by the number of scheduled timers.)
91-
//
92-
// Object maps are kept which contain linked lists keyed by their duration in
93-
// milliseconds.
94-
//
95-
/* eslint-disable node-core/non-ascii-character */
96-
//
97-
// ╔════ > Object Map
98-
// β•‘
99-
// ╠══
100-
// β•‘ lists: { '40': { }, '320': { etc } } (keys of millisecond duration)
101-
// β•šβ•β• β”Œβ”€β”€β”€β”€β”˜
102-
// β”‚
103-
// ╔══ β”‚
104-
// β•‘ TimersList { _idleNext: { }, _idlePrev: (self) }
105-
// β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
106-
// β•‘ ╔══ β”‚ ^
107-
// β•‘ β•‘ { _idleNext: { }, _idlePrev: { }, _onTimeout: (callback) }
108-
// β•‘ β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
109-
// β•‘ β•‘ β”‚ ^
110-
// β•‘ β•‘ { _idleNext: { etc }, _idlePrev: { }, _onTimeout: (callback) }
111-
// ╠══ ╠══
112-
// β•‘ β•‘
113-
// β•‘ β•šβ•β•β•β• > Actual JavaScript timeouts
114-
// β•‘
115-
// β•šβ•β•β•β• > Linked List
116-
//
117-
/* eslint-enable node-core/non-ascii-character */
118-
//
119-
// With this, virtually constant-time insertion (append), removal, and timeout
120-
// is possible in the JavaScript layer. Any one list of timers is able to be
121-
// sorted by just appending to it because all timers within share the same
122-
// duration. Therefore, any timer added later will always have been scheduled to
123-
// timeout later, thus only needing to be appended.
124-
// Removal from an object-property linked list is also virtually constant-time
125-
// as can be seen in the lib/internal/linkedlist.js implementation.
126-
// Timeouts only need to process any timers currently due to expire, which will
127-
// always be at the beginning of the list for reasons stated above. Any timers
128-
// after the first one encountered that does not yet need to timeout will also
129-
// always be due to timeout at a later time.
130-
//
131-
// Less-than constant time operations are thus contained in two places:
132-
// The PriorityQueue β€” an efficient binary heap implementation that does all
133-
// operations in worst-case O(log n) time β€” which manages the order of expiring
134-
// Timeout lists and the object map lookup of a specific list by the duration of
135-
// timers within (or creation of a new list). However, these operations combined
136-
// have shown to be trivial in comparison to other timers architectures.
137-
13866
// Remove a timer. Cancels the timeout and resets the relevant timer properties.
13967
function unenroll(item) {
14068
// Fewer checks may be possible, but these cover everything.

0 commit comments

Comments
Β (0)