@@ -246,55 +246,63 @@ struct StringPtr {
246246 size_t size_ = 0 ;
247247};
248248
249- struct ParserComparator {
250- bool operator ()(const Parser* lhs, const Parser* rhs) const ;
249+ // Intrusive doubly-linked list node, linked to itself when not in a list.
250+ struct ParserListNode {
251+ ParserListNode* prev = this ;
252+ ParserListNode* next = this ;
253+
254+ ParserListNode () = default ;
255+ ~ParserListNode () { Remove (); }
256+
257+ ParserListNode (const ParserListNode&) = delete ;
258+ ParserListNode& operator =(const ParserListNode&) = delete ;
259+
260+ void Remove () {
261+ prev->next = next;
262+ next->prev = prev;
263+ prev = this ;
264+ next = this ;
265+ }
251266};
252267
253268class ConnectionsList : public BaseObject {
254269 public:
255- static void New (const FunctionCallbackInfo<Value>& args);
270+ static void New (const FunctionCallbackInfo<Value>& args);
256271
257- static void All (const FunctionCallbackInfo<Value>& args);
272+ static void All (const FunctionCallbackInfo<Value>& args);
258273
259- static void Idle (const FunctionCallbackInfo<Value>& args);
274+ static void Idle (const FunctionCallbackInfo<Value>& args);
260275
261- static void Active (const FunctionCallbackInfo<Value>& args);
276+ static void Active (const FunctionCallbackInfo<Value>& args);
262277
263- static void Expired (const FunctionCallbackInfo<Value>& args);
278+ static void Expired (const FunctionCallbackInfo<Value>& args);
264279
265- void Push (Parser* parser) {
266- all_connections_.insert (parser);
267- }
280+ inline void Push (Parser* parser);
268281
269- void Pop (Parser* parser) {
270- all_connections_.erase (parser);
271- }
282+ inline void Pop (Parser* parser);
272283
273- void PushActive (Parser* parser) {
274- active_connections_.insert (parser);
275- }
284+ inline void PushActive (Parser* parser);
276285
277- void PopActive (Parser* parser) {
278- active_connections_.erase (parser);
279- }
286+ inline void PopActive (Parser* parser);
280287
281- SET_NO_MEMORY_INFO ()
282- SET_MEMORY_INFO_NAME (ConnectionsList)
283- SET_SELF_SIZE (ConnectionsList)
288+ SET_NO_MEMORY_INFO ()
289+ SET_MEMORY_INFO_NAME (ConnectionsList)
290+ SET_SELF_SIZE (ConnectionsList)
284291
285292 private:
286- ConnectionsList (Environment* env, Local<Object> object)
293+ ConnectionsList (Environment* env, Local<Object> object)
287294 : BaseObject(env, object) {
288- MakeWeak ();
289- }
295+ MakeWeak ();
296+ }
290297
291- std::set<Parser*, ParserComparator> all_connections_;
292- std::set<Parser*, ParserComparator> active_connections_;
298+ // active_connections_ is ordered by last_message_start_, as parsers are
299+ // appended right after it is assigned from the monotonic uv_hrtime().
300+ ParserListNode all_connections_;
301+ ParserListNode active_connections_;
293302};
294303
295304class Parser : public AsyncWrap , public StreamListener {
296305 friend class ConnectionsList ;
297- friend struct ParserComparator ;
298306
299307 public:
300308 Parser (BindingData* binding_data, Local<Object> wrap)
@@ -308,13 +316,6 @@ class Parser : public AsyncWrap, public StreamListener {
308316 SET_SELF_SIZE(Parser)
309317
310318 int on_message_begin() {
311- // Important: Pop from the lists BEFORE resetting the last_message_start_
312- // otherwise std::set.erase will fail.
313- if (connectionsList_ != nullptr ) {
314- connectionsList_->Pop (this );
315- connectionsList_->PopActive (this );
316- }
317-
318319 num_fields_ = num_values_ = 0 ;
319320 headers_completed_ = false ;
320321 chunk_extensions_nread_ = 0 ;
@@ -325,7 +326,6 @@ class Parser : public AsyncWrap, public StreamListener {
325326 status_message_.Reset ();
326327
327328 if (connectionsList_ != nullptr ) {
328- connectionsList_->Push (this );
329329 connectionsList_->PushActive (this );
330330 }
331331
@@ -344,7 +344,6 @@ class Parser : public AsyncWrap, public StreamListener {
344344 return 0 ;
345345 }
346346
347-
348347 int on_url (const char * at, size_t length) {
349348 int rv = TrackHeader (length);
350349 if (rv != 0 ) {
@@ -542,19 +541,12 @@ class Parser : public AsyncWrap, public StreamListener {
542541 int on_message_complete () {
543542 HandleScope scope (env ()->isolate ());
544543
545- // Important: Pop from the lists BEFORE resetting the last_message_start_
546- // otherwise std::set.erase will fail.
547544 if (connectionsList_ != nullptr ) {
548- connectionsList_->Pop (this );
549545 connectionsList_->PopActive (this );
550546 }
551547
552548 last_message_start_ = 0 ;
553549
554- if (connectionsList_ != nullptr ) {
555- connectionsList_->Push (this );
556- }
557-
558550 if (num_fields_)
559551 Flush (); // Flush trailing HTTP headers.
560552
@@ -740,8 +732,6 @@ class Parser : public AsyncWrap, public StreamListener {
740732 // server.timeout is left to the default value of zero.
741733 parser->last_message_start_ = uv_hrtime ();
742734
743- // Important: Push into the lists AFTER setting the last_message_start_
744- // otherwise std::set.erase will fail later.
745735 parser->connectionsList_ ->Push (parser);
746736 parser->connectionsList_ ->PushActive (parser);
747737 } else {
@@ -1116,6 +1106,8 @@ class Parser : public AsyncWrap, public StreamListener {
11161106 uint64_t max_http_header_size_;
11171107 uint64_t last_message_start_;
11181108 ConnectionsList* connectionsList_;
1109+ ParserListNode all_node_;
1110+ ParserListNode active_node_;
11191111
11201112 BaseObjectPtr<BindingData> binding_data_;
11211113
@@ -1143,18 +1135,34 @@ class Parser : public AsyncWrap, public StreamListener {
11431135 static const llhttp_settings_t settings;
11441136};
11451137
1146- bool ParserComparator::operator ()(const Parser* lhs, const Parser* rhs) const {
1147- if (lhs->last_message_start_ == 0 && rhs->last_message_start_ == 0 ) {
1148- // When both parsers are idle, guarantee strict order by
1149- // comparing pointers as ints.
1150- return lhs < rhs;
1151- } else if (lhs->last_message_start_ == 0 ) {
1152- return true ;
1153- } else if (rhs->last_message_start_ == 0 ) {
1154- return false ;
1155- }
1138+ namespace {
1139+
1140+ // Append `node` at the tail of the list headed by `head`, unlinking it from
1141+ // any list it is currently in.
1142+ void ListPushBack (ParserListNode* head, ParserListNode* node) {
1143+ node->Remove ();
1144+ node->prev = head->prev ;
1145+ node->next = head;
1146+ head->prev ->next = node;
1147+ head->prev = node;
1148+ }
1149+
1150+ } // anonymous namespace
11561151
1157- return lhs->last_message_start_ < rhs->last_message_start_ ;
1152+ void ConnectionsList::Push (Parser* parser) {
1153+ ListPushBack (&all_connections_, &parser->all_node_ );
1154+ }
1155+
1156+ void ConnectionsList::Pop (Parser* parser) {
1157+ parser->all_node_ .Remove ();
1158+ }
1159+
1160+ void ConnectionsList::PushActive (Parser* parser) {
1161+ ListPushBack (&active_connections_, &parser->active_node_ );
1162+ }
1163+
1164+ void ConnectionsList::PopActive (Parser* parser) {
1165+ parser->active_node_ .Remove ();
11581166}
11591167
11601168void ConnectionsList::New (const FunctionCallbackInfo<Value>& args) {
@@ -1172,8 +1180,10 @@ void ConnectionsList::All(const FunctionCallbackInfo<Value>& args) {
11721180 ASSIGN_OR_RETURN_UNWRAP (&list, args.This ());
11731181
11741182 LocalVector<Value> result (isolate);
1175- result.reserve (list->all_connections_ .size ());
1176- for (auto parser : list->all_connections_ ) {
1183+ for (ParserListNode* node = list->all_connections_ .next ;
1184+ node != &list->all_connections_ ;
1185+ node = node->next ) {
1186+ Parser* parser = ContainerOf (&Parser::all_node_, node);
11771187 result.emplace_back (parser->object ());
11781188 }
11791189
@@ -1189,8 +1199,10 @@ void ConnectionsList::Idle(const FunctionCallbackInfo<Value>& args) {
11891199 ASSIGN_OR_RETURN_UNWRAP (&list, args.This ());
11901200
11911201 LocalVector<Value> result (isolate);
1192- result.reserve (list->all_connections_ .size ());
1193- for (auto parser : list->all_connections_ ) {
1202+ for (ParserListNode* node = list->all_connections_ .next ;
1203+ node != &list->all_connections_ ;
1204+ node = node->next ) {
1205+ Parser* parser = ContainerOf (&Parser::all_node_, node);
11941206 if (parser->last_message_start_ == 0 || !parser->received_data_ ) {
11951207 result.emplace_back (parser->object ());
11961208 }
@@ -1208,8 +1220,10 @@ void ConnectionsList::Active(const FunctionCallbackInfo<Value>& args) {
12081220 ASSIGN_OR_RETURN_UNWRAP (&list, args.This ());
12091221
12101222 LocalVector<Value> result (isolate);
1211- result.reserve (list->active_connections_ .size ());
1212- for (auto parser : list->active_connections_ ) {
1223+ for (ParserListNode* node = list->active_connections_ .next ;
1224+ node != &list->active_connections_ ;
1225+ node = node->next ) {
1226+ Parser* parser = ContainerOf (&Parser::active_node_, node);
12131227 result.emplace_back (parser->object ());
12141228 }
12151229
@@ -1253,14 +1267,11 @@ void ConnectionsList::Expired(const FunctionCallbackInfo<Value>& args) {
12531267 return args.GetReturnValue ().Set (Array::New (isolate, 0 ));
12541268 }
12551269
1256- auto iter = list->active_connections_ .begin ();
1257- auto end = list->active_connections_ .end ();
1258-
12591270 LocalVector<Value> result (isolate);
1260- result. reserve ( list->active_connections_ .size ()) ;
1261- while (iter != end ) {
1262- Parser* parser = *iter ;
1263- iter++ ;
1271+ ParserListNode* node = list->active_connections_ .next ;
1272+ while (node != &list-> active_connections_ ) {
1273+ Parser* parser = ContainerOf (&Parser::active_node_, node) ;
1274+ node = node-> next ;
12641275
12651276 // Check for expiration.
12661277 if (
@@ -1272,7 +1283,7 @@ void ConnectionsList::Expired(const FunctionCallbackInfo<Value>& args) {
12721283 ) {
12731284 result.emplace_back (parser->object ());
12741285
1275- list-> active_connections_ . erase (parser );
1286+ parser-> active_node_ . Remove ( );
12761287 }
12771288 }
12781289
0 commit comments