uringmachine 0.11.1 → 0.12
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 +6 -0
- data/TODO.md +24 -0
- data/examples/bm_http_parse.rb +39 -37
- data/ext/um/um.h +2 -5
- data/ext/um/um_stream.c +63 -40
- data/ext/um/um_stream_class.c +6 -27
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_stream.rb +71 -20
- data/test/test_um.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f8224da7817436bd74a52e650362c9b77d5dbc8877c0fa1cefd1c52e57ceb03
|
4
|
+
data.tar.gz: c7bb88c42bf59a9d1f105e2356c4f71f0fec49c7cbbe662744465ee3b34d5141
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39d930e9f4d8a17676c28e4bf24f38b585dbd0cd124316272778abb285391be4bb9ecf14452d19568ffa8f6a0144c6a98b2e3ee1f50d58ec7c5101333f5de5e7
|
7
|
+
data.tar.gz: 95468f71d402a2a8abf675dbbae6e94b4e1919c5552f0b831b7387016d3fb24271756585cf66283130ed3440818ccc94f504d73a46d2ab8f9faa4607b0cc822b
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -22,3 +22,27 @@
|
|
22
22
|
When doing a `call`, we need to provide a mailbox for the response. can this be
|
23
23
|
automatic?
|
24
24
|
|
25
|
+
# streams
|
26
|
+
|
27
|
+
We're still missing:
|
28
|
+
|
29
|
+
- limit on line length in `get_line`
|
30
|
+
- ability to supply buffer to `get_line` and `get_string`
|
31
|
+
- allow read to eof, maybe with `read_to_eof`
|
32
|
+
|
33
|
+
For the sake of performance, simplicity and explicitness, we change the API as follows:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
stream.get_line(buf, limit)
|
37
|
+
# the defaults:
|
38
|
+
stream.get_line(nil, -1)
|
39
|
+
|
40
|
+
stream.get_string(len, buf)
|
41
|
+
# defaults:
|
42
|
+
stream.get_string(len, nil)
|
43
|
+
|
44
|
+
# and
|
45
|
+
stream.read_to_eof(buf)
|
46
|
+
# defaults:
|
47
|
+
stream.read_to_eof(nil)
|
48
|
+
```
|
data/examples/bm_http_parse.rb
CHANGED
@@ -132,11 +132,12 @@ end
|
|
132
132
|
def stream_parse_headers(fd)
|
133
133
|
stream = UM::Stream.new($machine, fd)
|
134
134
|
|
135
|
-
|
135
|
+
buf = String.new(capacity: 65536)
|
136
|
+
headers = stream_get_request_line(stream, buf)
|
136
137
|
return nil if !headers
|
137
138
|
|
138
139
|
while true
|
139
|
-
line = stream.get_line()
|
140
|
+
line = stream.get_line(buf, 0)
|
140
141
|
break if line.empty?
|
141
142
|
|
142
143
|
m = line.match(RE_HEADER_LINE)
|
@@ -148,8 +149,8 @@ def stream_parse_headers(fd)
|
|
148
149
|
headers
|
149
150
|
end
|
150
151
|
|
151
|
-
def stream_get_request_line(stream)
|
152
|
-
line = stream.get_line()
|
152
|
+
def stream_get_request_line(stream, buf)
|
153
|
+
line = stream.get_line(buf, 0)
|
153
154
|
|
154
155
|
m = line.match(RE_REQUEST_LINE)
|
155
156
|
return nil if !m
|
@@ -181,42 +182,43 @@ ensure
|
|
181
182
|
($machine.close(wfd) rescue nil) if wfd
|
182
183
|
end
|
183
184
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
# counts[:TOTAL] - counts[:FREE]
|
196
|
-
# end
|
185
|
+
def compare_allocs
|
186
|
+
GC.disable
|
187
|
+
x = 1000
|
188
|
+
p(
|
189
|
+
alloc_http_parser: alloc_count { x.times { parse_http_parser } },
|
190
|
+
alloc_stringio: alloc_count { x.times { parse_http_stringio } },
|
191
|
+
alloc_stream: alloc_count { x.times { parse_http_stream } }
|
192
|
+
)
|
193
|
+
ensure
|
194
|
+
GC.enable
|
195
|
+
end
|
197
196
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
# count1 = object_count
|
203
|
-
# count1 - count0
|
204
|
-
# end
|
197
|
+
def object_count
|
198
|
+
counts = ObjectSpace.count_objects
|
199
|
+
counts[:TOTAL] - counts[:FREE]
|
200
|
+
end
|
205
201
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
#
|
211
|
-
|
212
|
-
|
202
|
+
def alloc_count
|
203
|
+
GC.start
|
204
|
+
count0 = object_count
|
205
|
+
yield
|
206
|
+
# GC.start
|
207
|
+
count1 = object_count
|
208
|
+
count1 - count0
|
209
|
+
end
|
213
210
|
|
214
|
-
|
215
|
-
|
211
|
+
def benchmark
|
212
|
+
Benchmark.ips do |x|
|
213
|
+
x.config(:time => 5, :warmup => 3)
|
216
214
|
|
217
|
-
|
218
|
-
|
219
|
-
|
215
|
+
x.report("http_parser") { parse_http_parser }
|
216
|
+
x.report("stringio") { parse_http_stringio }
|
217
|
+
x.report("stream") { parse_http_stream }
|
220
218
|
|
221
|
-
|
219
|
+
x.compare!
|
220
|
+
end
|
222
221
|
end
|
222
|
+
|
223
|
+
compare_allocs
|
224
|
+
benchmark
|
data/ext/um/um.h
CHANGED
@@ -270,11 +270,8 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
|
270
270
|
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
271
271
|
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
272
272
|
|
273
|
-
|
274
|
-
VALUE
|
275
|
-
VALUE stream_get_string(struct um_stream *stream, ulong len);
|
276
|
-
VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer);
|
277
|
-
VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer);
|
273
|
+
VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen);
|
274
|
+
VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
|
278
275
|
VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
|
279
276
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
280
277
|
|
data/ext/um/um_stream.c
CHANGED
@@ -1,31 +1,5 @@
|
|
1
1
|
#include "um.h"
|
2
|
-
|
3
|
-
VALUE stream_get_line(struct um_stream *stream) {
|
4
|
-
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
5
|
-
while (true) {
|
6
|
-
char * lf_ptr = memchr(start, '\n', stream->len - stream->pos);
|
7
|
-
if (lf_ptr) {
|
8
|
-
ulong len = lf_ptr - start;
|
9
|
-
if (len && (start[len - 1] == '\r')) len -= 1;
|
10
|
-
|
11
|
-
VALUE str = rb_str_new(start, len);
|
12
|
-
stream->pos += lf_ptr - start + 1;
|
13
|
-
return str;
|
14
|
-
}
|
15
|
-
|
16
|
-
if (!stream_read_more(stream)) return Qnil;
|
17
|
-
}
|
18
|
-
}
|
19
|
-
|
20
|
-
VALUE stream_get_string(struct um_stream *stream, ulong len) {
|
21
|
-
while (stream->len - stream->pos < len)
|
22
|
-
if (!stream_read_more(stream)) return Qnil;
|
23
|
-
|
24
|
-
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
25
|
-
VALUE str = rb_utf8_str_new(start, len);
|
26
|
-
stream->pos += len;
|
27
|
-
return str;
|
28
|
-
}
|
2
|
+
#include <stdlib.h>
|
29
3
|
|
30
4
|
static inline void stream_check_truncate_buffer(struct um_stream *stream) {
|
31
5
|
if ((stream->pos == stream->len) && (stream->len >= 1 << 12)) {
|
@@ -67,10 +41,67 @@ int stream_read_more(struct um_stream *stream) {
|
|
67
41
|
return 1;
|
68
42
|
}
|
69
43
|
|
70
|
-
//
|
44
|
+
// ensures given string can hold at least given len bytes (+trailing null)
|
71
45
|
static inline void str_expand(VALUE str, size_t len) {
|
72
|
-
|
73
|
-
|
46
|
+
rb_str_resize(str, len);
|
47
|
+
}
|
48
|
+
|
49
|
+
static inline void str_copy_bytes(VALUE dest, const char *src, ssize_t len) {
|
50
|
+
str_expand(dest, len + 1);
|
51
|
+
char *dest_ptr = RSTRING_PTR(dest);
|
52
|
+
memcpy(dest_ptr, src, len);
|
53
|
+
dest_ptr[len] = 0;
|
54
|
+
rb_str_set_len(dest, len);
|
55
|
+
}
|
56
|
+
|
57
|
+
VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen) {
|
58
|
+
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
59
|
+
while (true) {
|
60
|
+
ssize_t pending_len = stream->len - stream->pos;
|
61
|
+
ssize_t search_len = pending_len;
|
62
|
+
ssize_t absmax_len = labs(maxlen);
|
63
|
+
int should_limit_len = (absmax_len > 0) && (search_len > maxlen);
|
64
|
+
if (should_limit_len) search_len = absmax_len;
|
65
|
+
|
66
|
+
char * lf_ptr = memchr(start, '\n', search_len);
|
67
|
+
if (lf_ptr) {
|
68
|
+
ssize_t len = lf_ptr - start;
|
69
|
+
if (len && (start[len - 1] == '\r')) len -= 1;
|
70
|
+
|
71
|
+
stream->pos += lf_ptr - start + 1;
|
72
|
+
if (NIL_P(buf)) return rb_utf8_str_new(start, len);
|
73
|
+
|
74
|
+
str_copy_bytes(buf, start, len);
|
75
|
+
return buf;
|
76
|
+
}
|
77
|
+
else if (should_limit_len && pending_len > search_len)
|
78
|
+
// maxlen
|
79
|
+
return Qnil;
|
80
|
+
|
81
|
+
if (!stream_read_more(stream))
|
82
|
+
return Qnil;
|
83
|
+
else
|
84
|
+
// update start ptr (it might have changed after reading)
|
85
|
+
start = RSTRING_PTR(stream->buffer) + stream->pos;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
|
90
|
+
size_t abslen = labs(len);
|
91
|
+
while (stream->len - stream->pos < abslen)
|
92
|
+
if (!stream_read_more(stream)) {
|
93
|
+
if (len > 0) return Qnil;
|
94
|
+
|
95
|
+
abslen = stream->len - stream->pos;
|
96
|
+
}
|
97
|
+
|
98
|
+
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
99
|
+
stream->pos += abslen;
|
100
|
+
|
101
|
+
if (NIL_P(buf)) return rb_utf8_str_new(start, abslen);
|
102
|
+
|
103
|
+
str_copy_bytes(buf, start, len);
|
104
|
+
return buf;
|
74
105
|
}
|
75
106
|
|
76
107
|
VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
|
@@ -89,11 +120,7 @@ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
|
|
89
120
|
return str;
|
90
121
|
}
|
91
122
|
|
92
|
-
|
93
|
-
char *dest_ptr = RSTRING_PTR(out_buffer);
|
94
|
-
memcpy(dest_ptr, start, len);
|
95
|
-
dest_ptr[len] = 0; // add null at end
|
96
|
-
rb_str_set_len(out_buffer, len);
|
123
|
+
str_copy_bytes(out_buffer, start, len);
|
97
124
|
return out_buffer;
|
98
125
|
}
|
99
126
|
|
@@ -116,11 +143,7 @@ VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
|
|
116
143
|
|
117
144
|
if (NIL_P(out_buffer)) return rb_utf8_str_new(start, len);
|
118
145
|
|
119
|
-
|
120
|
-
char *dest_ptr = RSTRING_PTR(out_buffer);
|
121
|
-
memcpy(dest_ptr, start, len);
|
122
|
-
dest_ptr[len] = 0; // add null at end
|
123
|
-
rb_str_set_len(out_buffer, len);
|
146
|
+
str_copy_bytes(out_buffer, start, len);
|
124
147
|
return out_buffer;
|
125
148
|
}
|
126
149
|
|
data/ext/um/um_stream_class.c
CHANGED
@@ -52,36 +52,18 @@ VALUE Stream_initialize(VALUE self, VALUE machine, VALUE fd) {
|
|
52
52
|
return self;
|
53
53
|
}
|
54
54
|
|
55
|
-
VALUE Stream_get_line(VALUE self) {
|
55
|
+
VALUE Stream_get_line(VALUE self, VALUE buf, VALUE limit) {
|
56
56
|
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
57
57
|
if (unlikely(stream->eof)) return Qnil;
|
58
58
|
|
59
|
-
return stream_get_line(stream);
|
59
|
+
return stream_get_line(stream, buf, NUM2LONG(limit));
|
60
60
|
}
|
61
61
|
|
62
|
-
VALUE Stream_get_string(VALUE self, VALUE len) {
|
62
|
+
VALUE Stream_get_string(VALUE self, VALUE buf, VALUE len) {
|
63
63
|
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
64
64
|
if (unlikely(stream->eof)) return Qnil;
|
65
65
|
|
66
|
-
return stream_get_string(stream,
|
67
|
-
}
|
68
|
-
|
69
|
-
VALUE Stream_resp_get_line(VALUE self) {
|
70
|
-
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
71
|
-
if (unlikely(stream->eof)) return Qnil;
|
72
|
-
|
73
|
-
VALUE line = resp_get_line(stream, Qnil);
|
74
|
-
RB_GC_GUARD(line);
|
75
|
-
return line;
|
76
|
-
}
|
77
|
-
|
78
|
-
VALUE Stream_resp_get_string(VALUE self, VALUE len) {
|
79
|
-
struct um_stream *stream = RTYPEDDATA_DATA(self);
|
80
|
-
if (unlikely(stream->eof)) return Qnil;
|
81
|
-
|
82
|
-
VALUE str = resp_get_string(stream, NUM2ULONG(len), Qnil);
|
83
|
-
RB_GC_GUARD(str);
|
84
|
-
return str;
|
66
|
+
return stream_get_string(stream, buf, NUM2LONG(len));
|
85
67
|
}
|
86
68
|
|
87
69
|
VALUE Stream_resp_decode(VALUE self) {
|
@@ -109,11 +91,8 @@ void Init_Stream(void) {
|
|
109
91
|
|
110
92
|
rb_define_method(cStream, "initialize", Stream_initialize, 2);
|
111
93
|
|
112
|
-
rb_define_method(cStream, "get_line", Stream_get_line,
|
113
|
-
rb_define_method(cStream, "get_string", Stream_get_string,
|
114
|
-
|
115
|
-
rb_define_method(cStream, "resp_get_line", Stream_resp_get_line, 0);
|
116
|
-
rb_define_method(cStream, "resp_get_string", Stream_resp_get_string, 1);
|
94
|
+
rb_define_method(cStream, "get_line", Stream_get_line, 2);
|
95
|
+
rb_define_method(cStream, "get_string", Stream_get_string, 2);
|
117
96
|
|
118
97
|
rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
|
119
98
|
|
data/lib/uringmachine/version.rb
CHANGED
data/test/test_stream.rb
CHANGED
@@ -15,41 +15,92 @@ class StreamTest < StreamBaseTest
|
|
15
15
|
machine.write(@wfd, "foo\nbar\r\nbaz")
|
16
16
|
machine.close(@wfd)
|
17
17
|
|
18
|
-
assert_equal 'foo', @stream.get_line
|
19
|
-
assert_equal 'bar', @stream.get_line
|
20
|
-
assert_nil @stream.get_line
|
18
|
+
assert_equal 'foo', @stream.get_line(nil, 0)
|
19
|
+
assert_equal 'bar', @stream.get_line(nil, 0)
|
20
|
+
assert_nil @stream.get_line(nil, 0)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_get_line_with_buf
|
24
|
+
machine.write(@wfd, "foo\nbar\r\nbaz")
|
25
|
+
machine.close(@wfd)
|
26
|
+
|
27
|
+
buf = +''
|
28
|
+
ret = @stream.get_line(buf, 0)
|
29
|
+
assert_equal 'foo', buf
|
30
|
+
assert_equal ret, buf
|
31
|
+
|
32
|
+
ret = @stream.get_line(buf, 0)
|
33
|
+
assert_equal 'bar', buf
|
34
|
+
assert_equal ret, buf
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_get_line_with_positive_maxlen
|
38
|
+
machine.write(@wfd, "foobar\r\n")
|
39
|
+
machine.close(@wfd)
|
40
|
+
|
41
|
+
buf = +''
|
42
|
+
ret = @stream.get_line(buf, 3)
|
43
|
+
assert_nil ret
|
44
|
+
assert_equal '', buf
|
45
|
+
|
46
|
+
# verify that stream pos has not changed
|
47
|
+
ret = @stream.get_line(buf, 0)
|
48
|
+
assert_equal 'foobar', buf
|
49
|
+
assert_equal ret, buf
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_get_line_with_negative_maxlen
|
53
|
+
machine.write(@wfd, "foobar\r\n")
|
54
|
+
machine.close(@wfd)
|
55
|
+
|
56
|
+
buf = +''
|
57
|
+
ret = @stream.get_line(buf, -3)
|
58
|
+
assert_nil ret
|
59
|
+
assert_equal '', buf
|
60
|
+
|
61
|
+
# verify that stream pos has not changed
|
62
|
+
ret = @stream.get_line(buf, 0)
|
63
|
+
assert_equal 'foobar', buf
|
64
|
+
assert_equal ret, buf
|
21
65
|
end
|
22
66
|
|
23
67
|
def test_get_string
|
24
68
|
machine.write(@wfd, "foobarbazblahzzz")
|
25
69
|
machine.close(@wfd)
|
26
70
|
|
27
|
-
assert_equal 'foobar', @stream.get_string(6)
|
28
|
-
assert_equal 'baz', @stream.get_string(3)
|
29
|
-
assert_equal 'blah', @stream.get_string(4)
|
30
|
-
assert_nil @stream.get_string(4)
|
71
|
+
assert_equal 'foobar', @stream.get_string(nil, 6)
|
72
|
+
assert_equal 'baz', @stream.get_string(nil, 3)
|
73
|
+
assert_equal 'blah', @stream.get_string(nil, 4)
|
74
|
+
assert_nil @stream.get_string(nil, 4)
|
31
75
|
end
|
32
|
-
end
|
33
76
|
|
34
|
-
|
35
|
-
|
36
|
-
machine.write(@wfd, "foo\r\nbarbar\r\nbaz\n")
|
77
|
+
def test_get_string_with_buf
|
78
|
+
machine.write(@wfd, "foobarbazblahzzz")
|
37
79
|
machine.close(@wfd)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
80
|
+
|
81
|
+
buf = +''
|
82
|
+
ret = @stream.get_string(buf, 6)
|
83
|
+
assert_equal 'foobar', buf
|
84
|
+
assert_equal ret, buf
|
85
|
+
|
86
|
+
ret = @stream.get_string(buf, 3)
|
87
|
+
assert_equal 'baz', buf
|
88
|
+
assert_equal ret, buf
|
42
89
|
end
|
43
90
|
|
44
|
-
def
|
45
|
-
machine.write(@wfd, "
|
91
|
+
def test_get_string_with_negative_len
|
92
|
+
machine.write(@wfd, "foobar")
|
46
93
|
machine.close(@wfd)
|
47
94
|
|
48
|
-
|
49
|
-
assert_equal '
|
50
|
-
|
95
|
+
ret = @stream.get_string(nil, -12)
|
96
|
+
assert_equal 'foobar', ret
|
97
|
+
|
98
|
+
ret = @stream.get_string(nil, -4)
|
99
|
+
assert_nil ret
|
51
100
|
end
|
101
|
+
end
|
52
102
|
|
103
|
+
class StreamRespTest < StreamBaseTest
|
53
104
|
def test_resp_decode
|
54
105
|
machine.write(@wfd, "+foo bar\r\n")
|
55
106
|
assert_equal "foo bar", @stream.resp_decode
|
data/test/test_um.rb
CHANGED