polyphony 0.47.3 → 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +318 -295
  3. data/Gemfile.lock +1 -1
  4. data/LICENSE +1 -1
  5. data/TODO.md +40 -27
  6. data/examples/core/supervisor.rb +3 -3
  7. data/examples/core/worker-thread.rb +3 -4
  8. data/examples/io/tcp_proxy.rb +32 -0
  9. data/examples/io/unix_socket.rb +26 -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 -0
  13. data/ext/polyphony/backend_common.h +2 -2
  14. data/ext/polyphony/backend_io_uring.c +42 -83
  15. data/ext/polyphony/backend_libev.c +32 -77
  16. data/ext/polyphony/event.c +1 -1
  17. data/ext/polyphony/polyphony.c +0 -2
  18. data/ext/polyphony/polyphony.h +5 -4
  19. data/ext/polyphony/queue.c +2 -2
  20. data/ext/polyphony/thread.c +9 -28
  21. data/lib/polyphony.rb +1 -0
  22. data/lib/polyphony/adapters/postgres.rb +3 -3
  23. data/lib/polyphony/core/global_api.rb +14 -2
  24. data/lib/polyphony/core/thread_pool.rb +3 -1
  25. data/lib/polyphony/core/throttler.rb +1 -1
  26. data/lib/polyphony/core/timer.rb +72 -0
  27. data/lib/polyphony/extensions/fiber.rb +32 -8
  28. data/lib/polyphony/extensions/io.rb +8 -14
  29. data/lib/polyphony/extensions/openssl.rb +4 -4
  30. data/lib/polyphony/extensions/socket.rb +68 -16
  31. data/lib/polyphony/version.rb +1 -1
  32. data/polyphony.gemspec +1 -1
  33. data/test/helper.rb +1 -0
  34. data/test/test_backend.rb +1 -1
  35. data/test/test_fiber.rb +64 -1
  36. data/test/test_global_api.rb +30 -0
  37. data/test/test_io.rb +26 -0
  38. data/test/test_socket.rb +32 -6
  39. data/test/test_supervise.rb +2 -1
  40. data/test/test_timer.rb +122 -0
  41. metadata +9 -4
  42. data/ext/polyphony/backend.h +0 -26
@@ -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
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'helper'
4
+ require 'fileutils'
4
5
 
5
6
  class SocketTest < MiniTest::Test
6
7
  def setup
@@ -24,7 +25,32 @@ class SocketTest < MiniTest::Test
24
25
  snooze
25
26
  client = TCPSocket.new('127.0.0.1', port)
26
27
  client.write("1234\n")
27
- assert_equal "1234\n", client.readpartial(8192)
28
+ assert_equal "1234\n", client.recv(8192)
29
+ client.close
30
+ ensure
31
+ server_fiber&.stop
32
+ server_fiber&.await
33
+ server&.close
34
+ end
35
+
36
+ def test_unix_socket
37
+ path = '/tmp/test_unix_socket'
38
+ FileUtils.rm(path) rescue nil
39
+ server = UNIXServer.new(path)
40
+ server_fiber = spin do
41
+ server.accept_loop do |socket|
42
+ spin do
43
+ while (data = socket.gets(8192))
44
+ socket << data
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ snooze
51
+ client = UNIXSocket.new(path)
52
+ client.write("1234\n")
53
+ assert_equal "1234\n", client.recv(8192)
28
54
  client.close
29
55
  ensure
30
56
  server_fiber&.stop
@@ -34,18 +60,18 @@ class SocketTest < MiniTest::Test
34
60
  end
35
61
 
36
62
  class HTTPClientTest < MiniTest::Test
37
- require 'httparty'
38
63
  require 'json'
39
64
 
40
65
  def test_http
41
- res = HTTParty.get('http://worldtimeapi.org/api/timezone/Europe/Paris')
66
+ res = HTTParty.get('http://ipinfo.io/')
67
+
42
68
  response = JSON.load(res.body)
43
- assert_equal "CET", response['abbreviation']
69
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
44
70
  end
45
71
 
46
72
  def test_https
47
- res = HTTParty.get('https://worldtimeapi.org/api/timezone/Europe/Paris')
73
+ res = HTTParty.get('https://ipinfo.io/')
48
74
  response = JSON.load(res.body)
49
- assert_equal "CET", response['abbreviation']
75
+ assert_equal 'https://ipinfo.io/missingauth', response['readme']
50
76
  end
51
77
  end
@@ -20,9 +20,10 @@ class SuperviseTest < MiniTest::Test
20
20
 
21
21
  f2 << 'bar'
22
22
  f2.await
23
+ assert_equal :runnable, p.state
23
24
  snooze
24
25
 
25
- assert_equal :waiting, p.state
26
+ assert_equal :dead, p.state
26
27
  end
27
28
 
28
29
  def test_supervise_with_restart
@@ -0,0 +1,122 @@
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_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_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.02, t1 - t0
35
+ assert_equal :bar, v
36
+ end
37
+
38
+ def test_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
+ nil
45
+ end
46
+ t1 = Time.now
47
+
48
+ assert_nil v
49
+ assert_in_range 0.014..0.02, t1 - t0
50
+ end
51
+ end
52
+
53
+ class CancelAfterTest < MiniTest::Test
54
+ def setup
55
+ @timer = Polyphony::Timer.new(resolution: 0.01)
56
+ end
57
+
58
+ def teardown
59
+ @timer.stop
60
+ end
61
+
62
+ def test_cancel_after
63
+ t0 = Time.now
64
+
65
+ assert_raises Polyphony::Cancel do
66
+ @timer.cancel_after(0.01) do
67
+ sleep 1
68
+ :foo
69
+ end
70
+ end
71
+ t1 = Time.now
72
+ assert_in_range 0.01..0.02, t1 - t0
73
+ end
74
+
75
+ def test_cancel_after_with_reset
76
+ t0 = Time.now
77
+ @timer.cancel_after(0.01) do
78
+ sleep 0.007
79
+ @timer.reset
80
+ sleep 0.007
81
+ end
82
+ t1 = Time.now
83
+ assert_in_range 0.014..0.024, t1 - t0
84
+ end
85
+
86
+ class CustomException < Exception
87
+ end
88
+
89
+ def test_cancel_after_with_custom_exception
90
+ assert_raises CustomException do
91
+ @timer.cancel_after(0.01, with_exception: CustomException) do
92
+ sleep 1
93
+ :foo
94
+ end
95
+ end
96
+
97
+ begin
98
+ err = nil
99
+ @timer.cancel_after(0.01, with_exception: [CustomException, 'custom message']) do
100
+ sleep 1
101
+ :foo
102
+ end
103
+ rescue Exception => err
104
+ ensure
105
+ assert_kind_of CustomException, err
106
+ assert_equal 'custom message', err.message
107
+ end
108
+
109
+
110
+ begin
111
+ e = nil
112
+ @timer.cancel_after(0.01, with_exception: 'foo') do
113
+ sleep 1
114
+ :foo
115
+ end
116
+ rescue => e
117
+ ensure
118
+ assert_kind_of RuntimeError, e
119
+ assert_equal 'foo', e.message
120
+ end
121
+ end
122
+ 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.3
4
+ version: 0.49.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-12 00:00:00.000000000 Z
11
+ date: 2021-01-11 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
@@ -383,13 +383,17 @@ files:
383
383
  - examples/io/raw.rb
384
384
  - examples/io/reline.rb
385
385
  - examples/io/system.rb
386
+ - examples/io/tcp_proxy.rb
386
387
  - examples/io/tcpserver.rb
387
388
  - examples/io/tcpsocket.rb
388
389
  - examples/io/tunnel.rb
390
+ - examples/io/unix_socket.rb
389
391
  - examples/io/zip.rb
390
392
  - examples/performance/fiber_resume.rb
391
393
  - examples/performance/fiber_transfer.rb
392
394
  - examples/performance/fs_read.rb
395
+ - examples/performance/line_splitting.rb
396
+ - examples/performance/loop.rb
393
397
  - examples/performance/mem-usage.rb
394
398
  - examples/performance/messaging.rb
395
399
  - examples/performance/multi_snooze.rb
@@ -432,7 +436,6 @@ files:
432
436
  - ext/liburing/setup.c
433
437
  - ext/liburing/syscall.c
434
438
  - ext/liburing/syscall.h
435
- - ext/polyphony/backend.h
436
439
  - ext/polyphony/backend_common.h
437
440
  - ext/polyphony/backend_io_uring.c
438
441
  - ext/polyphony/backend_io_uring_context.c
@@ -473,6 +476,7 @@ files:
473
476
  - lib/polyphony/core/sync.rb
474
477
  - lib/polyphony/core/thread_pool.rb
475
478
  - lib/polyphony/core/throttler.rb
479
+ - lib/polyphony/core/timer.rb
476
480
  - lib/polyphony/extensions/core.rb
477
481
  - lib/polyphony/extensions/debug.rb
478
482
  - lib/polyphony/extensions/fiber.rb
@@ -507,6 +511,7 @@ files:
507
511
  - test/test_thread.rb
508
512
  - test/test_thread_pool.rb
509
513
  - test/test_throttler.rb
514
+ - test/test_timer.rb
510
515
  - test/test_trace.rb
511
516
  homepage: https://digital-fabric.github.io/polyphony
512
517
  licenses:
@@ -1,26 +0,0 @@
1
- #ifndef BACKEND_H
2
- #define BACKEND_H
3
-
4
- #include "ruby.h"
5
-
6
- typedef VALUE (* backend_pending_count_t)(VALUE self);
7
- typedef VALUE (*backend_poll_t)(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue);
8
- typedef VALUE (* backend_ref_t)(VALUE self);
9
- typedef int (* backend_ref_count_t)(VALUE self);
10
- typedef void (* backend_reset_ref_count_t)(VALUE self);
11
- typedef VALUE (* backend_unref_t)(VALUE self);
12
- typedef VALUE (* backend_wait_event_t)(VALUE self, VALUE raise_on_exception);
13
- typedef VALUE (* backend_wakeup_t)(VALUE self);
14
-
15
- typedef struct backend_interface {
16
- backend_pending_count_t pending_count;
17
- backend_poll_t poll;
18
- backend_ref_t ref;
19
- backend_ref_count_t ref_count;
20
- backend_reset_ref_count_t reset_ref_count;
21
- backend_unref_t unref;
22
- backend_wait_event_t wait_event;
23
- backend_wakeup_t wakeup;
24
- } backend_interface_t;
25
-
26
- #endif /* BACKEND_H */