polyphony 0.47.5.1 → 0.50.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile.lock +1 -1
  4. data/LICENSE +1 -1
  5. data/TODO.md +37 -17
  6. data/examples/core/nested.rb +21 -0
  7. data/examples/core/suspend.rb +13 -0
  8. data/examples/core/terminate_main_fiber.rb +12 -0
  9. data/examples/io/tcp_proxy.rb +32 -0
  10. data/examples/performance/line_splitting.rb +34 -0
  11. data/examples/performance/loop.rb +32 -0
  12. data/examples/performance/thread-vs-fiber/polyphony_server.rb +6 -2
  13. data/ext/polyphony/backend_common.h +3 -3
  14. data/ext/polyphony/backend_io_uring.c +29 -68
  15. data/ext/polyphony/backend_libev.c +18 -59
  16. data/ext/polyphony/event.c +1 -1
  17. data/ext/polyphony/fiber.c +2 -1
  18. data/ext/polyphony/polyphony.c +0 -2
  19. data/ext/polyphony/polyphony.h +6 -4
  20. data/ext/polyphony/queue.c +2 -2
  21. data/ext/polyphony/runqueue.c +6 -0
  22. data/ext/polyphony/runqueue_ring_buffer.c +9 -0
  23. data/ext/polyphony/runqueue_ring_buffer.h +1 -0
  24. data/ext/polyphony/thread.c +23 -28
  25. data/lib/polyphony.rb +2 -1
  26. data/lib/polyphony/adapters/postgres.rb +3 -3
  27. data/lib/polyphony/adapters/process.rb +2 -0
  28. data/lib/polyphony/core/exceptions.rb +1 -0
  29. data/lib/polyphony/core/global_api.rb +15 -3
  30. data/lib/polyphony/core/thread_pool.rb +3 -1
  31. data/lib/polyphony/core/throttler.rb +1 -1
  32. data/lib/polyphony/core/timer.rb +115 -0
  33. data/lib/polyphony/extensions/core.rb +4 -4
  34. data/lib/polyphony/extensions/fiber.rb +30 -13
  35. data/lib/polyphony/extensions/io.rb +8 -14
  36. data/lib/polyphony/extensions/openssl.rb +4 -4
  37. data/lib/polyphony/extensions/socket.rb +1 -1
  38. data/lib/polyphony/extensions/thread.rb +1 -2
  39. data/lib/polyphony/net.rb +3 -6
  40. data/lib/polyphony/version.rb +1 -1
  41. data/polyphony.gemspec +1 -1
  42. data/test/helper.rb +2 -2
  43. data/test/test_backend.rb +26 -1
  44. data/test/test_fiber.rb +95 -1
  45. data/test/test_global_api.rb +30 -0
  46. data/test/test_io.rb +26 -0
  47. data/test/test_signal.rb +1 -2
  48. data/test/test_socket.rb +5 -5
  49. data/test/test_supervise.rb +1 -1
  50. data/test/test_timer.rb +157 -0
  51. metadata +11 -4
  52. data/ext/polyphony/backend.h +0 -26
@@ -349,6 +349,22 @@ class FiberTest < MiniTest::Test
349
349
  assert_equal [:foo, :terminate], buffer
350
350
  end
351
351
 
352
+ CMD_TERMINATE_MAIN_FIBER = <<~BASH
353
+ ruby -rbundler/setup -rpolyphony -e"spin { sleep 0.1; Thread.current.main_fiber.terminate }; begin; sleep; rescue Polyphony::Terminate; STDOUT << 'terminated'; end" 2>&1
354
+ BASH
355
+
356
+ CMD_TERMINATE_CHILD_FIBER = <<~BASH
357
+ ruby -rbundler/setup -rpolyphony -e"f = spin { sleep }; spin { sleep 0.1; f.terminate }; f.await" 2>&1
358
+ BASH
359
+
360
+ def test_terminate_main_fiber
361
+ output = `#{CMD_TERMINATE_CHILD_FIBER}`
362
+ assert_equal '', output
363
+
364
+ output = `#{CMD_TERMINATE_MAIN_FIBER}`
365
+ assert_equal 'terminated', output
366
+ end
367
+
352
368
  def test_interrupt_timer
353
369
  result = []
354
370
  f = Fiber.current.spin do
@@ -639,7 +655,6 @@ class FiberTest < MiniTest::Test
639
655
  i.close
640
656
  f.await
641
657
  rescue Exception => e
642
- trace e
643
658
  o << e.class.name
644
659
  o.close
645
660
  end
@@ -1038,3 +1053,82 @@ class RestartTest < MiniTest::Test
1038
1053
  assert_equal [f, 'foo', 'bar', :done, f2, 'baz', 42, :done], buffer
1039
1054
  end
1040
1055
  end
1056
+
1057
+ class ChildrenTerminationTest < MiniTest::Test
1058
+ def test_shutdown_all_children
1059
+ f = spin do
1060
+ 1000.times { spin { suspend } }
1061
+ suspend
1062
+ end
1063
+
1064
+ snooze
1065
+ assert_equal 1000, f.children.size
1066
+
1067
+ f.shutdown_all_children
1068
+ assert_equal 0, f.children.size
1069
+ end
1070
+ end
1071
+
1072
+ class GracefulTerminationTest < MiniTest::Test
1073
+ def test_graceful_termination
1074
+ buffer = []
1075
+ f = spin do
1076
+ buffer << 1
1077
+ snooze
1078
+ buffer << 2
1079
+ sleep 3
1080
+ buffer << 3
1081
+ ensure
1082
+ buffer << 4 if Fiber.current.graceful_shutdown?
1083
+ end
1084
+
1085
+ 3.times { snooze }
1086
+ f.terminate(false)
1087
+ f.await
1088
+ assert_equal [1, 2], buffer
1089
+
1090
+ buffer = []
1091
+ f = spin do
1092
+ buffer << 1
1093
+ snooze
1094
+ buffer << 2
1095
+ sleep 3
1096
+ buffer << 3
1097
+ ensure
1098
+ buffer << 4 if Fiber.current.graceful_shutdown?
1099
+ end
1100
+
1101
+ 3.times { snooze }
1102
+ f.terminate(true)
1103
+ f.await
1104
+ assert_equal [1, 2, 4], buffer
1105
+ end
1106
+
1107
+ def test_graceful_child_shutdown
1108
+ buffer = []
1109
+ f0 = spin do
1110
+ f1 = spin do
1111
+ sleep
1112
+ ensure
1113
+ buffer << 1 if Fiber.current.graceful_shutdown?
1114
+ end
1115
+
1116
+ f2 = spin do
1117
+ sleep
1118
+ ensure
1119
+ buffer << 2 if Fiber.current.graceful_shutdown?
1120
+ end
1121
+
1122
+ sleep
1123
+ ensure
1124
+ Fiber.current.terminate_all_children(true) if Fiber.current.graceful_shutdown?
1125
+ Fiber.current.await_all_children
1126
+ end
1127
+
1128
+ 3.times { snooze }
1129
+ f0.terminate(true)
1130
+ f0.await
1131
+
1132
+ assert_equal [1, 2], buffer
1133
+ end
1134
+ end
@@ -307,6 +307,36 @@ class SpinLoopTest < MiniTest::Test
307
307
  f.stop
308
308
  assert_in_range 1..3, counter
309
309
  end
310
+
311
+ def test_spin_loop_break
312
+ i = 0
313
+ f = spin_loop do
314
+ i += 1
315
+ snooze
316
+ break if i >= 5
317
+ end
318
+ f.await
319
+ assert_equal 5, i
320
+
321
+ i = 0
322
+ f = spin_loop do
323
+ i += 1
324
+ snooze
325
+ raise StopIteration if i >= 5
326
+ end
327
+ f.await
328
+ assert_equal 5, i
329
+ end
330
+
331
+ def test_throttled_spin_loop_break
332
+ i = 0
333
+ f = spin_loop(rate: 100) do
334
+ i += 1
335
+ break if i >= 5
336
+ end
337
+ f.await
338
+ assert_equal 5, i
339
+ end
310
340
  end
311
341
 
312
342
  class SpinScopeTest < MiniTest::Test
@@ -92,6 +92,32 @@ class IOTest < MiniTest::Test
92
92
  assert_raises(EOFError) { i.readpartial(1) }
93
93
  end
94
94
 
95
+ def test_gets
96
+ i, o = IO.pipe
97
+
98
+ buf = []
99
+ f = spin do
100
+ while (l = i.gets)
101
+ buf << l
102
+ end
103
+ end
104
+
105
+ snooze
106
+ assert_equal [], buf
107
+
108
+ o << 'fab'
109
+ snooze
110
+ assert_equal [], buf
111
+
112
+ o << "ulous\n"
113
+ 10.times { snooze }
114
+ assert_equal ["fabulous\n"], buf
115
+
116
+ o.close
117
+ f.await
118
+ assert_equal ["fabulous\n"], buf
119
+ end
120
+
95
121
  def test_getc
96
122
  i, o = IO.pipe
97
123
 
@@ -46,8 +46,7 @@ class SignalTrapTest < Minitest::Test
46
46
  end.await
47
47
  rescue Interrupt
48
48
  o.puts "3 - interrupted"
49
- Fiber.current.terminate_all_children
50
- Fiber.current.await_all_children
49
+ Fiber.current.shutdown_all_children
51
50
  ensure
52
51
  o.close
53
52
  end
@@ -60,18 +60,18 @@ class SocketTest < MiniTest::Test
60
60
  end
61
61
 
62
62
  class HTTPClientTest < MiniTest::Test
63
- require 'httparty'
64
63
  require 'json'
65
64
 
66
65
  def test_http
67
- res = HTTParty.get('http://worldtimeapi.org/api/timezone/Europe/Paris')
66
+ res = HTTParty.get('http://ipinfo.io/')
67
+
68
68
  response = JSON.load(res.body)
69
- assert_equal "CET", response['abbreviation']
69
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
70
70
  end
71
71
 
72
72
  def test_https
73
- res = HTTParty.get('https://worldtimeapi.org/api/timezone/Europe/Paris')
73
+ res = HTTParty.get('https://ipinfo.io/')
74
74
  response = JSON.load(res.body)
75
- assert_equal "CET", response['abbreviation']
75
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
76
76
  end
77
77
  end
@@ -20,7 +20,7 @@ class SuperviseTest < MiniTest::Test
20
20
 
21
21
  f2 << 'bar'
22
22
  f2.await
23
- assert_equal :waiting, p.state
23
+ assert_equal :runnable, p.state
24
24
  snooze
25
25
 
26
26
  assert_equal :dead, p.state
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class TimerMoveOnAfterTest < MiniTest::Test
6
+ def setup
7
+ @timer = Polyphony::Timer.new(resolution: 0.01)
8
+ end
9
+
10
+ def teardown
11
+ @timer.stop
12
+ end
13
+
14
+ def test_timer_move_on_after
15
+ t0 = Time.now
16
+ v = @timer.move_on_after(0.1) do
17
+ sleep 1
18
+ :foo
19
+ end
20
+ t1 = Time.now
21
+
22
+ assert_in_range 0.1..0.15, t1 - t0
23
+ assert_nil v
24
+ end
25
+
26
+ def test_timer_move_on_after_with_value
27
+ t0 = Time.now
28
+ v = @timer.move_on_after(0.01, with_value: :bar) do
29
+ sleep 1
30
+ :foo
31
+ end
32
+ t1 = Time.now
33
+
34
+ assert_in_range 0.01..0.025, t1 - t0
35
+ assert_equal :bar, v
36
+ end
37
+
38
+ def test_timer_move_on_after_with_reset
39
+ t0 = Time.now
40
+ v = @timer.move_on_after(0.01, with_value: :moved_on) do
41
+ sleep 0.007
42
+ @timer.reset
43
+ sleep 0.007
44
+ @timer.reset
45
+ sleep 0.007
46
+ nil
47
+ end
48
+ t1 = Time.now
49
+
50
+ assert_nil v
51
+ assert_in_range 0.015..0.03, t1 - t0
52
+ end
53
+ end
54
+
55
+ class TimerCancelAfterTest < MiniTest::Test
56
+ def setup
57
+ @timer = Polyphony::Timer.new(resolution: 0.01)
58
+ end
59
+
60
+ def teardown
61
+ @timer.stop
62
+ end
63
+
64
+ def test_timer_cancel_after
65
+ t0 = Time.now
66
+
67
+ assert_raises Polyphony::Cancel do
68
+ @timer.cancel_after(0.01) do
69
+ sleep 1
70
+ :foo
71
+ end
72
+ end
73
+ t1 = Time.now
74
+ assert_in_range 0.01..0.03, t1 - t0
75
+ end
76
+
77
+ def test_timer_cancel_after_with_reset
78
+ t0 = Time.now
79
+ @timer.cancel_after(0.01) do
80
+ sleep 0.007
81
+ @timer.reset
82
+ sleep 0.007
83
+ end
84
+ t1 = Time.now
85
+ assert_in_range 0.013..0.024, t1 - t0
86
+ end
87
+
88
+ class CustomException < Exception
89
+ end
90
+
91
+ def test_timer_cancel_after_with_custom_exception
92
+ assert_raises CustomException do
93
+ @timer.cancel_after(0.01, with_exception: CustomException) do
94
+ sleep 1
95
+ :foo
96
+ end
97
+ end
98
+
99
+ begin
100
+ err = nil
101
+ @timer.cancel_after(0.01, with_exception: [CustomException, 'custom message']) do
102
+ sleep 1
103
+ :foo
104
+ end
105
+ rescue Exception => err
106
+ ensure
107
+ assert_kind_of CustomException, err
108
+ assert_equal 'custom message', err.message
109
+ end
110
+
111
+
112
+ begin
113
+ e = nil
114
+ @timer.cancel_after(0.01, with_exception: 'foo') do
115
+ sleep 1
116
+ :foo
117
+ end
118
+ rescue => e
119
+ ensure
120
+ assert_kind_of RuntimeError, e
121
+ assert_equal 'foo', e.message
122
+ end
123
+ end
124
+ end
125
+
126
+ class TimerMiscTest < MiniTest::Test
127
+ def setup
128
+ @timer = Polyphony::Timer.new(resolution: 0.001)
129
+ sleep 0
130
+ end
131
+
132
+ def teardown
133
+ @timer.stop
134
+ end
135
+
136
+ def test_timer_after
137
+ buffer = []
138
+ f = @timer.after(0.01) { buffer << 2 }
139
+ assert_kind_of Fiber, f
140
+ snooze
141
+ assert_equal [], buffer
142
+ sleep 0.1
143
+ p :post_sleep
144
+ assert_equal [2], buffer
145
+ end
146
+
147
+ def test_timer_every
148
+ buffer = []
149
+ t0 = Time.now
150
+ f = spin do
151
+ @timer.every(0.01) { buffer << 1 }
152
+ end
153
+ sleep 0.05
154
+ f.stop
155
+ assert_in_range 4..6, buffer.size
156
+ end
157
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.47.5.1
4
+ version: 0.50.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-20 00:00:00.000000000 Z
11
+ date: 2021-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -269,7 +269,7 @@ dependencies:
269
269
  - !ruby/object:Gem::Version
270
270
  version: 0.3.0
271
271
  description:
272
- email: ciconia@gmail.com
272
+ email: sharon@noteflakes.com
273
273
  executables: []
274
274
  extensions:
275
275
  - ext/polyphony/extconf.rb
@@ -353,6 +353,7 @@ files:
353
353
  - examples/core/forking.rb
354
354
  - examples/core/handling-signals.rb
355
355
  - examples/core/interrupt.rb
356
+ - examples/core/nested.rb
356
357
  - examples/core/pingpong.rb
357
358
  - examples/core/recurrent-timer.rb
358
359
  - examples/core/resource_delegate.rb
@@ -360,6 +361,8 @@ files:
360
361
  - examples/core/spin_error_backtrace.rb
361
362
  - examples/core/supervise-process.rb
362
363
  - examples/core/supervisor.rb
364
+ - examples/core/suspend.rb
365
+ - examples/core/terminate_main_fiber.rb
363
366
  - examples/core/thread-sleep.rb
364
367
  - examples/core/thread_pool.rb
365
368
  - examples/core/throttling.rb
@@ -383,6 +386,7 @@ files:
383
386
  - examples/io/raw.rb
384
387
  - examples/io/reline.rb
385
388
  - examples/io/system.rb
389
+ - examples/io/tcp_proxy.rb
386
390
  - examples/io/tcpserver.rb
387
391
  - examples/io/tcpsocket.rb
388
392
  - examples/io/tunnel.rb
@@ -391,6 +395,8 @@ files:
391
395
  - examples/performance/fiber_resume.rb
392
396
  - examples/performance/fiber_transfer.rb
393
397
  - examples/performance/fs_read.rb
398
+ - examples/performance/line_splitting.rb
399
+ - examples/performance/loop.rb
394
400
  - examples/performance/mem-usage.rb
395
401
  - examples/performance/messaging.rb
396
402
  - examples/performance/multi_snooze.rb
@@ -433,7 +439,6 @@ files:
433
439
  - ext/liburing/setup.c
434
440
  - ext/liburing/syscall.c
435
441
  - ext/liburing/syscall.h
436
- - ext/polyphony/backend.h
437
442
  - ext/polyphony/backend_common.h
438
443
  - ext/polyphony/backend_io_uring.c
439
444
  - ext/polyphony/backend_io_uring_context.c
@@ -474,6 +479,7 @@ files:
474
479
  - lib/polyphony/core/sync.rb
475
480
  - lib/polyphony/core/thread_pool.rb
476
481
  - lib/polyphony/core/throttler.rb
482
+ - lib/polyphony/core/timer.rb
477
483
  - lib/polyphony/extensions/core.rb
478
484
  - lib/polyphony/extensions/debug.rb
479
485
  - lib/polyphony/extensions/fiber.rb
@@ -508,6 +514,7 @@ files:
508
514
  - test/test_thread.rb
509
515
  - test/test_thread_pool.rb
510
516
  - test/test_throttler.rb
517
+ - test/test_timer.rb
511
518
  - test/test_trace.rb
512
519
  homepage: https://digital-fabric.github.io/polyphony
513
520
  licenses: