pg_pipeline 0.3.3 → 0.3.4
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 +15 -0
- data/lib/pg_pipeline/bounded_queue.rb +8 -6
- data/lib/pg_pipeline/client.rb +55 -37
- data/lib/pg_pipeline/connection_driver.rb +349 -272
- data/lib/pg_pipeline/pool.rb +229 -157
- data/lib/pg_pipeline/prepared_statement.rb +5 -5
- data/lib/pg_pipeline/request.rb +18 -17
- data/lib/pg_pipeline/runtime/notification.rb +2 -1
- data/lib/pg_pipeline/runtime/semaphore.rb +3 -3
- data/lib/pg_pipeline/runtime/task.rb +14 -8
- data/lib/pg_pipeline/runtime.rb +17 -18
- data/lib/pg_pipeline/server_caps.rb +3 -3
- data/lib/pg_pipeline/session.rb +9 -7
- data/lib/pg_pipeline/session_guard.rb +108 -73
- data/lib/pg_pipeline/transaction.rb +33 -34
- data/lib/pg_pipeline/type_maps.rb +37 -22
- data/lib/pg_pipeline/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c47c7cb9266d0541b6d57aeba3c25f311f1e8ba6b661c2b79ddc0aea6fe5fe24
|
|
4
|
+
data.tar.gz: 8c34eae2688944b938ee4adfe2c07ae2730571536ff328dc41368add95667410
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a869a0dcfb3a2c8f0eaa9f7f4979ebf71f8af893b3792de15a4db6c8a2f9852f9f7a42474580468cdb3b9cac50f08ec0a2525627551fc731d715b70ac1c3d03c
|
|
7
|
+
data.tar.gz: ca9179c01ab0a824b07be2923578b51489d91ccd2e9076ba2da44d789f2aef666cffd77d481b85577c0265f8f7bc0f0b33fe028ba535007928bb7489b21c504c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.4] - 2026-10-28
|
|
4
|
+
|
|
5
|
+
Internal refactoring of the control plane. No intended public API or wire
|
|
6
|
+
behaviour changes.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- Centralized pool option defaults and validation.
|
|
11
|
+
- Split driver, pool, request, SQL-guard, and type-map operations into smaller
|
|
12
|
+
focused methods and removed redundant repeated lookups.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Readable driver events now trigger result draining.
|
|
17
|
+
|
|
3
18
|
## [0.3.3] - 2026-08-19
|
|
4
19
|
|
|
5
20
|
Opt-in typed result decoding for multiplexed prepared statements. Default
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
3
|
+
require_relative 'errors'
|
|
4
|
+
require_relative 'runtime'
|
|
5
5
|
|
|
6
6
|
module PgPipeline
|
|
7
7
|
class BoundedQueue
|
|
8
8
|
def initialize(limit)
|
|
9
9
|
@limit = Integer(limit)
|
|
10
|
-
raise ArgumentError,
|
|
10
|
+
raise ArgumentError, 'limit must be >= 1' if @limit < 1
|
|
11
11
|
rescue ArgumentError, TypeError
|
|
12
|
-
raise ArgumentError,
|
|
12
|
+
raise ArgumentError, 'limit must be an integer >= 1'
|
|
13
13
|
else
|
|
14
|
-
@items
|
|
14
|
+
@items = []
|
|
15
|
+
@consumers = []
|
|
16
|
+
@producers = []
|
|
15
17
|
|
|
16
18
|
@closed = false
|
|
17
19
|
@close_error = nil
|
|
@@ -93,7 +95,7 @@ module PgPipeline
|
|
|
93
95
|
end
|
|
94
96
|
|
|
95
97
|
def raise_close_error
|
|
96
|
-
error = @close_error || ShutdownError.new(
|
|
98
|
+
error = @close_error || ShutdownError.new('queue closed')
|
|
97
99
|
raise error.class, error.message
|
|
98
100
|
end
|
|
99
101
|
end
|
data/lib/pg_pipeline/client.rb
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
8
|
-
require_relative
|
|
9
|
-
require_relative
|
|
3
|
+
require_relative 'errors'
|
|
4
|
+
require_relative 'pool'
|
|
5
|
+
require_relative 'request'
|
|
6
|
+
require_relative 'prepared_statement'
|
|
7
|
+
require_relative 'session_guard'
|
|
8
|
+
require_relative 'session'
|
|
9
|
+
require_relative 'transaction'
|
|
10
10
|
|
|
11
11
|
module PgPipeline
|
|
12
12
|
class Client
|
|
13
13
|
attr_reader :guard
|
|
14
14
|
|
|
15
15
|
def initialize(connection_args = nil, guard: :default, **pool_opts)
|
|
16
|
-
@owner_thread
|
|
16
|
+
@owner_thread = nil
|
|
17
|
+
@scheduler = nil
|
|
17
18
|
|
|
18
19
|
@guard = SessionGuard.normalize_mode!(guard)
|
|
19
20
|
@pool = Pool.new(connection_args, **pool_opts)
|
|
@@ -26,9 +27,11 @@ module PgPipeline
|
|
|
26
27
|
|
|
27
28
|
def start = ClientOps.start(self)
|
|
28
29
|
def query(sql, params = RequestOps::EMPTY_PARAMS) = ClientOps.query(self, sql, params)
|
|
30
|
+
|
|
29
31
|
def prepare(name, sql, param_types = nil, typed: false)
|
|
30
32
|
ClientOps.prepare(self, name, sql, param_types, typed: typed)
|
|
31
33
|
end
|
|
34
|
+
|
|
32
35
|
def stats = ClientOps.stats(self)
|
|
33
36
|
|
|
34
37
|
def session(&block)
|
|
@@ -44,9 +47,8 @@ module PgPipeline
|
|
|
44
47
|
|
|
45
48
|
private
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
attr_writer :owner_thread, :scheduler
|
|
50
|
+
attr_accessor :owner_thread, :scheduler, :started
|
|
51
|
+
attr_reader :pool
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
module ClientOps
|
|
@@ -56,16 +58,18 @@ module PgPipeline
|
|
|
56
58
|
client = Client.new(connection_args, **opts).start
|
|
57
59
|
yield client
|
|
58
60
|
ensure
|
|
59
|
-
client
|
|
61
|
+
client&.close
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
def start(client)
|
|
63
|
-
raise Error,
|
|
64
|
-
|
|
65
|
+
raise Error, 'client already started' if started?(client)
|
|
66
|
+
|
|
67
|
+
scheduler = Fiber.scheduler
|
|
68
|
+
raise Error, 'client start requires an active Fiber scheduler' unless scheduler
|
|
65
69
|
|
|
66
70
|
pool(client).start
|
|
67
71
|
client.__send__(:owner_thread=, Thread.current)
|
|
68
|
-
client.__send__(:scheduler=,
|
|
72
|
+
client.__send__(:scheduler=, scheduler)
|
|
69
73
|
client.__send__(:started=, true)
|
|
70
74
|
client
|
|
71
75
|
end
|
|
@@ -108,26 +112,38 @@ module PgPipeline
|
|
|
108
112
|
|
|
109
113
|
def submit_with_failover(client)
|
|
110
114
|
attempts = 0
|
|
111
|
-
|
|
115
|
+
client_pool = pool(client)
|
|
116
|
+
limit = [client_pool.pipeline_size, 1].max
|
|
112
117
|
last_error = nil
|
|
113
118
|
|
|
114
119
|
while attempts < limit
|
|
115
120
|
request = yield
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
attempts += 1
|
|
122
|
-
rescue ShutdownError => e
|
|
123
|
-
last_error = e
|
|
124
|
-
attempts += 1
|
|
125
|
-
break unless request.state == :new && !request.settled?
|
|
126
|
-
end
|
|
121
|
+
last_error = submit_attempt(client_pool, request)
|
|
122
|
+
return request unless last_error
|
|
123
|
+
|
|
124
|
+
attempts += 1
|
|
125
|
+
break if stop_retrying?(request, last_error)
|
|
127
126
|
end
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
raise_submission_error(last_error)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def submit_attempt(client_pool, request)
|
|
132
|
+
client_pool.__send__(:pipeline_driver).submit(request)
|
|
133
|
+
nil
|
|
134
|
+
rescue NotDispatchedError, ShutdownError => e
|
|
135
|
+
e
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def stop_retrying?(request, error)
|
|
139
|
+
error.is_a?(ShutdownError) && (request.state != :new || request.settled?)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def raise_submission_error(error)
|
|
143
|
+
error ||= NotDispatchedError.new('no live pipeline connections; request was not dispatched')
|
|
144
|
+
raise error if error.is_a?(NotDispatchedError)
|
|
145
|
+
|
|
146
|
+
raise NotDispatchedError, error.message
|
|
131
147
|
end
|
|
132
148
|
|
|
133
149
|
def session(client)
|
|
@@ -143,13 +159,13 @@ module PgPipeline
|
|
|
143
159
|
end
|
|
144
160
|
end
|
|
145
161
|
|
|
146
|
-
def transaction(client)
|
|
162
|
+
def transaction(client, &block)
|
|
147
163
|
ensure_started!(client)
|
|
148
164
|
|
|
149
165
|
pool(client).__send__(:with_pinned) do |conn|
|
|
150
166
|
tx = Transaction.new(conn)
|
|
151
167
|
begin
|
|
152
|
-
TransactionOps.run(tx)
|
|
168
|
+
TransactionOps.run(tx, &block)
|
|
153
169
|
ensure
|
|
154
170
|
SessionOps.close!(tx)
|
|
155
171
|
end
|
|
@@ -165,10 +181,11 @@ module PgPipeline
|
|
|
165
181
|
return unless started?(client)
|
|
166
182
|
|
|
167
183
|
ensure_context!(client)
|
|
184
|
+
client_pool = pool(client)
|
|
168
185
|
begin
|
|
169
|
-
|
|
186
|
+
client_pool.graceful_close
|
|
170
187
|
ensure
|
|
171
|
-
client.__send__(:started=, false) if
|
|
188
|
+
client.__send__(:started=, false) if client_pool.closing?
|
|
172
189
|
end
|
|
173
190
|
end
|
|
174
191
|
|
|
@@ -176,10 +193,11 @@ module PgPipeline
|
|
|
176
193
|
return unless started?(client)
|
|
177
194
|
|
|
178
195
|
ensure_context!(client)
|
|
196
|
+
client_pool = pool(client)
|
|
179
197
|
begin
|
|
180
|
-
|
|
198
|
+
client_pool.abort!
|
|
181
199
|
ensure
|
|
182
|
-
client.__send__(:started=, false) if
|
|
200
|
+
client.__send__(:started=, false) if client_pool.closing?
|
|
183
201
|
end
|
|
184
202
|
end
|
|
185
203
|
|
|
@@ -188,7 +206,7 @@ module PgPipeline
|
|
|
188
206
|
end
|
|
189
207
|
|
|
190
208
|
def ensure_started!(client)
|
|
191
|
-
raise Error,
|
|
209
|
+
raise Error, 'client not started; call #start or use Client.open' unless started?(client)
|
|
192
210
|
|
|
193
211
|
ensure_context!(client)
|
|
194
212
|
end
|
|
@@ -197,7 +215,7 @@ module PgPipeline
|
|
|
197
215
|
return if Thread.current.equal?(client.__send__(:owner_thread)) &&
|
|
198
216
|
Fiber.scheduler.equal?(client.__send__(:scheduler))
|
|
199
217
|
|
|
200
|
-
raise Error,
|
|
218
|
+
raise Error, 'client is reactor-local and cannot be used from another thread/scheduler'
|
|
201
219
|
end
|
|
202
220
|
|
|
203
221
|
def started?(client)
|