polyphony 0.43.2 → 0.43.8
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/.github/workflows/test.yml +2 -2
- data/CHANGELOG.md +43 -0
- data/Gemfile.lock +2 -2
- data/README.md +2 -0
- data/TODO.md +2 -3
- data/docs/_includes/head.html +40 -0
- data/docs/_includes/title.html +1 -0
- data/docs/_user-guide/web-server.md +11 -11
- data/docs/getting-started/overview.md +4 -4
- data/docs/index.md +4 -3
- data/docs/main-concepts/design-principles.md +23 -34
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/docs/polyphony-logo.png +0 -0
- data/examples/adapters/concurrent-ruby.rb +9 -0
- data/examples/core/xx-daemon.rb +14 -0
- data/examples/io/xx-happy-eyeballs.rb +21 -22
- data/examples/io/xx-zip.rb +19 -0
- data/examples/performance/fiber_transfer.rb +47 -0
- data/examples/performance/mem-usage.rb +34 -28
- data/examples/performance/messaging.rb +29 -0
- data/examples/performance/multi_snooze.rb +11 -9
- data/examples/xx-spin.rb +32 -0
- data/ext/polyphony/libev_agent.c +181 -24
- data/ext/polyphony/polyphony.c +0 -2
- data/ext/polyphony/polyphony.h +14 -7
- data/ext/polyphony/polyphony_ext.c +2 -2
- data/ext/polyphony/queue.c +168 -0
- data/ext/polyphony/ring_buffer.c +96 -0
- data/ext/polyphony/ring_buffer.h +28 -0
- data/ext/polyphony/thread.c +16 -8
- data/lib/polyphony.rb +28 -12
- data/lib/polyphony/core/global_api.rb +5 -3
- data/lib/polyphony/core/resource_pool.rb +19 -9
- data/lib/polyphony/core/thread_pool.rb +1 -1
- data/lib/polyphony/event.rb +5 -15
- data/lib/polyphony/extensions/core.rb +40 -0
- data/lib/polyphony/extensions/fiber.rb +9 -14
- data/lib/polyphony/extensions/io.rb +17 -16
- data/lib/polyphony/extensions/openssl.rb +8 -0
- data/lib/polyphony/extensions/socket.rb +12 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +1 -1
- data/test/q.rb +24 -0
- data/test/test_agent.rb +3 -3
- data/test/test_event.rb +11 -0
- data/test/test_fiber.rb +3 -3
- data/test/test_global_api.rb +48 -15
- data/test/test_io.rb +24 -2
- data/test/test_queue.rb +39 -1
- data/test/test_resource_pool.rb +12 -0
- data/test/test_throttler.rb +6 -5
- data/test/test_trace.rb +18 -17
- metadata +15 -4
- data/ext/polyphony/libev_queue.c +0 -217
data/test/test_event.rb
CHANGED
@@ -45,4 +45,15 @@ class EventTest < MiniTest::Test
|
|
45
45
|
t&.kill
|
46
46
|
t&.join
|
47
47
|
end
|
48
|
+
|
49
|
+
def test_exception_while_waiting_for_event
|
50
|
+
e = Polyphony::Event.new
|
51
|
+
|
52
|
+
f = spin { e.await }
|
53
|
+
g = spin { f.raise 'foo' }
|
54
|
+
|
55
|
+
assert_raises(RuntimeError) do
|
56
|
+
f.await
|
57
|
+
end
|
58
|
+
end
|
48
59
|
end
|
data/test/test_fiber.rb
CHANGED
@@ -482,9 +482,9 @@ class FiberTest < MiniTest::Test
|
|
482
482
|
def test_select_from_multiple_fibers
|
483
483
|
sleep 0
|
484
484
|
buffer = []
|
485
|
-
f1 = spin { sleep 0.
|
486
|
-
f2 = spin { sleep 0.
|
487
|
-
f3 = spin { sleep 0.
|
485
|
+
f1 = spin { sleep 0.1; buffer << :foo; :foo }
|
486
|
+
f2 = spin { sleep 0.3; buffer << :bar; :bar }
|
487
|
+
f3 = spin { sleep 0.5; buffer << :baz; :baz }
|
488
488
|
|
489
489
|
selected, result = Fiber.select(f1, f2, f3)
|
490
490
|
assert_equal :foo, result
|
data/test/test_global_api.rb
CHANGED
@@ -106,7 +106,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
106
106
|
end
|
107
107
|
t1 = Time.now
|
108
108
|
|
109
|
-
assert t1 - t0 < 0.
|
109
|
+
assert t1 - t0 < 0.1
|
110
110
|
assert_nil v
|
111
111
|
end
|
112
112
|
|
@@ -118,7 +118,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
118
118
|
end
|
119
119
|
t1 = Time.now
|
120
120
|
|
121
|
-
assert t1 - t0 < 0.
|
121
|
+
assert t1 - t0 < 0.1
|
122
122
|
assert_equal :bar, v
|
123
123
|
end
|
124
124
|
|
@@ -129,7 +129,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
129
129
|
assert_equal Fiber.current, f.parent
|
130
130
|
v = sleep 1
|
131
131
|
t1 = Time.now
|
132
|
-
assert t1 - t0 < 0.
|
132
|
+
assert t1 - t0 < 0.1
|
133
133
|
assert_equal 'foo', v
|
134
134
|
end
|
135
135
|
end
|
@@ -159,6 +159,30 @@ class CancelAfterTest < MiniTest::Test
|
|
159
159
|
t1 = Time.now
|
160
160
|
assert t1 - t0 < 0.1
|
161
161
|
end
|
162
|
+
|
163
|
+
class CustomException < Exception
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_cancel_after_with_custom_exception
|
167
|
+
assert_raises CustomException do
|
168
|
+
cancel_after(0.01, with_exception: CustomException) do
|
169
|
+
sleep 1
|
170
|
+
:foo
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
begin
|
175
|
+
e = nil
|
176
|
+
cancel_after(0.01, with_exception: 'foo') do
|
177
|
+
sleep 1
|
178
|
+
:foo
|
179
|
+
end
|
180
|
+
rescue => e
|
181
|
+
ensure
|
182
|
+
assert_kind_of RuntimeError, e
|
183
|
+
assert_equal 'foo', e.message
|
184
|
+
end
|
185
|
+
end
|
162
186
|
end
|
163
187
|
|
164
188
|
|
@@ -187,13 +211,13 @@ class SpinLoopTest < MiniTest::Test
|
|
187
211
|
|
188
212
|
def test_spin_loop_location
|
189
213
|
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
190
|
-
f = spin_loop {}
|
214
|
+
f = spin_loop { snooze }
|
191
215
|
|
192
216
|
assert_match location, f.location
|
193
217
|
end
|
194
218
|
|
195
219
|
def test_spin_loop_tag
|
196
|
-
f = spin_loop(:my_loop) {}
|
220
|
+
f = spin_loop(:my_loop) { snooze }
|
197
221
|
|
198
222
|
assert_equal :my_loop, f.tag
|
199
223
|
end
|
@@ -201,10 +225,13 @@ class SpinLoopTest < MiniTest::Test
|
|
201
225
|
def test_spin_loop_with_rate
|
202
226
|
buffer = []
|
203
227
|
counter = 0
|
204
|
-
|
228
|
+
t0 = Time.now
|
229
|
+
f = spin_loop(rate: 10) { buffer << (counter += 1) }
|
205
230
|
sleep 0.2
|
206
231
|
f.stop
|
207
|
-
|
232
|
+
elapsed = Time.now - t0
|
233
|
+
expected = (elapsed * 10).to_i
|
234
|
+
assert counter >= expected - 1 && counter <= expected + 1
|
208
235
|
end
|
209
236
|
end
|
210
237
|
|
@@ -212,12 +239,15 @@ class ThrottledLoopTest < MiniTest::Test
|
|
212
239
|
def test_throttled_loop
|
213
240
|
buffer = []
|
214
241
|
counter = 0
|
242
|
+
t0 = Time.now
|
215
243
|
f = spin do
|
216
|
-
throttled_loop(
|
244
|
+
throttled_loop(10) { buffer << (counter += 1) }
|
217
245
|
end
|
218
|
-
sleep 0.
|
246
|
+
sleep 0.3
|
219
247
|
f.stop
|
220
|
-
|
248
|
+
elapsed = Time.now - t0
|
249
|
+
expected = (elapsed * 10).to_i
|
250
|
+
assert counter >= expected - 1 && counter <= expected + 1
|
221
251
|
end
|
222
252
|
|
223
253
|
def test_throttled_loop_with_count
|
@@ -243,19 +273,22 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
243
273
|
|
244
274
|
def test_every
|
245
275
|
buffer = []
|
276
|
+
t0 = Time.now
|
246
277
|
f = spin do
|
247
|
-
every(0.
|
278
|
+
every(0.1) { buffer << 1 }
|
248
279
|
end
|
249
|
-
sleep 0.
|
280
|
+
sleep 0.5
|
250
281
|
f.stop
|
251
|
-
|
282
|
+
elapsed = Time.now - t0
|
283
|
+
expected = (elapsed / 0.1).to_i
|
284
|
+
assert buffer.size >= expected - 2 && buffer.size <= expected + 2
|
252
285
|
end
|
253
286
|
|
254
287
|
def test_sleep
|
255
288
|
t0 = Time.now
|
256
|
-
sleep 0.
|
289
|
+
sleep 0.1
|
257
290
|
elapsed = Time.now - t0
|
258
|
-
assert (0.
|
291
|
+
assert (0.05..0.15).include? elapsed
|
259
292
|
|
260
293
|
f = spin { sleep }
|
261
294
|
snooze
|
data/test/test_io.rb
CHANGED
@@ -30,6 +30,14 @@ class IOTest < MiniTest::Test
|
|
30
30
|
assert_equal 'hello', msg
|
31
31
|
end
|
32
32
|
|
33
|
+
def test_write_multiple_arguments
|
34
|
+
i, o = IO.pipe
|
35
|
+
count = o.write('a', 'b', "\n", 'c')
|
36
|
+
assert_equal 4, count
|
37
|
+
o.close
|
38
|
+
assert_equal "ab\nc", i.read
|
39
|
+
end
|
40
|
+
|
33
41
|
def test_that_double_chevron_method_returns_io
|
34
42
|
assert_equal @o, @o << 'foo'
|
35
43
|
|
@@ -83,6 +91,20 @@ class IOTest < MiniTest::Test
|
|
83
91
|
|
84
92
|
assert_raises(EOFError) { i.readpartial(1) }
|
85
93
|
end
|
94
|
+
|
95
|
+
# see https://github.com/digital-fabric/polyphony/issues/30
|
96
|
+
def test_reopened_tempfile
|
97
|
+
file = Tempfile.new
|
98
|
+
file << 'hello: world'
|
99
|
+
file.close
|
100
|
+
|
101
|
+
buf = nil
|
102
|
+
File.open(file, 'r:bom|utf-8') do |f|
|
103
|
+
buf = f.read(16384)
|
104
|
+
end
|
105
|
+
|
106
|
+
assert_equal 'hello: world', buf
|
107
|
+
end
|
86
108
|
end
|
87
109
|
|
88
110
|
class IOClassMethodsTest < MiniTest::Test
|
@@ -121,7 +143,7 @@ class IOClassMethodsTest < MiniTest::Test
|
|
121
143
|
assert_equal "end\n", lines[-1]
|
122
144
|
end
|
123
145
|
|
124
|
-
def
|
146
|
+
def test_read_class_method
|
125
147
|
s = IO.read(__FILE__)
|
126
148
|
assert_kind_of String, s
|
127
149
|
assert(!s.empty?)
|
@@ -144,7 +166,7 @@ class IOClassMethodsTest < MiniTest::Test
|
|
144
166
|
|
145
167
|
WRITE_DATA = "foo\nbar קוקו"
|
146
168
|
|
147
|
-
def
|
169
|
+
def test_write_class_method
|
148
170
|
fn = '/tmp/test_write'
|
149
171
|
FileUtils.rm(fn) rescue nil
|
150
172
|
|
data/test/test_queue.rb
CHANGED
@@ -8,7 +8,7 @@ class QueueTest < MiniTest::Test
|
|
8
8
|
@queue = Polyphony::Queue.new
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def test_push_shift
|
12
12
|
spin {
|
13
13
|
@queue << 42
|
14
14
|
}
|
@@ -21,6 +21,18 @@ class QueueTest < MiniTest::Test
|
|
21
21
|
assert_equal [1, 2, 3, 4], buf
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_unshift
|
25
|
+
@queue.push 1
|
26
|
+
@queue.push 2
|
27
|
+
@queue.push 3
|
28
|
+
@queue.unshift 4
|
29
|
+
|
30
|
+
buf = []
|
31
|
+
buf << @queue.shift while !@queue.empty?
|
32
|
+
|
33
|
+
assert_equal [4, 1, 2, 3], buf
|
34
|
+
end
|
35
|
+
|
24
36
|
def test_multiple_waiters
|
25
37
|
a = spin { @queue.shift }
|
26
38
|
b = spin { @queue.shift }
|
@@ -41,6 +53,19 @@ class QueueTest < MiniTest::Test
|
|
41
53
|
buf = []
|
42
54
|
@queue.shift_each { |i| buf << i }
|
43
55
|
assert_equal [1, 2, 3, 4], buf
|
56
|
+
|
57
|
+
buf = []
|
58
|
+
@queue.shift_each { |i| buf << i }
|
59
|
+
assert_equal [], buf
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_shift_all
|
63
|
+
(1..4).each { |i| @queue << i }
|
64
|
+
buf = @queue.shift_all
|
65
|
+
assert_equal [1, 2, 3, 4], buf
|
66
|
+
|
67
|
+
buf = @queue.shift_all
|
68
|
+
assert_equal [], buf
|
44
69
|
end
|
45
70
|
|
46
71
|
def test_empty?
|
@@ -71,4 +96,17 @@ class QueueTest < MiniTest::Test
|
|
71
96
|
assert_nil f2.await
|
72
97
|
assert_equal :bar, f3.await
|
73
98
|
end
|
99
|
+
|
100
|
+
def test_fiber_removal_from_queue_simple
|
101
|
+
f1 = spin { @queue.shift }
|
102
|
+
|
103
|
+
# let fibers run
|
104
|
+
snooze
|
105
|
+
|
106
|
+
f1.stop
|
107
|
+
snooze
|
108
|
+
|
109
|
+
@queue << :foo
|
110
|
+
assert_nil f1.await
|
111
|
+
end
|
74
112
|
end
|
data/test/test_resource_pool.rb
CHANGED
@@ -123,4 +123,16 @@ class ResourcePoolTest < MiniTest::Test
|
|
123
123
|
pool.preheat!
|
124
124
|
assert_equal 2, pool.size
|
125
125
|
end
|
126
|
+
|
127
|
+
def test_reentrant_resource_pool
|
128
|
+
resources = [+'a', +'b']
|
129
|
+
pool = Polyphony::ResourcePool.new(limit: 1) { resources.shift }
|
130
|
+
|
131
|
+
pool.acquire do |r|
|
132
|
+
assert_equal 'a', r
|
133
|
+
pool.acquire do |r|
|
134
|
+
assert_equal 'a', r
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
126
138
|
end
|
data/test/test_throttler.rb
CHANGED
@@ -4,14 +4,15 @@ require_relative 'helper'
|
|
4
4
|
|
5
5
|
class ThrottlerTest < MiniTest::Test
|
6
6
|
def test_throttler_with_rate
|
7
|
-
t = Polyphony::Throttler.new(
|
7
|
+
t = Polyphony::Throttler.new(10)
|
8
8
|
buffer = []
|
9
|
+
t0 = Time.now
|
9
10
|
f = spin { loop { t.process { buffer << 1 } } }
|
10
|
-
sleep 0.
|
11
|
+
sleep 0.2
|
11
12
|
f.stop
|
12
|
-
|
13
|
-
|
14
|
-
assert buffer.size <=
|
13
|
+
elapsed = Time.now - t0
|
14
|
+
expected = (elapsed * 10).to_i
|
15
|
+
assert buffer.size >= expected - 1 && buffer.size <= expected + 1
|
15
16
|
ensure
|
16
17
|
t.stop
|
17
18
|
end
|
data/test/test_trace.rb
CHANGED
@@ -34,7 +34,8 @@ class TraceTest < MiniTest::Test
|
|
34
34
|
|
35
35
|
def test_2_fiber_trace
|
36
36
|
records = []
|
37
|
-
|
37
|
+
thread = Thread.current
|
38
|
+
t = Polyphony::Trace.new(:fiber_all) { |r| records << r if Thread.current == thread && r[:event] =~ /^fiber_/ }
|
38
39
|
t.enable
|
39
40
|
Polyphony.trace(true)
|
40
41
|
|
@@ -42,23 +43,23 @@ class TraceTest < MiniTest::Test
|
|
42
43
|
suspend
|
43
44
|
sleep 0
|
44
45
|
|
45
|
-
events = records.map { |r| [r[:fiber], r[:event]] }
|
46
|
+
events = records.map { |r| [r[:fiber] == f ? :f : :current, r[:event]] }
|
46
47
|
assert_equal [
|
47
|
-
[f, :fiber_create],
|
48
|
-
[f, :fiber_schedule],
|
49
|
-
[
|
50
|
-
[f, :fiber_run],
|
51
|
-
[f, :fiber_switchpoint],
|
52
|
-
[f, :fiber_ev_loop_enter],
|
53
|
-
[f, :fiber_schedule],
|
54
|
-
[f, :fiber_ev_loop_leave],
|
55
|
-
[f, :fiber_run],
|
56
|
-
[f, :fiber_terminate],
|
57
|
-
[
|
58
|
-
[
|
59
|
-
[
|
60
|
-
[
|
61
|
-
[
|
48
|
+
[:f, :fiber_create],
|
49
|
+
[:f, :fiber_schedule],
|
50
|
+
[:current, :fiber_switchpoint],
|
51
|
+
[:f, :fiber_run],
|
52
|
+
[:f, :fiber_switchpoint],
|
53
|
+
[:f, :fiber_ev_loop_enter],
|
54
|
+
[:f, :fiber_schedule],
|
55
|
+
[:f, :fiber_ev_loop_leave],
|
56
|
+
[:f, :fiber_run],
|
57
|
+
[:f, :fiber_terminate],
|
58
|
+
[:current, :fiber_switchpoint],
|
59
|
+
[:current, :fiber_ev_loop_enter],
|
60
|
+
[:current, :fiber_schedule],
|
61
|
+
[:current, :fiber_ev_loop_leave],
|
62
|
+
[:current, :fiber_run]
|
62
63
|
], events
|
63
64
|
ensure
|
64
65
|
t&.disable
|
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.43.
|
4
|
+
version: 0.43.8
|
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-07-
|
11
|
+
date: 2020-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -242,6 +242,8 @@ files:
|
|
242
242
|
- TODO.md
|
243
243
|
- bin/polyphony-debug
|
244
244
|
- docs/_config.yml
|
245
|
+
- docs/_includes/head.html
|
246
|
+
- docs/_includes/title.html
|
245
247
|
- docs/_sass/custom/custom.scss
|
246
248
|
- docs/_sass/overrides.scss
|
247
249
|
- docs/_user-guide/all-about-timers.md
|
@@ -280,6 +282,7 @@ files:
|
|
280
282
|
- docs/main-concepts/fiber-scheduling.md
|
281
283
|
- docs/main-concepts/index.md
|
282
284
|
- docs/polyphony-logo.png
|
285
|
+
- examples/adapters/concurrent-ruby.rb
|
283
286
|
- examples/adapters/pg_client.rb
|
284
287
|
- examples/adapters/pg_notify.rb
|
285
288
|
- examples/adapters/pg_pool.rb
|
@@ -297,6 +300,7 @@ files:
|
|
297
300
|
- examples/core/xx-at_exit.rb
|
298
301
|
- examples/core/xx-caller.rb
|
299
302
|
- examples/core/xx-channels.rb
|
303
|
+
- examples/core/xx-daemon.rb
|
300
304
|
- examples/core/xx-deadlock.rb
|
301
305
|
- examples/core/xx-deferring-an-operation.rb
|
302
306
|
- examples/core/xx-erlang-style-genserver.rb
|
@@ -349,8 +353,11 @@ files:
|
|
349
353
|
- examples/io/xx-system.rb
|
350
354
|
- examples/io/xx-tcpserver.rb
|
351
355
|
- examples/io/xx-tcpsocket.rb
|
356
|
+
- examples/io/xx-zip.rb
|
357
|
+
- examples/performance/fiber_transfer.rb
|
352
358
|
- examples/performance/fs_read.rb
|
353
359
|
- examples/performance/mem-usage.rb
|
360
|
+
- examples/performance/messaging.rb
|
354
361
|
- examples/performance/multi_snooze.rb
|
355
362
|
- examples/performance/snooze.rb
|
356
363
|
- examples/performance/snooze_raw.rb
|
@@ -364,6 +371,7 @@ files:
|
|
364
371
|
- examples/performance/xx-array.rb
|
365
372
|
- examples/performance/xx-fiber-switch.rb
|
366
373
|
- examples/performance/xx-snooze.rb
|
374
|
+
- examples/xx-spin.rb
|
367
375
|
- ext/libev/Changes
|
368
376
|
- ext/libev/LICENSE
|
369
377
|
- ext/libev/README
|
@@ -385,10 +393,12 @@ files:
|
|
385
393
|
- ext/polyphony/libev.c
|
386
394
|
- ext/polyphony/libev.h
|
387
395
|
- ext/polyphony/libev_agent.c
|
388
|
-
- ext/polyphony/libev_queue.c
|
389
396
|
- ext/polyphony/polyphony.c
|
390
397
|
- ext/polyphony/polyphony.h
|
391
398
|
- ext/polyphony/polyphony_ext.c
|
399
|
+
- ext/polyphony/queue.c
|
400
|
+
- ext/polyphony/ring_buffer.c
|
401
|
+
- ext/polyphony/ring_buffer.h
|
392
402
|
- ext/polyphony/thread.c
|
393
403
|
- ext/polyphony/tracing.c
|
394
404
|
- lib/polyphony.rb
|
@@ -418,6 +428,7 @@ files:
|
|
418
428
|
- test/coverage.rb
|
419
429
|
- test/eg.rb
|
420
430
|
- test/helper.rb
|
431
|
+
- test/q.rb
|
421
432
|
- test/run.rb
|
422
433
|
- test/stress.rb
|
423
434
|
- test/test_agent.rb
|
@@ -464,7 +475,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
464
475
|
- !ruby/object:Gem::Version
|
465
476
|
version: '0'
|
466
477
|
requirements: []
|
467
|
-
rubygems_version: 3.
|
478
|
+
rubygems_version: 3.1.2
|
468
479
|
signing_key:
|
469
480
|
specification_version: 4
|
470
481
|
summary: Fine grained concurrency for Ruby
|