uringmachine 0.28.3 → 0.29.1

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.
data/ext/um/um_stream.c CHANGED
@@ -1,164 +1,428 @@
1
1
  #include "um.h"
2
2
  #include <stdlib.h>
3
3
 
4
- static inline void stream_check_truncate_buffer(struct um_stream *stream) {
5
- if ((stream->pos == stream->len) && (stream->len >= 1 << 12)) {
6
- rb_str_modify(stream->buffer);
7
- rb_str_set_len(stream->buffer, 0);
8
- stream->len = 0;
9
- stream->pos = 0;
10
- }
11
- else if (stream->pos >= 1 << 12) {
12
- rb_str_modify(stream->buffer);
13
- char *base = RSTRING_PTR(stream->buffer);
14
- int len_rest = stream->len - stream->pos;
15
- memmove(base, base + stream->pos, len_rest);
16
- rb_str_set_len(stream->buffer, len_rest);
17
- stream->len = len_rest;
18
- stream->pos = 0;
4
+ inline void stream_add_segment(struct um_stream *stream, struct um_segment *segment) {
5
+ segment->next = NULL;
6
+ if (stream->tail) {
7
+ stream->tail->next = segment;
8
+ stream->tail = segment;
19
9
  }
10
+ else
11
+ stream->head = stream->tail = segment;
12
+ stream->pending_len += segment->len;
20
13
  }
21
14
 
22
- // returns true if eof
23
- int stream_read_more(struct um_stream *stream) {
24
- stream_check_truncate_buffer(stream);
25
-
26
- size_t maxlen = 1 << 12;
27
- size_t capa = rb_str_capacity(stream->buffer);
28
- if (capa - stream->pos < maxlen)
29
- rb_str_modify_expand(stream->buffer, maxlen - (capa - stream->pos));
15
+ inline int stream_process_op_result(struct um_stream *stream, struct um_op_result *result) {
16
+ if (likely(result->res > 0)) {
17
+ if (likely(result->segment)) {
18
+ stream_add_segment(stream, result->segment);
19
+ result->segment = NULL;
20
+ }
21
+ }
22
+ else
23
+ stream->eof = 1;
30
24
 
31
- rb_str_modify(stream->buffer);
32
- char *ptr = RSTRING_PTR(stream->buffer) + stream->pos;
33
- size_t ret = um_read_raw(stream->machine, stream->fd, ptr, maxlen);
25
+ return result->res;
26
+ }
34
27
 
35
- if (ret == 0) {
36
- stream->eof = 1;
37
- return 0;
28
+ #define STREAM_OP_FLAGS (OP_F_MULTISHOT | OP_F_BUFFER_POOL)
29
+
30
+ void stream_multishot_op_start(struct um_stream *stream) {
31
+ if (!stream->op)
32
+ stream->op = um_op_acquire(stream->machine);
33
+ struct io_uring_sqe *sqe;
34
+
35
+ bp_ensure_commit_level(stream->machine);
36
+
37
+ switch (stream->mode) {
38
+ case STREAM_BP_READ:
39
+ um_prep_op(stream->machine, stream->op, OP_READ_MULTISHOT, 2, STREAM_OP_FLAGS);
40
+ sqe = um_get_sqe(stream->machine, stream->op);
41
+ io_uring_prep_read_multishot(sqe, stream->fd, 0, -1, BP_BGID);
42
+ break;
43
+ case STREAM_BP_RECV:
44
+ um_prep_op(stream->machine, stream->op, OP_RECV_MULTISHOT, 2, STREAM_OP_FLAGS);
45
+ sqe = um_get_sqe(stream->machine, stream->op);
46
+ io_uring_prep_recv_multishot(sqe, stream->fd, NULL, 0, 0);
47
+ sqe->buf_group = BP_BGID;
48
+ sqe->flags |= IOSQE_BUFFER_SELECT;
49
+ break;
50
+ default:
51
+ um_raise_internal_error("Invalid multishot op");
38
52
  }
39
-
40
- stream->len = stream->pos + ret;
41
- rb_str_set_len(stream->buffer, stream->len);
42
- return 1;
53
+ stream->op->bp_commit_level = stream->machine->bp_commit_level;
43
54
  }
44
55
 
45
- // ensures given string can hold at least given len bytes (+trailing null)
46
- static inline void str_expand(VALUE str, size_t len) {
47
- rb_str_resize(str, len);
56
+ void stream_multishot_op_stop(struct um_stream *stream) {
57
+ assert(!stream->op);
58
+
59
+ if (!(stream->op->flags & OP_F_CQE_DONE)) {
60
+ stream->op->flags |= OP_F_ASYNC;
61
+ um_cancel_op(stream->machine, stream->op);
62
+ }
63
+ else
64
+ um_op_release(stream->machine, stream->op);
65
+ stream->op = NULL;
48
66
  }
49
67
 
50
- static inline void str_copy_bytes(VALUE dest, const char *src, ssize_t len) {
51
- str_expand(dest, len + 1);
52
- char *dest_ptr = RSTRING_PTR(dest);
53
- memcpy(dest_ptr, src, len);
54
- dest_ptr[len] = 0;
55
- rb_str_set_len(dest, len);
68
+ void um_stream_cleanup(struct um_stream *stream) {
69
+ if (stream->op) stream_multishot_op_stop(stream);
70
+
71
+ while (stream->head) {
72
+ struct um_segment *next = stream->head->next;
73
+ um_segment_checkin(stream->machine, stream->head);
74
+ stream->head = next;
75
+ }
76
+ stream->pending_len = 0;
56
77
  }
57
78
 
58
- VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen) {
59
- while (true) {
60
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
61
- ssize_t pending_len = stream->len - stream->pos;
62
- ssize_t search_len = pending_len;
63
- ssize_t absmax_len = labs(maxlen);
64
- int should_limit_len = (absmax_len > 0) && (search_len > maxlen);
65
- if (should_limit_len) search_len = absmax_len;
66
-
67
- char * lf_ptr = memchr(start, '\n', search_len);
68
- if (lf_ptr) {
69
- ssize_t len = lf_ptr - start;
70
- if (len && (start[len - 1] == '\r')) len -= 1;
79
+ // returns true if case of ENOBUFS error, sets more to true if more data forthcoming
80
+ inline int stream_process_segments(
81
+ struct um_stream *stream, size_t *total_bytes, int *more) {
82
+
83
+ *more = 0;
84
+ struct um_op_result *result = &stream->op->result;
85
+ stream->op->flags &= ~OP_F_CQE_SEEN;
86
+ while (result) {
87
+ if (unlikely(result->res == -ENOBUFS)) {
88
+ *more = 0;
89
+ return true;
90
+ }
91
+ if (unlikely(result->res == -ECANCELED)) {
92
+ *more = 0;
93
+ return false;
94
+ }
95
+ um_raise_on_error_result(result->res);
71
96
 
72
- stream->pos += lf_ptr - start + 1;
73
- if (NIL_P(buf)) return rb_utf8_str_new(start, len);
97
+ *more = (result->flags & IORING_CQE_F_MORE);
98
+ *total_bytes += result->res;
99
+ stream_process_op_result(stream, result);
100
+ result = result->next;
101
+ }
102
+ return false;
103
+ }
74
104
 
75
- str_copy_bytes(buf, start, len);
76
- return buf;
105
+ void stream_clear(struct um_stream *stream) {
106
+ if (stream->op && stream->machine->ring_initialized) {
107
+ if (OP_CQE_SEEN_P(stream->op)) {
108
+ size_t total_bytes = 0;
109
+ int more = false;
110
+ stream_process_segments(stream, &total_bytes, &more);
111
+ um_op_multishot_results_clear(stream->machine, stream->op);
77
112
  }
78
- else if (should_limit_len && pending_len > search_len)
79
- // hit maxlen
80
- return Qnil;
81
113
 
82
- if (!stream_read_more(stream))
83
- return Qnil;
114
+ if (OP_CQE_DONE_P(stream->op))
115
+ um_op_release(stream->machine, stream->op);
116
+ else
117
+ um_cancel_op_and_discard_cqe(stream->machine, stream->op);
118
+
119
+ stream->op = NULL;
120
+ }
121
+
122
+ while (stream->head) {
123
+ struct um_segment *next = stream->head->next;
124
+ um_segment_checkin(stream->machine, stream->head);
125
+ stream->head = next;
126
+ }
127
+ stream->pending_len = 0;
128
+
129
+ if (stream->working_buffer) {
130
+ bp_buffer_checkin(stream->machine, stream->working_buffer);
131
+ stream->working_buffer = NULL;
84
132
  }
85
133
  }
86
134
 
87
- VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
88
- size_t abslen = labs(len);
89
- while (stream->len - stream->pos < abslen) {
90
- if (!stream_read_more(stream)) {
91
- if (len > 0)
92
- return Qnil;
135
+ inline void stream_await_segments(struct um_stream *stream) {
136
+ if (unlikely(!stream->op)) stream_multishot_op_start(stream);
137
+
138
+ if (!OP_CQE_SEEN_P(stream->op)) {
139
+ stream->op->flags &= ~OP_F_ASYNC;
140
+ VALUE ret = um_yield(stream->machine);
141
+ stream->op->flags |= OP_F_ASYNC;
142
+ if (!OP_CQE_SEEN_P(stream->op)) RAISE_IF_EXCEPTION(ret);
143
+ RB_GC_GUARD(ret);
144
+ }
145
+ }
146
+
147
+ int stream_get_more_segments_bp(struct um_stream *stream) {
148
+ size_t total_bytes = 0;
149
+ int more = false;
150
+ int enobufs = false;
151
+
152
+ while (1) {
153
+ if (unlikely(stream->eof)) return 0;
154
+
155
+ stream_await_segments(stream);
156
+ enobufs = stream_process_segments(stream, &total_bytes, &more);
157
+ um_op_multishot_results_clear(stream->machine, stream->op);
158
+ if (unlikely(enobufs)) {
159
+ int should_restart = stream->pending_len < (stream->machine->bp_buffer_size * 4);
160
+ // int same_threshold = stream->op->bp_commit_level == stream->machine->bp_commit_level;
161
+
162
+ // fprintf(stderr, "%p enobufs total: %ld pending: %ld threshold: %ld bc: %d (same: %d, restart: %d)\n",
163
+ // stream,
164
+ // total_bytes, stream->pending_len, stream->machine->bp_commit_level,
165
+ // stream->machine->bp_buffer_count,
166
+ // same_threshold, should_restart
167
+ // );
168
+
169
+ // If multiple stream ops are happening at the same time, they'll all get
170
+ // ENOBUFS! We track the commit threshold in the op in order to prevent
171
+ // running bp_handle_enobufs() more than once.
172
+
173
+ if (should_restart) {
174
+ if (stream->op->bp_commit_level == stream->machine->bp_commit_level)
175
+ bp_handle_enobufs(stream->machine);
176
+
177
+ um_op_release(stream->machine, stream->op);
178
+ stream->op = NULL;
179
+ // stream_multishot_op_start(stream);
180
+ }
181
+ else {
182
+ um_op_release(stream->machine, stream->op);
183
+ stream->op = NULL;
184
+ }
93
185
 
94
- abslen = stream->len - stream->pos;
186
+ if (total_bytes) return total_bytes;
187
+ }
188
+ else {
189
+ if (more)
190
+ stream->op->flags &= ~OP_F_CQE_SEEN;
191
+ if (total_bytes || stream->eof) return total_bytes;
95
192
  }
96
193
  }
194
+ }
97
195
 
98
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
99
- stream->pos += abslen;
196
+ int stream_get_more_segments_ssl(struct um_stream *stream) {
197
+ if (!stream->working_buffer)
198
+ stream->working_buffer = bp_buffer_checkout(stream->machine);
100
199
 
101
- if (NIL_P(buf)) return rb_utf8_str_new(start, abslen);
200
+ char *ptr = stream->working_buffer->buf + stream->working_buffer->pos;
201
+ size_t maxlen = stream->working_buffer->len - stream->working_buffer->pos;
202
+ int res = um_ssl_read_raw(stream->machine, stream->target, ptr, maxlen);
203
+ if (res == 0) return 0;
204
+ if (res < 0) rb_raise(eUMError, "Failed to read segment");
102
205
 
103
- str_copy_bytes(buf, start, abslen);
104
- return buf;
206
+ struct um_segment *segment = bp_buffer_consume(stream->machine, stream->working_buffer, res);
207
+ if ((size_t)res == maxlen) {
208
+ bp_buffer_checkin(stream->machine, stream->working_buffer);
209
+ stream->working_buffer = NULL;
210
+ }
211
+ stream_add_segment(stream, segment);
212
+ return 1;
105
213
  }
106
214
 
107
- VALUE stream_skip(struct um_stream *stream, size_t len) {
108
- while (stream->len - stream->pos < len)
109
- if (!stream_read_more(stream)) {
110
- return Qnil;
215
+ int stream_get_more_segments(struct um_stream *stream) {
216
+ switch (stream->mode) {
217
+ case STREAM_BP_READ:
218
+ case STREAM_BP_RECV:
219
+ return stream_get_more_segments_bp(stream);
220
+ case STREAM_SSL:
221
+ return stream_get_more_segments_ssl(stream);
222
+ default:
223
+ rb_raise(eUMError, "Invalid stream mode");
224
+ }
225
+ }
226
+
227
+ ///////////////////////////////////////////////////////////////////////////////////////
228
+
229
+ inline void stream_shift_head(struct um_stream *stream) {
230
+ struct um_segment *consumed = stream->head;
231
+ stream->head = consumed->next;
232
+ if (!stream->head) stream->tail = NULL;
233
+ um_segment_checkin(stream->machine, consumed);
234
+ stream->pos = 0;
235
+ }
236
+
237
+ inline void stream_skip(struct um_stream *stream, size_t inc, int safe_inc) {
238
+ while (inc) {
239
+ size_t segment_len = stream->head->len - stream->pos;
240
+ size_t inc_len = (segment_len <= inc) ? segment_len : inc;
241
+ inc -= inc_len;
242
+ stream->pos += inc_len;
243
+ stream->pending_len -= inc_len;
244
+ if (stream->pos == stream->head->len) {
245
+ stream_shift_head(stream);
246
+ if (inc && safe_inc && !stream->head) {
247
+ if (!stream_get_more_segments(stream)) break;
248
+ }
111
249
  }
250
+ }
251
+ }
112
252
 
113
- stream->pos += len;
114
- return NUM2INT(len);
253
+ inline void stream_copy(struct um_stream *stream, char *dest, size_t len) {
254
+ while (len) {
255
+ char *segment_ptr = stream->head->ptr + stream->pos;
256
+ size_t segment_len = stream->head->len - stream->pos;
257
+ size_t cpy_len = (segment_len <= len) ? segment_len : len;
258
+ memcpy(dest, segment_ptr, cpy_len);
259
+
260
+ len -= cpy_len;
261
+ stream->pos += cpy_len;
262
+ stream->pending_len -= cpy_len;
263
+ dest += cpy_len;
264
+ if (stream->pos == stream->head->len) stream_shift_head(stream);
265
+ }
115
266
  }
116
267
 
117
- VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
118
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
268
+ VALUE stream_consume_string(struct um_stream *stream, VALUE out_buffer, size_t len, size_t inc, int safe_inc) {
269
+ VALUE str = Qnil;
270
+ if (!NIL_P(out_buffer)) {
271
+ str = out_buffer;
272
+ size_t str_len = RSTRING_LEN(str);
273
+ if (str_len < len)
274
+ rb_str_resize(str, len);
275
+ else if (str_len > len)
276
+ rb_str_set_len(str, len);
277
+ }
278
+ else
279
+ str = rb_str_new(NULL, len);
280
+ char *dest = RSTRING_PTR(str);
281
+
282
+ stream_copy(stream, dest, len);
283
+ stream_skip(stream, inc, safe_inc);
284
+ return str;
285
+ RB_GC_GUARD(str);
286
+ }
287
+
288
+ VALUE stream_get_line(struct um_stream *stream, VALUE out_buffer, size_t maxlen) {
289
+ // if (stream->head) {
290
+ // fprintf(stderr, "head: %p pos: %ld: %.*s\n",
291
+ // stream->head, stream->pos,
292
+ // (int)(stream->head->len - stream->pos), stream->head->ptr + stream->pos
293
+ // );
294
+ // }
295
+
296
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
297
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
298
+
299
+ struct um_segment *last = NULL;
300
+ struct um_segment *current = stream->head;
301
+ size_t remaining_len = maxlen;
302
+ size_t total_len = 0;
303
+ size_t inc = 1;
304
+ size_t pos = stream->pos;
305
+
119
306
  while (true) {
120
- char * lf_ptr = memchr(start, '\r', stream->len - stream->pos);
307
+ size_t segment_len = current->len - pos;
308
+ size_t search_len = segment_len;
309
+ if (maxlen && (search_len > remaining_len)) search_len = remaining_len;
310
+ char *start = current->ptr + pos;
311
+ char *lf_ptr = memchr(start, '\n', search_len);
312
+
121
313
  if (lf_ptr) {
122
- ulong len = lf_ptr - start;
123
- stream->pos += len + 2;
124
-
125
- if (NIL_P(out_buffer)) {
126
- VALUE str = rb_interned_str(start, len + 1);
127
- rb_str_set_len(str, len);
128
- RSTRING_PTR(str)[len] = 0;
129
- RB_GC_GUARD(str);
130
- return str;
314
+ size_t len = lf_ptr - start;
315
+
316
+ total_len += len;
317
+
318
+ // search for \r
319
+ if (total_len) {
320
+ if (len) {
321
+ if (start[len - 1] == '\r') {
322
+ total_len -= 1;
323
+ inc = 2;
324
+ }
325
+ }
326
+ else {
327
+ if (last && (((char *)last->ptr)[last->len - 1] == '\r')) {
328
+ total_len -= 1;
329
+ inc = 2;
330
+ }
331
+ }
131
332
  }
132
333
 
133
- str_copy_bytes(out_buffer, start, len);
134
- return out_buffer;
334
+ return stream_consume_string(stream, out_buffer, total_len, inc, false);
135
335
  }
336
+ else {
337
+ // not found, early return if segment len exceeds maxlen
338
+ if (maxlen && segment_len >= maxlen) return Qnil;
136
339
 
137
- if (stream_read_more(stream))
138
- // buffer ptr and pos may have changed after reading
139
- start = RSTRING_PTR(stream->buffer) + stream->pos;
140
- else
141
- return Qnil;
340
+ total_len += segment_len;
341
+ remaining_len -= segment_len;
342
+ }
343
+
344
+ if (!current->next) {
345
+ if (!stream_get_more_segments(stream)) {
346
+ return Qnil;
347
+ }
348
+ }
349
+
350
+ last = current;
351
+ current = current->next;
352
+ pos = 0;
142
353
  }
143
354
  }
144
355
 
145
- VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
146
- ulong read_len = len + 2;
356
+ VALUE stream_get_string(struct um_stream *stream, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc) {
357
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
358
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
147
359
 
148
- while (stream->len - stream->pos < read_len)
149
- if (!stream_read_more(stream)) return Qnil;
360
+ struct um_segment *current = stream->head;
361
+ size_t abs_len = labs(len);
362
+ size_t remaining_len = abs_len;
363
+ size_t total_len = 0;
364
+ size_t pos = stream->pos;
150
365
 
151
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
152
- stream->pos += read_len;
366
+ while (true) {
367
+ size_t segment_len = current->len - pos;
368
+ if (abs_len && segment_len > remaining_len) {
369
+ segment_len = remaining_len;
370
+ }
371
+ total_len += segment_len;
372
+ if (abs_len) {
373
+ remaining_len -= segment_len;
374
+ if (!remaining_len)
375
+ return stream_consume_string(stream, out_buffer, total_len, inc, safe_inc);
376
+ }
377
+
378
+ if (!current->next) {
379
+ if (len <= 0)
380
+ return stream_consume_string(stream, out_buffer, total_len, inc, safe_inc);
381
+
382
+ if (!stream_get_more_segments(stream))
383
+ return Qnil;
384
+ }
385
+ current = current->next;
386
+ pos = 0;
387
+ }
388
+ }
389
+
390
+ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
391
+ if (unlikely(stream->eof && !stream->head)) return Qnil;
392
+ if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
393
+
394
+ struct um_segment *current = stream->head;
395
+ size_t total_len = 0;
396
+ size_t pos = stream->pos;
397
+
398
+ while (true) {
399
+ size_t segment_len = current->len - pos;
400
+ char *start = current->ptr + pos;
401
+ char *lf_ptr = memchr(start, '\r', segment_len);
402
+ if (lf_ptr) {
403
+ size_t len = lf_ptr - start;
404
+ total_len += len;
405
+ return stream_consume_string(stream, out_buffer, total_len, 2, true);
406
+ }
407
+ else
408
+ total_len += segment_len;
153
409
 
154
- if (NIL_P(out_buffer)) return rb_utf8_str_new(start, len);
410
+ if (!current->next)
411
+ if (!stream_get_more_segments(stream)) return Qnil;
155
412
 
156
- str_copy_bytes(out_buffer, start, len);
157
- return out_buffer;
413
+ current = current->next;
414
+ }
415
+ }
416
+
417
+ inline VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
418
+ return stream_get_string(stream, out_buffer, len, 2, true);
158
419
  }
159
420
 
160
421
  inline ulong resp_parse_length_field(const char *ptr, int len) {
161
- return strtoul(ptr + 1, NULL, 10);
422
+ ulong acc = 0;
423
+ for(int i = 1; i < len; i++)
424
+ acc = acc * 10 + (ptr[i] - '0');
425
+ return acc;
162
426
  }
163
427
 
164
428
  VALUE resp_decode_hash(struct um_stream *stream, VALUE out_buffer, ulong len) {
@@ -180,8 +444,7 @@ VALUE resp_decode_array(struct um_stream *stream, VALUE out_buffer, ulong len) {
180
444
  VALUE array = rb_ary_new2(len);
181
445
 
182
446
  for (ulong i = 0; i < len; i++) {
183
- VALUE buf = rb_str_new(NULL, 100);
184
- VALUE value = resp_decode(stream, buf);
447
+ VALUE value = resp_decode(stream, out_buffer);
185
448
  rb_ary_push(array, value);
186
449
  RB_GC_GUARD(value);
187
450
  }
@@ -191,11 +454,11 @@ VALUE resp_decode_array(struct um_stream *stream, VALUE out_buffer, ulong len) {
191
454
  }
192
455
 
193
456
  static inline VALUE resp_decode_simple_string(char *ptr, ulong len) {
194
- return rb_interned_str(ptr + 1, len - 1);
457
+ return rb_str_new(ptr + 1, len - 1);
195
458
  }
196
459
 
197
- static inline VALUE resp_decode_string(struct um_stream *stream, ulong len) {
198
- return resp_get_string(stream, len, Qnil);
460
+ static inline VALUE resp_decode_string(struct um_stream *stream, VALUE out_buffer, ulong len) {
461
+ return resp_get_string(stream, len, out_buffer);
199
462
  }
200
463
 
201
464
  static inline VALUE resp_decode_string_with_encoding(struct um_stream *stream, VALUE out_buffer, ulong len) {
@@ -221,7 +484,7 @@ static inline VALUE resp_decode_simple_error(char *ptr, ulong len) {
221
484
  static ID ID_new = 0;
222
485
  if (!ID_new) ID_new = rb_intern("new");
223
486
 
224
- VALUE msg = rb_interned_str(ptr + 1, len - 1);
487
+ VALUE msg = rb_str_new(ptr + 1, len - 1);
225
488
  VALUE err = rb_funcall(eStreamRESPError, ID_new, 1, msg);
226
489
  RB_GC_GUARD(msg);
227
490
  return err;
@@ -231,7 +494,7 @@ static inline VALUE resp_decode_error(struct um_stream *stream, VALUE out_buffer
231
494
  static ID ID_new = 0;
232
495
  if (!ID_new) ID_new = rb_intern("new");
233
496
 
234
- VALUE msg = resp_decode_string(stream, len);
497
+ VALUE msg = resp_decode_string(stream, out_buffer, len);
235
498
  VALUE err = rb_funcall(eStreamRESPError, ID_new, 1, msg);
236
499
  RB_GC_GUARD(msg);
237
500
  return err;
@@ -262,7 +525,7 @@ VALUE resp_decode(struct um_stream *stream, VALUE out_buffer) {
262
525
  return resp_decode_simple_string(ptr, len);
263
526
  case '$': // string
264
527
  data_len = resp_parse_length_field(ptr, len);
265
- return resp_decode_string(stream, data_len);
528
+ return resp_decode_string(stream, out_buffer, data_len);
266
529
  case '=': // string with encoding
267
530
  data_len = resp_parse_length_field(ptr, len);
268
531
  return resp_decode_string_with_encoding(stream, out_buffer, data_len);
@@ -404,34 +667,3 @@ void resp_encode(struct um_write_buffer *buf, VALUE obj) {
404
667
  um_raise_internal_error("Can't encode object");
405
668
  }
406
669
  }
407
-
408
- void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv) {
409
- char tmp1[48];
410
- char tmp2[60];
411
-
412
- sprintf(tmp1, "*%d\r\n", argc);
413
- write_buffer_append_cstr(buf, tmp1);
414
- for (int i = 0; i < argc; i++) {
415
- switch (TYPE(argv[i])) {
416
- case T_FIXNUM:
417
- sprintf(tmp1, "%ld", NUM2LONG(argv[i]));
418
- sprintf(tmp2, "$%ld\r\n%s\r\n", strlen(tmp1), (char *)tmp1);
419
- write_buffer_append_cstr(buf, tmp2);
420
- break;
421
- case T_FLOAT:
422
- sprintf(tmp1, "%lg", NUM2DBL(argv[i]));
423
- sprintf(tmp2, "$%ld\r\n%s\r\n", strlen(tmp1), (char *)tmp1);
424
- write_buffer_append_cstr(buf, tmp2);
425
- break;
426
- case T_STRING:
427
- write_buffer_append_resp_bulk_string(buf, argv[i]);
428
- break;
429
- case T_SYMBOL:
430
- write_buffer_append_resp_bulk_string(buf, rb_sym_to_s(argv[i]));
431
- break;
432
- default:
433
- um_raise_internal_error("Can't encode object");
434
- }
435
- }
436
- return;
437
- }