pg_pipeline 0.2.5 → 0.3.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.
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timeout"
4
+
5
+ require_relative "errors"
6
+
7
+ module PgPipeline
8
+ module Runtime
9
+ class Cancel < Exception; end
10
+ class TimeoutError < Error; end
11
+
12
+ module_function
13
+
14
+ CURRENT_TASK_KEY = :pg_pipeline_current_task
15
+ WAITER_KEY = :pg_pipeline_waiter
16
+
17
+ def spawn(name: nil, &block)
18
+ Task.spawn(name: name, &block)
19
+ end
20
+
21
+ def scheduler!
22
+ Fiber.scheduler or raise Error, "operation requires an active Fiber scheduler"
23
+ end
24
+
25
+ def current_task
26
+ Thread.current[CURRENT_TASK_KEY]
27
+ end
28
+
29
+ def build_waiter(blocker)
30
+ waiter = Thread.current[WAITER_KEY] ||= {
31
+ fiber: nil, scheduler: nil, ready: false, blocker: nil
32
+ }
33
+
34
+ if waiter[:blocker]
35
+ raise Error, "waiter already parked on #{waiter[:blocker].class}; " \
36
+ "a fiber may only park in one place at a time"
37
+ end
38
+
39
+ waiter[:fiber] = Fiber.current
40
+ waiter[:scheduler] = scheduler!
41
+ waiter[:ready] = false
42
+ waiter[:queued] = false
43
+ waiter[:blocker] = blocker
44
+ waiter
45
+ end
46
+
47
+ def park(blocker, waiter)
48
+ scheduler = waiter[:scheduler]
49
+ task = current_task
50
+ task&.enter_block(waiter)
51
+
52
+ until waiter[:ready] || yield
53
+ scheduler.block(blocker, nil)
54
+ task&.raise_if_cancelled!
55
+ end
56
+ nil
57
+ ensure
58
+ waiter[:blocker] = nil
59
+ task&.exit_block
60
+ end
61
+
62
+ def with_waiter(blocker, waiters)
63
+ waiter = build_waiter(blocker)
64
+ waiter[:queued] = true
65
+ waiters << waiter
66
+ yield waiter
67
+ ensure
68
+ waiters.delete(waiter) if waiter[:queued]
69
+ end
70
+
71
+ def wake_dequeued(waiter, blocker)
72
+ waiter[:queued] = false
73
+ wake(waiter, blocker)
74
+ end
75
+
76
+ def with_timeout(duration)
77
+ return yield if duration.nil?
78
+
79
+ timeout = Float(duration)
80
+ raise ArgumentError, "timeout must be non-negative and finite" unless timeout.finite? && timeout >= 0
81
+
82
+ ::Timeout.timeout(timeout, TimeoutError) { yield }
83
+ end
84
+
85
+ def wake(waiter, blocker)
86
+ waiter[:ready] = true
87
+ fiber = waiter[:fiber]
88
+ return unless fiber.alive?
89
+
90
+ waiter[:scheduler].unblock(blocker, fiber)
91
+ end
92
+ end
93
+ end
94
+
95
+ require_relative "runtime/notification"
96
+ require_relative "runtime/queue"
97
+ require_relative "runtime/semaphore"
98
+ require_relative "runtime/task"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgPipeline
4
- VERSION = "0.2.5"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/pg_pipeline.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "pg_pipeline/version"
4
4
  require_relative "pg_pipeline/errors"
5
+ require_relative "pg_pipeline/runtime"
5
6
  require_relative "pg_pipeline/server_caps"
6
7
  require_relative "pg_pipeline/session_guard"
7
8
  require_relative "pg_pipeline/session"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Hajdarov
@@ -9,20 +9,6 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: async
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '2.42'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '2.42'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: pg
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -43,6 +29,20 @@ dependencies:
43
29
  - - "<"
44
30
  - !ruby/object:Gem::Version
45
31
  version: '2'
32
+ - !ruby/object:Gem::Dependency
33
+ name: async
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '2.42'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '2.42'
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: rake
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -101,10 +101,12 @@ dependencies:
101
101
  version: '0.2'
102
102
  description: |
103
103
  A driver-adjacent Ruby control-plane over ruby-pg/libpq. It multiplexes
104
- independent, session-neutral extended-protocol operations from many Async
105
- fibers onto a small number of PostgreSQL connections while keeping explicit
104
+ independent, session-neutral extended-protocol operations from many fibers
105
+ onto a small number of PostgreSQL connections while keeping explicit
106
106
  transactions and session-changing work on exclusive pinned connections.
107
- Control-plane only: all wire work stays in libpq. Zero lines of C.
107
+ Requires any Fiber::Scheduler host (Async::Scheduler, Itsi::Scheduler, …);
108
+ the gem does not depend on a particular reactor. Control-plane only: all
109
+ wire work stays in libpq.
108
110
  email:
109
111
  - romanhajdarov@gmail.com
110
112
  executables: []
@@ -123,6 +125,11 @@ files:
123
125
  - lib/pg_pipeline/pool.rb
124
126
  - lib/pg_pipeline/prepared_statement.rb
125
127
  - lib/pg_pipeline/request.rb
128
+ - lib/pg_pipeline/runtime.rb
129
+ - lib/pg_pipeline/runtime/notification.rb
130
+ - lib/pg_pipeline/runtime/queue.rb
131
+ - lib/pg_pipeline/runtime/semaphore.rb
132
+ - lib/pg_pipeline/runtime/task.rb
126
133
  - lib/pg_pipeline/server_caps.rb
127
134
  - lib/pg_pipeline/session.rb
128
135
  - lib/pg_pipeline/session_guard.rb
@@ -152,5 +159,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
159
  requirements: []
153
160
  rubygems_version: 3.6.7
154
161
  specification_version: 4
155
- summary: Async-native PostgreSQL pipeline multiplexing on top of ruby-pg
162
+ summary: Fiber-scheduler PostgreSQL pipeline multiplexing on top of ruby-pg
156
163
  test_files: []