raptor 0.22.3 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/Dockerfile +3 -1
  4. data/README.md +38 -31
  5. data/docs/raptor-vs-puma.md +44 -38
  6. data/docs/talk.md +1295 -0
  7. data/ext/raptor_bpf/reuseport_select.bpf.c +18 -9
  8. data/ext/raptor_http/extconf.rb +2 -0
  9. data/ext/raptor_http/raptor_http.c +91 -119
  10. data/ext/raptor_http2/raptor_http2.c +272 -223
  11. data/ext/raptor_native/raptor_native.c +38 -20
  12. data/lib/rackup/handler/raptor.rb +12 -11
  13. data/lib/raptor/binder.rb +12 -12
  14. data/lib/raptor/cli.rb +18 -18
  15. data/lib/raptor/cluster.rb +44 -44
  16. data/lib/raptor/control_server.rb +3 -2
  17. data/lib/raptor/detached_body.rb +6 -2
  18. data/lib/raptor/http.rb +7 -5
  19. data/lib/raptor/http1.rb +232 -207
  20. data/lib/raptor/http2.rb +312 -265
  21. data/lib/raptor/reactor.rb +138 -148
  22. data/lib/raptor/reuseport_bpf.rb +62 -38
  23. data/lib/raptor/server.rb +45 -34
  24. data/lib/raptor/stats.rb +15 -3
  25. data/lib/raptor/thread_locals.rb +4 -3
  26. data/lib/raptor/version.rb +1 -1
  27. data/sig/generated/rackup/handler/raptor.rbs +2 -1
  28. data/sig/generated/raptor/binder.rbs +9 -9
  29. data/sig/generated/raptor/cli.rbs +6 -6
  30. data/sig/generated/raptor/cluster.rbs +9 -9
  31. data/sig/generated/raptor/control_server.rbs +2 -1
  32. data/sig/generated/raptor/detached_body.rbs +5 -1
  33. data/sig/generated/raptor/http.rbs +3 -3
  34. data/sig/generated/raptor/http1.rbs +100 -91
  35. data/sig/generated/raptor/http2.rbs +200 -189
  36. data/sig/generated/raptor/reactor.rbs +107 -118
  37. data/sig/generated/raptor/reuseport_bpf.rbs +54 -17
  38. data/sig/generated/raptor/server.rbs +26 -26
  39. data/sig/generated/raptor/stats.rbs +3 -2
  40. data/sig/generated/raptor/thread_locals.rbs +4 -3
  41. metadata +2 -2
  42. data/docs/brisrails-talk.md +0 -2398
@@ -5,11 +5,20 @@ module Raptor
5
5
  # ready bytes to the parser pipeline, and hands completed requests back
6
6
  # to the caller-provided handlers.
7
7
  class Reactor
8
+ CHUNK_SIZE: untyped
9
+
10
+ DETACHED_CONNECTION_BUFFER_SIZE: untyped
11
+
12
+ DETACHED_WRITE_BATCH: ::Integer
13
+
14
+ DETACHED_WORKER_BUFFER_SIZE: untyped
15
+
16
+ TIMEOUT_RESPONSE: ::String
17
+
8
18
  # A client connection node ordered by absolute expiry time so the
9
19
  # soonest-to-expire is always at the tree's minimum.
10
20
  class TimeoutClient < RedBlackTree::Node
11
- # @rbs attr_accessor timeout_at: Float
12
- attr_accessor timeout_at: untyped
21
+ attr_accessor timeout_at: Float
13
22
 
14
23
  # Returns the client connection state.
15
24
  #
@@ -39,26 +48,19 @@ module Raptor
39
48
 
40
49
  # Tracks reactor-owned output state for a connection.
41
50
  class ConnectionIO
42
- # @rbs attr_accessor offset: Integer
43
- attr_accessor offset: untyped
51
+ attr_accessor offset: Integer
44
52
 
45
- # @rbs attr_accessor wait: Symbol?
46
- attr_accessor wait: untyped
53
+ attr_accessor wait: Symbol?
47
54
 
48
- # @rbs attr_accessor reading: bool
49
- attr_accessor reading: untyped
55
+ attr_accessor reading: bool
50
56
 
51
- # @rbs attr_accessor closing: bool
52
- attr_accessor closing: untyped
57
+ attr_accessor closing: bool
53
58
 
54
- # @rbs attr_accessor monitor: NIO::Monitor?
55
- attr_accessor monitor: untyped
59
+ attr_accessor monitor: NIO::Monitor?
56
60
 
57
- # @rbs attr_accessor timeout: TimeoutClient?
58
- attr_accessor timeout: untyped
61
+ attr_accessor timeout: TimeoutClient?
59
62
 
60
- # @rbs attr_reader output: Array[String]
61
- attr_reader output: untyped
63
+ attr_reader output: Array[String]
62
64
 
63
65
  # Creates empty connection I/O state for reactor-owned writes.
64
66
  #
@@ -77,25 +79,20 @@ module Raptor
77
79
 
78
80
  # Tracks reactor-owned I/O state for an HTTP/1.x detached response.
79
81
  class Http1IO < ConnectionIO
80
- # @rbs attr_accessor body: DetachedBody?
81
- attr_accessor body: untyped
82
+ attr_accessor body: DetachedBody?
82
83
 
83
- # @rbs attr_accessor finishing: bool
84
- attr_accessor finishing: untyped
84
+ attr_accessor finishing: bool
85
85
 
86
- # @rbs attr_reader budget: DetachedBody::Budget
87
- attr_reader budget: untyped
86
+ attr_reader budget: DetachedBody::Budget
88
87
 
89
- # @rbs attr_reader input: String
90
- attr_reader input: untyped
88
+ attr_reader input: String
91
89
 
92
- # @rbs attr_reader state: Hash[Symbol, untyped]
93
- attr_reader state: untyped
90
+ attr_reader state: Hash[Symbol, untyped]
94
91
 
95
92
  # Creates I/O state for an HTTP/1.x detached response.
96
93
  #
97
94
  # @param body [DetachedBody] the response body
98
- # @param state [Hash] connection state restored after the response finishes
95
+ # @param state [Hash] connection state restored after the response finishes, including bytes the client pipelined after the request
99
96
  # @return [void]
100
97
  #
101
98
  # @rbs (DetachedBody body, Hash[Symbol, untyped] state) -> void
@@ -111,17 +108,13 @@ module Raptor
111
108
 
112
109
  # Tracks reactor-owned I/O state for an HTTP/2 connection.
113
110
  class Http2IO < ConnectionIO
114
- # @rbs attr_reader detached: Hash[Integer, DetachedBody]
115
- attr_reader detached: untyped
111
+ attr_reader detached: Hash[Integer, DetachedBody]
116
112
 
117
- # @rbs attr_reader ready: Array[Integer]
118
- attr_reader ready: untyped
113
+ attr_reader ready: Array[Integer]
119
114
 
120
- # @rbs attr_reader ready_streams: Hash[Integer, bool]
121
- attr_reader ready_streams: untyped
115
+ attr_reader ready_streams: Hash[Integer, bool]
122
116
 
123
- # @rbs attr_reader budget: DetachedBody::Budget
124
- attr_reader budget: untyped
117
+ attr_reader budget: DetachedBody::Budget
125
118
 
126
119
  # Creates empty I/O state for an HTTP/2 connection and its detached streams.
127
120
  #
@@ -138,18 +131,6 @@ module Raptor
138
131
  def empty?: () -> bool
139
132
  end
140
133
 
141
- CHUNK_SIZE: untyped
142
-
143
- DETACHED_CONNECTION_BUFFER_SIZE: untyped
144
-
145
- DETACHED_WRITE_BATCH: ::Integer
146
-
147
- DETACHED_WORKER_BUFFER_SIZE: untyped
148
-
149
- TIMEOUT_RESPONSE: ::String
150
-
151
- @timeouts: RedBlackTree[TimeoutClient]
152
-
153
134
  @io_applied: AtomicConditionVariable
154
135
 
155
136
  @io_queue: AtomicQueue
@@ -162,19 +143,23 @@ module Raptor
162
143
 
163
144
  @http2_keepalive_interval: Integer
164
145
 
165
- @write_timeout: Integer
166
-
167
146
  @persistent_data_timeout: Integer
168
147
 
148
+ @write_timeout: Integer
149
+
169
150
  @chunk_data_timeout: Integer
170
151
 
171
152
  @first_data_timeout: Integer
172
153
 
173
- @http2_ractor_pool: untyped
154
+ @thread_pool: AtomicThreadPool
174
155
 
175
- @http1_ractor_pool: untyped
156
+ @http2_ractor_pool: RactorPool?
176
157
 
177
- @thread_pool: untyped
158
+ @http1_ractor_pool: RactorPool
159
+
160
+ @http1: Http1
161
+
162
+ @timeouts: RedBlackTree[TimeoutClient]
178
163
 
179
164
  @id_to_socket: Hash[Integer, TCPSocket]
180
165
 
@@ -182,9 +167,9 @@ module Raptor
182
167
 
183
168
  @id_to_timeout: Hash[Integer, TimeoutClient]
184
169
 
185
- @id_to_writer: Hash[Integer, untyped]
170
+ @id_to_writer: Hash[Integer, Http2::Writer]
186
171
 
187
- @id_to_flow_control: Hash[Integer, untyped]
172
+ @id_to_flow_control: Hash[Integer, Http2::FlowControl]
188
173
 
189
174
  @id_to_http2_last_stream: Hash[Integer, Integer]
190
175
 
@@ -202,8 +187,9 @@ module Raptor
202
187
 
203
188
  @thread: Thread?
204
189
 
205
- # Creates a new Reactor instance.
190
+ # Creates a new Reactor.
206
191
  #
192
+ # @param http1 [Http1] the HTTP/1.1 handler that resumes idle keep-alive connections
207
193
  # @param http1_ractor_pool [RactorPool] ractor pool for HTTP/1.x parsing
208
194
  # @param http2_ractor_pool [RactorPool, nil] ractor pool for HTTP/2 parsing, or nil when no listener supports HTTP/2
209
195
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
@@ -218,8 +204,8 @@ module Raptor
218
204
  # @option http2_options [Integer] :keepalive_timeout time to await a PING acknowledgement
219
205
  # @return [void]
220
206
  #
221
- # @rbs (untyped http1_ractor_pool, untyped http2_ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped], http2_options: Hash[Symbol, untyped]) -> void
222
- def initialize: (untyped http1_ractor_pool, untyped http2_ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped], http2_options: Hash[Symbol, untyped]) -> void
207
+ # @rbs (Http1 http1, RactorPool http1_ractor_pool, RactorPool? http2_ractor_pool, AtomicThreadPool thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped], http2_options: Hash[Symbol, untyped]) -> void
208
+ def initialize: (Http1 http1, RactorPool http1_ractor_pool, RactorPool? http2_ractor_pool, AtomicThreadPool thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped], http2_options: Hash[Symbol, untyped]) -> void
223
209
 
224
210
  # Starts the reactor's main event loop in a new thread. Runs until
225
211
  # shutdown work and pending writes are drained.
@@ -233,7 +219,7 @@ module Raptor
233
219
  #
234
220
  # @param state [Hash] client connection state including socket and ID
235
221
  # @option state [TCPSocket] :socket the client socket
236
- # @option state [Integer] :id unique identifier for the client
222
+ # @option state [Integer] :id unique connection identifier
237
223
  # @return [void]
238
224
  #
239
225
  # @rbs (Hash[Symbol, untyped] state) -> void
@@ -243,7 +229,7 @@ module Raptor
243
229
  # it for further I/O.
244
230
  #
245
231
  # @param state [Hash] updated client connection state
246
- # @option state [Integer] :id client identifier
232
+ # @option state [Integer] :id unique connection identifier
247
233
  # @return [void]
248
234
  #
249
235
  # @rbs (Hash[Symbol, untyped] state) -> void
@@ -253,7 +239,7 @@ module Raptor
253
239
  # has been handed off to the thread pool. The socket itself is kept
254
240
  # open so the worker can write the response.
255
241
  #
256
- # @param id [Integer] unique client identifier
242
+ # @param id [Integer] unique connection identifier
257
243
  # @return [TCPSocket, nil] the socket associated with `id`, if any
258
244
  #
259
245
  # @rbs (Integer id) -> TCPSocket?
@@ -263,45 +249,45 @@ module Raptor
263
249
  # under the persistent-data timeout.
264
250
  #
265
251
  # @param socket [TCPSocket] the kept-alive client socket
266
- # @param id [Integer] the unique client identifier
252
+ # @param id [Integer] unique connection identifier
267
253
  # @param request_count [Integer] number of requests handled on this connection
268
- # @param remote_addr [String] the client's remote IP address
254
+ # @param remote_addr [String] the client IP address
269
255
  # @param url_scheme [String] "http" or "https"
270
256
  # @return [void]
271
257
  #
272
258
  # @rbs (TCPSocket socket, Integer id, Integer request_count, remote_addr: String, url_scheme: String) -> void
273
259
  def persist: (TCPSocket socket, Integer id, Integer request_count, remote_addr: String, url_scheme: String) -> void
274
260
 
275
- # Returns the socket for a given client identifier without removing it.
261
+ # Returns the socket for a given connection identifier without removing it.
276
262
  #
277
- # @param id [Integer] unique client identifier
263
+ # @param id [Integer] unique connection identifier
278
264
  # @return [TCPSocket, nil] the socket, if found
279
265
  #
280
266
  # @rbs (Integer id) -> TCPSocket?
281
267
  def socket_for: (Integer id) -> TCPSocket?
282
268
 
283
- # Returns the writer object associated with a given connection, if one
284
- # was supplied when the connection was added.
269
+ # Returns the HTTP/2 frame writer registered by {attach_http2} for a
270
+ # connection.
285
271
  #
286
- # @param id [Integer] unique client identifier
287
- # @return [Object, nil] the writer, if found
272
+ # @param id [Integer] unique connection identifier
273
+ # @return [Http2::Writer, nil] the writer, if found
288
274
  #
289
- # @rbs (Integer id) -> untyped?
290
- def writer_for: (Integer id) -> untyped?
275
+ # @rbs (Integer id) -> Http2::Writer?
276
+ def writer_for: (Integer id) -> Http2::Writer?
291
277
 
292
- # Returns the flow controller associated with a given connection, if
293
- # one was supplied when the connection was added.
278
+ # Returns the HTTP/2 flow controller registered by {attach_http2} for a
279
+ # connection.
294
280
  #
295
- # @param id [Integer] unique client identifier
296
- # @return [Object, nil] the flow controller, if found
281
+ # @param id [Integer] unique connection identifier
282
+ # @return [Http2::FlowControl, nil] the flow controller, if found
297
283
  #
298
- # @rbs (Integer id) -> untyped?
299
- def flow_control_for: (Integer id) -> untyped?
284
+ # @rbs (Integer id) -> Http2::FlowControl?
285
+ def flow_control_for: (Integer id) -> Http2::FlowControl?
300
286
 
301
287
  # Attaches a detached response body to an HTTP/1.x connection.
302
288
  #
303
289
  # @param socket [TCPSocket] the client socket
304
- # @param id [Integer] unique client identifier
290
+ # @param id [Integer] unique connection identifier
305
291
  # @param body [DetachedBody] the response body
306
292
  # @param state [Hash] connection state restored once the response finishes
307
293
  # @param finished [Proc] called with the close reason
@@ -314,7 +300,7 @@ module Raptor
314
300
  # that arrived after graceful draining began.
315
301
  #
316
302
  # @param id [Integer] unique connection identifier
317
- # @param stream_id [Integer] HTTP/2 stream identifier
303
+ # @param stream_id [Integer] the HTTP/2 stream identifier
318
304
  # @return [Boolean] whether the stream may be dispatched
319
305
  #
320
306
  # @rbs (Integer id, Integer stream_id) -> bool
@@ -323,7 +309,8 @@ module Raptor
323
309
  # Sends GOAWAY on every HTTP/2 connection and fixes the last stream each
324
310
  # connection may dispatch while existing application work drains.
325
311
  #
326
- # @yieldparam stream_id [Integer] last dispatched stream identifier
312
+ # @yield for each HTTP/2 connection
313
+ # @yieldparam stream_id [Integer] the last dispatched HTTP/2 stream identifier
327
314
  # @yieldreturn [String] serialized GOAWAY frame
328
315
  # @return [void]
329
316
  #
@@ -343,7 +330,7 @@ module Raptor
343
330
  # Attaches a detached response body to an HTTP/2 stream.
344
331
  #
345
332
  # @param id [Integer] unique connection identifier
346
- # @param stream_id [Integer] HTTP/2 stream identifier
333
+ # @param stream_id [Integer] the HTTP/2 stream identifier
347
334
  # @param body [DetachedBody] the response body
348
335
  # @param finished [Proc] called with the close reason
349
336
  # @return [Boolean] whether the body was attached
@@ -362,7 +349,7 @@ module Raptor
362
349
  # Cancels a detached response stream.
363
350
  #
364
351
  # @param id [Integer] unique connection identifier
365
- # @param stream_id [Integer] HTTP/2 stream identifier
352
+ # @param stream_id [Integer] the HTTP/2 stream identifier
366
353
  # @return [void]
367
354
  #
368
355
  # @rbs (Integer id, Integer stream_id) -> void
@@ -380,17 +367,17 @@ module Raptor
380
367
  # Stores an HTTP/2 connection's socket, state, writer, and flow
381
368
  # controller in the reactor's per-connection maps.
382
369
  #
383
- # @param id [Integer] unique client identifier
370
+ # @param id [Integer] unique connection identifier
384
371
  # @param socket [TCPSocket] the connection socket
385
372
  # @param state [Hash] initial connection state
386
- # @param writer [Http2::Writer] per-connection frame writer
373
+ # @param writer [Http2::Writer] frame writer for the connection
387
374
  # @param flow_control [Http2::FlowControl] per-connection outbound flow controller
388
375
  # @param ping_frame [String] serialized PING frame for keepalive probes
389
376
  # @param ping_payload [String] payload expected in the corresponding acknowledgement
390
377
  # @return [void]
391
378
  #
392
- # @rbs (id: Integer, socket: TCPSocket, state: Hash[Symbol, untyped], writer: untyped, flow_control: untyped, ping_frame: String, ping_payload: String) -> void
393
- def attach_http2: (id: Integer, socket: TCPSocket, state: Hash[Symbol, untyped], writer: untyped, flow_control: untyped, ping_frame: String, ping_payload: String) -> void
379
+ # @rbs (id: Integer, socket: TCPSocket, state: Hash[Symbol, untyped], writer: Http2::Writer, flow_control: Http2::FlowControl, ping_frame: String, ping_payload: String) -> void
380
+ def attach_http2: (id: Integer, socket: TCPSocket, state: Hash[Symbol, untyped], writer: Http2::Writer, flow_control: Http2::FlowControl, ping_frame: String, ping_payload: String) -> void
394
381
 
395
382
  # Records acknowledgements for server keepalive probes.
396
383
  #
@@ -403,24 +390,15 @@ module Raptor
403
390
 
404
391
  # Registers an attached socket for future reactor-driven reads.
405
392
  #
406
- # @param id [Integer] unique client identifier
393
+ # @param id [Integer] unique connection identifier
407
394
  # @return [void]
408
395
  #
409
396
  # @rbs (Integer id) -> void
410
397
  def watch: (Integer id) -> void
411
398
 
412
- # Updates connection state for an HTTP/2 connection and re-registers
413
- # the socket for further reads.
414
- #
415
- # @param state [Hash] updated connection state from the ractor pool
416
- # @return [void]
417
- #
418
- # @rbs (Hash[Symbol, untyped] state) -> void
419
- def update_http2_state: (Hash[Symbol, untyped] state) -> void
420
-
421
399
  # Closes a connection after writing any frames already queued for it.
422
400
  #
423
- # @param id [Integer] unique client identifier
401
+ # @param id [Integer] unique connection identifier
424
402
  # @return [void]
425
403
  #
426
404
  # @rbs (Integer id) -> void
@@ -469,7 +447,7 @@ module Raptor
469
447
  # Adds a detached body to an HTTP/1.x connection.
470
448
  #
471
449
  # @param socket [TCPSocket] the client socket
472
- # @param id [Integer] unique client identifier
450
+ # @param id [Integer] unique connection identifier
473
451
  # @param body [DetachedBody] the response body
474
452
  # @param state [Hash] connection state restored once the response finishes
475
453
  # @param finished [Proc] called with the close reason
@@ -480,7 +458,7 @@ module Raptor
480
458
 
481
459
  # Writes buffered HTTP/1.x body chunks without blocking.
482
460
  #
483
- # @param id [Integer] unique client identifier
461
+ # @param id [Integer] unique connection identifier
484
462
  # @return [void]
485
463
  #
486
464
  # @rbs (Integer id) -> void
@@ -488,7 +466,7 @@ module Raptor
488
466
 
489
467
  # Finishes an HTTP/1.x detached response and either reuses or closes its connection.
490
468
  #
491
- # @param id [Integer] unique client identifier
469
+ # @param id [Integer] unique connection identifier
492
470
  # @param io [Http1IO] connection I/O state
493
471
  # @return [void]
494
472
  #
@@ -497,7 +475,7 @@ module Raptor
497
475
 
498
476
  # Cancels an HTTP/1.x detached response and closes its connection.
499
477
  #
500
- # @param id [Integer] unique client identifier
478
+ # @param id [Integer] unique connection identifier
501
479
  # @param reason [Symbol] why the response closed
502
480
  # @return [void]
503
481
  #
@@ -507,7 +485,7 @@ module Raptor
507
485
  # Adds a detached body to an HTTP/2 stream.
508
486
  #
509
487
  # @param id [Integer] unique connection identifier
510
- # @param stream_id [Integer] HTTP/2 stream identifier
488
+ # @param stream_id [Integer] the HTTP/2 stream identifier
511
489
  # @param body [DetachedBody] the response body
512
490
  # @param finished [Proc] called with the close reason
513
491
  # @return [void]
@@ -518,7 +496,7 @@ module Raptor
518
496
  # Marks an HTTP/2 detached stream eligible for fair scheduling.
519
497
  #
520
498
  # @param id [Integer] unique connection identifier
521
- # @param stream_id [Integer] HTTP/2 stream identifier
499
+ # @param stream_id [Integer] the HTTP/2 stream identifier
522
500
  # @return [void]
523
501
  #
524
502
  # @rbs (Integer id, Integer stream_id) -> void
@@ -543,7 +521,7 @@ module Raptor
543
521
  # Finishes an HTTP/2 detached stream with DATA or trailing HEADERS.
544
522
  #
545
523
  # @param id [Integer] unique connection identifier
546
- # @param stream_id [Integer] HTTP/2 stream identifier
524
+ # @param stream_id [Integer] the HTTP/2 stream identifier
547
525
  # @param body [DetachedBody] the response body
548
526
  # @return [void]
549
527
  #
@@ -553,7 +531,7 @@ module Raptor
553
531
  # Removes an HTTP/2 detached stream and schedules its close callback.
554
532
  #
555
533
  # @param id [Integer] unique connection identifier
556
- # @param stream_id [Integer] HTTP/2 stream identifier
534
+ # @param stream_id [Integer] the HTTP/2 stream identifier
557
535
  # @param reason [Symbol] why the stream closed
558
536
  # @return [void]
559
537
  #
@@ -576,7 +554,7 @@ module Raptor
576
554
 
577
555
  # Closes a connection once its queued frames are written.
578
556
  #
579
- # @param id [Integer] unique client identifier
557
+ # @param id [Integer] unique connection identifier
580
558
  # @return [void]
581
559
  #
582
560
  # @rbs (Integer id) -> void
@@ -584,15 +562,15 @@ module Raptor
584
562
 
585
563
  # Immediately closes a connection and drops its reactor state.
586
564
  #
587
- # @param id [Integer] unique client identifier
565
+ # @param id [Integer] unique connection identifier
588
566
  # @return [void]
589
567
  #
590
568
  # @rbs (Integer id) -> void
591
569
  def remove_connection: (Integer id) -> void
592
570
 
593
- # Adds bytes to one connection and writes as much as the socket accepts.
571
+ # Appends bytes to one connection's pending output.
594
572
  #
595
- # @param io [ConnectionIO] connection I/O state
573
+ # @param io [ConnectionIO, nil] connection I/O state
596
574
  # @param data [String] serialized response bytes
597
575
  # @return [void]
598
576
  #
@@ -602,7 +580,7 @@ module Raptor
602
580
  # Drains one connection's queued response bytes without blocking.
603
581
  #
604
582
  # @param id [Integer] unique connection identifier
605
- # @param io [ConnectionIO] connection I/O state
583
+ # @param io [ConnectionIO, nil] connection I/O state
606
584
  # @return [void]
607
585
  #
608
586
  # @rbs (Integer id, ConnectionIO? io) -> void
@@ -692,13 +670,14 @@ module Raptor
692
670
  # Handles readiness for an HTTP/1.x detached response.
693
671
  #
694
672
  # @param monitor [NIO::Monitor] ready selector monitor
695
- # @param id [Integer] unique client identifier
673
+ # @param id [Integer] unique connection identifier
696
674
  # @return [void]
697
675
  #
698
676
  # @rbs (NIO::Monitor monitor, Integer id) -> void
699
677
  def handle_http1_detached_monitor: (NIO::Monitor monitor, Integer id) -> void
700
678
 
701
- # Handles socket wakeup by deregistering and queuing for processing.
679
+ # Deregisters a readable socket and resumes its idle keep-alive
680
+ # connection or queues its bytes for parsing.
702
681
  #
703
682
  # @param socket [TCPSocket] the socket that became ready
704
683
  # @return [void]
@@ -706,15 +685,25 @@ module Raptor
706
685
  # @rbs (TCPSocket socket) -> void
707
686
  def wakeup!: (TCPSocket socket) -> void
708
687
 
688
+ # Resumes a readable keep-alive connection on an application thread,
689
+ # avoiding a Ractor round trip for complete requests.
690
+ #
691
+ # @param socket [TCPSocket] the readable client socket
692
+ # @param state [Hash] current connection state
693
+ # @return [void]
694
+ #
695
+ # @rbs (TCPSocket socket, Hash[Symbol, untyped] state) -> void
696
+ def resume_keepalive: (TCPSocket socket, Hash[Symbol, untyped] state) -> void
697
+
709
698
  # Reads data from a socket and either queues it for parsing or
710
699
  # returns it to the selector.
711
700
  #
712
701
  # @param socket [TCPSocket] the socket to read from and queue
713
702
  # @param state [Hash] current connection state
714
- # @return [Hash, nil] updated state, if successful
703
+ # @return [void]
715
704
  #
716
- # @rbs (TCPSocket socket, Hash[Symbol, untyped] state) -> Hash[Symbol, untyped]?
717
- def read_and_queue_for_parse: (TCPSocket socket, Hash[Symbol, untyped] state) -> Hash[Symbol, untyped]?
705
+ # @rbs (TCPSocket socket, Hash[Symbol, untyped] state) -> void
706
+ def read_and_queue_for_parse: (TCPSocket socket, Hash[Symbol, untyped] state) -> void
718
707
 
719
708
  # Cleans up a client connection by removing it from tracking and closing the socket.
720
709
  #
@@ -724,18 +713,18 @@ module Raptor
724
713
  # @rbs (TCPSocket socket) -> void
725
714
  def cleanup: (TCPSocket socket) -> void
726
715
 
727
- # Returns true when the request has been fully parsed.
716
+ # Returns whether the request has been fully parsed.
728
717
  #
729
718
  # @param state [Hash] connection state
730
- # @return [Boolean] true if the request is complete
719
+ # @return [Boolean]
731
720
  #
732
721
  # @rbs (Hash[Symbol, untyped] state) -> bool
733
722
  def complete?: (Hash[Symbol, untyped] state) -> bool
734
723
 
735
- # Checks if any data has been received for this connection.
724
+ # Returns whether any data has been received for this connection.
736
725
  #
737
726
  # @param state [Hash] connection state
738
- # @return [Boolean] true if first data has been received
727
+ # @return [Boolean]
739
728
  #
740
729
  # @rbs (Hash[Symbol, untyped] state) -> bool
741
730
  def first_data_received?: (Hash[Symbol, untyped] state) -> bool
@@ -6,14 +6,41 @@ module Raptor
6
6
  #
7
7
  # Auto-enabled on Linux when the `libbpf-ruby` gem is installed and the
8
8
  # BPF object file has been compiled. Falls back silently to standard
9
- # `SO_REUSEPORT` when either is missing. Raises when the kernel refuses
10
- # the BPF program. Wraps `tcp://` bindings only; non-tcp bindings are
11
- # left to the binder's shared listeners.
9
+ # `SO_REUSEPORT` when either is missing, or when there are more workers
10
+ # or listeners than the BPF maps have slots for. Raises when the kernel
11
+ # refuses the BPF program. Wraps `tcp://` bindings only; non-tcp bindings
12
+ # are left to the binder's shared listeners.
12
13
  module ReuseportBPF
13
14
  LIBBPF_LOADED: untyped
14
15
 
15
16
  BPF_OBJECT_PATH: untyped
16
17
 
18
+ TCP_INFO_UNACKED_OFFSET: ::Integer
19
+
20
+ UNAVAILABLE_LOAD: ::Integer
21
+
22
+ MAX_WORKERS: ::Integer
23
+
24
+ MAX_LISTENERS: ::Integer
25
+
26
+ self.@accepted_load_value: String
27
+
28
+ self.@load_value: String
29
+
30
+ self.@load_key: String
31
+
32
+ self.@worker_listeners: Array[TCPServer]
33
+
34
+ self.@shared_listeners: Array[TCPServer]
35
+
36
+ self.@loads_fd: Integer?
37
+
38
+ self.@socks_fd: Integer
39
+
40
+ self.@program_fd: Integer
41
+
42
+ self.@object: untyped
43
+
17
44
  # Returns true when the preconditions for BPF-directed reuseport are
18
45
  # met on this platform.
19
46
  #
@@ -22,28 +49,30 @@ module Raptor
22
49
  # @rbs () -> bool
23
50
  def self.supported?: () -> bool
24
51
 
25
- # Prepares BPF-directed routing for `worker_count` workers.
52
+ # Prepares BPF-directed routing for `worker_count` workers across the
53
+ # addresses `shared_listeners` are bound to.
26
54
  #
27
55
  # Returns true when BPF-directed dispatch is active. Returns false
28
- # when the platform is unsupported. Raises when the kernel refuses
29
- # the program.
56
+ # when the platform is unsupported or the counts exceed the map slots.
57
+ # Raises when the kernel refuses the program.
30
58
  #
31
59
  # @param worker_count [Integer] number of worker processes that will bind sockets
60
+ # @param shared_listeners [Array<TCPServer>] the binder's tcp listeners
32
61
  # @return [Boolean]
33
62
  #
34
- # @rbs (Integer worker_count) -> bool
35
- def self.setup: (Integer worker_count) -> bool
63
+ # @rbs (Integer worker_count, Array[TCPServer] shared_listeners) -> bool
64
+ def self.setup: (Integer worker_count, Array[TCPServer] shared_listeners) -> bool
36
65
 
37
- # Returns tcp listening sockets bound and registered for `worker_index`.
38
- # Skips non-tcp bind URIs.
66
+ # Creates this worker's BPF-routed listeners at the shared listeners'
67
+ # bound addresses, including resolved `localhost` addresses and ports
68
+ # assigned by the kernel for port 0.
39
69
  #
40
- # @param bind_uris [Array<String>] the configured bind URIs
41
70
  # @param worker_index [Integer] slot index for this worker in the socks map
42
71
  # @param socket_backlog [Integer] kernel listen() queue depth
43
72
  # @return [Array<TCPServer>] the tcp listening sockets created for this worker
44
73
  #
45
- # @rbs (Array[String] bind_uris, Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
46
- def self.create_worker_listeners: (Array[String] bind_uris, Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
74
+ # @rbs (Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
75
+ def self.create_worker_listeners: (Integer worker_index, Integer socket_backlog) -> Array[TCPServer]
47
76
 
48
77
  # Prepares this worker's load-reporting slot so subsequent
49
78
  # {update_load} calls can publish its backlog.
@@ -54,7 +83,7 @@ module Raptor
54
83
  # @rbs (Integer worker_index) -> void
55
84
  def self.enable_load_reporting: (Integer worker_index) -> void
56
85
 
57
- # Publishes this worker's current backlog to the BPF map.
86
+ # Publishes this worker's load to the BPF map.
58
87
  #
59
88
  # @param backlog [Integer] the worker's current reactor backlog
60
89
  # @return [void]
@@ -62,7 +91,7 @@ module Raptor
62
91
  # @rbs (Integer backlog) -> void
63
92
  def self.update_load: (Integer backlog) -> void
64
93
 
65
- # Publishes an accept-side backlog estimate. This uses a separate value
94
+ # Publishes an accept-side load estimate. This uses a separate value
66
95
  # buffer because the server and load reporter call into the map from
67
96
  # different threads.
68
97
  #
@@ -72,13 +101,21 @@ module Raptor
72
101
  # @rbs (Integer backlog) -> void
73
102
  def self.update_accepted_load: (Integer backlog) -> void
74
103
 
75
- # Marks a worker's slot as unavailable by parking its load at the
76
- # sentinel maximum so the BPF program's least-loaded pick skips it.
104
+ # Parks a worker's load at the maximum so BPF favors other workers.
105
+ # Stop publishing its load first to avoid overwriting the sentinel.
77
106
  #
78
107
  # @param worker_index [Integer] slot index for the worker to mark
79
108
  # @return [void]
80
109
  #
81
110
  # @rbs (Integer worker_index) -> void
82
111
  def self.mark_unavailable: (Integer worker_index) -> void
112
+
113
+ # Returns the number of connections waiting in this worker's accept
114
+ # queues, which the reactor backlog cannot see.
115
+ #
116
+ # @return [Integer]
117
+ #
118
+ # @rbs () -> Integer
119
+ def self.accept_queue_length: () -> Integer
83
120
  end
84
121
  end