pgtk 0.31.0 → 0.31.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bce43b422e6baef8427e57d0635f613f2af93eea4a2f783b2fa62c85520b565
4
- data.tar.gz: ea73771e5ea9c4f17919d257316d548280cf623e77f50266f6283e8f0ed71d8b
3
+ metadata.gz: b7db2cc332dfccb4c405f590cc7aa64ffc55d1aa916aea3c0ea68379208c2568
4
+ data.tar.gz: c7a03b2c8b6ccf2b931b1ab4d16bf83f352edeb0099c1d5fcc8f21a5f274a789
5
5
  SHA512:
6
- metadata.gz: 908b1a4e77e794a5d91aae82169969bac770d3638771356f65b7f5ac7b2b490b14a99f5cc7caba4e63e99e09678d423f51944faf52f6c368040a6f4d55eb9b78
7
- data.tar.gz: 5a15b9c10cb8f238b00888d761436633d8381e7b52c731af3c8fa67c5c4c48cd27274dc3975d9b3eaf612f189ffa871c026eca758991924b4d0aa3b3a4b9099a
6
+ metadata.gz: d0e7ca8dc2192a5acb274b9e4b02fda11fdfaf471fe607c7d5d8ac0cf85cd8b527bb35f3de93f271102ba4b483a285452df5d6e1f308df8f503e987b42b10197
7
+ data.tar.gz: d028000b4d1e869d9766105a7706f8b415f012a1c6f3254f2c2bdd6bb8578b97f27fd22f317cc06f7609ca3b79667814d60ca1713b21be3145a51b1b41e5d752
data/Gemfile.lock CHANGED
@@ -42,7 +42,7 @@ GEM
42
42
  loog (0.8.0)
43
43
  ellipsized
44
44
  logger (~> 1.0)
45
- minitest (6.0.4)
45
+ minitest (6.0.5)
46
46
  drb (~> 2.0)
47
47
  prism (~> 1.5)
48
48
  minitest-mock (5.27.0)
@@ -108,7 +108,7 @@ GEM
108
108
  rubocop-ast (1.49.1)
109
109
  parser (>= 3.3.7.2)
110
110
  prism (~> 1.7)
111
- rubocop-elegant (0.0.18)
111
+ rubocop-elegant (0.0.20)
112
112
  lint_roller (~> 1.1)
113
113
  rubocop (~> 1.75)
114
114
  rubocop-minitest (0.39.1)
@@ -142,9 +142,9 @@ GEM
142
142
  unicode-emoji (~> 4.1)
143
143
  unicode-emoji (4.2.0)
144
144
  waitutil (0.2.1)
145
- xcop (0.8.0)
145
+ xcop (0.9.0)
146
146
  differ (~> 0.1.2)
147
- nokogiri (~> 1.10)
147
+ nokogiri (~> 1.8)
148
148
  rainbow (~> 3.0)
149
149
  slop (~> 4.4)
150
150
  yard (0.9.43)
@@ -119,13 +119,19 @@ class Pgtk::Impatient
119
119
  end
120
120
  end
121
121
 
122
- # Run a transaction with a timeout for each query.
122
+ # Run a transaction with a timeout for each query and for idle time inside
123
+ # the transaction. If the transaction stays in the +INTRANS+ state (idle
124
+ # inside transaction) for longer than the configured timeout, PostgreSQL
125
+ # terminates the session, which frees locks and releases the connection
126
+ # slot back to the pool.
123
127
  #
124
128
  # @yield [Pgtk::Impatient] Yields an impatient transaction
125
129
  # @return [Object] Result of the block
126
130
  def transaction
127
131
  @pool.transaction do |t|
128
- t.exec("SET LOCAL statement_timeout = #{Integer((@timeout * 1000).to_s, 10)}")
132
+ ms = Integer((@timeout * 1000).to_s, 10)
133
+ t.exec("SET LOCAL statement_timeout = #{ms}")
134
+ t.exec("SET LOCAL idle_in_transaction_session_timeout = #{ms}")
129
135
  yield(Pgtk::Impatient.new(t, @timeout))
130
136
  end
131
137
  end
data/lib/pgtk/stash.rb CHANGED
@@ -57,7 +57,7 @@ class Pgtk::Stash
57
57
  # @param [Concurrent::ReentrantReadWriteLock] entrance Read-write lock for thread-safe access
58
58
  def initialize(
59
59
  pool,
60
- stash: { queries: {}, tables: {} },
60
+ stash: { queries: {}, tables: {}, table_mod: {} },
61
61
  loog: Loog::NULL,
62
62
  entrance: Concurrent::ReentrantReadWriteLock.new,
63
63
  refill: 16,
@@ -71,6 +71,7 @@ class Pgtk::Stash
71
71
  )
72
72
  @pool = pool
73
73
  @stash = stash
74
+ @stash[:table_mod] ||= {}
74
75
  @loog = loog
75
76
  @entrance = entrance
76
77
  @refill = refill
@@ -216,11 +217,13 @@ class Pgtk::Stash
216
217
  tables = pure.scan(ALTS_RE).flatten
217
218
  tables.uniq!
218
219
  ret = @pool.exec(pure, params, result)
220
+ now = Time.now
219
221
  @entrance.with_write_lock do
220
222
  tables.each do |t|
223
+ @stash[:table_mod][t] = now
221
224
  @stash[:tables][t]&.each do |q|
222
225
  @stash[:queries][q]&.each_key do |key|
223
- @stash[:queries][q][key][:stale] = Time.now
226
+ @stash[:queries][q][key][:stale] = now
224
227
  end
225
228
  end
226
229
  end
@@ -233,16 +236,17 @@ class Pgtk::Stash
233
236
  ret = @stash.dig(:queries, pure, key, :ret)
234
237
  if ret.nil? || @stash.dig(:queries, pure, key, :stale)
235
238
  mark = @stash.dig(:queries, pure, key, :stale)
239
+ tables = pure.scan(/(?<=^|\s)(?:FROM|JOIN) ([a-z_]+)(?=\s|;|$)/).flatten
240
+ tables.uniq!
241
+ marks = tables.to_h { |t| [t, @stash[:table_mod][t]] }
236
242
  ret = @pool.exec(pure, params, result)
237
- cache(pure, key, params, result, ret, mark) unless pure.include?(' NOW() ')
243
+ cache(pure, key, params, result, ret, mark, tables, marks) unless pure.include?(' NOW() ')
238
244
  end
239
245
  bump(pure, key) if @stash.dig(:queries, pure, key)
240
246
  ret
241
247
  end
242
248
 
243
- def cache(pure, key, params, result, ret, mark)
244
- tables = pure.scan(/(?<=^|\s)(?:FROM|JOIN) ([a-z_]+)(?=\s|;|$)/).flatten
245
- tables.uniq!
249
+ def cache(pure, key, params, result, ret, mark, tables, marks)
246
250
  raise(ArgumentError, "No tables at #{pure.inspect}") if tables.empty?
247
251
  @entrance.with_write_lock do
248
252
  tables.each do |t|
@@ -252,8 +256,9 @@ class Pgtk::Stash
252
256
  @stash[:queries][pure] ||= {}
253
257
  existing = @stash[:queries][pure][key]
254
258
  stale = existing && existing[:stale]
259
+ stillborn = tables.any? { |t| (cur = @stash[:table_mod][t]) && cur != marks[t] }
255
260
  entry = { ret:, params:, result:, used: Time.now }
256
- entry[:stale] = stale if stale && stale != mark
261
+ entry[:stale] = stale == mark ? Time.now : stale if (stale && stale != mark) || stillborn
257
262
  @stash[:queries][pure][key] = entry
258
263
  end
259
264
  end
@@ -294,7 +299,7 @@ class Pgtk::Stash
294
299
  m = @stash[:queries][q].values.map { |h| h[:used] }.min
295
300
  next unless m
296
301
  @stash[:queries][q].delete_if { |_, h| h[:used] == m }
297
- @stash[:queries].delete_if { |_, kk| kk.empty? }
302
+ evict(q) if @stash[:queries][q].empty?
298
303
  end
299
304
  end
300
305
  end
@@ -306,12 +311,18 @@ class Pgtk::Stash
306
311
  @entrance.with_write_lock do
307
312
  @stash[:queries].each_key do |q|
308
313
  @stash[:queries][q].delete_if { |_, h| h[:used] < Time.now - @retire }
309
- @stash[:queries].delete_if { |_, kk| kk.empty? }
314
+ evict(q) if @stash[:queries][q].empty?
310
315
  end
311
316
  end
312
317
  end
313
318
  end
314
319
 
320
+ def evict(query)
321
+ @stash[:queries].delete(query)
322
+ @stash[:tables].each_value { |list| list.delete(query) }
323
+ @stash[:tables].delete_if { |_, list| list.empty? }
324
+ end
325
+
315
326
  def refiller!
316
327
  Concurrent::TimerTask.execute(execution_interval: @refill, executor: @tpool) do
317
328
  ranked.each { |q| replenish(q) }
@@ -328,16 +339,22 @@ class Pgtk::Stash
328
339
  end
329
340
 
330
341
  def replenish(query)
331
- @entrance.with_write_lock { @stash[:queries][query].keys }.each do |k|
332
- next unless @stash[:queries][query][k][:stale]
333
- next if @stash[:queries][query][k][:stale] > Time.now - @delay
342
+ snapshot =
343
+ @entrance.with_read_lock do
344
+ @stash[:queries][query]&.filter_map do |k, h|
345
+ next unless h[:stale]
346
+ next if h[:stale] > Time.now - @delay
347
+ [k, h[:params], h[:result], h[:stale]]
348
+ end
349
+ end
350
+ return unless snapshot
351
+ snapshot.each do |k, params, result, mark|
334
352
  next if @tpool.queue_length >= @maxqueue
335
353
  @tpool.post do
336
- h = @stash[:queries][query][k]
337
- mark = h[:stale]
338
- ret = @pool.exec(query, h[:params], h[:result])
354
+ ret = @pool.exec(query, params, result)
339
355
  @entrance.with_write_lock do
340
- h = @stash[:queries][query][k]
356
+ h = @stash[:queries][query]&.dig(k)
357
+ next unless h
341
358
  if h[:stale] == mark
342
359
  h[:ret] = ret
343
360
  h.delete(:stale)
data/lib/pgtk/version.rb CHANGED
@@ -10,5 +10,5 @@ require_relative '../pgtk'
10
10
  # Copyright:: Copyright (c) 2019-2026 Yegor Bugayenko
11
11
  # License:: MIT
12
12
  module Pgtk
13
- VERSION = '0.31.0' unless defined?(VERSION)
13
+ VERSION = '0.31.2' unless defined?(VERSION)
14
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgtk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.0
4
+ version: 0.31.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko