uringmachine 0.29.2 → 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 +18 -4
- data/README.md +46 -38
- data/TODO.md +68 -75
- data/benchmark/bm_io_ssl.rb +128 -0
- data/benchmark/bm_redis_client.rb +76 -0
- data/benchmark/common.rb +1 -0
- data/benchmark/gets.rb +7 -7
- data/benchmark/gets_concurrent.rb +10 -10
- data/benchmark/http_parse.rb +15 -15
- 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 +71 -3
- data/ext/um/um.h +34 -22
- data/ext/um/um_buffer_pool.c +11 -11
- data/ext/um/um_class.c +57 -0
- data/ext/um/um_connection.c +775 -0
- data/ext/um/um_connection_class.c +394 -0
- data/ext/um/um_ssl.c +43 -7
- data/ext/um/um_utils.c +1 -1
- data/grant-2025/final-report.md +269 -0
- data/grant-2025/journal.md +1 -1
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +47 -6
- data/test/{test_stream.rb → test_connection.rb} +321 -151
- data/test/test_ssl.rb +27 -0
- data/test/test_um.rb +174 -17
- metadata +13 -6
- data/ext/um/um_stream.c +0 -674
- data/ext/um/um_stream_class.c +0 -303
data/ext/um/um.h
CHANGED
|
@@ -48,6 +48,9 @@ enum um_op_kind {
|
|
|
48
48
|
OP_CLOSE,
|
|
49
49
|
OP_CLOSE_ASYNC,
|
|
50
50
|
OP_STATX,
|
|
51
|
+
OP_SPLICE,
|
|
52
|
+
OP_TEE,
|
|
53
|
+
OP_FSYNC,
|
|
51
54
|
|
|
52
55
|
OP_ACCEPT,
|
|
53
56
|
OP_RECV,
|
|
@@ -77,12 +80,12 @@ enum um_op_kind {
|
|
|
77
80
|
OP_TIMEOUT_MULTISHOT,
|
|
78
81
|
};
|
|
79
82
|
|
|
80
|
-
enum
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
enum um_connection_mode {
|
|
84
|
+
CONNECTION_FD,
|
|
85
|
+
CONNECTION_SOCKET,
|
|
86
|
+
CONNECTION_SSL,
|
|
87
|
+
CONNECTION_STRING,
|
|
88
|
+
CONNECTION_IO_BUFFER
|
|
86
89
|
};
|
|
87
90
|
|
|
88
91
|
#define OP_F_CQE_SEEN (1U << 0) // CQE has been seen
|
|
@@ -161,7 +164,7 @@ struct um_op {
|
|
|
161
164
|
struct iovec *iovecs; // used for vectorized write/send
|
|
162
165
|
siginfo_t siginfo; // used for waitid
|
|
163
166
|
int int_value; // used for getsockopt
|
|
164
|
-
size_t bp_commit_level; // buffer pool commit
|
|
167
|
+
size_t bp_commit_level; // buffer pool commit level
|
|
165
168
|
};
|
|
166
169
|
};
|
|
167
170
|
|
|
@@ -269,11 +272,11 @@ struct um_async_op {
|
|
|
269
272
|
struct um_op *op;
|
|
270
273
|
};
|
|
271
274
|
|
|
272
|
-
struct
|
|
275
|
+
struct um_connection {
|
|
273
276
|
VALUE self;
|
|
274
277
|
struct um *machine;
|
|
275
278
|
|
|
276
|
-
enum
|
|
279
|
+
enum um_connection_mode mode;
|
|
277
280
|
union {
|
|
278
281
|
int fd;
|
|
279
282
|
VALUE target;
|
|
@@ -301,7 +304,7 @@ extern VALUE eUMError;
|
|
|
301
304
|
extern VALUE cMutex;
|
|
302
305
|
extern VALUE cQueue;
|
|
303
306
|
extern VALUE cAsyncOp;
|
|
304
|
-
extern VALUE
|
|
307
|
+
extern VALUE eConnectionRESPError;
|
|
305
308
|
|
|
306
309
|
struct um *um_get_machine(VALUE self);
|
|
307
310
|
void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec, int sidecar_mode);
|
|
@@ -325,7 +328,6 @@ void um_op_list_compact(struct um *machine, struct um_op *head);
|
|
|
325
328
|
void um_op_multishot_results_push(struct um *machine, struct um_op *op, __s32 res, __u32 flags);
|
|
326
329
|
void um_op_multishot_results_clear(struct um *machine, struct um_op *op);
|
|
327
330
|
|
|
328
|
-
struct um_segment *um_segment_alloc(struct um *machine);
|
|
329
331
|
void um_segment_free(struct um *machine, struct um_segment *segment);
|
|
330
332
|
|
|
331
333
|
void um_runqueue_push(struct um *machine, struct um_op *op);
|
|
@@ -350,7 +352,7 @@ int um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *siz
|
|
|
350
352
|
void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
|
|
351
353
|
void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 result);
|
|
352
354
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
|
353
|
-
VALUE
|
|
355
|
+
VALUE um_read_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
354
356
|
void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
|
|
355
357
|
struct iovec *um_alloc_iovecs_for_writing(int argc, VALUE *argv, size_t *total_len);
|
|
356
358
|
void um_advance_iovecs_for_writing(struct iovec **ptr, int *len, size_t adv);
|
|
@@ -376,7 +378,7 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t b
|
|
|
376
378
|
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
|
|
377
379
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
|
378
380
|
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
379
|
-
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t
|
|
381
|
+
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t len);
|
|
380
382
|
VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv);
|
|
381
383
|
VALUE um_write_async(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
382
384
|
VALUE um_close(struct um *machine, int fd);
|
|
@@ -391,6 +393,9 @@ VALUE um_waitid_status(struct um *machine, int idtype, int id, int options);
|
|
|
391
393
|
#endif
|
|
392
394
|
|
|
393
395
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask);
|
|
396
|
+
VALUE um_splice(struct um *machine, int in_fd, int out_fd, uint nbytes);
|
|
397
|
+
VALUE um_tee(struct um *machine, int in_fd, int out_fd, uint nbytes);
|
|
398
|
+
VALUE um_fsync(struct um *machine, int fd);
|
|
394
399
|
|
|
395
400
|
VALUE um_accept(struct um *machine, int fd);
|
|
396
401
|
VALUE um_accept_each(struct um *machine, int fd);
|
|
@@ -398,6 +403,7 @@ VALUE um_accept_into_queue(struct um *machine, int fd, VALUE queue);
|
|
|
398
403
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags);
|
|
399
404
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
|
|
400
405
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags);
|
|
406
|
+
size_t um_send_raw(struct um *machine, int fd, const char *buffer, size_t len, int flags);
|
|
401
407
|
VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv);
|
|
402
408
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings);
|
|
403
409
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags);
|
|
@@ -432,12 +438,16 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
|
|
432
438
|
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
|
433
439
|
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
|
434
440
|
|
|
435
|
-
void
|
|
436
|
-
void
|
|
437
|
-
VALUE
|
|
438
|
-
VALUE
|
|
439
|
-
|
|
440
|
-
|
|
441
|
+
void connection_teardown(struct um_connection *conn);
|
|
442
|
+
void connection_clear(struct um_connection *conn);
|
|
443
|
+
VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t maxlen);
|
|
444
|
+
VALUE connection_read(struct um_connection *conn, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc);
|
|
445
|
+
VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VALUE delim, ssize_t maxlen);
|
|
446
|
+
void connection_skip(struct um_connection *conn, size_t inc, int safe_inc);
|
|
447
|
+
void connection_read_each(struct um_connection *conn);
|
|
448
|
+
size_t connection_write_raw(struct um_connection *conn, const char *buffer, size_t len);
|
|
449
|
+
VALUE connection_writev(struct um_connection *conn, int argc, VALUE *argv);
|
|
450
|
+
VALUE resp_read(struct um_connection *conn, VALUE out_buffer);
|
|
441
451
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
442
452
|
void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
|
|
443
453
|
|
|
@@ -454,9 +464,11 @@ void um_sidecar_signal_wait(struct um *machine);
|
|
|
454
464
|
void um_sidecar_signal_wake(struct um *machine);
|
|
455
465
|
|
|
456
466
|
void um_ssl_set_bio(struct um *machine, VALUE ssl_obj);
|
|
457
|
-
int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf,
|
|
458
|
-
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr,
|
|
459
|
-
int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf,
|
|
467
|
+
int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf, size_t maxlen);
|
|
468
|
+
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr, size_t maxlen);
|
|
469
|
+
int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf, size_t len);
|
|
470
|
+
int um_ssl_write_raw(struct um *machine, VALUE ssl, const char *buffer, size_t len);
|
|
471
|
+
int um_ssl_writev(struct um *machine, VALUE ssl, int argc, VALUE *argv);
|
|
460
472
|
|
|
461
473
|
void bp_setup(struct um *machine);
|
|
462
474
|
void bp_teardown(struct um *machine);
|
data/ext/um/um_buffer_pool.c
CHANGED
|
@@ -18,7 +18,7 @@ inline struct um_buffer *buffer_alloc(struct um *machine) {
|
|
|
18
18
|
return buffer;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
struct um_buffer *bp_buffer_checkout(struct um *machine) {
|
|
22
22
|
struct um_buffer *buffer = machine->bp_buffer_freelist;
|
|
23
23
|
if (buffer) {
|
|
24
24
|
struct um_buffer *next = buffer->next;
|
|
@@ -50,13 +50,13 @@ inline void buffer_free(struct um *machine, struct um_buffer *buffer) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
void bp_buffer_checkin(struct um *machine, struct um_buffer *buffer) {
|
|
54
54
|
assert(buffer->ref_count > 0);
|
|
55
55
|
buffer->ref_count--;
|
|
56
56
|
if (!buffer->ref_count) buffer_free(machine, buffer);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
void bp_discard_buffer_freelist(struct um *machine) {
|
|
60
60
|
while (machine->bp_buffer_freelist) {
|
|
61
61
|
struct um_buffer *buffer = machine->bp_buffer_freelist;
|
|
62
62
|
struct um_buffer *next = buffer->next;
|
|
@@ -69,7 +69,7 @@ inline void bp_discard_buffer_freelist(struct um *machine) {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
void bp_setup(struct um *machine) {
|
|
73
73
|
int ret;
|
|
74
74
|
machine->bp_br = io_uring_setup_buf_ring(&machine->ring, BP_BR_ENTRIES, BP_BGID, IOU_PBUF_RING_INC, &ret);
|
|
75
75
|
if (unlikely(!machine->bp_br)) rb_syserr_fail(ret, strerror(ret));
|
|
@@ -85,7 +85,7 @@ inline void bp_setup(struct um *machine) {
|
|
|
85
85
|
machine->bp_total_commited = 0;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
void bp_teardown(struct um *machine) {
|
|
89
89
|
bp_discard_buffer_freelist(machine);
|
|
90
90
|
for (int i = 0; i < BP_BR_ENTRIES; i++) {
|
|
91
91
|
struct um_buffer *buffer = machine->bp_commited_buffers[i];
|
|
@@ -162,7 +162,7 @@ inline int should_commit_more_p(struct um *machine) {
|
|
|
162
162
|
(machine->bp_total_commited < machine->bp_commit_level);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
void bp_ensure_commit_level(struct um *machine) {
|
|
166
166
|
if (machine->bp_total_commited > (machine->bp_commit_level / 2))
|
|
167
167
|
return;
|
|
168
168
|
|
|
@@ -179,7 +179,7 @@ inline void bp_ensure_commit_level(struct um *machine) {
|
|
|
179
179
|
// size.
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
void bp_handle_enobufs(struct um *machine) {
|
|
183
183
|
if (unlikely(machine->bp_commit_level >= BP_MAX_COMMIT_LEVEL))
|
|
184
184
|
rb_raise(eUMError, "Buffer starvation");
|
|
185
185
|
|
|
@@ -189,7 +189,7 @@ inline void bp_handle_enobufs(struct um *machine) {
|
|
|
189
189
|
bp_discard_buffer_freelist(machine);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
inline struct um_segment *
|
|
192
|
+
inline struct um_segment *segment_alloc(struct um *machine) {
|
|
193
193
|
if (machine->segment_freelist) {
|
|
194
194
|
struct um_segment *segment = machine->segment_freelist;
|
|
195
195
|
machine->segment_freelist = segment->next;
|
|
@@ -208,14 +208,14 @@ inline struct um_segment *um_segment_alloc(struct um *machine) {
|
|
|
208
208
|
return batch;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
void um_segment_free(struct um *machine, struct um_segment *segment) {
|
|
212
212
|
segment->next = machine->segment_freelist;
|
|
213
213
|
machine->segment_freelist = segment;
|
|
214
214
|
machine->metrics.segments_free++;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
struct um_segment *segment =
|
|
217
|
+
struct um_segment *bp_buffer_consume(struct um *machine, struct um_buffer *buffer, size_t len) {
|
|
218
|
+
struct um_segment *segment = segment_alloc(machine);
|
|
219
219
|
segment->ptr = buffer->buf + buffer->pos;
|
|
220
220
|
segment->len = len;
|
|
221
221
|
segment->buffer = buffer;
|
data/ext/um/um_class.c
CHANGED
|
@@ -534,6 +534,60 @@ VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
|
|
|
534
534
|
return um_statx(machine, NUM2INT(dirfd), path, NUM2INT(flags), NUM2UINT(mask));
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
+
/* call-seq:
|
|
538
|
+
* machine.splice(in_fd, out_fd, nbytes) -> len
|
|
539
|
+
*
|
|
540
|
+
* Splices bytes from in_fd to out_fd. At least one of the given fds must be a
|
|
541
|
+
* pipe.
|
|
542
|
+
*
|
|
543
|
+
* - https://www.man7.org/linux/man-pages/man2/splice.2.html
|
|
544
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_splice.3.html
|
|
545
|
+
*
|
|
546
|
+
* @param in_fd [Integer] fd to splice from
|
|
547
|
+
* @param out_fd [Integer] fd to splice to
|
|
548
|
+
* @param nbytes [Integer] number of bytes to splice
|
|
549
|
+
* @return [Integer] number of bytes spliced
|
|
550
|
+
*/
|
|
551
|
+
VALUE UM_splice(VALUE self, VALUE in_fd, VALUE out_fd, VALUE nbytes) {
|
|
552
|
+
struct um *machine = um_get_machine(self);
|
|
553
|
+
return um_splice(machine, NUM2INT(in_fd), NUM2INT(out_fd), NUM2UINT(nbytes));
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/* call-seq:
|
|
557
|
+
* machine.tee(in_fd, out_fd, nbytes) -> len
|
|
558
|
+
*
|
|
559
|
+
* Duplicates bytes from in_fd to out_fd. At least one of the given fds must be
|
|
560
|
+
* a pipe.
|
|
561
|
+
*
|
|
562
|
+
* - https://www.man7.org/linux/man-pages/man2/tee.2.html
|
|
563
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_tee.3.html
|
|
564
|
+
*
|
|
565
|
+
* @param in_fd [Integer] fd to copy from
|
|
566
|
+
* @param out_fd [Integer] fd to copy to
|
|
567
|
+
* @param nbytes [Integer] number of bytes to duplicate
|
|
568
|
+
* @return [Integer] number of bytes duplicated
|
|
569
|
+
*/
|
|
570
|
+
VALUE UM_tee(VALUE self, VALUE in_fd, VALUE out_fd, VALUE nbytes) {
|
|
571
|
+
struct um *machine = um_get_machine(self);
|
|
572
|
+
return um_tee(machine, NUM2INT(in_fd), NUM2INT(out_fd), NUM2UINT(nbytes));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* call-seq:
|
|
576
|
+
* machine.fsync(fd) -> 0
|
|
577
|
+
*
|
|
578
|
+
* Flushes all modified file data to the storage device.
|
|
579
|
+
*
|
|
580
|
+
* - https://www.man7.org/linux/man-pages/man2/fsync.2.html
|
|
581
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_fsync.3.html
|
|
582
|
+
*
|
|
583
|
+
* @param fd [Integer] fd
|
|
584
|
+
* @return [Integer] 0 if successful
|
|
585
|
+
*/
|
|
586
|
+
VALUE UM_fsync(VALUE self, VALUE fd) {
|
|
587
|
+
struct um *machine = um_get_machine(self);
|
|
588
|
+
return um_fsync(machine, NUM2INT(fd));
|
|
589
|
+
}
|
|
590
|
+
|
|
537
591
|
/* call-seq:
|
|
538
592
|
* machine.close(fd) -> 0
|
|
539
593
|
*
|
|
@@ -1480,6 +1534,9 @@ void Init_UM(void) {
|
|
|
1480
1534
|
rb_define_method(cUM, "writev", UM_writev, -1);
|
|
1481
1535
|
rb_define_method(cUM, "write_async", UM_write_async, -1);
|
|
1482
1536
|
rb_define_method(cUM, "statx", UM_statx, 4);
|
|
1537
|
+
rb_define_method(cUM, "splice", UM_splice, 3);
|
|
1538
|
+
rb_define_method(cUM, "tee", UM_tee, 3);
|
|
1539
|
+
rb_define_method(cUM, "fsync", UM_fsync, 1);
|
|
1483
1540
|
|
|
1484
1541
|
rb_define_method(cUM, "poll", UM_poll, 2);
|
|
1485
1542
|
rb_define_method(cUM, "select", UM_select, 3);
|