polyphony 0.99.3 → 0.99.5
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/.rubocop.yml +10 -0
- data/.yardopts +3 -1
- data/README.md +1 -1
- data/docs/readme.md +102 -0
- data/examples/pipes/gzip_http_server.rb +2 -2
- data/examples/pipes/http_server.rb +1 -1
- data/examples/pipes/tcp_proxy.rb +1 -1
- data/ext/polyphony/backend_common.c +4 -4
- data/ext/polyphony/backend_io_uring.c +8 -8
- data/ext/polyphony/backend_libev.c +5 -5
- data/ext/polyphony/fiber.c +32 -41
- data/ext/polyphony/io_extensions.c +50 -37
- data/ext/polyphony/pipe.c +6 -18
- data/ext/polyphony/polyphony.c +63 -133
- data/ext/polyphony/queue.c +25 -63
- data/ext/polyphony/thread.c +3 -12
- data/lib/polyphony/adapters/process.rb +1 -2
- data/lib/polyphony/adapters/sequel.rb +2 -2
- data/lib/polyphony/core/debug.rb +1 -1
- data/lib/polyphony/core/exceptions.rb +1 -1
- data/lib/polyphony/core/global_api.rb +24 -38
- data/lib/polyphony/core/resource_pool.rb +7 -8
- data/lib/polyphony/core/sync.rb +1 -2
- data/lib/polyphony/core/thread_pool.rb +2 -5
- data/lib/polyphony/core/throttler.rb +1 -5
- data/lib/polyphony/core/timer.rb +24 -25
- data/lib/polyphony/extensions/fiber.rb +507 -540
- data/lib/polyphony/extensions/io.rb +3 -12
- data/lib/polyphony/extensions/openssl.rb +2 -23
- data/lib/polyphony/extensions/pipe.rb +4 -15
- data/lib/polyphony/extensions/socket.rb +15 -109
- data/lib/polyphony/extensions/thread.rb +0 -13
- data/lib/polyphony/extensions/timeout.rb +0 -1
- data/lib/polyphony/net.rb +5 -8
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -6
- data/test/test_io.rb +221 -221
- data/test/test_socket.rb +3 -3
- data/test/test_trace.rb +2 -2
- metadata +3 -2
@@ -8,12 +8,11 @@ module Polyphony
|
|
8
8
|
# Watches a forked or spawned process, waiting for it to terminate. If
|
9
9
|
# `cmd` is given it is spawned, otherwise the process is forked with the
|
10
10
|
# given block.
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# If the operation is interrupted for any reason, the spawned or forked
|
13
13
|
# process is killed.
|
14
14
|
#
|
15
15
|
# @param cmd [String, nil] command to spawn
|
16
|
-
# @yield [] block to fork
|
17
16
|
# @return [void]
|
18
17
|
def watch(cmd = nil, &block)
|
19
18
|
terminated = nil
|
@@ -4,10 +4,10 @@ require_relative '../../polyphony'
|
|
4
4
|
require 'sequel'
|
5
5
|
|
6
6
|
module Polyphony
|
7
|
-
|
7
|
+
|
8
8
|
# Sequel ConnectionPool that delegates to Polyphony::ResourcePool.
|
9
9
|
class FiberConnectionPool < Sequel::ConnectionPool
|
10
|
-
|
10
|
+
|
11
11
|
# Initializes the connection pool.
|
12
12
|
#
|
13
13
|
# @param db [any] db to connect to
|
data/lib/polyphony/core/debug.rb
CHANGED
@@ -32,7 +32,7 @@ module Polyphony
|
|
32
32
|
# If an IO instance is given, events are dumped to it instead.
|
33
33
|
#
|
34
34
|
# @param io [IO, nil] IO instance
|
35
|
-
# @yield [Hash] event
|
35
|
+
# @yield [Hash] event information
|
36
36
|
# @return [void]
|
37
37
|
def start_event_firehose(io = nil, &block)
|
38
38
|
Thread.backend.trace_proc = firehose_proc(io, block)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative './throttler'
|
4
4
|
|
5
5
|
module Polyphony
|
6
|
-
|
6
|
+
|
7
7
|
# Global API methods to be included in `::Object`
|
8
8
|
module GlobalAPI
|
9
9
|
|
@@ -11,7 +11,6 @@ module Polyphony
|
|
11
11
|
# given delay.
|
12
12
|
#
|
13
13
|
# @param interval [Number] delay in seconds before running the given block
|
14
|
-
# @yield [] block to run
|
15
14
|
# @return [Fiber] spun fiber
|
16
15
|
def after(interval, &block)
|
17
16
|
spin do
|
@@ -20,14 +19,6 @@ module Polyphony
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
# call-seq:
|
24
|
-
# cancel_after(interval) { ... }
|
25
|
-
# cancel_after(interval, with_exception: exception) { ... }
|
26
|
-
# cancel_after(interval, with_exception: [klass, message]) { ... }
|
27
|
-
# cancel_after(interval) { |timeout| ... }
|
28
|
-
# cancel_after(interval, with_exception: exception) { |timeout| ... }
|
29
|
-
# cancel_after(interval, with_exception: [klass, message]) { |timeout| ... }
|
30
|
-
#
|
31
22
|
# Runs the given block after setting up a cancellation timer for
|
32
23
|
# cancellation. If the cancellation timer elapses, the execution will be
|
33
24
|
# interrupted with an exception defaulting to `Polyphony::Cancel`.
|
@@ -55,10 +46,20 @@ module Polyphony
|
|
55
46
|
# end
|
56
47
|
# end
|
57
48
|
#
|
58
|
-
# @
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
49
|
+
# @overload cancel_after(interval)
|
50
|
+
# @param interval [Number] timout in seconds
|
51
|
+
# @yield [Fiber] timeout fiber
|
52
|
+
# @return [any] block's return value
|
53
|
+
# @overload cancel_after(interval, with_exception: exception)
|
54
|
+
# @param interval [Number] timout in seconds
|
55
|
+
# @param with_exception [Class, Exception] exception or exception class
|
56
|
+
# @yield [Fiber] timeout fiber
|
57
|
+
# @return [any] block's return value
|
58
|
+
# @overload cancel_after(interval, with_exception: [klass, message])
|
59
|
+
# @param interval [Number] timout in seconds
|
60
|
+
# @param with_exception [Array] array containing class and message to use as exception
|
61
|
+
# @yield [Fiber] timeout fiber
|
62
|
+
# @return [any] block's return value
|
62
63
|
def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
|
63
64
|
if block.arity > 0
|
64
65
|
cancel_after_with_optional_reset(interval, with_exception, &block)
|
@@ -70,7 +71,6 @@ module Polyphony
|
|
70
71
|
# Spins up a new fiber.
|
71
72
|
#
|
72
73
|
# @param tag [any] optional tag for the new fiber
|
73
|
-
# @yield [any] fiber block
|
74
74
|
# @return [Fiber] new fiber
|
75
75
|
def spin(tag = nil, &block)
|
76
76
|
Fiber.current.spin(tag, caller, &block)
|
@@ -83,7 +83,6 @@ module Polyphony
|
|
83
83
|
# @param tag [any] optional tag for the new fiber
|
84
84
|
# @param rate [Number, nil] loop rate (times per second)
|
85
85
|
# @param interval [Number, nil] interval between consecutive iterations in seconds
|
86
|
-
# @yield [any] code to run
|
87
86
|
# @return [Fiber] new fiber
|
88
87
|
def spin_loop(tag = nil, rate: nil, interval: nil, &block)
|
89
88
|
if rate || interval
|
@@ -98,7 +97,6 @@ module Polyphony
|
|
98
97
|
# Runs the given code, then waits for any child fibers of the current fibers
|
99
98
|
# to terminate.
|
100
99
|
#
|
101
|
-
# @yield [any] code to run
|
102
100
|
# @return [any] given block's return value
|
103
101
|
def spin_scope(&block)
|
104
102
|
raise unless block
|
@@ -114,18 +112,11 @@ module Polyphony
|
|
114
112
|
# consecutive iterations.
|
115
113
|
#
|
116
114
|
# @param interval [Number] interval between consecutive iterations in seconds
|
117
|
-
# @yield [any] block to run
|
118
115
|
# @return [void]
|
119
116
|
def every(interval, &block)
|
120
117
|
Polyphony.backend_timer_loop(interval, &block)
|
121
118
|
end
|
122
119
|
|
123
|
-
# call-seq:
|
124
|
-
# move_on_after(interval) { ... }
|
125
|
-
# move_on_after(interval, with_value: value) { ... }
|
126
|
-
# move_on_after(interval) { |canceller| ... }
|
127
|
-
# move_on_after(interval, with_value: value) { |canceller| ... }
|
128
|
-
#
|
129
120
|
# Runs the given block after setting up a cancellation timer for
|
130
121
|
# cancellation. If the cancellation timer elapses, the execution will be
|
131
122
|
# interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
|
@@ -159,10 +150,15 @@ module Polyphony
|
|
159
150
|
# end
|
160
151
|
# end
|
161
152
|
#
|
162
|
-
# @
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
153
|
+
# @overload move_on_after(interval) { ... }
|
154
|
+
# @param interval [Number] timout in seconds
|
155
|
+
# @yield [Fiber] timeout fiber
|
156
|
+
# @return [any] block's return value
|
157
|
+
# @overload move_on_after(interval, with_value: value) { ... }
|
158
|
+
# @param interval [Number] timout in seconds
|
159
|
+
# @param with_value [any] return value in case of timeout
|
160
|
+
# @yield [Fiber] timeout fiber
|
161
|
+
# @return [any] block's return value
|
166
162
|
def move_on_after(interval, with_value: nil, &block)
|
167
163
|
if block.arity > 0
|
168
164
|
move_on_after_with_optional_reset(interval, with_value, &block)
|
@@ -191,7 +187,6 @@ module Polyphony
|
|
191
187
|
#
|
192
188
|
# @param args [Array] positional parameters
|
193
189
|
# @param opts [Hash] named parameters
|
194
|
-
# @yield [any] given block
|
195
190
|
# @return [void]
|
196
191
|
def supervise(*args, **opts, &block)
|
197
192
|
Fiber.current.supervise(*args, **opts, &block)
|
@@ -207,12 +202,6 @@ module Polyphony
|
|
207
202
|
Polyphony.backend_sleep(duration) : Polyphony.backend_wait_event(true)
|
208
203
|
end
|
209
204
|
|
210
|
-
# call-seq:
|
211
|
-
# throttled_loop(rate) { ... }
|
212
|
-
# throttled_loop(interval: value) { ... }
|
213
|
-
# throttled_loop(rate: value) { ... }
|
214
|
-
# throttled_loop(rate, count: value) { ... }
|
215
|
-
#
|
216
205
|
# Starts a throttled loop with the given rate. If `count:` is given, the
|
217
206
|
# loop is run for the given number of times. Otherwise, the loop is
|
218
207
|
# infinite. The loop rate (times per second) can be given as the rate
|
@@ -223,7 +212,6 @@ module Polyphony
|
|
223
212
|
# @option opts [Number] :rate loop rate (times per second)
|
224
213
|
# @option opts [Number] :interval loop interval in seconds
|
225
214
|
# @option opts [Number] :count number of iterations (nil for infinite)
|
226
|
-
# @yield [] code to run
|
227
215
|
# @return [void]
|
228
216
|
def throttled_loop(rate = nil, **opts, &block)
|
229
217
|
throttler = Polyphony::Throttler.new(rate || opts)
|
@@ -244,7 +232,6 @@ module Polyphony
|
|
244
232
|
#
|
245
233
|
# @param interval [Number] timeout interval in seconds
|
246
234
|
# @param exception [Exception, Class, Array<class, message>] exception spec
|
247
|
-
# @yield [Fiber] block to run
|
248
235
|
# @return [any] block's return value
|
249
236
|
def cancel_after_with_optional_reset(interval, exception, &block)
|
250
237
|
fiber = Fiber.current
|
@@ -290,7 +277,6 @@ module Polyphony
|
|
290
277
|
#
|
291
278
|
# @param interval [Number] timeout interval in seconds
|
292
279
|
# @param value [any] return value in case of timeout
|
293
|
-
# @yield [Fiber] code to run
|
294
280
|
# @return [any] return value of given block or timeout value
|
295
281
|
def move_on_after_with_optional_reset(interval, value, &block)
|
296
282
|
fiber = Fiber.current
|
@@ -5,13 +5,15 @@ module Polyphony
|
|
5
5
|
class ResourcePool
|
6
6
|
attr_reader :limit, :size
|
7
7
|
|
8
|
-
# Initializes a new resource pool.
|
8
|
+
# Initializes a new resource pool. The given block is used for creating a
|
9
|
+
# resource:
|
9
10
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
11
|
+
# ResourcePool.new { Sequel.connect(DB_URL) }
|
12
|
+
#
|
13
|
+
# @param limit [Integer] maximum open resources
|
14
|
+
def initialize(limit: 4, &block)
|
13
15
|
@allocator = block
|
14
|
-
@limit =
|
16
|
+
@limit = limit
|
15
17
|
@size = 0
|
16
18
|
@stock = Polyphony::Queue.new
|
17
19
|
@acquired_resources = {}
|
@@ -36,7 +38,6 @@ module Polyphony
|
|
36
38
|
# db.query(sql).to_a
|
37
39
|
# end
|
38
40
|
#
|
39
|
-
# @yield [any] code to run
|
40
41
|
# @return [any] return value of block
|
41
42
|
def acquire(&block)
|
42
43
|
fiber = Fiber.current
|
@@ -55,7 +56,6 @@ module Polyphony
|
|
55
56
|
#
|
56
57
|
# @param sym [Symbol] method name
|
57
58
|
# @param args [Array<any>] method arguments
|
58
|
-
# @yield [any] block passed to method
|
59
59
|
# @return [any] result of method call
|
60
60
|
def method_missing(sym, *args, &block)
|
61
61
|
acquire { |r| r.send(sym, *args, &block) }
|
@@ -88,7 +88,6 @@ module Polyphony
|
|
88
88
|
# Acquires a resource from stock, yielding it to the given block.
|
89
89
|
#
|
90
90
|
# @param fiber [Fiber] the fiber the resource will be associated with
|
91
|
-
# @yield [any] given block
|
92
91
|
# @return [any] return value of block
|
93
92
|
def acquire_from_stock(fiber)
|
94
93
|
add_to_stock if (@stock.empty? || @stock.pending?) && @size < @limit
|
data/lib/polyphony/core/sync.rb
CHANGED
@@ -17,7 +17,6 @@ module Polyphony
|
|
17
17
|
# This method is re-entrant. Recursive calls from the given block will not
|
18
18
|
# block.
|
19
19
|
#
|
20
|
-
# @yield [] code to run
|
21
20
|
# @return [any] return value of block
|
22
21
|
def synchronize(&block)
|
23
22
|
return yield if @holding_fiber == Fiber.current
|
@@ -64,7 +63,7 @@ module Polyphony
|
|
64
63
|
# @return [Mutex] self
|
65
64
|
def lock
|
66
65
|
raise ThreadError if owned?
|
67
|
-
|
66
|
+
|
68
67
|
@token = @store.shift
|
69
68
|
@holding_fiber = Fiber.current
|
70
69
|
self
|
@@ -3,16 +3,15 @@
|
|
3
3
|
require 'etc'
|
4
4
|
|
5
5
|
module Polyphony
|
6
|
-
|
6
|
+
|
7
7
|
# Implements a pool of threads
|
8
8
|
class ThreadPool
|
9
|
-
|
9
|
+
|
10
10
|
# The pool size.
|
11
11
|
attr_reader :size
|
12
12
|
|
13
13
|
# Runs the given block on an available thread from the default thread pool.
|
14
14
|
#
|
15
|
-
# @yield [] given block
|
16
15
|
# @return [any] return value of given block
|
17
16
|
def self.process(&block)
|
18
17
|
@default_pool ||= new
|
@@ -41,7 +40,6 @@ module Polyphony
|
|
41
40
|
|
42
41
|
# Runs the given block on an available thread from the pool.
|
43
42
|
#
|
44
|
-
# @yield [] given block
|
45
43
|
# @return [any] return value of block
|
46
44
|
def process(&block)
|
47
45
|
setup unless @task_queue
|
@@ -55,7 +53,6 @@ module Polyphony
|
|
55
53
|
# method does not block. The task will be performed once a thread becomes
|
56
54
|
# available.
|
57
55
|
#
|
58
|
-
# @yield [] given block
|
59
56
|
# @return [Polyphony::ThreadPool] self
|
60
57
|
def cast(&block)
|
61
58
|
setup unless @task_queue
|
@@ -13,10 +13,6 @@ module Polyphony
|
|
13
13
|
@next_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
14
14
|
end
|
15
15
|
|
16
|
-
# call-seq:
|
17
|
-
# throttler.call { ... }
|
18
|
-
# throttler.process { ... }
|
19
|
-
#
|
20
16
|
# Invokes the throttler with the given block. The throttler will
|
21
17
|
# automatically introduce a delay to keep to the maximum specified rate.
|
22
18
|
# The throttler instance is passed to the given block.
|
@@ -32,7 +28,7 @@ module Polyphony
|
|
32
28
|
@next_time += @min_dt
|
33
29
|
break if @next_time > now
|
34
30
|
end
|
35
|
-
|
31
|
+
|
36
32
|
result
|
37
33
|
end
|
38
34
|
alias_method :process, :call
|
data/lib/polyphony/core/timer.rb
CHANGED
@@ -44,7 +44,6 @@ module Polyphony
|
|
44
44
|
# given delay.
|
45
45
|
#
|
46
46
|
# @param interval [Number] delay in seconds before running the given block
|
47
|
-
# @yield [] block to run
|
48
47
|
# @return [Fiber] spun fiber
|
49
48
|
def after(interval, &block)
|
50
49
|
spin do
|
@@ -57,7 +56,6 @@ module Polyphony
|
|
57
56
|
# consecutive iterations.
|
58
57
|
#
|
59
58
|
# @param interval [Number] interval between consecutive iterations in seconds
|
60
|
-
# @yield [] block to run
|
61
59
|
# @return [void]
|
62
60
|
def every(interval)
|
63
61
|
fiber = Fiber.current
|
@@ -74,14 +72,6 @@ module Polyphony
|
|
74
72
|
@timeouts.delete(fiber)
|
75
73
|
end
|
76
74
|
|
77
|
-
# call-seq:
|
78
|
-
# timer.cancel_after(interval) { ... }
|
79
|
-
# timer.cancel_after(interval, with_exception: exception) { ... }
|
80
|
-
# timer.cancel_after(interval, with_exception: [klass, message]) { ... }
|
81
|
-
# timer.cancel_after(interval) { |timeout| ... }
|
82
|
-
# timer.cancel_after(interval, with_exception: exception) { |timeout| ... }
|
83
|
-
# timer.cancel_after(interval, with_exception: [klass, message]) { |timeout| ... }
|
84
|
-
#
|
85
75
|
# Runs the given block after setting up a cancellation timer for
|
86
76
|
# cancellation. If the cancellation timer elapses, the execution will be
|
87
77
|
# interrupted with an exception defaulting to `Polyphony::Cancel`.
|
@@ -108,10 +98,20 @@ module Polyphony
|
|
108
98
|
# end
|
109
99
|
# end
|
110
100
|
#
|
111
|
-
# @
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
101
|
+
# @overload cancel_after(interval)
|
102
|
+
# @param interval [Number] timout in seconds
|
103
|
+
# @yield [Fiber] timeout fiber
|
104
|
+
# @return [any] block's return value
|
105
|
+
# @overload cancel_after(interval, with_exception: exception)
|
106
|
+
# @param interval [Number] timout in seconds
|
107
|
+
# @param with_exception [Class, Exception] exception or exception class
|
108
|
+
# @yield [Fiber] timeout fiber
|
109
|
+
# @return [any] block's return value
|
110
|
+
# @overload cancel_after(interval, with_exception: [klass, message])
|
111
|
+
# @param interval [Number] timout in seconds
|
112
|
+
# @param with_exception [Array] array containing class and message to use as exception
|
113
|
+
# @yield [Fiber] timeout fiber
|
114
|
+
# @return [any] block's return value
|
115
115
|
def cancel_after(interval, with_exception: Polyphony::Cancel)
|
116
116
|
fiber = Fiber.current
|
117
117
|
@timeouts[fiber] = {
|
@@ -124,12 +124,6 @@ module Polyphony
|
|
124
124
|
@timeouts.delete(fiber)
|
125
125
|
end
|
126
126
|
|
127
|
-
# call-seq:
|
128
|
-
# timer.move_on_after(interval) { ... }
|
129
|
-
# timer.move_on_after(interval, with_value: value) { ... }
|
130
|
-
# timer.move_on_after(interval) { |canceller| ... }
|
131
|
-
# timer.move_on_after(interval, with_value: value) { |canceller| ... }
|
132
|
-
#
|
133
127
|
# Runs the given block after setting up a cancellation timer for
|
134
128
|
# cancellation. If the cancellation timer elapses, the execution will be
|
135
129
|
# interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
|
@@ -162,10 +156,15 @@ module Polyphony
|
|
162
156
|
# end
|
163
157
|
# end
|
164
158
|
#
|
165
|
-
# @
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
159
|
+
# @overload move_on_after(interval) { ... }
|
160
|
+
# @param interval [Number] timout in seconds
|
161
|
+
# @yield [Fiber] timeout fiber
|
162
|
+
# @return [any] block's return value
|
163
|
+
# @overload move_on_after(interval, with_value: value) { ... }
|
164
|
+
# @param interval [Number] timout in seconds
|
165
|
+
# @param with_value [any] return value in case of timeout
|
166
|
+
# @yield [Fiber] timeout fiber
|
167
|
+
# @return [any] block's return value
|
169
168
|
def move_on_after(interval, with_value: nil)
|
170
169
|
fiber = Fiber.current
|
171
170
|
@timeouts[fiber] = {
|
@@ -218,7 +217,7 @@ module Polyphony
|
|
218
217
|
|
219
218
|
# Runs a timer iteration, invoking any timeouts that are due.
|
220
219
|
#
|
221
|
-
# @return [void]
|
220
|
+
# @return [void]
|
222
221
|
def update
|
223
222
|
return if @timeouts.empty?
|
224
223
|
|