uringmachine 0.29.1 → 0.30.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 -0
- data/README.md +106 -6
- data/TODO.md +24 -86
- data/benchmark/bm_io_ssl.rb +128 -0
- data/benchmark/bm_redis_client.rb +76 -0
- data/benchmark/common.rb +1 -0
- data/benchmark/http_parse.rb +3 -3
- data/docs/design/buffer_pool.md +1 -1
- data/ext/um/um.c +51 -0
- data/ext/um/um.h +13 -6
- data/ext/um/um_buffer_pool.c +11 -11
- data/ext/um/um_class.c +57 -0
- data/ext/um/um_ssl.c +6 -5
- data/ext/um/um_stream.c +46 -9
- data/ext/um/um_stream_class.c +126 -0
- data/grant-2025/final-report.md +267 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +50 -0
- data/test/test_ssl.rb +27 -0
- data/test/test_stream.rb +76 -0
- data/test/test_um.rb +209 -0
- metadata +4 -1
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,
|
|
@@ -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
|
|
|
@@ -283,7 +286,8 @@ struct um_stream {
|
|
|
283
286
|
struct um_op *op;
|
|
284
287
|
struct um_segment *head;
|
|
285
288
|
struct um_segment *tail;
|
|
286
|
-
size_t
|
|
289
|
+
size_t consumed_bytes;
|
|
290
|
+
size_t pending_bytes;
|
|
287
291
|
size_t pos;
|
|
288
292
|
int eof;
|
|
289
293
|
};
|
|
@@ -324,7 +328,6 @@ void um_op_list_compact(struct um *machine, struct um_op *head);
|
|
|
324
328
|
void um_op_multishot_results_push(struct um *machine, struct um_op *op, __s32 res, __u32 flags);
|
|
325
329
|
void um_op_multishot_results_clear(struct um *machine, struct um_op *op);
|
|
326
330
|
|
|
327
|
-
struct um_segment *um_segment_alloc(struct um *machine);
|
|
328
331
|
void um_segment_free(struct um *machine, struct um_segment *segment);
|
|
329
332
|
|
|
330
333
|
void um_runqueue_push(struct um *machine, struct um_op *op);
|
|
@@ -390,6 +393,9 @@ VALUE um_waitid_status(struct um *machine, int idtype, int id, int options);
|
|
|
390
393
|
#endif
|
|
391
394
|
|
|
392
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);
|
|
393
399
|
|
|
394
400
|
VALUE um_accept(struct um *machine, int fd);
|
|
395
401
|
VALUE um_accept_each(struct um *machine, int fd);
|
|
@@ -436,6 +442,7 @@ void stream_clear(struct um_stream *stream);
|
|
|
436
442
|
VALUE stream_get_line(struct um_stream *stream, VALUE buf, size_t maxlen);
|
|
437
443
|
VALUE stream_get_string(struct um_stream *stream, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc);
|
|
438
444
|
void stream_skip(struct um_stream *stream, size_t inc, int safe_inc);
|
|
445
|
+
void stream_each(struct um_stream *stream);
|
|
439
446
|
VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
|
|
440
447
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
441
448
|
void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
|
|
@@ -453,9 +460,9 @@ void um_sidecar_signal_wait(struct um *machine);
|
|
|
453
460
|
void um_sidecar_signal_wake(struct um *machine);
|
|
454
461
|
|
|
455
462
|
void um_ssl_set_bio(struct um *machine, VALUE ssl_obj);
|
|
456
|
-
int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf,
|
|
457
|
-
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr,
|
|
458
|
-
int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf,
|
|
463
|
+
int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf, size_t maxlen);
|
|
464
|
+
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr, size_t maxlen);
|
|
465
|
+
int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf, size_t len);
|
|
459
466
|
|
|
460
467
|
void bp_setup(struct um *machine);
|
|
461
468
|
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);
|
data/ext/um/um_ssl.c
CHANGED
|
@@ -75,7 +75,7 @@ void um_ssl_set_bio(struct um *machine, VALUE ssl_obj)
|
|
|
75
75
|
SSL_set0_wbio(ssl, bio);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr,
|
|
78
|
+
int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr, size_t maxlen) {
|
|
79
79
|
SSL *ssl = RTYPEDDATA_GET_DATA(ssl_obj);
|
|
80
80
|
|
|
81
81
|
int ret = SSL_read(ssl, ptr, maxlen);
|
|
@@ -84,22 +84,23 @@ int um_ssl_read_raw(struct um *machine, VALUE ssl_obj, char *ptr, int maxlen) {
|
|
|
84
84
|
return ret;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
int um_ssl_read(struct um *machine, VALUE ssl_obj, VALUE buf,
|
|
87
|
+
int um_ssl_read(struct um *machine, VALUE ssl_obj, VALUE buf, size_t maxlen) {
|
|
88
88
|
void *ptr = um_prepare_read_buffer(buf, maxlen, 0);
|
|
89
89
|
int ret = um_ssl_read_raw(machine, ssl_obj, ptr, maxlen);
|
|
90
90
|
um_update_read_buffer(buf, 0, ret);
|
|
91
91
|
return ret;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
int um_ssl_write(struct um *machine, VALUE ssl_obj, VALUE buf,
|
|
94
|
+
int um_ssl_write(struct um *machine, VALUE ssl_obj, VALUE buf, size_t len) {
|
|
95
95
|
SSL *ssl = RTYPEDDATA_GET_DATA(ssl_obj);
|
|
96
96
|
const void *base;
|
|
97
97
|
size_t size;
|
|
98
98
|
um_get_buffer_bytes_for_writing(buf, &base, &size, true);
|
|
99
|
-
if (
|
|
99
|
+
if (!len || (len > size)) len = size;
|
|
100
|
+
if (len > INT_MAX) len = INT_MAX;
|
|
100
101
|
if (unlikely(!len)) return INT2NUM(0);
|
|
101
102
|
|
|
102
|
-
int ret = SSL_write(ssl, base, len);
|
|
103
|
+
int ret = SSL_write(ssl, base, (int)len);
|
|
103
104
|
if (ret <= 0) rb_raise(eUMError, "Failed to write");
|
|
104
105
|
|
|
105
106
|
return ret;
|
data/ext/um/um_stream.c
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
#include "um.h"
|
|
2
1
|
#include <stdlib.h>
|
|
2
|
+
#include <ruby/io/buffer.h>
|
|
3
|
+
#include "um.h"
|
|
3
4
|
|
|
4
5
|
inline void stream_add_segment(struct um_stream *stream, struct um_segment *segment) {
|
|
5
6
|
segment->next = NULL;
|
|
@@ -9,7 +10,7 @@ inline void stream_add_segment(struct um_stream *stream, struct um_segment *segm
|
|
|
9
10
|
}
|
|
10
11
|
else
|
|
11
12
|
stream->head = stream->tail = segment;
|
|
12
|
-
stream->
|
|
13
|
+
stream->pending_bytes += segment->len;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
inline int stream_process_op_result(struct um_stream *stream, struct um_op_result *result) {
|
|
@@ -73,7 +74,7 @@ void um_stream_cleanup(struct um_stream *stream) {
|
|
|
73
74
|
um_segment_checkin(stream->machine, stream->head);
|
|
74
75
|
stream->head = next;
|
|
75
76
|
}
|
|
76
|
-
stream->
|
|
77
|
+
stream->pending_bytes = 0;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
// returns true if case of ENOBUFS error, sets more to true if more data forthcoming
|
|
@@ -124,7 +125,7 @@ void stream_clear(struct um_stream *stream) {
|
|
|
124
125
|
um_segment_checkin(stream->machine, stream->head);
|
|
125
126
|
stream->head = next;
|
|
126
127
|
}
|
|
127
|
-
stream->
|
|
128
|
+
stream->pending_bytes = 0;
|
|
128
129
|
|
|
129
130
|
if (stream->working_buffer) {
|
|
130
131
|
bp_buffer_checkin(stream->machine, stream->working_buffer);
|
|
@@ -156,12 +157,12 @@ int stream_get_more_segments_bp(struct um_stream *stream) {
|
|
|
156
157
|
enobufs = stream_process_segments(stream, &total_bytes, &more);
|
|
157
158
|
um_op_multishot_results_clear(stream->machine, stream->op);
|
|
158
159
|
if (unlikely(enobufs)) {
|
|
159
|
-
int should_restart = stream->
|
|
160
|
+
int should_restart = stream->pending_bytes < (stream->machine->bp_buffer_size * 4);
|
|
160
161
|
// int same_threshold = stream->op->bp_commit_level == stream->machine->bp_commit_level;
|
|
161
162
|
|
|
162
163
|
// fprintf(stderr, "%p enobufs total: %ld pending: %ld threshold: %ld bc: %d (same: %d, restart: %d)\n",
|
|
163
164
|
// stream,
|
|
164
|
-
// total_bytes, stream->
|
|
165
|
+
// total_bytes, stream->pending_bytes, stream->machine->bp_commit_level,
|
|
165
166
|
// stream->machine->bp_buffer_count,
|
|
166
167
|
// same_threshold, should_restart
|
|
167
168
|
// );
|
|
@@ -173,7 +174,7 @@ int stream_get_more_segments_bp(struct um_stream *stream) {
|
|
|
173
174
|
if (should_restart) {
|
|
174
175
|
if (stream->op->bp_commit_level == stream->machine->bp_commit_level)
|
|
175
176
|
bp_handle_enobufs(stream->machine);
|
|
176
|
-
|
|
177
|
+
|
|
177
178
|
um_op_release(stream->machine, stream->op);
|
|
178
179
|
stream->op = NULL;
|
|
179
180
|
// stream_multishot_op_start(stream);
|
|
@@ -234,13 +235,24 @@ inline void stream_shift_head(struct um_stream *stream) {
|
|
|
234
235
|
stream->pos = 0;
|
|
235
236
|
}
|
|
236
237
|
|
|
238
|
+
inline VALUE make_segment_io_buffer(struct um_segment *segment, size_t pos) {
|
|
239
|
+
return rb_io_buffer_new(
|
|
240
|
+
segment->ptr + pos, segment->len - pos,
|
|
241
|
+
RB_IO_BUFFER_LOCKED|RB_IO_BUFFER_READONLY
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
237
245
|
inline void stream_skip(struct um_stream *stream, size_t inc, int safe_inc) {
|
|
246
|
+
if (unlikely(stream->eof && !stream->head)) return;
|
|
247
|
+
if (safe_inc && !stream->tail && !stream_get_more_segments(stream)) return;
|
|
248
|
+
|
|
238
249
|
while (inc) {
|
|
239
250
|
size_t segment_len = stream->head->len - stream->pos;
|
|
240
251
|
size_t inc_len = (segment_len <= inc) ? segment_len : inc;
|
|
241
252
|
inc -= inc_len;
|
|
242
253
|
stream->pos += inc_len;
|
|
243
|
-
stream->
|
|
254
|
+
stream->consumed_bytes += inc_len;
|
|
255
|
+
stream->pending_bytes -= inc_len;
|
|
244
256
|
if (stream->pos == stream->head->len) {
|
|
245
257
|
stream_shift_head(stream);
|
|
246
258
|
if (inc && safe_inc && !stream->head) {
|
|
@@ -250,6 +262,30 @@ inline void stream_skip(struct um_stream *stream, size_t inc, int safe_inc) {
|
|
|
250
262
|
}
|
|
251
263
|
}
|
|
252
264
|
|
|
265
|
+
inline void stream_each(struct um_stream *stream) {
|
|
266
|
+
if (unlikely(stream->eof && !stream->head)) return;
|
|
267
|
+
if (!stream->tail && !stream_get_more_segments(stream)) return;
|
|
268
|
+
|
|
269
|
+
struct um_segment *current = stream->head;
|
|
270
|
+
size_t pos = stream->pos;
|
|
271
|
+
|
|
272
|
+
VALUE buffer = Qnil;
|
|
273
|
+
while (true) {
|
|
274
|
+
struct um_segment *next = current->next;
|
|
275
|
+
buffer = make_segment_io_buffer(current, pos);
|
|
276
|
+
rb_yield(buffer);
|
|
277
|
+
rb_io_buffer_free_locked(buffer);
|
|
278
|
+
stream_shift_head(stream);
|
|
279
|
+
|
|
280
|
+
if (!next) {
|
|
281
|
+
if (!stream_get_more_segments(stream)) return;
|
|
282
|
+
}
|
|
283
|
+
current = stream->head;
|
|
284
|
+
pos = 0;
|
|
285
|
+
}
|
|
286
|
+
RB_GC_GUARD(buffer);
|
|
287
|
+
}
|
|
288
|
+
|
|
253
289
|
inline void stream_copy(struct um_stream *stream, char *dest, size_t len) {
|
|
254
290
|
while (len) {
|
|
255
291
|
char *segment_ptr = stream->head->ptr + stream->pos;
|
|
@@ -259,7 +295,8 @@ inline void stream_copy(struct um_stream *stream, char *dest, size_t len) {
|
|
|
259
295
|
|
|
260
296
|
len -= cpy_len;
|
|
261
297
|
stream->pos += cpy_len;
|
|
262
|
-
stream->
|
|
298
|
+
stream->consumed_bytes += cpy_len;
|
|
299
|
+
stream->pending_bytes -= cpy_len;
|
|
263
300
|
dest += cpy_len;
|
|
264
301
|
if (stream->pos == stream->head->len) stream_shift_head(stream);
|
|
265
302
|
}
|
data/ext/um/um_stream_class.c
CHANGED
|
@@ -102,6 +102,20 @@ static inline void stream_setup(struct um_stream *stream, VALUE target, VALUE mo
|
|
|
102
102
|
rb_raise(eUMError, "Invalid stream mode");
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/* call-seq:
|
|
106
|
+
* UM::Stream.new(machine, fd, mode = nil) -> stream
|
|
107
|
+
* machine.stream(fd, mode = nil) -> stream
|
|
108
|
+
* machine.stream(fd, mode = nil) { |stream| ... }
|
|
109
|
+
*
|
|
110
|
+
* Initializes a new stream with the given UringMachine instance, target and
|
|
111
|
+
* optional mode. The target maybe a file descriptor, or an instance of
|
|
112
|
+
* OpenSSL::SSL::SSLSocket. In case of an SSL socket, the mode should be :ssl.
|
|
113
|
+
*
|
|
114
|
+
* @param machine [UringMachine] UringMachine instance
|
|
115
|
+
* @param target [integer, OpenSSL::SSL::SSLSocket] stream target: file descriptor or SSL socket
|
|
116
|
+
* @param mode [Symbol] optional stream mode: :bp_read, :bp_recv, :ssl
|
|
117
|
+
* @return [void]
|
|
118
|
+
*/
|
|
105
119
|
VALUE Stream_initialize(int argc, VALUE *argv, VALUE self) {
|
|
106
120
|
VALUE machine;
|
|
107
121
|
VALUE target;
|
|
@@ -118,6 +132,13 @@ VALUE Stream_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
118
132
|
return self;
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
/* call-seq:
|
|
136
|
+
* stream.mode -> mode
|
|
137
|
+
*
|
|
138
|
+
* Returns the stream mode.
|
|
139
|
+
*
|
|
140
|
+
* @return [Symbol] stream mode
|
|
141
|
+
*/
|
|
121
142
|
VALUE Stream_mode(VALUE self) {
|
|
122
143
|
struct um_stream *stream = um_get_stream(self);
|
|
123
144
|
switch (stream->mode) {
|
|
@@ -129,16 +150,70 @@ VALUE Stream_mode(VALUE self) {
|
|
|
129
150
|
return Qnil;
|
|
130
151
|
}
|
|
131
152
|
|
|
153
|
+
/* call-seq:
|
|
154
|
+
* stream.get_line(limit) -> str
|
|
155
|
+
*
|
|
156
|
+
* Reads from the string until a newline character is encountered. Returns the
|
|
157
|
+
* line without the newline delimiter. If limit is 0, the line length is not
|
|
158
|
+
* limited. If no newline delimiter is found before EOF, returns nil.
|
|
159
|
+
*
|
|
160
|
+
* @param limit [integer] maximum line length (0 means no limit)
|
|
161
|
+
* @return [String, nil] read data or nil
|
|
162
|
+
*/
|
|
132
163
|
VALUE Stream_get_line(VALUE self, VALUE limit) {
|
|
133
164
|
struct um_stream *stream = um_get_stream(self);
|
|
134
165
|
return stream_get_line(stream, Qnil, NUM2ULONG(limit));
|
|
135
166
|
}
|
|
136
167
|
|
|
168
|
+
/* call-seq:
|
|
169
|
+
* stream.get_string(len) -> str
|
|
170
|
+
*
|
|
171
|
+
* Reads len bytes from the stream. If len is 0, reads all available bytes. If
|
|
172
|
+
* len is negative, reads up to -len available bytes. If len is positive and eof
|
|
173
|
+
* is encountered before len bytes are read, returns nil.
|
|
174
|
+
*
|
|
175
|
+
* @param len [integer] number of bytes to read
|
|
176
|
+
* @return [String, nil] read data or nil
|
|
177
|
+
*/
|
|
137
178
|
VALUE Stream_get_string(VALUE self, VALUE len) {
|
|
138
179
|
struct um_stream *stream = um_get_stream(self);
|
|
139
180
|
return stream_get_string(stream, Qnil, NUM2LONG(len), 0, false);
|
|
140
181
|
}
|
|
141
182
|
|
|
183
|
+
/* call-seq:
|
|
184
|
+
* stream.skip(len) -> len
|
|
185
|
+
*
|
|
186
|
+
* Skips len bytes in the stream.
|
|
187
|
+
*
|
|
188
|
+
* @param len [integer] number of bytes to skip
|
|
189
|
+
* @return [Integer] len
|
|
190
|
+
*/
|
|
191
|
+
VALUE Stream_skip(VALUE self, VALUE len) {
|
|
192
|
+
struct um_stream *stream = um_get_stream(self);
|
|
193
|
+
stream_skip(stream, NUM2LONG(len), true);
|
|
194
|
+
return len;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* call-seq:
|
|
198
|
+
* stream.each { |data| } -> stream
|
|
199
|
+
*
|
|
200
|
+
* Reads from the target, passing each chunk to the given block.
|
|
201
|
+
*
|
|
202
|
+
* @return [UringMachine::Stream] stream
|
|
203
|
+
*/
|
|
204
|
+
VALUE Stream_each(VALUE self) {
|
|
205
|
+
struct um_stream *stream = um_get_stream(self);
|
|
206
|
+
stream_each(stream);
|
|
207
|
+
return self;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* call-seq:
|
|
211
|
+
* stream.resp_decode -> obj
|
|
212
|
+
*
|
|
213
|
+
* Decodes an object from a RESP (Redis protocol) message.
|
|
214
|
+
*
|
|
215
|
+
* @return [any] decoded object
|
|
216
|
+
*/
|
|
142
217
|
VALUE Stream_resp_decode(VALUE self) {
|
|
143
218
|
struct um_stream *stream = um_get_stream(self);
|
|
144
219
|
VALUE out_buffer = rb_utf8_str_new_literal("");
|
|
@@ -147,6 +222,15 @@ VALUE Stream_resp_decode(VALUE self) {
|
|
|
147
222
|
return obj;
|
|
148
223
|
}
|
|
149
224
|
|
|
225
|
+
/* call-seq:
|
|
226
|
+
* stream.resp_encode(obj) -> string
|
|
227
|
+
*
|
|
228
|
+
* Encodes an object into a RESP (Redis protocol) message.
|
|
229
|
+
*
|
|
230
|
+
* @param str [String] string buffer
|
|
231
|
+
* @param obj [any] object to be encoded
|
|
232
|
+
* @return [String] str
|
|
233
|
+
*/
|
|
150
234
|
VALUE Stream_resp_encode(VALUE self, VALUE str, VALUE obj) {
|
|
151
235
|
struct um_write_buffer buf;
|
|
152
236
|
write_buffer_init(&buf, str);
|
|
@@ -156,11 +240,49 @@ VALUE Stream_resp_encode(VALUE self, VALUE str, VALUE obj) {
|
|
|
156
240
|
return str;
|
|
157
241
|
}
|
|
158
242
|
|
|
243
|
+
/* call-seq:
|
|
244
|
+
* stream.eof? -> bool
|
|
245
|
+
*
|
|
246
|
+
* Returns true if stream has reached EOF.
|
|
247
|
+
*
|
|
248
|
+
* @return [bool] EOF reached
|
|
249
|
+
*/
|
|
159
250
|
VALUE Stream_eof_p(VALUE self) {
|
|
160
251
|
struct um_stream *stream = um_get_stream(self);
|
|
161
252
|
return stream->eof ? Qtrue : Qfalse;
|
|
162
253
|
}
|
|
163
254
|
|
|
255
|
+
/* call-seq:
|
|
256
|
+
* stream.consumed -> int
|
|
257
|
+
*
|
|
258
|
+
* Returns the total number of bytes consumed from the stream.
|
|
259
|
+
*
|
|
260
|
+
* @return [Integer] total bytes consumed
|
|
261
|
+
*/
|
|
262
|
+
VALUE Stream_consumed(VALUE self) {
|
|
263
|
+
struct um_stream *stream = um_get_stream(self);
|
|
264
|
+
return LONG2NUM(stream->consumed_bytes);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* call-seq:
|
|
268
|
+
* stream.pending -> int
|
|
269
|
+
*
|
|
270
|
+
* Returns the number of bytes available for reading.
|
|
271
|
+
*
|
|
272
|
+
* @return [Integer] bytes available
|
|
273
|
+
*/
|
|
274
|
+
VALUE Stream_pending(VALUE self) {
|
|
275
|
+
struct um_stream *stream = um_get_stream(self);
|
|
276
|
+
return LONG2NUM(stream->pending_bytes);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* call-seq:
|
|
280
|
+
* stream.clear -> stream
|
|
281
|
+
*
|
|
282
|
+
* Clears all available bytes and stops any ongoing read operation.
|
|
283
|
+
*
|
|
284
|
+
* @return [UM::Stream] self
|
|
285
|
+
*/
|
|
164
286
|
VALUE Stream_clear(VALUE self) {
|
|
165
287
|
struct um_stream *stream = um_get_stream(self);
|
|
166
288
|
stream_clear(stream);
|
|
@@ -176,11 +298,15 @@ void Init_Stream(void) {
|
|
|
176
298
|
|
|
177
299
|
rb_define_method(cStream, "get_line", Stream_get_line, 1);
|
|
178
300
|
rb_define_method(cStream, "get_string", Stream_get_string, 1);
|
|
301
|
+
rb_define_method(cStream, "skip", Stream_skip, 1);
|
|
302
|
+
rb_define_method(cStream, "each", Stream_each, 0);
|
|
179
303
|
|
|
180
304
|
rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
|
|
181
305
|
rb_define_singleton_method(cStream, "resp_encode", Stream_resp_encode, 2);
|
|
182
306
|
|
|
183
307
|
rb_define_method(cStream, "eof?", Stream_eof_p, 0);
|
|
308
|
+
rb_define_method(cStream, "consumed", Stream_consumed, 0);
|
|
309
|
+
rb_define_method(cStream, "pending", Stream_pending, 0);
|
|
184
310
|
rb_define_method(cStream, "clear", Stream_clear, 0);
|
|
185
311
|
|
|
186
312
|
eStreamRESPError = rb_define_class_under(cStream, "RESPError", rb_eStandardError);
|