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
data/ext/um/um_stream_class.c
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
#include "um.h"
|
|
2
|
-
|
|
3
|
-
VALUE cStream;
|
|
4
|
-
VALUE eStreamRESPError;
|
|
5
|
-
|
|
6
|
-
VALUE SYM_bp_read;
|
|
7
|
-
VALUE SYM_bp_recv;
|
|
8
|
-
VALUE SYM_ssl;
|
|
9
|
-
|
|
10
|
-
inline int stream_has_target_obj_p(struct um_stream *stream) {
|
|
11
|
-
switch (stream->mode) {
|
|
12
|
-
case STREAM_SSL:
|
|
13
|
-
case STREAM_STRING:
|
|
14
|
-
case STREAM_IO_BUFFER:
|
|
15
|
-
return true;
|
|
16
|
-
default:
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
inline void stream_mark_segments(struct um_stream *stream) {
|
|
22
|
-
struct um_segment *curr = stream->head;
|
|
23
|
-
while (curr) {
|
|
24
|
-
// rb_gc_mark_movable(curr->obj);
|
|
25
|
-
curr = curr->next;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
inline void stream_compact_segments(struct um_stream *stream) {
|
|
30
|
-
struct um_segment *curr = stream->head;
|
|
31
|
-
while (curr) {
|
|
32
|
-
// curr->obj = rb_gc_location(curr->obj);
|
|
33
|
-
curr = curr->next;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static void Stream_mark(void *ptr) {
|
|
38
|
-
struct um_stream *stream = ptr;
|
|
39
|
-
rb_gc_mark_movable(stream->self);
|
|
40
|
-
rb_gc_mark_movable(stream->machine->self);
|
|
41
|
-
|
|
42
|
-
if (stream_has_target_obj_p(stream)) {
|
|
43
|
-
rb_gc_mark_movable(stream->target);
|
|
44
|
-
stream_mark_segments(stream);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
static void Stream_compact(void *ptr) {
|
|
49
|
-
struct um_stream *stream = ptr;
|
|
50
|
-
stream->self = rb_gc_location(stream->self);
|
|
51
|
-
|
|
52
|
-
if (stream_has_target_obj_p(stream)) {
|
|
53
|
-
stream->target = rb_gc_location(stream->target);
|
|
54
|
-
stream_compact_segments(stream);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
static void Stream_free(void *ptr) {
|
|
59
|
-
struct um_stream *stream = ptr;
|
|
60
|
-
stream_clear(stream);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static const rb_data_type_t Stream_type = {
|
|
64
|
-
.wrap_struct_name = "UringMachine::Stream",
|
|
65
|
-
.function = {
|
|
66
|
-
.dmark = Stream_mark,
|
|
67
|
-
.dfree = Stream_free,
|
|
68
|
-
.dsize = NULL,
|
|
69
|
-
.dcompact = Stream_compact
|
|
70
|
-
},
|
|
71
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
static VALUE Stream_allocate(VALUE klass) {
|
|
75
|
-
struct um_stream *stream;
|
|
76
|
-
VALUE self = TypedData_Make_Struct(klass, struct um_stream, &Stream_type, stream);
|
|
77
|
-
return self;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
static inline struct um_stream *um_get_stream(VALUE self) {
|
|
81
|
-
struct um_stream *stream;
|
|
82
|
-
TypedData_Get_Struct(self, struct um_stream, &Stream_type, stream);
|
|
83
|
-
return stream;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static inline void stream_setup(struct um_stream *stream, VALUE target, VALUE mode) {
|
|
87
|
-
stream->working_buffer = NULL;
|
|
88
|
-
if (mode == SYM_bp_read || mode == Qnil) {
|
|
89
|
-
stream->mode = STREAM_BP_READ;
|
|
90
|
-
stream->fd = NUM2INT(target);
|
|
91
|
-
}
|
|
92
|
-
else if (mode == SYM_bp_recv) {
|
|
93
|
-
stream->mode = STREAM_BP_RECV;
|
|
94
|
-
stream->fd = NUM2INT(target);
|
|
95
|
-
}
|
|
96
|
-
else if (mode == SYM_ssl) {
|
|
97
|
-
stream->mode = STREAM_SSL;
|
|
98
|
-
stream->target = target;
|
|
99
|
-
um_ssl_set_bio(stream->machine, target);
|
|
100
|
-
}
|
|
101
|
-
else
|
|
102
|
-
rb_raise(eUMError, "Invalid stream mode");
|
|
103
|
-
}
|
|
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
|
-
*/
|
|
119
|
-
VALUE Stream_initialize(int argc, VALUE *argv, VALUE self) {
|
|
120
|
-
VALUE machine;
|
|
121
|
-
VALUE target;
|
|
122
|
-
VALUE mode;
|
|
123
|
-
rb_scan_args(argc, argv, "21", &machine, &target, &mode);
|
|
124
|
-
|
|
125
|
-
struct um_stream *stream = um_get_stream(self);
|
|
126
|
-
memset(stream, 0, sizeof(struct um_stream));
|
|
127
|
-
|
|
128
|
-
RB_OBJ_WRITE(self, &stream->self, self);
|
|
129
|
-
stream->machine = um_get_machine(machine);
|
|
130
|
-
stream_setup(stream, target, mode);
|
|
131
|
-
|
|
132
|
-
return self;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/* call-seq:
|
|
136
|
-
* stream.mode -> mode
|
|
137
|
-
*
|
|
138
|
-
* Returns the stream mode.
|
|
139
|
-
*
|
|
140
|
-
* @return [Symbol] stream mode
|
|
141
|
-
*/
|
|
142
|
-
VALUE Stream_mode(VALUE self) {
|
|
143
|
-
struct um_stream *stream = um_get_stream(self);
|
|
144
|
-
switch (stream->mode) {
|
|
145
|
-
case STREAM_BP_READ: return SYM_bp_read;
|
|
146
|
-
case STREAM_BP_RECV: return SYM_bp_recv;
|
|
147
|
-
case STREAM_SSL: return SYM_ssl;
|
|
148
|
-
default: return Qnil;
|
|
149
|
-
}
|
|
150
|
-
return Qnil;
|
|
151
|
-
}
|
|
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
|
-
*/
|
|
163
|
-
VALUE Stream_get_line(VALUE self, VALUE limit) {
|
|
164
|
-
struct um_stream *stream = um_get_stream(self);
|
|
165
|
-
return stream_get_line(stream, Qnil, NUM2ULONG(limit));
|
|
166
|
-
}
|
|
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
|
-
*/
|
|
178
|
-
VALUE Stream_get_string(VALUE self, VALUE len) {
|
|
179
|
-
struct um_stream *stream = um_get_stream(self);
|
|
180
|
-
return stream_get_string(stream, Qnil, NUM2LONG(len), 0, false);
|
|
181
|
-
}
|
|
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
|
-
*/
|
|
217
|
-
VALUE Stream_resp_decode(VALUE self) {
|
|
218
|
-
struct um_stream *stream = um_get_stream(self);
|
|
219
|
-
VALUE out_buffer = rb_utf8_str_new_literal("");
|
|
220
|
-
VALUE obj = resp_decode(stream, out_buffer);
|
|
221
|
-
RB_GC_GUARD(out_buffer);
|
|
222
|
-
return obj;
|
|
223
|
-
}
|
|
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
|
-
*/
|
|
234
|
-
VALUE Stream_resp_encode(VALUE self, VALUE str, VALUE obj) {
|
|
235
|
-
struct um_write_buffer buf;
|
|
236
|
-
write_buffer_init(&buf, str);
|
|
237
|
-
rb_str_modify(str);
|
|
238
|
-
resp_encode(&buf, obj);
|
|
239
|
-
write_buffer_update_len(&buf);
|
|
240
|
-
return str;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/* call-seq:
|
|
244
|
-
* stream.eof? -> bool
|
|
245
|
-
*
|
|
246
|
-
* Returns true if stream has reached EOF.
|
|
247
|
-
*
|
|
248
|
-
* @return [bool] EOF reached
|
|
249
|
-
*/
|
|
250
|
-
VALUE Stream_eof_p(VALUE self) {
|
|
251
|
-
struct um_stream *stream = um_get_stream(self);
|
|
252
|
-
return stream->eof ? Qtrue : Qfalse;
|
|
253
|
-
}
|
|
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
|
-
*/
|
|
286
|
-
VALUE Stream_clear(VALUE self) {
|
|
287
|
-
struct um_stream *stream = um_get_stream(self);
|
|
288
|
-
stream_clear(stream);
|
|
289
|
-
return self;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
void Init_Stream(void) {
|
|
293
|
-
cStream = rb_define_class_under(cUM, "Stream", rb_cObject);
|
|
294
|
-
rb_define_alloc_func(cStream, Stream_allocate);
|
|
295
|
-
|
|
296
|
-
rb_define_method(cStream, "initialize", Stream_initialize, -1);
|
|
297
|
-
rb_define_method(cStream, "mode", Stream_mode, 0);
|
|
298
|
-
|
|
299
|
-
rb_define_method(cStream, "get_line", Stream_get_line, 1);
|
|
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);
|
|
303
|
-
|
|
304
|
-
rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
|
|
305
|
-
rb_define_singleton_method(cStream, "resp_encode", Stream_resp_encode, 2);
|
|
306
|
-
|
|
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);
|
|
310
|
-
rb_define_method(cStream, "clear", Stream_clear, 0);
|
|
311
|
-
|
|
312
|
-
eStreamRESPError = rb_define_class_under(cStream, "RESPError", rb_eStandardError);
|
|
313
|
-
|
|
314
|
-
SYM_bp_read = ID2SYM(rb_intern("bp_read"));
|
|
315
|
-
SYM_bp_recv = ID2SYM(rb_intern("bp_recv"));
|
|
316
|
-
SYM_ssl = ID2SYM(rb_intern("ssl"));
|
|
317
|
-
}
|