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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +54 -1
- data/lib/pg_pipeline/bounded_queue.rb +10 -12
- data/lib/pg_pipeline/client.rb +12 -17
- data/lib/pg_pipeline/connection_driver.rb +128 -71
- data/lib/pg_pipeline/pool.rb +82 -48
- data/lib/pg_pipeline/request.rb +5 -7
- data/lib/pg_pipeline/runtime/notification.rb +32 -0
- data/lib/pg_pipeline/runtime/queue.rb +31 -0
- data/lib/pg_pipeline/runtime/semaphore.rb +138 -0
- data/lib/pg_pipeline/runtime/task.rb +124 -0
- data/lib/pg_pipeline/runtime.rb +98 -0
- data/lib/pg_pipeline/version.rb +1 -1
- data/lib/pg_pipeline.rb +1 -0
- metadata +26 -19
|
@@ -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"
|
data/lib/pg_pipeline/version.rb
CHANGED
data/lib/pg_pipeline.rb
CHANGED
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.
|
|
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
|
|
105
|
-
|
|
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
|
-
|
|
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:
|
|
162
|
+
summary: Fiber-scheduler PostgreSQL pipeline multiplexing on top of ruby-pg
|
|
156
163
|
test_files: []
|