uringmachine 0.30.0 → 0.31.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -4
- data/README.md +46 -38
- data/TODO.md +56 -2
- data/benchmark/gets.rb +7 -7
- data/benchmark/gets_concurrent.rb +10 -10
- data/benchmark/http_parse.rb +14 -14
- data/benchmark/http_server_accept_queue.rb +11 -7
- data/benchmark/http_server_multi_accept.rb +7 -7
- data/benchmark/http_server_multi_ractor.rb +7 -7
- data/benchmark/http_server_single_thread.rb +7 -7
- data/benchmark/openssl.rb +50 -22
- data/docs/design/buffer_pool.md +1 -1
- data/examples/fiber_concurrency_io.rb +52 -0
- data/examples/fiber_concurrency_naive.rb +26 -0
- data/examples/fiber_concurrency_runqueue.rb +33 -0
- data/examples/io_uring_simple.c +24 -0
- data/examples/pg.rb +2 -2
- data/examples/stream.rb +2 -2
- data/ext/um/um.c +20 -3
- data/ext/um/um.h +24 -18
- data/ext/um/um_connection.c +775 -0
- data/ext/um/um_connection_class.c +394 -0
- data/ext/um/um_ssl.c +37 -2
- data/ext/um/um_utils.c +1 -1
- data/grant-2025/final-report.md +2 -0
- data/grant-2025/journal.md +1 -1
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +16 -16
- data/test/{test_stream.rb → test_connection.rb} +290 -153
- data/test/test_um.rb +18 -18
- metadata +10 -6
- data/ext/um/um_stream.c +0 -706
- data/ext/um/um_stream_class.c +0 -317
|
@@ -5,24 +5,24 @@ require 'securerandom'
|
|
|
5
5
|
require 'openssl'
|
|
6
6
|
require 'localhost/authority'
|
|
7
7
|
|
|
8
|
-
class
|
|
9
|
-
attr_reader :
|
|
8
|
+
class ConnectionBaseTest < UMBaseTest
|
|
9
|
+
attr_reader :conn
|
|
10
10
|
|
|
11
11
|
def setup
|
|
12
12
|
super
|
|
13
13
|
@rfd, @wfd = UM.pipe
|
|
14
|
-
@
|
|
14
|
+
@conn = UM::Connection.new(@machine, @rfd)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def teardown
|
|
18
|
-
@
|
|
18
|
+
@conn = nil
|
|
19
19
|
machine.close(@rfd) rescue nil
|
|
20
20
|
machine.close(@wfd) rescue nil
|
|
21
21
|
super
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
class
|
|
25
|
+
class ConnectionTest < ConnectionBaseTest
|
|
26
26
|
def buffer_metrics
|
|
27
27
|
machine.metrics.fetch_values(
|
|
28
28
|
:buffers_allocated,
|
|
@@ -33,19 +33,19 @@ class StreamTest < StreamBaseTest
|
|
|
33
33
|
)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def test_connection_basic_usage
|
|
37
37
|
assert_equal [0, 0, 0, 0, 0], buffer_metrics
|
|
38
38
|
machine.write(@wfd, "foobar")
|
|
39
39
|
machine.close(@wfd)
|
|
40
40
|
|
|
41
|
-
buf =
|
|
41
|
+
buf = conn.read(3)
|
|
42
42
|
assert_equal 'foo', buf
|
|
43
43
|
|
|
44
|
-
buf =
|
|
44
|
+
buf = conn.read(-6)
|
|
45
45
|
assert_equal 'bar', buf
|
|
46
|
-
assert
|
|
46
|
+
assert conn.eof?
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
conn.clear
|
|
49
49
|
|
|
50
50
|
# initial buffer size: 6BKV, initial buffers commited: 16 (256KB)
|
|
51
51
|
# (plus an additional buffer commited after first usage)
|
|
@@ -53,20 +53,20 @@ class StreamTest < StreamBaseTest
|
|
|
53
53
|
assert_equal 0, machine.metrics[:ops_pending]
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def
|
|
56
|
+
def test_connection_clear
|
|
57
57
|
rfd, wfd = UM.pipe
|
|
58
|
-
|
|
58
|
+
conn = UM::Connection.new(machine, rfd)
|
|
59
59
|
|
|
60
60
|
assert_equal [0, 0, 0, 0, 0], buffer_metrics
|
|
61
61
|
machine.write(wfd, "foobar")
|
|
62
62
|
|
|
63
|
-
buf =
|
|
63
|
+
buf = conn.read(3)
|
|
64
64
|
assert_equal 'foo', buf
|
|
65
65
|
|
|
66
66
|
assert_equal 1, machine.metrics[:ops_pending]
|
|
67
67
|
assert_equal 255, machine.metrics[:segments_free]
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
conn.clear
|
|
70
70
|
machine.snooze
|
|
71
71
|
assert_equal 0, machine.metrics[:ops_pending]
|
|
72
72
|
assert_equal 256, machine.metrics[:segments_free]
|
|
@@ -77,9 +77,9 @@ class StreamTest < StreamBaseTest
|
|
|
77
77
|
machine.close(wfd) rescue nil
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def
|
|
80
|
+
def test_connection_big_read
|
|
81
81
|
s1, s2 = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
82
|
-
|
|
82
|
+
conn = UM::Connection.new(machine, s2)
|
|
83
83
|
|
|
84
84
|
msg = '1234567' * 20000
|
|
85
85
|
|
|
@@ -89,16 +89,16 @@ class StreamTest < StreamBaseTest
|
|
|
89
89
|
machine.shutdown(s1, UM::SHUT_WR)
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
buf =
|
|
92
|
+
buf = conn.read(msg.bytesize)
|
|
93
93
|
assert_equal msg, buf
|
|
94
94
|
ensure
|
|
95
95
|
machine.terminate(f)
|
|
96
96
|
machine.join(f)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
def
|
|
99
|
+
def test_connection_buffer_reuse
|
|
100
100
|
s1, s2 = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
101
|
-
|
|
101
|
+
conn = UM::Connection.new(machine, s2)
|
|
102
102
|
|
|
103
103
|
msg = '1234567' * 20000
|
|
104
104
|
|
|
@@ -109,19 +109,19 @@ class StreamTest < StreamBaseTest
|
|
|
109
109
|
machine.shutdown(s1, UM::SHUT_WR)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
buf =
|
|
112
|
+
buf = conn.read(msg.bytesize)
|
|
113
113
|
assert_equal msg, buf
|
|
114
114
|
|
|
115
|
-
buf =
|
|
115
|
+
buf = conn.read(msg.bytesize)
|
|
116
116
|
assert_equal msg, buf
|
|
117
117
|
|
|
118
|
-
buf =
|
|
118
|
+
buf = conn.read(msg.bytesize)
|
|
119
119
|
assert_equal msg, buf
|
|
120
120
|
|
|
121
|
-
buf =
|
|
121
|
+
buf = conn.read(msg.bytesize)
|
|
122
122
|
assert_equal msg, buf
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
conn.clear
|
|
125
125
|
# numbers may vary with different kernel versions
|
|
126
126
|
assert_in_range 24..32, machine.metrics[:buffers_allocated]
|
|
127
127
|
assert_in_range 10..18, machine.metrics[:buffers_free]
|
|
@@ -131,23 +131,23 @@ class StreamTest < StreamBaseTest
|
|
|
131
131
|
machine.join(f)
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
-
def
|
|
134
|
+
def test_connection_read_line
|
|
135
135
|
machine.write(@wfd, "foo\nbar\r\nbaz")
|
|
136
136
|
machine.close(@wfd)
|
|
137
137
|
|
|
138
138
|
assert_equal [0, 0, 0, 0, 0], buffer_metrics
|
|
139
139
|
|
|
140
|
-
assert_equal 'foo',
|
|
140
|
+
assert_equal 'foo', conn.read_line(0)
|
|
141
141
|
|
|
142
142
|
assert_equal [16, 0, 255, 16384 * 16, 16384 * 16 - 12], buffer_metrics
|
|
143
|
-
assert_equal 'bar',
|
|
144
|
-
assert_nil
|
|
145
|
-
assert_equal "baz",
|
|
143
|
+
assert_equal 'bar', conn.read_line(0)
|
|
144
|
+
assert_nil conn.read_line(0)
|
|
145
|
+
assert_equal "baz", conn.read(-6)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
-
def
|
|
148
|
+
def test_connection_read_line_segmented
|
|
149
149
|
machine.write(@wfd, "foo\n")
|
|
150
|
-
assert_equal 'foo',
|
|
150
|
+
assert_equal 'foo', conn.read_line(0)
|
|
151
151
|
|
|
152
152
|
machine.write(@wfd, "bar")
|
|
153
153
|
machine.write(@wfd, "\r\n")
|
|
@@ -156,19 +156,19 @@ class StreamTest < StreamBaseTest
|
|
|
156
156
|
|
|
157
157
|
# three segments received
|
|
158
158
|
assert_equal [16, 0, 253, 16384 * 16, 16384 * 16 - 13], buffer_metrics
|
|
159
|
-
assert_equal 'bar',
|
|
159
|
+
assert_equal 'bar', conn.read_line(0)
|
|
160
160
|
assert_equal [16, 0, 255, 16384 * 16, 16384 * 16 - 13], buffer_metrics
|
|
161
|
-
assert_equal 'baz',
|
|
161
|
+
assert_equal 'baz', conn.read_line(0)
|
|
162
162
|
assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 13], buffer_metrics
|
|
163
|
-
assert_nil
|
|
163
|
+
assert_nil conn.read_line(0)
|
|
164
164
|
end
|
|
165
165
|
|
|
166
|
-
def
|
|
166
|
+
def test_connection_read_line_maxlen
|
|
167
167
|
machine.write(@wfd, "foobar\r\n")
|
|
168
168
|
|
|
169
|
-
assert_nil
|
|
170
|
-
# verify that
|
|
171
|
-
assert_equal 'foobar',
|
|
169
|
+
assert_nil conn.read_line(3)
|
|
170
|
+
# verify that connecvtion pos has not changed
|
|
171
|
+
assert_equal 'foobar', conn.read_line(0)
|
|
172
172
|
|
|
173
173
|
machine.write(@wfd, "baz")
|
|
174
174
|
machine.write(@wfd, "\n")
|
|
@@ -176,62 +176,83 @@ class StreamTest < StreamBaseTest
|
|
|
176
176
|
machine.write(@wfd, "\n")
|
|
177
177
|
machine.close(@wfd)
|
|
178
178
|
|
|
179
|
-
assert_nil
|
|
180
|
-
assert_nil
|
|
181
|
-
assert_equal 'baz',
|
|
179
|
+
assert_nil conn.read_line(2)
|
|
180
|
+
assert_nil conn.read_line(3)
|
|
181
|
+
assert_equal 'baz', conn.read_line(4)
|
|
182
182
|
|
|
183
|
-
assert_nil
|
|
184
|
-
assert_nil
|
|
185
|
-
assert_equal 'bizz',
|
|
183
|
+
assert_nil conn.read_line(3)
|
|
184
|
+
assert_nil conn.read_line(4)
|
|
185
|
+
assert_equal 'bizz', conn.read_line(5)
|
|
186
186
|
|
|
187
|
-
assert_nil
|
|
187
|
+
assert_nil conn.read_line(8)
|
|
188
188
|
assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 17], buffer_metrics
|
|
189
189
|
end
|
|
190
190
|
|
|
191
|
-
def
|
|
191
|
+
def test_connection_read
|
|
192
192
|
machine.write(@wfd, "foobarbazblahzzz")
|
|
193
193
|
machine.close(@wfd)
|
|
194
194
|
|
|
195
|
-
assert_equal 'foobar',
|
|
196
|
-
assert_equal 'baz',
|
|
197
|
-
assert_equal 'blah',
|
|
198
|
-
assert_nil
|
|
195
|
+
assert_equal 'foobar', conn.read(6)
|
|
196
|
+
assert_equal 'baz', conn.read(3)
|
|
197
|
+
assert_equal 'blah', conn.read(4)
|
|
198
|
+
assert_nil conn.read(4)
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
-
def
|
|
201
|
+
def test_connection_read_zero_len
|
|
202
202
|
machine.write(@wfd, "foobar")
|
|
203
203
|
|
|
204
|
-
assert_equal 'foobar',
|
|
204
|
+
assert_equal 'foobar', conn.read(0)
|
|
205
205
|
|
|
206
206
|
machine.write(@wfd, "bazblah")
|
|
207
207
|
machine.close(@wfd)
|
|
208
|
-
assert_equal 'bazblah',
|
|
209
|
-
assert_nil
|
|
208
|
+
assert_equal 'bazblah', conn.read(0)
|
|
209
|
+
assert_nil conn.read(0)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
-
def
|
|
212
|
+
def test_connection_read_negative_len
|
|
213
213
|
machine.write(@wfd, "foobar")
|
|
214
214
|
|
|
215
|
-
assert_equal 'foo',
|
|
216
|
-
assert_equal 'bar',
|
|
215
|
+
assert_equal 'foo', conn.read(-3)
|
|
216
|
+
assert_equal 'bar', conn.read(-6)
|
|
217
217
|
|
|
218
218
|
machine.write(@wfd, "bazblah")
|
|
219
219
|
machine.close(@wfd)
|
|
220
|
-
assert_equal 'bazblah',
|
|
221
|
-
assert_nil
|
|
220
|
+
assert_equal 'bazblah', conn.read(-12)
|
|
221
|
+
assert_nil conn.read(-3)
|
|
222
222
|
end
|
|
223
223
|
|
|
224
|
-
def
|
|
224
|
+
def test_connection_read_to_delim
|
|
225
|
+
machine.write(@wfd, "abc,def,ghi")
|
|
226
|
+
machine.close(@wfd)
|
|
227
|
+
|
|
228
|
+
assert_nil conn.read_to_delim('!', 0) # not there
|
|
229
|
+
assert_nil conn.read_to_delim(',', 2) # too long
|
|
230
|
+
assert_equal 'abc', conn.read_to_delim(',', 0)
|
|
231
|
+
assert_equal 'def', conn.read_to_delim(',', 0)
|
|
232
|
+
assert_nil conn.read_to_delim(',', 0)
|
|
233
|
+
assert_equal 'ghi', conn.read_to_delim(',', -3)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def test_connection_read_to_delim_invalid_delim
|
|
237
|
+
machine.write(@wfd, "abc,def,ghi")
|
|
238
|
+
|
|
239
|
+
assert_raises(ArgumentError) { conn.read_to_delim(:foo, 0) }
|
|
240
|
+
assert_raises(UM::Error) { conn.read_to_delim('', 0) }
|
|
241
|
+
assert_raises(UM::Error) { conn.read_to_delim('ab', 0) }
|
|
242
|
+
assert_raises(UM::Error) { conn.read_to_delim('🙂', 0) }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def test_connection_skip
|
|
225
246
|
machine.write(@wfd, "foobarbaz")
|
|
226
247
|
|
|
227
|
-
|
|
228
|
-
assert_equal 'obar',
|
|
248
|
+
conn.skip(2)
|
|
249
|
+
assert_equal 'obar', conn.read(4)
|
|
229
250
|
|
|
230
|
-
|
|
231
|
-
assert_equal 'az',
|
|
251
|
+
conn.skip(1)
|
|
252
|
+
assert_equal 'az', conn.read(0)
|
|
232
253
|
end
|
|
233
254
|
|
|
234
|
-
def
|
|
255
|
+
def test_connection_big_data
|
|
235
256
|
data = SecureRandom.random_bytes(300_000)
|
|
236
257
|
fiber = machine.spin {
|
|
237
258
|
machine.writev(@wfd, data)
|
|
@@ -240,7 +261,7 @@ class StreamTest < StreamBaseTest
|
|
|
240
261
|
|
|
241
262
|
received = []
|
|
242
263
|
loop {
|
|
243
|
-
msg =
|
|
264
|
+
msg = conn.read(-60_000)
|
|
244
265
|
break if !msg
|
|
245
266
|
|
|
246
267
|
received << msg
|
|
@@ -252,11 +273,11 @@ class StreamTest < StreamBaseTest
|
|
|
252
273
|
assert_equal data, received.join
|
|
253
274
|
end
|
|
254
275
|
|
|
255
|
-
def
|
|
276
|
+
def test_connection_read_each
|
|
256
277
|
bufs = []
|
|
257
278
|
f = machine.spin do
|
|
258
279
|
bufs << :ready
|
|
259
|
-
|
|
280
|
+
conn.read_each {
|
|
260
281
|
assert_kind_of IO::Buffer, it
|
|
261
282
|
bufs << it.get_string
|
|
262
283
|
}
|
|
@@ -286,87 +307,190 @@ class StreamTest < StreamBaseTest
|
|
|
286
307
|
end
|
|
287
308
|
end
|
|
288
309
|
|
|
289
|
-
class
|
|
290
|
-
|
|
310
|
+
class ConnectionWriteTest < UMBaseTest
|
|
311
|
+
attr_reader :conn
|
|
312
|
+
|
|
313
|
+
def setup
|
|
314
|
+
super
|
|
315
|
+
@s1, @s2 = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
316
|
+
@conn = UM::Connection.new(@machine, @s1)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def teardown
|
|
320
|
+
@conn = nil
|
|
321
|
+
machine.close(@s1) rescue nil
|
|
322
|
+
machine.close(@s2) rescue nil
|
|
323
|
+
super
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def test_connection_write_single_buf
|
|
327
|
+
assert_equal 3, conn.write('foo')
|
|
328
|
+
|
|
329
|
+
buf = +''
|
|
330
|
+
machine.read(@s2, buf, 100)
|
|
331
|
+
assert_equal 'foo', buf
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def test_connection_write_multi_buf
|
|
335
|
+
assert_equal 6, conn.write('foo', 'bar')
|
|
336
|
+
|
|
337
|
+
buf = +''
|
|
338
|
+
machine.read(@s2, buf, 100)
|
|
339
|
+
assert_equal 'foobar', buf
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def test_connection_write_socket_mode
|
|
343
|
+
conn = machine.connection(@s2, :socket)
|
|
344
|
+
|
|
345
|
+
assert_equal 6, conn.write('foo', 'bar')
|
|
346
|
+
|
|
347
|
+
buf = +''
|
|
348
|
+
machine.read(@s1, buf, 100)
|
|
349
|
+
assert_equal 'foobar', buf
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def test_connection_write_ssl_mode
|
|
353
|
+
ssl1 = OpenSSL::SSL::SSLSocket.new(IO.for_fd(@s1), Localhost::Authority.fetch.server_context)
|
|
354
|
+
ssl1.sync_close = true
|
|
355
|
+
ssl2 = OpenSSL::SSL::SSLSocket.new(IO.for_fd(@s2), OpenSSL::SSL::SSLContext.new)
|
|
356
|
+
ssl2.sync_close = true
|
|
357
|
+
|
|
358
|
+
machine.ssl_set_bio(ssl1)
|
|
359
|
+
machine.ssl_set_bio(ssl2)
|
|
360
|
+
|
|
361
|
+
f = machine.spin { ssl1.accept rescue nil }
|
|
362
|
+
|
|
363
|
+
ssl2.connect
|
|
364
|
+
refute_equal 0, @machine.metrics[:total_ops]
|
|
365
|
+
|
|
366
|
+
conn1 = machine.connection(ssl1)
|
|
367
|
+
conn2 = machine.connection(ssl2)
|
|
368
|
+
|
|
369
|
+
assert_equal 10, conn1.write('foobar', "\n", 'baz')
|
|
370
|
+
|
|
371
|
+
assert_equal "foobar\nbaz", conn2.read(10)
|
|
372
|
+
ensure
|
|
373
|
+
ssl1.close rescue nil
|
|
374
|
+
ss2.close rescue nil
|
|
375
|
+
if f
|
|
376
|
+
machine.terminate(f)
|
|
377
|
+
machine.join(f)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
class ConnectionRespTest < ConnectionBaseTest
|
|
383
|
+
def test_connection_resp_read
|
|
291
384
|
machine.write(@wfd, "+foo bar\r\n")
|
|
292
|
-
assert_equal "foo bar",
|
|
385
|
+
assert_equal "foo bar", conn.resp_read
|
|
293
386
|
|
|
294
387
|
machine.write(@wfd, "+baz\r\n")
|
|
295
|
-
assert_equal "baz",
|
|
388
|
+
assert_equal "baz", conn.resp_read
|
|
296
389
|
|
|
297
390
|
machine.write(@wfd, "-foobar\r\n")
|
|
298
|
-
o =
|
|
299
|
-
assert_kind_of UM::
|
|
391
|
+
o = conn.resp_read
|
|
392
|
+
assert_kind_of UM::Connection::RESPError, o
|
|
300
393
|
assert_equal "foobar", o.message
|
|
301
394
|
|
|
302
395
|
machine.write(@wfd, "!3\r\nbaz\r\n")
|
|
303
|
-
o =
|
|
304
|
-
assert_kind_of UM::
|
|
396
|
+
o = conn.resp_read
|
|
397
|
+
assert_kind_of UM::Connection::RESPError, o
|
|
305
398
|
assert_equal "baz", o.message
|
|
306
399
|
|
|
307
400
|
machine.write(@wfd, ":123\r\n")
|
|
308
|
-
assert_equal 123,
|
|
401
|
+
assert_equal 123, conn.resp_read
|
|
309
402
|
|
|
310
403
|
machine.write(@wfd, ":-123\r\n")
|
|
311
|
-
assert_equal(-123,
|
|
404
|
+
assert_equal(-123, conn.resp_read)
|
|
312
405
|
|
|
313
406
|
machine.write(@wfd, ",123.321\r\n")
|
|
314
|
-
assert_equal 123.321,
|
|
407
|
+
assert_equal 123.321, conn.resp_read
|
|
315
408
|
|
|
316
409
|
machine.write(@wfd, "_\r\n")
|
|
317
|
-
assert_nil
|
|
410
|
+
assert_nil conn.resp_read
|
|
318
411
|
|
|
319
412
|
machine.write(@wfd, "#t\r\n")
|
|
320
|
-
assert_equal true,
|
|
413
|
+
assert_equal true, conn.resp_read
|
|
321
414
|
|
|
322
415
|
machine.write(@wfd, "#f\r\n")
|
|
323
|
-
assert_equal false,
|
|
416
|
+
assert_equal false, conn.resp_read
|
|
324
417
|
|
|
325
418
|
machine.write(@wfd, "$6\r\nfoobar\r\n")
|
|
326
|
-
assert_equal "foobar",
|
|
419
|
+
assert_equal "foobar", conn.resp_read
|
|
327
420
|
|
|
328
421
|
machine.write(@wfd, "$3\r\nbaz\r\n")
|
|
329
|
-
assert_equal "baz",
|
|
422
|
+
assert_equal "baz", conn.resp_read
|
|
330
423
|
|
|
331
424
|
machine.write(@wfd, "=10\r\ntxt:foobar\r\n")
|
|
332
|
-
assert_equal "foobar",
|
|
425
|
+
assert_equal "foobar", conn.resp_read
|
|
333
426
|
|
|
334
427
|
machine.write(@wfd, "*3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
|
|
335
|
-
assert_equal ['foo', 42, 'bar'],
|
|
428
|
+
assert_equal ['foo', 42, 'bar'], conn.resp_read
|
|
336
429
|
|
|
337
430
|
machine.write(@wfd, "~3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
|
|
338
|
-
assert_equal ['foo', 42, 'bar'],
|
|
431
|
+
assert_equal ['foo', 42, 'bar'], conn.resp_read
|
|
339
432
|
|
|
340
433
|
machine.write(@wfd, ">3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
|
|
341
|
-
assert_equal ['foo', 42, 'bar'],
|
|
434
|
+
assert_equal ['foo', 42, 'bar'], conn.resp_read
|
|
342
435
|
|
|
343
436
|
machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n:43\r\n")
|
|
344
|
-
assert_equal({ 'a' => 42, 'b' => 43 },
|
|
437
|
+
assert_equal({ 'a' => 42, 'b' => 43 }, conn.resp_read)
|
|
345
438
|
|
|
346
439
|
machine.write(@wfd, "|2\r\n+a\r\n:42\r\n+b\r\n:43\r\n")
|
|
347
|
-
assert_equal({ 'a' => 42, 'b' => 43 },
|
|
440
|
+
assert_equal({ 'a' => 42, 'b' => 43 }, conn.resp_read)
|
|
348
441
|
|
|
349
442
|
machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n*3\r\n+foo\r\n+bar\r\n+baz\r\n")
|
|
350
|
-
assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] },
|
|
443
|
+
assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] }, conn.resp_read)
|
|
351
444
|
end
|
|
352
445
|
|
|
353
|
-
def
|
|
446
|
+
def test_connection_resp_read_segmented
|
|
354
447
|
machine.write(@wfd, "\n")
|
|
355
|
-
assert_equal "",
|
|
448
|
+
assert_equal "", conn.read_line(0)
|
|
356
449
|
|
|
357
450
|
machine.write(@wfd, "+foo")
|
|
358
451
|
machine.write(@wfd, " ")
|
|
359
452
|
machine.write(@wfd, "bar\r")
|
|
360
453
|
machine.write(@wfd, "\n")
|
|
361
|
-
assert_equal "foo bar",
|
|
454
|
+
assert_equal "foo bar", conn.resp_read
|
|
362
455
|
machine.write(@wfd, "$6\r")
|
|
363
456
|
machine.write(@wfd, "\nbazbug")
|
|
364
457
|
machine.write(@wfd, "\r\n")
|
|
365
|
-
assert_equal "bazbug",
|
|
458
|
+
assert_equal "bazbug", conn.resp_read
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
def test_connection_resp_write
|
|
462
|
+
writer = machine.connection(@wfd)
|
|
463
|
+
|
|
464
|
+
writer.resp_write(nil);
|
|
465
|
+
assert_equal "_\r\n", conn.read(-100)
|
|
466
|
+
|
|
467
|
+
writer.resp_write(true);
|
|
468
|
+
assert_equal "#t\r\n", conn.read(-100)
|
|
469
|
+
|
|
470
|
+
writer.resp_write(false);
|
|
471
|
+
assert_equal "#f\r\n", conn.read(-100)
|
|
472
|
+
|
|
473
|
+
writer.resp_write(42);
|
|
474
|
+
assert_equal ":42\r\n", conn.read(-100)
|
|
475
|
+
|
|
476
|
+
writer.resp_write(42.1)
|
|
477
|
+
assert_equal ",42.1\r\n", conn.read(-100)
|
|
478
|
+
|
|
479
|
+
writer.resp_write('foobar')
|
|
480
|
+
assert_equal "$6\r\nfoobar\r\n", conn.read(-100)
|
|
481
|
+
|
|
482
|
+
writer.resp_write('פובאר')
|
|
483
|
+
assert_equal (+"$10\r\nפובאר\r\n").force_encoding('ASCII-8BIT'), conn.read(-100)
|
|
484
|
+
|
|
485
|
+
writer.resp_write(['foo', 'bar'])
|
|
486
|
+
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n", conn.read(-100)
|
|
487
|
+
|
|
488
|
+
writer.resp_write({ 'foo' => 'bar', 'baz' => 42 })
|
|
489
|
+
assert_equal "%2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nbaz\r\n:42\r\n", conn.read(-100)
|
|
366
490
|
end
|
|
367
491
|
|
|
368
|
-
def
|
|
369
|
-
s = UM::
|
|
492
|
+
def test_connection_resp_encode
|
|
493
|
+
s = UM::Connection
|
|
370
494
|
assert_equal "_\r\n", s.resp_encode(+'', nil)
|
|
371
495
|
assert_equal "#t\r\n", s.resp_encode(+'', true)
|
|
372
496
|
assert_equal "#f\r\n", s.resp_encode(+'', false)
|
|
@@ -383,7 +507,7 @@ class StreamRespTest < StreamBaseTest
|
|
|
383
507
|
end
|
|
384
508
|
end
|
|
385
509
|
|
|
386
|
-
class
|
|
510
|
+
class ConnectionStressTest < UMBaseTest
|
|
387
511
|
def setup
|
|
388
512
|
super
|
|
389
513
|
|
|
@@ -401,8 +525,8 @@ class StreamStressTest < UMBaseTest
|
|
|
401
525
|
|
|
402
526
|
def start_connection_fiber(fd)
|
|
403
527
|
machine.spin do
|
|
404
|
-
|
|
405
|
-
while (msg =
|
|
528
|
+
conn = UM::Connection.new(machine, fd)
|
|
529
|
+
while (msg = conn.read_line(0))
|
|
406
530
|
@received << msg
|
|
407
531
|
end
|
|
408
532
|
machine.sendv(fd, @response_headers, @response_body)
|
|
@@ -413,7 +537,7 @@ class StreamStressTest < UMBaseTest
|
|
|
413
537
|
end
|
|
414
538
|
end
|
|
415
539
|
|
|
416
|
-
def
|
|
540
|
+
def test_connection_server_big_lines
|
|
417
541
|
server_fibers = []
|
|
418
542
|
server_fibers << machine.spin do
|
|
419
543
|
machine.accept_each(@listen_fd) { |fd|
|
|
@@ -456,7 +580,7 @@ class StreamStressTest < UMBaseTest
|
|
|
456
580
|
assert_equal msg * client_count, @received.map { it + "\n" }.join
|
|
457
581
|
end
|
|
458
582
|
|
|
459
|
-
def
|
|
583
|
+
def test_connection_server_http
|
|
460
584
|
server_fibers = []
|
|
461
585
|
server_fibers << machine.spin do
|
|
462
586
|
machine.accept_each(@listen_fd) { |fd|
|
|
@@ -496,50 +620,50 @@ class StreamStressTest < UMBaseTest
|
|
|
496
620
|
end
|
|
497
621
|
end
|
|
498
622
|
|
|
499
|
-
class
|
|
500
|
-
def
|
|
623
|
+
class ConnectionDevRandomTest < UMBaseTest
|
|
624
|
+
def test_connection_dev_random_read_line
|
|
501
625
|
fd = machine.open('/dev/random', UM::O_RDONLY)
|
|
502
|
-
|
|
626
|
+
conn = UM::Connection.new(machine, fd)
|
|
503
627
|
|
|
504
628
|
n = 100000
|
|
505
629
|
lines = []
|
|
506
630
|
n.times {
|
|
507
|
-
lines <<
|
|
631
|
+
lines << conn.read_line(0)
|
|
508
632
|
}
|
|
509
633
|
|
|
510
634
|
assert_equal n, lines.size
|
|
511
635
|
ensure
|
|
512
|
-
|
|
636
|
+
conn.clear rescue nil
|
|
513
637
|
machine.close(fd) rescue nil
|
|
514
638
|
end
|
|
515
639
|
|
|
516
|
-
def
|
|
640
|
+
def read_line_do(n, acc)
|
|
517
641
|
fd = @machine.open('/dev/random', UM::O_RDONLY)
|
|
518
|
-
|
|
519
|
-
n.times { acc <<
|
|
642
|
+
conn = UM::Connection.new(@machine, fd)
|
|
643
|
+
n.times { acc << conn.read_line(0) }
|
|
520
644
|
end
|
|
521
645
|
|
|
522
|
-
def
|
|
646
|
+
def test_connection_dev_random_read_line_concurrent
|
|
523
647
|
acc = []
|
|
524
648
|
c = 1
|
|
525
649
|
n = 100000
|
|
526
650
|
ff = c.times.map {
|
|
527
|
-
machine.spin {
|
|
651
|
+
machine.spin { read_line_do(n, acc) }
|
|
528
652
|
}
|
|
529
653
|
machine.await(ff)
|
|
530
654
|
assert_equal c * n, acc.size
|
|
531
655
|
end
|
|
532
656
|
|
|
533
|
-
def
|
|
657
|
+
def test_connection_dev_random_read
|
|
534
658
|
fd = machine.open('/dev/random', UM::O_RDONLY)
|
|
535
|
-
|
|
659
|
+
conn = UM::Connection.new(machine, fd)
|
|
536
660
|
|
|
537
661
|
n = 256
|
|
538
662
|
size = 65536 * 8
|
|
539
663
|
count = 0
|
|
540
664
|
# lines = []
|
|
541
665
|
n.times {
|
|
542
|
-
l =
|
|
666
|
+
l = conn.read(size)
|
|
543
667
|
refute_nil l
|
|
544
668
|
assert_equal size, l.bytesize
|
|
545
669
|
|
|
@@ -548,49 +672,62 @@ class StreamDevRandomTest < UMBaseTest
|
|
|
548
672
|
|
|
549
673
|
assert_equal n, count
|
|
550
674
|
ensure
|
|
551
|
-
|
|
675
|
+
conn.clear rescue nil
|
|
552
676
|
end
|
|
553
677
|
end
|
|
554
678
|
|
|
555
|
-
class
|
|
556
|
-
def
|
|
679
|
+
class ConnectionModeTest < UMBaseTest
|
|
680
|
+
def test_connection_default_mode
|
|
557
681
|
r, w = UM.pipe
|
|
558
|
-
|
|
559
|
-
assert_equal :
|
|
682
|
+
conn = UM::Connection.new(machine, r)
|
|
683
|
+
assert_equal :fd, conn.mode
|
|
560
684
|
ensure
|
|
561
685
|
machine.close(r) rescue nil
|
|
562
686
|
machine.close(w) rescue nil
|
|
563
687
|
end
|
|
564
688
|
|
|
565
|
-
def
|
|
689
|
+
def test_connection_default_mode_ssl
|
|
690
|
+
authority = Localhost::Authority.fetch
|
|
691
|
+
@server_ctx = authority.server_context
|
|
692
|
+
sock1, sock2 = UNIXSocket.pair
|
|
693
|
+
|
|
694
|
+
s1 = OpenSSL::SSL::SSLSocket.new(sock1, @server_ctx)
|
|
695
|
+
conn = UM::Connection.new(machine, s1)
|
|
696
|
+
assert_equal :ssl, conn.mode
|
|
697
|
+
ensure
|
|
698
|
+
sock1&.close rescue nil
|
|
699
|
+
sock2&.close rescue nil
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def test_connection_socket_mode_non_socket
|
|
566
703
|
r, w = UM.pipe
|
|
567
704
|
machine.write(w, 'foobar')
|
|
568
705
|
machine.close(w)
|
|
569
706
|
|
|
570
|
-
|
|
571
|
-
assert_equal :
|
|
572
|
-
# assert :
|
|
573
|
-
assert_raises(Errno::ENOTSOCK) {
|
|
707
|
+
conn = UM::Connection.new(machine, r, :socket)
|
|
708
|
+
assert_equal :socket, conn.mode
|
|
709
|
+
# assert :socket, conn.mode
|
|
710
|
+
assert_raises(Errno::ENOTSOCK) { conn.read(0) }
|
|
574
711
|
ensure
|
|
575
712
|
machine.close(r) rescue nil
|
|
576
713
|
machine.close(w) rescue nil
|
|
577
714
|
end
|
|
578
715
|
|
|
579
|
-
def
|
|
716
|
+
def test_connection_socket_mode_socket
|
|
580
717
|
r, w = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
581
718
|
machine.write(w, 'foobar')
|
|
582
719
|
machine.close(w)
|
|
583
720
|
|
|
584
|
-
|
|
585
|
-
assert_equal :
|
|
586
|
-
buf =
|
|
721
|
+
conn = UM::Connection.new(machine, r, :socket)
|
|
722
|
+
assert_equal :socket, conn.mode
|
|
723
|
+
buf = conn.read(0)
|
|
587
724
|
assert_equal 'foobar', buf
|
|
588
725
|
ensure
|
|
589
726
|
machine.close(r) rescue nil
|
|
590
727
|
machine.close(w) rescue nil
|
|
591
728
|
end
|
|
592
729
|
|
|
593
|
-
def
|
|
730
|
+
def test_connection_ssl_mode
|
|
594
731
|
authority = Localhost::Authority.fetch
|
|
595
732
|
@server_ctx = authority.server_context
|
|
596
733
|
sock1, sock2 = UNIXSocket.pair
|
|
@@ -614,18 +751,18 @@ class StreamModeTest < UMBaseTest
|
|
|
614
751
|
assert_equal 10, @machine.ssl_write(s1, buf, buf.bytesize)
|
|
615
752
|
buf = +''
|
|
616
753
|
|
|
617
|
-
|
|
618
|
-
assert_equal "foobar",
|
|
754
|
+
conn = UM::Connection.new(machine, s2, :ssl)
|
|
755
|
+
assert_equal "foobar", conn.read_line(0)
|
|
619
756
|
|
|
620
757
|
buf = "buh"
|
|
621
758
|
@machine.ssl_write(s1, buf, buf.bytesize)
|
|
622
759
|
|
|
623
|
-
assert_equal "baz",
|
|
624
|
-
assert_equal "buh",
|
|
760
|
+
assert_equal "baz", conn.read(0)
|
|
761
|
+
assert_equal "buh", conn.read(0)
|
|
625
762
|
|
|
626
763
|
s1.close
|
|
627
764
|
|
|
628
|
-
assert_nil
|
|
765
|
+
assert_nil conn.read(0)
|
|
629
766
|
rescue => e
|
|
630
767
|
p e
|
|
631
768
|
p e.backtrace
|
|
@@ -637,35 +774,35 @@ class StreamModeTest < UMBaseTest
|
|
|
637
774
|
end
|
|
638
775
|
end
|
|
639
776
|
|
|
640
|
-
class
|
|
641
|
-
def
|
|
777
|
+
class ConnectionByteCountsTest < ConnectionBaseTest
|
|
778
|
+
def test_connection_byte_counts
|
|
642
779
|
machine.write(@wfd, "foobar")
|
|
643
780
|
|
|
644
|
-
assert_equal 0,
|
|
645
|
-
assert_equal 0,
|
|
781
|
+
assert_equal 0, conn.consumed
|
|
782
|
+
assert_equal 0, conn.pending
|
|
646
783
|
|
|
647
|
-
buf =
|
|
784
|
+
buf = conn.read(2)
|
|
648
785
|
assert_equal 'fo', buf
|
|
649
|
-
assert_equal 2,
|
|
650
|
-
assert_equal 4,
|
|
786
|
+
assert_equal 2, conn.consumed
|
|
787
|
+
assert_equal 4, conn.pending
|
|
651
788
|
|
|
652
|
-
buf =
|
|
789
|
+
buf = conn.read(3)
|
|
653
790
|
assert_equal 'oba', buf
|
|
654
|
-
assert_equal 5,
|
|
655
|
-
assert_equal 1,
|
|
791
|
+
assert_equal 5, conn.consumed
|
|
792
|
+
assert_equal 1, conn.pending
|
|
656
793
|
|
|
657
794
|
machine.write(@wfd, "abc\ndef")
|
|
658
795
|
machine.snooze
|
|
659
|
-
assert_equal 5,
|
|
660
|
-
assert_equal 1,
|
|
796
|
+
assert_equal 5, conn.consumed
|
|
797
|
+
assert_equal 1, conn.pending
|
|
661
798
|
|
|
662
|
-
buf =
|
|
799
|
+
buf = conn.read_line(0)
|
|
663
800
|
assert_equal 'rabc', buf
|
|
664
|
-
assert_equal 10,
|
|
665
|
-
assert_equal 3,
|
|
801
|
+
assert_equal 10, conn.consumed
|
|
802
|
+
assert_equal 3, conn.pending
|
|
666
803
|
|
|
667
|
-
|
|
668
|
-
assert_equal 10,
|
|
669
|
-
assert_equal 0,
|
|
804
|
+
conn.clear
|
|
805
|
+
assert_equal 10, conn.consumed
|
|
806
|
+
assert_equal 0, conn.pending
|
|
670
807
|
end
|
|
671
808
|
end
|