polyphony 0.43.6 → 0.44.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/Gemfile.lock +5 -1
  4. data/README.md +20 -5
  5. data/TODO.md +10 -14
  6. data/bin/stress.rb +28 -0
  7. data/docs/getting-started/overview.md +2 -2
  8. data/examples/adapters/sequel_mysql.rb +23 -0
  9. data/examples/adapters/sequel_mysql_pool.rb +33 -0
  10. data/examples/core/xx-channels.rb +4 -2
  11. data/examples/core/xx-using-a-mutex.rb +2 -1
  12. data/examples/performance/fiber_transfer.rb +47 -0
  13. data/ext/polyphony/agent.h +41 -0
  14. data/ext/polyphony/event.c +86 -0
  15. data/ext/polyphony/fiber.c +0 -5
  16. data/ext/polyphony/libev_agent.c +201 -128
  17. data/ext/polyphony/polyphony.c +4 -2
  18. data/ext/polyphony/polyphony.h +24 -24
  19. data/ext/polyphony/polyphony_ext.c +4 -2
  20. data/ext/polyphony/queue.c +208 -0
  21. data/ext/polyphony/ring_buffer.c +0 -24
  22. data/ext/polyphony/thread.c +53 -38
  23. data/lib/polyphony.rb +13 -31
  24. data/lib/polyphony/adapters/mysql2.rb +19 -0
  25. data/lib/polyphony/adapters/sequel.rb +45 -0
  26. data/lib/polyphony/core/channel.rb +3 -34
  27. data/lib/polyphony/core/exceptions.rb +11 -0
  28. data/lib/polyphony/core/resource_pool.rb +23 -72
  29. data/lib/polyphony/core/sync.rb +12 -9
  30. data/lib/polyphony/extensions/core.rb +15 -8
  31. data/lib/polyphony/extensions/fiber.rb +4 -0
  32. data/lib/polyphony/extensions/socket.rb +9 -9
  33. data/lib/polyphony/extensions/thread.rb +1 -1
  34. data/lib/polyphony/net.rb +2 -1
  35. data/lib/polyphony/version.rb +1 -1
  36. data/polyphony.gemspec +2 -0
  37. data/test/helper.rb +2 -2
  38. data/test/test_agent.rb +2 -2
  39. data/test/test_event.rb +12 -0
  40. data/test/test_fiber.rb +17 -1
  41. data/test/test_io.rb +14 -0
  42. data/test/test_queue.rb +33 -0
  43. data/test/test_resource_pool.rb +34 -43
  44. data/test/test_signal.rb +2 -26
  45. data/test/test_socket.rb +0 -43
  46. data/test/test_trace.rb +18 -17
  47. metadata +40 -5
  48. data/ext/polyphony/libev_queue.c +0 -288
  49. data/lib/polyphony/event.rb +0 -27
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.6
4
+ version: 0.44.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-07-18 00:00:00.000000000 Z
11
+ date: 2020-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -164,6 +164,34 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: 0.6.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: mysql2
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '='
172
+ - !ruby/object:Gem::Version
173
+ version: 0.5.3
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '='
179
+ - !ruby/object:Gem::Version
180
+ version: 0.5.3
181
+ - !ruby/object:Gem::Dependency
182
+ name: sequel
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '='
186
+ - !ruby/object:Gem::Version
187
+ version: 5.34.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '='
193
+ - !ruby/object:Gem::Version
194
+ version: 5.34.0
167
195
  - !ruby/object:Gem::Dependency
168
196
  name: jekyll
169
197
  requirement: !ruby/object:Gem::Requirement
@@ -241,6 +269,7 @@ files:
241
269
  - Rakefile
242
270
  - TODO.md
243
271
  - bin/polyphony-debug
272
+ - bin/stress.rb
244
273
  - docs/_config.yml
245
274
  - docs/_includes/head.html
246
275
  - docs/_includes/title.html
@@ -292,6 +321,8 @@ files:
292
321
  - examples/adapters/redis_client.rb
293
322
  - examples/adapters/redis_pubsub.rb
294
323
  - examples/adapters/redis_pubsub_perf.rb
324
+ - examples/adapters/sequel_mysql.rb
325
+ - examples/adapters/sequel_mysql_pool.rb
295
326
  - examples/core/01-spinning-up-fibers.rb
296
327
  - examples/core/02-awaiting-fibers.rb
297
328
  - examples/core/03-interrupting.rb
@@ -354,6 +385,7 @@ files:
354
385
  - examples/io/xx-tcpserver.rb
355
386
  - examples/io/xx-tcpsocket.rb
356
387
  - examples/io/xx-zip.rb
388
+ - examples/performance/fiber_transfer.rb
357
389
  - examples/performance/fs_read.rb
358
390
  - examples/performance/mem-usage.rb
359
391
  - examples/performance/messaging.rb
@@ -387,15 +419,17 @@ files:
387
419
  - ext/libev/ev_win32.c
388
420
  - ext/libev/ev_wrap.h
389
421
  - ext/libev/test_libev_win32.c
422
+ - ext/polyphony/agent.h
423
+ - ext/polyphony/event.c
390
424
  - ext/polyphony/extconf.rb
391
425
  - ext/polyphony/fiber.c
392
426
  - ext/polyphony/libev.c
393
427
  - ext/polyphony/libev.h
394
428
  - ext/polyphony/libev_agent.c
395
- - ext/polyphony/libev_queue.c
396
429
  - ext/polyphony/polyphony.c
397
430
  - ext/polyphony/polyphony.h
398
431
  - ext/polyphony/polyphony_ext.c
432
+ - ext/polyphony/queue.c
399
433
  - ext/polyphony/ring_buffer.c
400
434
  - ext/polyphony/ring_buffer.h
401
435
  - ext/polyphony/thread.c
@@ -403,9 +437,11 @@ files:
403
437
  - lib/polyphony.rb
404
438
  - lib/polyphony/adapters/fs.rb
405
439
  - lib/polyphony/adapters/irb.rb
440
+ - lib/polyphony/adapters/mysql2.rb
406
441
  - lib/polyphony/adapters/postgres.rb
407
442
  - lib/polyphony/adapters/process.rb
408
443
  - lib/polyphony/adapters/redis.rb
444
+ - lib/polyphony/adapters/sequel.rb
409
445
  - lib/polyphony/adapters/trace.rb
410
446
  - lib/polyphony/core/channel.rb
411
447
  - lib/polyphony/core/exceptions.rb
@@ -414,7 +450,6 @@ files:
414
450
  - lib/polyphony/core/sync.rb
415
451
  - lib/polyphony/core/thread_pool.rb
416
452
  - lib/polyphony/core/throttler.rb
417
- - lib/polyphony/event.rb
418
453
  - lib/polyphony/extensions/core.rb
419
454
  - lib/polyphony/extensions/fiber.rb
420
455
  - lib/polyphony/extensions/io.rb
@@ -474,7 +509,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
474
509
  - !ruby/object:Gem::Version
475
510
  version: '0'
476
511
  requirements: []
477
- rubygems_version: 3.0.6
512
+ rubygems_version: 3.1.2
478
513
  signing_key:
479
514
  specification_version: 4
480
515
  summary: Fine grained concurrency for Ruby
@@ -1,288 +0,0 @@
1
- #include "polyphony.h"
2
- #include "ring_buffer.h"
3
-
4
- struct async_watcher {
5
- ev_async async;
6
- struct ev_loop *ev_loop;
7
- VALUE fiber;
8
- };
9
-
10
- struct async_watcher_queue {
11
- struct async_watcher **queue;
12
- unsigned int length;
13
- unsigned int count;
14
- unsigned int push_idx;
15
- unsigned int shift_idx;
16
- };
17
-
18
- void async_watcher_queue_init(struct async_watcher_queue *queue) {
19
- queue->length = 1;
20
- queue->count = 0;
21
- queue->queue = malloc(sizeof(struct async_watcher *) * queue->length);
22
- queue->push_idx = 0;
23
- queue->shift_idx = 0;
24
- }
25
-
26
- void async_watcher_queue_free(struct async_watcher_queue *queue) {
27
- free(queue->queue);
28
- }
29
-
30
- void async_watcher_queue_realign(struct async_watcher_queue *queue) {
31
- memmove(
32
- queue->queue,
33
- queue->queue + queue->shift_idx,
34
- queue->count * sizeof(struct async_watcher *)
35
- );
36
- queue->push_idx = queue->push_idx - queue->shift_idx;
37
- queue->shift_idx = 0;
38
- }
39
-
40
- #define QUEUE_REALIGN_THRESHOLD 32
41
-
42
- void async_watcher_queue_push(struct async_watcher_queue *queue, struct async_watcher *watcher) {
43
- if (queue->count == 0) {
44
- queue->push_idx = 0;
45
- queue->shift_idx = 0;
46
- }
47
- if (queue->push_idx == queue->length) {
48
- // prevent shift idx moving too much away from zero
49
- if (queue->length >= QUEUE_REALIGN_THRESHOLD && queue->shift_idx >= (queue->length / 2))
50
- async_watcher_queue_realign(queue);
51
- else {
52
- queue->length = (queue->length == 1) ? 4 : queue->length * 2;
53
- queue->queue = realloc(queue->queue, sizeof(struct async_watcher *) * queue->length);
54
- }
55
- }
56
- queue->count++;
57
- queue->queue[queue->push_idx++] = watcher;
58
- }
59
-
60
- struct async_watcher *async_watcher_queue_shift(struct async_watcher_queue *queue) {
61
- if (queue->count == 0) return 0;
62
-
63
- queue->count--;
64
-
65
- return queue->queue[queue->shift_idx++];
66
- }
67
-
68
- void async_watcher_queue_remove_at_idx(struct async_watcher_queue *queue, unsigned int remove_idx) {
69
- queue->count--;
70
- queue->push_idx--;
71
- if (remove_idx < queue->push_idx)
72
- memmove(
73
- queue->queue + remove_idx,
74
- queue->queue + remove_idx + 1,
75
- (queue->push_idx - remove_idx) * sizeof(struct async_watcher *)
76
- );
77
- }
78
-
79
- void async_watcher_queue_remove_by_fiber(struct async_watcher_queue *queue, VALUE fiber) {
80
- if (queue->count == 0) return;
81
-
82
- for (unsigned idx = queue->shift_idx; idx < queue->push_idx; idx++) {
83
- if (queue->queue[idx]->fiber == fiber) {
84
- async_watcher_queue_remove_at_idx(queue, idx);
85
- return;
86
- }
87
- }
88
- }
89
-
90
- typedef struct queue {
91
- ring_buffer values;
92
- struct async_watcher_queue shift_queue;
93
- } LibevQueue_t;
94
-
95
- VALUE cLibevQueue = Qnil;
96
-
97
- static void LibevQueue_mark(void *ptr) {
98
- LibevQueue_t *queue = ptr;
99
- ring_buffer_mark(&queue->values);
100
- }
101
-
102
- static void LibevQueue_free(void *ptr) {
103
- LibevQueue_t *queue = ptr;
104
- ring_buffer_free(&queue->values);
105
- async_watcher_queue_free(&queue->shift_queue);
106
- xfree(ptr);
107
- }
108
-
109
- static size_t LibevQueue_size(const void *ptr) {
110
- return sizeof(LibevQueue_t);
111
- }
112
-
113
- static const rb_data_type_t LibevQueue_type = {
114
- "Queue",
115
- {LibevQueue_mark, LibevQueue_free, LibevQueue_size,},
116
- 0, 0, 0
117
- };
118
-
119
- static VALUE LibevQueue_allocate(VALUE klass) {
120
- LibevQueue_t *queue;
121
-
122
- queue = ALLOC(LibevQueue_t);
123
- return TypedData_Wrap_Struct(klass, &LibevQueue_type, queue);
124
- }
125
-
126
- #define GetQueue(obj, queue) \
127
- TypedData_Get_Struct((obj), LibevQueue_t, &LibevQueue_type, (queue))
128
-
129
- static VALUE LibevQueue_initialize(VALUE self) {
130
- LibevQueue_t *queue;
131
- GetQueue(self, queue);
132
-
133
- ring_buffer_init(&queue->values);
134
- async_watcher_queue_init(&queue->shift_queue);
135
-
136
- return self;
137
- }
138
-
139
- VALUE LibevQueue_push(VALUE self, VALUE value) {
140
- LibevQueue_t *queue;
141
- GetQueue(self, queue);
142
- if (queue->shift_queue.count > 0) {
143
- struct async_watcher *watcher = async_watcher_queue_shift(&queue->shift_queue);
144
- if (watcher) {
145
- ev_async_send(watcher->ev_loop, &watcher->async);
146
- }
147
- }
148
- ring_buffer_push(&queue->values, value);
149
- return self;
150
- }
151
-
152
- VALUE LibevQueue_unshift(VALUE self, VALUE value) {
153
- LibevQueue_t *queue;
154
- GetQueue(self, queue);
155
- if (queue->shift_queue.count > 0) {
156
- struct async_watcher *watcher = async_watcher_queue_shift(&queue->shift_queue);
157
- if (watcher) {
158
- ev_async_send(watcher->ev_loop, &watcher->async);
159
- }
160
- }
161
- ring_buffer_unshift(&queue->values, value);
162
- return self;
163
- }
164
-
165
- struct ev_loop *LibevAgent_ev_loop(VALUE self);
166
-
167
- void async_watcher_queue_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
168
- struct async_watcher *watcher = (struct async_watcher *)ev_async;
169
- Fiber_make_runnable(watcher->fiber, Qnil);
170
- }
171
-
172
- VALUE libev_agent_await(VALUE self);
173
-
174
- VALUE LibevQueue_shift(VALUE self) {
175
- LibevQueue_t *queue;
176
- GetQueue(self, queue);
177
-
178
- if (queue->values.count == 0) {
179
- struct async_watcher watcher;
180
- VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
181
- VALUE switchpoint_result = Qnil;
182
-
183
- watcher.ev_loop = LibevAgent_ev_loop(agent);
184
- watcher.fiber = rb_fiber_current();
185
- async_watcher_queue_push(&queue->shift_queue, &watcher);
186
- ev_async_init(&watcher.async, async_watcher_queue_callback);
187
- ev_async_start(watcher.ev_loop, &watcher.async);
188
-
189
- switchpoint_result = libev_agent_await(agent);
190
- ev_async_stop(watcher.ev_loop, &watcher.async);
191
-
192
- if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
193
- async_watcher_queue_remove_by_fiber(&queue->shift_queue, watcher.fiber);
194
- return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
195
- }
196
- RB_GC_GUARD(watcher.fiber);
197
- RB_GC_GUARD(agent);
198
- RB_GC_GUARD(switchpoint_result);
199
- }
200
-
201
- return ring_buffer_shift(&queue->values);
202
- }
203
-
204
- VALUE LibevQueue_shift_no_wait(VALUE self) {
205
- LibevQueue_t *queue;
206
- GetQueue(self, queue);
207
-
208
- return ring_buffer_shift(&queue->values);
209
- }
210
-
211
- VALUE LibevQueue_delete(VALUE self, VALUE value) {
212
- LibevQueue_t *queue;
213
- GetQueue(self, queue);
214
-
215
- ring_buffer_delete(&queue->values, value);
216
- return self;
217
- }
218
-
219
- VALUE LibevQueue_clear(VALUE self) {
220
- LibevQueue_t *queue;
221
- GetQueue(self, queue);
222
-
223
- ring_buffer_clear(&queue->values);
224
- return self;
225
- }
226
-
227
- long LibevQueue_len(VALUE self) {
228
- LibevQueue_t *queue;
229
- GetQueue(self, queue);
230
-
231
- return queue->values.count;
232
- }
233
-
234
- VALUE LibevQueue_shift_each(VALUE self) {
235
- LibevQueue_t *queue;
236
- GetQueue(self, queue);
237
-
238
- ring_buffer_shift_each(&queue->values);
239
- return self;
240
- }
241
-
242
- VALUE LibevQueue_shift_all(VALUE self) {
243
- LibevQueue_t *queue;
244
- GetQueue(self, queue);
245
-
246
- return ring_buffer_shift_all(&queue->values);
247
- }
248
-
249
- VALUE LibevQueue_empty_p(VALUE self) {
250
- LibevQueue_t *queue;
251
- GetQueue(self, queue);
252
-
253
- return (queue->values.count == 0) ? Qtrue : Qfalse;
254
- }
255
-
256
- void LibevQueue_trace(VALUE self) {
257
- LibevQueue_t *queue;
258
- GetQueue(self, queue);
259
-
260
- printf(
261
- "queue size: %d count: %d head: %d tail: %d\n",
262
- queue->values.size,
263
- queue->values.count,
264
- queue->values.head,
265
- queue->values.tail
266
- );
267
- }
268
-
269
- void Init_LibevQueue() {
270
- cLibevQueue = rb_define_class_under(mPolyphony, "LibevQueue", rb_cData);
271
- rb_define_alloc_func(cLibevQueue, LibevQueue_allocate);
272
-
273
- rb_define_method(cLibevQueue, "initialize", LibevQueue_initialize, 0);
274
- rb_define_method(cLibevQueue, "push", LibevQueue_push, 1);
275
- rb_define_method(cLibevQueue, "<<", LibevQueue_push, 1);
276
- rb_define_method(cLibevQueue, "unshift", LibevQueue_unshift, 1);
277
-
278
- rb_define_method(cLibevQueue, "shift", LibevQueue_shift, 0);
279
- rb_define_method(cLibevQueue, "pop", LibevQueue_shift, 0);
280
- rb_define_method(cLibevQueue, "shift_no_wait", LibevQueue_shift_no_wait, 0);
281
- rb_define_method(cLibevQueue, "delete", LibevQueue_delete, 1);
282
-
283
- rb_define_method(cLibevQueue, "shift_each", LibevQueue_shift_each, 0);
284
- rb_define_method(cLibevQueue, "shift_all", LibevQueue_shift_all, 0);
285
- rb_define_method(cLibevQueue, "empty?", LibevQueue_empty_p, 0);
286
- }
287
-
288
-
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Polyphony
4
- # Event watcher for thread-safe synchronisation
5
- class Event
6
- def initialize
7
- @i, @o = IO.pipe
8
- end
9
-
10
- def await
11
- Thread.current.agent.read(@i, +'', 8192, false)
12
- raise @value if @value.is_a?(Exception)
13
-
14
- @value
15
- end
16
-
17
- def await_no_raise
18
- Thread.current.agent.read(@i, +'', 8192, false)
19
- @value
20
- end
21
-
22
- def signal(value = nil)
23
- @value = value
24
- Thread.current.agent.write(@o, '1')
25
- end
26
- end
27
- end