tigerbeetle-node 0.4.2 → 0.5.2

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.
Files changed (58) hide show
  1. package/README.md +19 -5
  2. package/dist/benchmark.js.map +1 -1
  3. package/dist/index.d.ts +18 -16
  4. package/dist/index.js +35 -13
  5. package/dist/index.js.map +1 -1
  6. package/dist/test.js +12 -0
  7. package/dist/test.js.map +1 -1
  8. package/package.json +2 -2
  9. package/scripts/postinstall.sh +2 -2
  10. package/src/benchmark.ts +2 -2
  11. package/src/index.ts +29 -4
  12. package/src/node.zig +120 -17
  13. package/src/test.ts +14 -0
  14. package/src/tigerbeetle/scripts/install.sh +1 -1
  15. package/src/tigerbeetle/scripts/install_zig.bat +109 -0
  16. package/src/tigerbeetle/scripts/install_zig.sh +4 -2
  17. package/src/tigerbeetle/scripts/lint.zig +8 -2
  18. package/src/tigerbeetle/scripts/vopr.bat +48 -0
  19. package/src/tigerbeetle/src/benchmark.zig +10 -8
  20. package/src/tigerbeetle/src/cli.zig +6 -4
  21. package/src/tigerbeetle/src/config.zig +2 -2
  22. package/src/tigerbeetle/src/demo.zig +119 -89
  23. package/src/tigerbeetle/src/demo_01_create_accounts.zig +5 -3
  24. package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +2 -3
  25. package/src/tigerbeetle/src/demo_03_create_transfers.zig +5 -3
  26. package/src/tigerbeetle/src/demo_04_create_transfers_two_phase_commit.zig +5 -3
  27. package/src/tigerbeetle/src/demo_05_accept_transfers.zig +5 -3
  28. package/src/tigerbeetle/src/demo_06_reject_transfers.zig +5 -3
  29. package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +7 -0
  30. package/src/tigerbeetle/src/io/benchmark.zig +238 -0
  31. package/src/tigerbeetle/src/{io_darwin.zig → io/darwin.zig} +89 -124
  32. package/src/tigerbeetle/src/io/linux.zig +933 -0
  33. package/src/tigerbeetle/src/io/test.zig +621 -0
  34. package/src/tigerbeetle/src/io.zig +7 -1328
  35. package/src/tigerbeetle/src/main.zig +18 -10
  36. package/src/tigerbeetle/src/message_bus.zig +43 -60
  37. package/src/tigerbeetle/src/message_pool.zig +3 -2
  38. package/src/tigerbeetle/src/ring_buffer.zig +135 -68
  39. package/src/tigerbeetle/src/simulator.zig +41 -37
  40. package/src/tigerbeetle/src/state_machine.zig +851 -26
  41. package/src/tigerbeetle/src/storage.zig +49 -46
  42. package/src/tigerbeetle/src/test/cluster.zig +2 -2
  43. package/src/tigerbeetle/src/test/message_bus.zig +6 -6
  44. package/src/tigerbeetle/src/test/network.zig +3 -3
  45. package/src/tigerbeetle/src/test/packet_simulator.zig +32 -29
  46. package/src/tigerbeetle/src/test/state_checker.zig +2 -2
  47. package/src/tigerbeetle/src/test/state_machine.zig +4 -0
  48. package/src/tigerbeetle/src/test/storage.zig +39 -19
  49. package/src/tigerbeetle/src/test/time.zig +2 -2
  50. package/src/tigerbeetle/src/tigerbeetle.zig +6 -129
  51. package/src/tigerbeetle/src/time.zig +6 -5
  52. package/src/tigerbeetle/src/vsr/client.zig +11 -11
  53. package/src/tigerbeetle/src/vsr/clock.zig +26 -43
  54. package/src/tigerbeetle/src/vsr/journal.zig +7 -6
  55. package/src/tigerbeetle/src/vsr/marzullo.zig +6 -3
  56. package/src/tigerbeetle/src/vsr/replica.zig +51 -48
  57. package/src/tigerbeetle/src/vsr.zig +24 -20
  58. package/src/translate.zig +55 -55
@@ -0,0 +1,621 @@
1
+ const std = @import("std");
2
+ const os = std.os;
3
+ const testing = std.testing;
4
+ const assert = std.debug.assert;
5
+
6
+ const Time = @import("../time.zig").Time;
7
+ const IO = @import("../io.zig").IO;
8
+
9
+ test "write/fsync/read/close" {
10
+ try struct {
11
+ const Context = @This();
12
+
13
+ io: IO,
14
+ done: bool = false,
15
+ fd: os.fd_t,
16
+
17
+ write_buf: [20]u8 = [_]u8{97} ** 20,
18
+ read_buf: [20]u8 = [_]u8{98} ** 20,
19
+
20
+ written: usize = 0,
21
+ fsynced: bool = false,
22
+ read: usize = 0,
23
+
24
+ fn run_test() !void {
25
+ const path = "test_io_write_fsync_read";
26
+ const file = try std.fs.cwd().createFile(path, .{ .read = true, .truncate = true });
27
+ defer std.fs.cwd().deleteFile(path) catch {};
28
+
29
+ var self: Context = .{
30
+ .io = try IO.init(32, 0),
31
+ .fd = file.handle,
32
+ };
33
+ defer self.io.deinit();
34
+
35
+ var completion: IO.Completion = undefined;
36
+
37
+ self.io.write(
38
+ *Context,
39
+ &self,
40
+ write_callback,
41
+ &completion,
42
+ self.fd,
43
+ &self.write_buf,
44
+ 10,
45
+ );
46
+ while (!self.done) try self.io.tick();
47
+
48
+ try testing.expectEqual(self.write_buf.len, self.written);
49
+ try testing.expect(self.fsynced);
50
+ try testing.expectEqual(self.read_buf.len, self.read);
51
+ try testing.expectEqualSlices(u8, &self.write_buf, &self.read_buf);
52
+ }
53
+
54
+ fn write_callback(
55
+ self: *Context,
56
+ completion: *IO.Completion,
57
+ result: IO.WriteError!usize,
58
+ ) void {
59
+ self.written = result catch @panic("write error");
60
+ self.io.fsync(*Context, self, fsync_callback, completion, self.fd);
61
+ }
62
+
63
+ fn fsync_callback(
64
+ self: *Context,
65
+ completion: *IO.Completion,
66
+ result: IO.FsyncError!void,
67
+ ) void {
68
+ _ = result catch @panic("fsync error");
69
+
70
+ self.fsynced = true;
71
+ self.io.read(*Context, self, read_callback, completion, self.fd, &self.read_buf, 10);
72
+ }
73
+
74
+ fn read_callback(
75
+ self: *Context,
76
+ completion: *IO.Completion,
77
+ result: IO.ReadError!usize,
78
+ ) void {
79
+ self.read = result catch @panic("read error");
80
+ self.io.close(*Context, self, close_callback, completion, self.fd);
81
+ }
82
+
83
+ fn close_callback(
84
+ self: *Context,
85
+ completion: *IO.Completion,
86
+ result: IO.CloseError!void,
87
+ ) void {
88
+ _ = completion;
89
+ _ = result catch @panic("close error");
90
+
91
+ self.done = true;
92
+ }
93
+ }.run_test();
94
+ }
95
+
96
+ test "accept/connect/send/receive" {
97
+ try struct {
98
+ const Context = @This();
99
+
100
+ io: IO,
101
+ done: bool = false,
102
+ server: os.socket_t,
103
+ client: os.socket_t,
104
+
105
+ accepted_sock: os.socket_t = undefined,
106
+
107
+ send_buf: [10]u8 = [_]u8{ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 },
108
+ recv_buf: [5]u8 = [_]u8{ 0, 1, 0, 1, 0 },
109
+
110
+ sent: usize = 0,
111
+ received: usize = 0,
112
+
113
+ fn run_test() !void {
114
+ const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
115
+ const kernel_backlog = 1;
116
+ const server = try IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
117
+ defer os.closeSocket(server);
118
+
119
+ const client = try IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
120
+ defer os.closeSocket(client);
121
+
122
+ try os.setsockopt(
123
+ server,
124
+ os.SOL.SOCKET,
125
+ os.SO.REUSEADDR,
126
+ &std.mem.toBytes(@as(c_int, 1)),
127
+ );
128
+ try os.bind(server, &address.any, address.getOsSockLen());
129
+ try os.listen(server, kernel_backlog);
130
+
131
+ var self: Context = .{
132
+ .io = try IO.init(32, 0),
133
+ .server = server,
134
+ .client = client,
135
+ };
136
+ defer self.io.deinit();
137
+
138
+ var client_completion: IO.Completion = undefined;
139
+ self.io.connect(
140
+ *Context,
141
+ &self,
142
+ connect_callback,
143
+ &client_completion,
144
+ client,
145
+ address,
146
+ );
147
+
148
+ var server_completion: IO.Completion = undefined;
149
+ self.io.accept(*Context, &self, accept_callback, &server_completion, server);
150
+
151
+ while (!self.done) try self.io.tick();
152
+
153
+ try testing.expectEqual(self.send_buf.len, self.sent);
154
+ try testing.expectEqual(self.recv_buf.len, self.received);
155
+
156
+ try testing.expectEqualSlices(u8, self.send_buf[0..self.received], &self.recv_buf);
157
+ }
158
+
159
+ fn connect_callback(
160
+ self: *Context,
161
+ completion: *IO.Completion,
162
+ result: IO.ConnectError!void,
163
+ ) void {
164
+ _ = result catch @panic("connect error");
165
+
166
+ self.io.send(
167
+ *Context,
168
+ self,
169
+ send_callback,
170
+ completion,
171
+ self.client,
172
+ &self.send_buf,
173
+ );
174
+ }
175
+
176
+ fn send_callback(
177
+ self: *Context,
178
+ completion: *IO.Completion,
179
+ result: IO.SendError!usize,
180
+ ) void {
181
+ _ = completion;
182
+
183
+ self.sent = result catch @panic("send error");
184
+ }
185
+
186
+ fn accept_callback(
187
+ self: *Context,
188
+ completion: *IO.Completion,
189
+ result: IO.AcceptError!os.socket_t,
190
+ ) void {
191
+ self.accepted_sock = result catch @panic("accept error");
192
+ self.io.recv(
193
+ *Context,
194
+ self,
195
+ recv_callback,
196
+ completion,
197
+ self.accepted_sock,
198
+ &self.recv_buf,
199
+ );
200
+ }
201
+
202
+ fn recv_callback(
203
+ self: *Context,
204
+ completion: *IO.Completion,
205
+ result: IO.RecvError!usize,
206
+ ) void {
207
+ _ = completion;
208
+
209
+ self.received = result catch @panic("recv error");
210
+ self.done = true;
211
+ }
212
+ }.run_test();
213
+ }
214
+
215
+ test "timeout" {
216
+ const ms = 20;
217
+ const margin = 5;
218
+ const count = 10;
219
+
220
+ try struct {
221
+ const Context = @This();
222
+
223
+ io: IO,
224
+ timer: *Time,
225
+ count: u32 = 0,
226
+ stop_time: u64 = 0,
227
+
228
+ fn run_test() !void {
229
+ var timer = Time{};
230
+ const start_time = timer.monotonic();
231
+
232
+ var self: Context = .{
233
+ .timer = &timer,
234
+ .io = try IO.init(32, 0),
235
+ };
236
+ defer self.io.deinit();
237
+
238
+ var completions: [count]IO.Completion = undefined;
239
+ for (completions) |*completion| {
240
+ self.io.timeout(
241
+ *Context,
242
+ &self,
243
+ timeout_callback,
244
+ completion,
245
+ ms * std.time.ns_per_ms,
246
+ );
247
+ }
248
+ while (self.count < count) try self.io.tick();
249
+
250
+ try self.io.tick();
251
+ try testing.expectEqual(@as(u32, count), self.count);
252
+
253
+ try testing.expectApproxEqAbs(
254
+ @as(f64, ms),
255
+ @intToFloat(f64, (self.stop_time - start_time) / std.time.ns_per_ms),
256
+ margin,
257
+ );
258
+ }
259
+
260
+ fn timeout_callback(
261
+ self: *Context,
262
+ completion: *IO.Completion,
263
+ result: IO.TimeoutError!void,
264
+ ) void {
265
+ _ = completion;
266
+ _ = result catch @panic("timeout error");
267
+
268
+ if (self.stop_time == 0) self.stop_time = self.timer.monotonic();
269
+ self.count += 1;
270
+ }
271
+ }.run_test();
272
+ }
273
+
274
+ test "submission queue full" {
275
+ const ms = 20;
276
+ const count = 10;
277
+
278
+ try struct {
279
+ const Context = @This();
280
+
281
+ io: IO,
282
+ count: u32 = 0,
283
+
284
+ fn run_test() !void {
285
+ var self: Context = .{ .io = try IO.init(1, 0) };
286
+ defer self.io.deinit();
287
+
288
+ var completions: [count]IO.Completion = undefined;
289
+ for (completions) |*completion| {
290
+ self.io.timeout(
291
+ *Context,
292
+ &self,
293
+ timeout_callback,
294
+ completion,
295
+ ms * std.time.ns_per_ms,
296
+ );
297
+ }
298
+ while (self.count < count) try self.io.tick();
299
+
300
+ try self.io.tick();
301
+ try testing.expectEqual(@as(u32, count), self.count);
302
+ }
303
+
304
+ fn timeout_callback(
305
+ self: *Context,
306
+ completion: *IO.Completion,
307
+ result: IO.TimeoutError!void,
308
+ ) void {
309
+ _ = completion;
310
+ _ = result catch @panic("timeout error");
311
+
312
+ self.count += 1;
313
+ }
314
+ }.run_test();
315
+ }
316
+
317
+ test "tick to wait" {
318
+ // Use only IO.tick() to see if pending IO is actually processsed
319
+
320
+ try struct {
321
+ const Context = @This();
322
+
323
+ io: IO,
324
+ accepted: os.socket_t = -1,
325
+ connected: bool = false,
326
+ received: bool = false,
327
+
328
+ fn run_test() !void {
329
+ var self: Context = .{ .io = try IO.init(1, 0) };
330
+ defer self.io.deinit();
331
+
332
+ const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
333
+ const kernel_backlog = 1;
334
+
335
+ const server = try IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
336
+ defer os.closeSocket(server);
337
+
338
+ try os.setsockopt(
339
+ server,
340
+ os.SOL.SOCKET,
341
+ os.SO.REUSEADDR,
342
+ &std.mem.toBytes(@as(c_int, 1)),
343
+ );
344
+ try os.bind(server, &address.any, address.getOsSockLen());
345
+ try os.listen(server, kernel_backlog);
346
+
347
+ const client = try IO.openSocket(address.any.family, os.SOCK.STREAM, os.IPPROTO.TCP);
348
+ defer os.closeSocket(client);
349
+
350
+ // Start the accept
351
+ var server_completion: IO.Completion = undefined;
352
+ self.io.accept(*Context, &self, accept_callback, &server_completion, server);
353
+
354
+ // Start the connect
355
+ var client_completion: IO.Completion = undefined;
356
+ self.io.connect(
357
+ *Context,
358
+ &self,
359
+ connect_callback,
360
+ &client_completion,
361
+ client,
362
+ address,
363
+ );
364
+
365
+ // Tick the IO to drain the accept & connect completions
366
+ assert(!self.connected);
367
+ assert(self.accepted == -1);
368
+
369
+ while (self.accepted == -1 or !self.connected)
370
+ try self.io.tick();
371
+
372
+ assert(self.connected);
373
+ assert(self.accepted != -1);
374
+ defer os.closeSocket(self.accepted);
375
+
376
+ // Start receiving on the client
377
+ var recv_completion: IO.Completion = undefined;
378
+ var recv_buffer: [64]u8 = undefined;
379
+ std.mem.set(u8, &recv_buffer, 0xaa);
380
+ self.io.recv(
381
+ *Context,
382
+ &self,
383
+ recv_callback,
384
+ &recv_completion,
385
+ client,
386
+ &recv_buffer,
387
+ );
388
+
389
+ // Drain out the recv completion from any internal IO queues
390
+ try self.io.tick();
391
+ try self.io.tick();
392
+ try self.io.tick();
393
+
394
+ // Complete the recv() *outside* of the IO instance.
395
+ // Other tests already check .tick() with IO based completions.
396
+ // This simulates IO being completed by an external system
397
+ var send_buf = std.mem.zeroes([64]u8);
398
+ const wrote = try os.write(self.accepted, &send_buf);
399
+ try testing.expectEqual(wrote, send_buf.len);
400
+
401
+ // Wait for the recv() to complete using only IO.tick().
402
+ // If tick is broken, then this will deadlock
403
+ assert(!self.received);
404
+ while (!self.received) {
405
+ try self.io.tick();
406
+ }
407
+
408
+ // Make sure the receive actually happened
409
+ assert(self.received);
410
+ try testing.expect(std.mem.eql(u8, &recv_buffer, &send_buf));
411
+ }
412
+
413
+ fn accept_callback(
414
+ self: *Context,
415
+ completion: *IO.Completion,
416
+ result: IO.AcceptError!os.socket_t,
417
+ ) void {
418
+ _ = completion;
419
+
420
+ assert(self.accepted == -1);
421
+ self.accepted = result catch @panic("accept error");
422
+ }
423
+
424
+ fn connect_callback(
425
+ self: *Context,
426
+ completion: *IO.Completion,
427
+ result: IO.ConnectError!void,
428
+ ) void {
429
+ _ = completion;
430
+ _ = result catch @panic("connect error");
431
+
432
+ assert(!self.connected);
433
+ self.connected = true;
434
+ }
435
+
436
+ fn recv_callback(
437
+ self: *Context,
438
+ completion: *IO.Completion,
439
+ result: IO.RecvError!usize,
440
+ ) void {
441
+ _ = completion;
442
+ _ = result catch |err| std.debug.panic("recv error: {}", .{err});
443
+
444
+ assert(!self.received);
445
+ self.received = true;
446
+ }
447
+ }.run_test();
448
+ }
449
+
450
+ test "pipe data over socket" {
451
+ try struct {
452
+ io: IO,
453
+ tx: Pipe,
454
+ rx: Pipe,
455
+ server: Socket = .{},
456
+
457
+ const buffer_size = 1 * 1024 * 1024;
458
+
459
+ const Context = @This();
460
+ const Socket = struct {
461
+ fd: os.socket_t = -1,
462
+ completion: IO.Completion = undefined,
463
+ };
464
+ const Pipe = struct {
465
+ socket: Socket = .{},
466
+ buffer: []u8,
467
+ transferred: usize = 0,
468
+ };
469
+
470
+ fn run() !void {
471
+ const tx_buf = try testing.allocator.alloc(u8, buffer_size);
472
+ defer testing.allocator.free(tx_buf);
473
+
474
+ const rx_buf = try testing.allocator.alloc(u8, buffer_size);
475
+ defer testing.allocator.free(rx_buf);
476
+
477
+ std.mem.set(u8, tx_buf, 1);
478
+ std.mem.set(u8, rx_buf, 0);
479
+
480
+ var self = Context{
481
+ .io = try IO.init(32, 0),
482
+ .tx = .{ .buffer = tx_buf },
483
+ .rx = .{ .buffer = rx_buf },
484
+ };
485
+ defer self.io.deinit();
486
+
487
+ self.server.fd = try IO.openSocket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
488
+ defer os.closeSocket(self.server.fd);
489
+
490
+ const address = try std.net.Address.parseIp4("127.0.0.1", 3131);
491
+ try os.setsockopt(
492
+ self.server.fd,
493
+ os.SOL.SOCKET,
494
+ os.SO.REUSEADDR,
495
+ &std.mem.toBytes(@as(c_int, 1)),
496
+ );
497
+
498
+ try os.bind(self.server.fd, &address.any, address.getOsSockLen());
499
+ try os.listen(self.server.fd, 1);
500
+
501
+ self.io.accept(
502
+ *Context,
503
+ &self,
504
+ on_accept,
505
+ &self.server.completion,
506
+ self.server.fd,
507
+ );
508
+
509
+ self.tx.socket.fd = try IO.openSocket(os.AF.INET, os.SOCK.STREAM, os.IPPROTO.TCP);
510
+ defer os.closeSocket(self.tx.socket.fd);
511
+
512
+ self.io.connect(
513
+ *Context,
514
+ &self,
515
+ on_connect,
516
+ &self.tx.socket.completion,
517
+ self.tx.socket.fd,
518
+ address,
519
+ );
520
+
521
+ var tick: usize = 0xdeadbeef;
522
+ while (self.rx.transferred != self.rx.buffer.len) : (tick +%= 1) {
523
+ if (tick % 61 == 0) {
524
+ const timeout_ns = tick % (10 * std.time.ns_per_ms);
525
+ try self.io.run_for_ns(@intCast(u63, timeout_ns));
526
+ } else {
527
+ try self.io.tick();
528
+ }
529
+ }
530
+
531
+ try testing.expect(self.server.fd != -1);
532
+ try testing.expect(self.tx.socket.fd != -1);
533
+ try testing.expect(self.rx.socket.fd != -1);
534
+ os.closeSocket(self.rx.socket.fd);
535
+
536
+ try testing.expectEqual(self.tx.transferred, buffer_size);
537
+ try testing.expectEqual(self.rx.transferred, buffer_size);
538
+ try testing.expect(std.mem.eql(u8, self.tx.buffer, self.rx.buffer));
539
+ }
540
+
541
+ fn on_accept(
542
+ self: *Context,
543
+ completion: *IO.Completion,
544
+ result: IO.AcceptError!os.socket_t,
545
+ ) void {
546
+ assert(self.rx.socket.fd == -1);
547
+ assert(&self.server.completion == completion);
548
+ self.rx.socket.fd = result catch |err| std.debug.panic("accept error {}", .{err});
549
+
550
+ assert(self.rx.transferred == 0);
551
+ self.do_receiver(0);
552
+ }
553
+
554
+ fn on_connect(
555
+ self: *Context,
556
+ completion: *IO.Completion,
557
+ result: IO.ConnectError!void,
558
+ ) void {
559
+ _ = completion;
560
+ _ = result catch unreachable;
561
+
562
+ assert(self.tx.socket.fd != -1);
563
+ assert(&self.tx.socket.completion == completion);
564
+
565
+ assert(self.tx.transferred == 0);
566
+ self.do_sender(0);
567
+ }
568
+
569
+ fn do_sender(self: *Context, bytes: usize) void {
570
+ self.tx.transferred += bytes;
571
+ assert(self.tx.transferred <= self.tx.buffer.len);
572
+
573
+ if (self.tx.transferred < self.tx.buffer.len) {
574
+ self.io.send(
575
+ *Context,
576
+ self,
577
+ on_send,
578
+ &self.tx.socket.completion,
579
+ self.tx.socket.fd,
580
+ self.tx.buffer[self.tx.transferred..],
581
+ );
582
+ }
583
+ }
584
+
585
+ fn on_send(
586
+ self: *Context,
587
+ completion: *IO.Completion,
588
+ result: IO.SendError!usize,
589
+ ) void {
590
+ const bytes = result catch |err| std.debug.panic("send error: {}", .{err});
591
+ assert(&self.tx.socket.completion == completion);
592
+ self.do_sender(bytes);
593
+ }
594
+
595
+ fn do_receiver(self: *Context, bytes: usize) void {
596
+ self.rx.transferred += bytes;
597
+ assert(self.rx.transferred <= self.rx.buffer.len);
598
+
599
+ if (self.rx.transferred < self.rx.buffer.len) {
600
+ self.io.recv(
601
+ *Context,
602
+ self,
603
+ on_recv,
604
+ &self.rx.socket.completion,
605
+ self.rx.socket.fd,
606
+ self.rx.buffer[self.rx.transferred..],
607
+ );
608
+ }
609
+ }
610
+
611
+ fn on_recv(
612
+ self: *Context,
613
+ completion: *IO.Completion,
614
+ result: IO.RecvError!usize,
615
+ ) void {
616
+ const bytes = result catch |err| std.debug.panic("recv error: {}", .{err});
617
+ assert(&self.rx.socket.completion == completion);
618
+ self.do_receiver(bytes);
619
+ }
620
+ }.run();
621
+ }