polyphony 0.57.0 → 0.60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Gemfile.lock +15 -29
  4. data/examples/core/message_based_supervision.rb +51 -0
  5. data/ext/polyphony/backend_common.c +108 -3
  6. data/ext/polyphony/backend_common.h +23 -0
  7. data/ext/polyphony/backend_io_uring.c +117 -39
  8. data/ext/polyphony/backend_io_uring_context.c +11 -3
  9. data/ext/polyphony/backend_io_uring_context.h +5 -3
  10. data/ext/polyphony/backend_libev.c +92 -30
  11. data/ext/polyphony/extconf.rb +2 -2
  12. data/ext/polyphony/fiber.c +1 -34
  13. data/ext/polyphony/polyphony.c +12 -19
  14. data/ext/polyphony/polyphony.h +10 -20
  15. data/ext/polyphony/polyphony_ext.c +0 -4
  16. data/ext/polyphony/queue.c +12 -12
  17. data/ext/polyphony/runqueue.c +17 -85
  18. data/ext/polyphony/runqueue.h +27 -0
  19. data/ext/polyphony/thread.c +10 -99
  20. data/lib/polyphony/core/timer.rb +2 -2
  21. data/lib/polyphony/extensions/fiber.rb +102 -82
  22. data/lib/polyphony/extensions/io.rb +10 -9
  23. data/lib/polyphony/extensions/openssl.rb +14 -4
  24. data/lib/polyphony/extensions/socket.rb +15 -15
  25. data/lib/polyphony/extensions/thread.rb +8 -0
  26. data/lib/polyphony/version.rb +1 -1
  27. data/polyphony.gemspec +0 -7
  28. data/test/test_backend.rb +71 -5
  29. data/test/test_ext.rb +1 -1
  30. data/test/test_fiber.rb +106 -18
  31. data/test/test_global_api.rb +1 -1
  32. data/test/test_io.rb +29 -0
  33. data/test/test_supervise.rb +100 -100
  34. data/test/test_thread.rb +57 -11
  35. data/test/test_thread_pool.rb +1 -1
  36. data/test/test_trace.rb +28 -49
  37. metadata +4 -108
  38. data/ext/polyphony/tracing.c +0 -11
  39. data/lib/polyphony/adapters/trace.rb +0 -138
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.57.0'
4
+ VERSION = '0.60'
5
5
  end
data/polyphony.gemspec CHANGED
@@ -29,13 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'pry', '0.13.1'
30
30
 
31
31
  s.add_development_dependency 'msgpack', '1.4.2'
32
- s.add_development_dependency 'pg', '1.1.4'
33
- s.add_development_dependency 'redis', '4.1.0'
34
- s.add_development_dependency 'hiredis', '0.6.3'
35
- s.add_development_dependency 'http_parser.rb', '~>0.6.0'
36
- s.add_development_dependency 'rack', '>=2.0.8', '<2.3.0'
37
- s.add_development_dependency 'mysql2', '0.5.3'
38
- s.add_development_dependency 'sequel', '5.34.0'
39
32
  s.add_development_dependency 'httparty', '0.17.1'
40
33
  s.add_development_dependency 'localhost', '~>1.1.4'
41
34
 
data/test/test_backend.rb CHANGED
@@ -33,7 +33,7 @@ class BackendTest < MiniTest::Test
33
33
  def test_write_read_partial
34
34
  i, o = IO.pipe
35
35
  buf = +''
36
- f = spin { @backend.read(i, buf, 5, false) }
36
+ f = spin { @backend.read(i, buf, 5, false, 0) }
37
37
  @backend.write(o, 'Hello world')
38
38
  return_value = f.await
39
39
 
@@ -44,7 +44,7 @@ class BackendTest < MiniTest::Test
44
44
  def test_write_read_to_eof_limited_buffer
45
45
  i, o = IO.pipe
46
46
  buf = +''
47
- f = spin { @backend.read(i, buf, 5, true) }
47
+ f = spin { @backend.read(i, buf, 5, true, 0) }
48
48
  @backend.write(o, 'Hello')
49
49
  snooze
50
50
  @backend.write(o, ' world')
@@ -59,7 +59,7 @@ class BackendTest < MiniTest::Test
59
59
  def test_write_read_to_eof
60
60
  i, o = IO.pipe
61
61
  buf = +''
62
- f = spin { @backend.read(i, buf, 10**6, true) }
62
+ f = spin { @backend.read(i, buf, 10**6, true, 0) }
63
63
  @backend.write(o, 'Hello')
64
64
  snooze
65
65
  @backend.write(o, ' world')
@@ -71,6 +71,33 @@ class BackendTest < MiniTest::Test
71
71
  assert_equal return_value, buf
72
72
  end
73
73
 
74
+ def test_write_read_with_buffer_position
75
+ i, o = IO.pipe
76
+ buf = +'abcdefghij'
77
+ f = spin { @backend.read(i, buf, 20, false, 0) }
78
+ @backend.write(o, 'blah')
79
+ return_value = f.await
80
+
81
+ assert_equal 'blah', buf
82
+ assert_equal return_value, buf
83
+
84
+ buf = +'abcdefghij'
85
+ f = spin { @backend.read(i, buf, 20, false, -1) }
86
+ @backend.write(o, 'klmn')
87
+ return_value = f.await
88
+
89
+ assert_equal 'abcdefghijklmn', buf
90
+ assert_equal return_value, buf
91
+
92
+ buf = +'abcdefghij'
93
+ f = spin { @backend.read(i, buf, 20, false, 3) }
94
+ @backend.write(o, 'DEF')
95
+ return_value = f.await
96
+
97
+ assert_equal 'abcDEF', buf
98
+ assert_equal return_value, buf
99
+ end
100
+
74
101
  def test_waitpid
75
102
  pid = fork do
76
103
  @backend.post_fork
@@ -87,7 +114,7 @@ class BackendTest < MiniTest::Test
87
114
  buf = []
88
115
  f = spin do
89
116
  buf << :ready
90
- @backend.read_loop(i) { |d| buf << d }
117
+ @backend.read_loop(i, 8192) { |d| buf << d }
91
118
  buf << :done
92
119
  end
93
120
 
@@ -107,7 +134,7 @@ class BackendTest < MiniTest::Test
107
134
  parent = spin do
108
135
  f = spin do
109
136
  buf << :ready
110
- @backend.read_loop(i) { |d| buf << d }
137
+ @backend.read_loop(i, 8192) { |d| buf << d }
111
138
  buf << :done
112
139
  end
113
140
  suspend
@@ -125,6 +152,16 @@ class BackendTest < MiniTest::Test
125
152
  assert_equal [:ready, 'foo', 'bar'], buf
126
153
  end
127
154
 
155
+ def test_read_loop_with_max_len
156
+ r, w = IO.pipe
157
+
158
+ w << 'foobar'
159
+ w.close
160
+ buf = []
161
+ @backend.read_loop(r, 3) { |data| buf << data }
162
+ assert_equal ['foo', 'bar'], buf
163
+ end
164
+
128
165
  Net = Polyphony::Net
129
166
 
130
167
  def test_accept
@@ -340,9 +377,38 @@ class BackendTest < MiniTest::Test
340
377
  # GC period.
341
378
  sleep 0.05
342
379
  assert_equal count + 1, GC.count
380
+
381
+ @backend.idle_gc_period = 0
382
+ count = GC.count
383
+ sleep 0.001
384
+ sleep 0.002
385
+ sleep 0.003
386
+ assert_equal count, GC.count
343
387
  ensure
344
388
  GC.enable
345
389
  end
390
+
391
+ def test_idle_proc
392
+ counter = 0
393
+
394
+ @backend.idle_proc = proc { counter += 1 }
395
+
396
+ 3.times { snooze }
397
+ assert_equal 0, counter
398
+
399
+ sleep 0.01
400
+ assert_equal 1, counter
401
+ sleep 0.01
402
+ assert_equal 2, counter
403
+
404
+ assert_equal 2, counter
405
+ 3.times { snooze }
406
+ assert_equal 2, counter
407
+
408
+ @backend.idle_proc = nil
409
+ sleep 0.01
410
+ assert_equal 2, counter
411
+ end
346
412
  end
347
413
 
348
414
  class BackendChainTest < MiniTest::Test
data/test/test_ext.rb CHANGED
@@ -42,7 +42,7 @@ class ExceptionTest < MiniTest::Test
42
42
  end
43
43
 
44
44
  class ProcessTest < MiniTest::Test
45
- def test_detach
45
+ def test_process_detach
46
46
  pid = Polyphony.fork { sleep 0.05; exit! 42 }
47
47
  buffer = []
48
48
  spin { 3.times { |i| buffer << i; snooze } }
data/test/test_fiber.rb CHANGED
@@ -43,6 +43,14 @@ class FiberTest < MiniTest::Test
43
43
  f&.stop
44
44
  end
45
45
 
46
+ def test_await_dead_children
47
+ f1 = spin { :foo }
48
+ f2 = spin { :bar }
49
+ 2.times { snooze }
50
+
51
+ assert_equal [:foo, :bar], Fiber.await(f1, f2)
52
+ end
53
+
46
54
  def test_await_from_multiple_fibers
47
55
  buffer = []
48
56
  f1 = spin {
@@ -348,12 +356,12 @@ class FiberTest < MiniTest::Test
348
356
  assert_equal [:foo, :terminate], buffer
349
357
  end
350
358
 
351
- CMD_TERMINATE_MAIN_FIBER = <<~BASH
352
- ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
359
+ CMD_TERMINATE_CHILD_FIBER = <<~BASH
360
+ ruby -rbundler/setup -rpolyphony -e'f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await' 2>&1
353
361
  BASH
354
362
 
355
- CMD_TERMINATE_CHILD_FIBER = <<~BASH
356
- ruby -rbundler/setup -rpolyphony -e"f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await" 2>&1
363
+ CMD_TERMINATE_MAIN_FIBER = <<~BASH
364
+ ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
357
365
  BASH
358
366
 
359
367
  def test_terminate_main_fiber
@@ -547,24 +555,38 @@ class FiberTest < MiniTest::Test
547
555
  assert f.location =~ location
548
556
  end
549
557
 
550
- def test_when_done
551
- flag = nil
552
- values = []
553
- f = spin do
554
- snooze until flag
558
+ def test_monitor
559
+ child = nil
560
+ parent = spin do
561
+ child = spin { receive }
562
+ child.await
555
563
  end
556
- f.when_done { values << 42 }
557
564
 
558
565
  snooze
559
- assert values.empty?
560
- snooze
561
- flag = true
562
- assert values.empty?
563
- assert f.alive?
566
+ child.monitor
567
+ spin { child << :foo }
568
+
569
+ msg = receive
570
+ assert_equal [child, :foo], msg
571
+ end
564
572
 
573
+ def test_unmonitor
574
+ child = nil
575
+ parent = spin(:parent) do
576
+ child = spin(:child) { receive }
577
+ child.await
578
+ end
579
+
580
+ snooze
581
+ child.monitor
582
+ spin { child << :foo }
565
583
  snooze
566
- assert_equal [42], values
567
- assert !f.running?
584
+
585
+ child.unmonitor
586
+
587
+ Fiber.current << :bar
588
+ msg = receive
589
+ assert_equal :bar, msg
568
590
  end
569
591
 
570
592
  def test_children
@@ -732,6 +754,72 @@ class FiberTest < MiniTest::Test
732
754
  assert_equal ['bar'], buffer
733
755
  snooze
734
756
  end
757
+
758
+ def test_detach
759
+ buf = []
760
+ child = nil
761
+ parent = spin(:parent) do
762
+ buf << :hi_from_parent
763
+ child = spin(:child) do
764
+ buf << :hi_from_child
765
+ # wait for message (from main fiber)
766
+ buf << receive
767
+ end
768
+ snooze
769
+ buf << :bye_from_parent
770
+ end
771
+
772
+ snooze
773
+ assert_equal parent, child.parent
774
+ child.detach
775
+ assert_equal Fiber.current, child.parent
776
+ parent.await
777
+
778
+ child << :bye
779
+ child.await
780
+
781
+ assert_equal [
782
+ :hi_from_parent,
783
+ :hi_from_child,
784
+ :bye_from_parent,
785
+ :bye
786
+ ], buf
787
+ end
788
+
789
+ def test_attach
790
+ buf = []
791
+ child = nil
792
+ parent = spin(:parent) do
793
+ buf << :hi_from_parent
794
+ child = spin(:child) do
795
+ buf << :hi_from_child
796
+ # wait for message (from main fiber)
797
+ buf << receive
798
+ end
799
+ snooze
800
+ buf << :bye_from_parent
801
+ end
802
+
803
+ new_parent = spin(:new_parent) { buf << receive }
804
+
805
+ snooze
806
+ assert_equal parent, child.parent
807
+ child.attach(new_parent)
808
+ assert_equal new_parent, child.parent
809
+ parent.await
810
+
811
+ child << :bye
812
+ new_parent << :bye_new_parent
813
+ snooze
814
+
815
+ assert_equal [
816
+ :hi_from_parent,
817
+ :hi_from_child,
818
+ :bye_from_parent,
819
+ :bye,
820
+ :bye_new_parent
821
+ ], buf
822
+ end
735
823
  end
736
824
 
737
825
  class MailboxTest < MiniTest::Test
@@ -964,7 +1052,7 @@ class FiberControlTest < MiniTest::Test
964
1052
  assert_equal 'foo', result.message
965
1053
  assert_equal f1, result.source_fiber
966
1054
  assert_equal :dead, f1.state
967
- assert_equal :dead, f2.state
1055
+ assert_equal :waiting, f2.state
968
1056
  end
969
1057
 
970
1058
  def test_select_with_interruption
@@ -372,7 +372,7 @@ class SpinScopeTest < MiniTest::Test
372
372
  rescue => e
373
373
  buffer << e.message
374
374
  end
375
- 6.times { snooze }
375
+ 10.times { snooze }
376
376
  assert_equal 0, Fiber.current.children.size
377
377
  assert_equal ['foobar'], buffer
378
378
  end
data/test/test_io.rb CHANGED
@@ -416,4 +416,33 @@ class IOClassMethodsTest < MiniTest::Test
416
416
  assert_equal "foo\nbar\n", pipe_read { |f| f.puts 'foo', 'bar' }
417
417
  assert_equal "foo\nbar\n", pipe_read { |f| f.puts 'foo', "bar\n" }
418
418
  end
419
+
420
+ def test_read_loop
421
+ i, o = IO.pipe
422
+
423
+ buf = []
424
+ f = spin do
425
+ buf << :ready
426
+ i.read_loop { |d| buf << d }
427
+ buf << :done
428
+ end
429
+
430
+ # writing always causes snoozing
431
+ o << 'foo'
432
+ o << 'bar'
433
+ o.close
434
+
435
+ f.await
436
+ assert_equal [:ready, 'foo', 'bar', :done], buf
437
+ end
438
+
439
+ def test_read_loop_with_max_len
440
+ r, w = IO.pipe
441
+
442
+ w << 'foobar'
443
+ w.close
444
+ buf = []
445
+ r.read_loop(3) { |data| buf << data }
446
+ assert_equal ['foo', 'bar'], buf
447
+ end
419
448
  end
@@ -2,103 +2,103 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class SuperviseTest < MiniTest::Test
6
- def test_supervise
7
- p = spin { supervise }
8
- snooze
9
- f1 = p.spin { receive }
10
- f2 = p.spin { receive }
11
-
12
- snooze
13
- assert_equal p.state, :waiting
14
- f1 << 'foo'
15
- f1.await
16
- snooze
17
-
18
- assert_equal :waiting, p.state
19
- assert_equal :waiting, f2.state
20
-
21
- f2 << 'bar'
22
- f2.await
23
- assert_equal :runnable, p.state
24
- snooze
25
-
26
- assert_equal :dead, p.state
27
- end
28
-
29
- def test_supervise_with_restart
30
- watcher = spin { receive }
31
- parent = spin { supervise(restart: true, watcher: watcher) }
32
- snooze
33
-
34
- buffer = []
35
- f1 = parent.spin do
36
- buffer << 'f1'
37
- end
38
-
39
- f1.await
40
- assert_equal ['f1'], buffer
41
- watcher.await
42
- assert_equal ['f1', 'f1'], buffer
43
- end
44
-
45
- def test_supervise_with_restart_on_error
46
- parent = spin { supervise(restart: true) }
47
- snooze
48
-
49
- buffer = []
50
- f1 = parent.spin do
51
- buffer << 'f1'
52
- buffer << receive
53
- end
54
-
55
- snooze
56
- assert_equal ['f1'], buffer
57
-
58
- f1.raise 'foo'
59
-
60
- 3.times { snooze }
61
-
62
- assert_equal ['f1', 'f1'], buffer
63
- assert_equal :dead, f1.state
64
-
65
- # f1 should have been restarted by supervisor
66
- f1 = parent.children.first
67
- assert_kind_of Fiber, f1
68
-
69
- f1 << 'foo'
70
- f1.await
71
-
72
- assert_equal ['f1', 'f1', 'foo'], buffer
73
- end
74
-
75
- def test_supervisor_termination
76
- f = nil
77
- p = spin do
78
- f = spin { sleep 1 }
79
- supervise
80
- end
81
- sleep 0.01
82
-
83
- p.terminate
84
- p.await
85
-
86
- assert :dead, f.state
87
- assert :dead, p.state
88
- end
89
-
90
- def test_supervisor_termination_with_restart
91
- f = nil
92
- p = spin do
93
- f = spin { sleep 1 }
94
- supervise(restart: true)
95
- end
96
- sleep 0.01
97
-
98
- p.terminate
99
- p.await
100
-
101
- assert :dead, f.state
102
- assert :dead, p.state
103
- end
104
- end
5
+ # class SuperviseTest < MiniTest::Test
6
+ # def test_supervise
7
+ # p = spin { supervise }
8
+ # snooze
9
+ # f1 = p.spin { receive }
10
+ # f2 = p.spin { receive }
11
+
12
+ # snooze
13
+ # assert_equal p.state, :waiting
14
+ # f1 << 'foo'
15
+ # f1.await
16
+ # snooze
17
+
18
+ # assert_equal :waiting, p.state
19
+ # assert_equal :waiting, f2.state
20
+
21
+ # f2 << 'bar'
22
+ # f2.await
23
+ # assert_equal :runnable, p.state
24
+
25
+ # 3.times { snooze }
26
+ # assert_equal :dead, p.state
27
+ # end
28
+
29
+ # def test_supervise_with_restart
30
+ # watcher = spin { receive }
31
+ # parent = spin { supervise(restart: true, watcher: watcher) }
32
+ # snooze
33
+
34
+ # buffer = []
35
+ # f1 = parent.spin do
36
+ # buffer << 'f1'
37
+ # end
38
+
39
+ # f1.await
40
+ # assert_equal ['f1'], buffer
41
+ # watcher.await
42
+ # assert_equal ['f1', 'f1'], buffer
43
+ # end
44
+
45
+ # def test_supervise_with_restart_on_error
46
+ # parent = spin { supervise(restart: true) }
47
+ # snooze
48
+
49
+ # buffer = []
50
+ # f1 = parent.spin do
51
+ # buffer << 'f1'
52
+ # buffer << receive
53
+ # end
54
+
55
+ # snooze
56
+ # assert_equal ['f1'], buffer
57
+
58
+ # f1.raise 'foo'
59
+
60
+ # 3.times { snooze }
61
+
62
+ # assert_equal ['f1', 'f1'], buffer
63
+ # assert_equal :dead, f1.state
64
+
65
+ # # f1 should have been restarted by supervisor
66
+ # f1 = parent.children.first
67
+ # assert_kind_of Fiber, f1
68
+
69
+ # f1 << 'foo'
70
+ # f1.await
71
+
72
+ # assert_equal ['f1', 'f1', 'foo'], buffer
73
+ # end
74
+
75
+ # def test_supervisor_termination
76
+ # f = nil
77
+ # p = spin do
78
+ # f = spin { sleep 1 }
79
+ # supervise
80
+ # end
81
+ # sleep 0.01
82
+
83
+ # p.terminate
84
+ # p.await
85
+
86
+ # assert :dead, f.state
87
+ # assert :dead, p.state
88
+ # end
89
+
90
+ # def test_supervisor_termination_with_restart
91
+ # f = nil
92
+ # p = spin do
93
+ # f = spin { sleep 1 }
94
+ # supervise(restart: true)
95
+ # end
96
+ # sleep 0.01
97
+
98
+ # p.terminate
99
+ # p.await
100
+
101
+ # assert :dead, f.state
102
+ # assert :dead, p.state
103
+ # end
104
+ # end