pgtk 0.32.8 → 0.33.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb85109114237337349767ef8260821c03422e3a2cf8f91039b927aad36041da
4
- data.tar.gz: ae133a07f824180406a4a9d4ff7bb9534db7a63db50be4a9f20e77f7526187ee
3
+ metadata.gz: 7acb299c9e4e6cd1e272651041704fd89da2858bd1e4b2aa935eed9724815419
4
+ data.tar.gz: 1260a6fb42a11e34d1a733eb9d1bff8ba6a28f81724457e12986adccd134ebc5
5
5
  SHA512:
6
- metadata.gz: b7495aa0b7cbc4ecc2fab5196d1c227ca47becc6ec52b8565cefc4e750b9062fd5bd15ac68332c7460b99c0aeb45eee7b2bd0081e339b4531fe8ce7e82fde339
7
- data.tar.gz: bcf02ab40a3dfe2b2fdf3f3b4d1871ad8e56eaff0856f85e5d930b5d19364b6778f9c1c71a09c774ef5fad4f237b1296530747a1e993d3e38acff5265a9bd64f
6
+ metadata.gz: 29aad3a51e77675418fc5eaffa72d7e0015d4e6d1464c87cc118f3ab94e223b0ce4461cffba91e7f4e2d22b594bb0a61f2d4b299db1055d2637d9afca5a0533d
7
+ data.tar.gz: 8483ec44d6da87cd0e57f57e2ca14373965269a5463bc74ba7e38ac4693b4acf35299a64b6ec91a17fc04812160ca31e6826313fce660cdd3e210c8cc3007c81
data/Gemfile.lock CHANGED
@@ -36,7 +36,7 @@ GEM
36
36
  tago (~> 0.1)
37
37
  ellipsized (0.3.0)
38
38
  joined (0.4.0)
39
- json (2.19.9)
39
+ json (2.20.0)
40
40
  language_server-protocol (3.17.0.5)
41
41
  lint_roller (1.1.0)
42
42
  logger (1.7.0)
@@ -95,7 +95,7 @@ GEM
95
95
  tago (~> 0.0)
96
96
  regexp_parser (2.12.0)
97
97
  rexml (3.4.4)
98
- rubocop (1.87.0)
98
+ rubocop (1.88.1)
99
99
  json (~> 2.3)
100
100
  language_server-protocol (~> 3.17.0.2)
101
101
  lint_roller (~> 1.1.0)
@@ -109,7 +109,7 @@ GEM
109
109
  rubocop-ast (1.49.1)
110
110
  parser (>= 3.3.7.2)
111
111
  prism (~> 1.7)
112
- rubocop-elegant (0.6.0)
112
+ rubocop-elegant (0.7.0)
113
113
  lint_roller (~> 1.1)
114
114
  rubocop (~> 1.75)
115
115
  rubocop-minitest (0.39.1)
data/lib/pgtk/stash.rb CHANGED
@@ -6,6 +6,7 @@
6
6
  require 'concurrent-ruby'
7
7
  require 'joined'
8
8
  require 'loog'
9
+ require 'objspace'
9
10
  require 'tago'
10
11
  require_relative '../pgtk'
11
12
 
@@ -15,6 +16,10 @@ require_relative '../pgtk'
15
16
  # the cache when tables are modified. Read queries are cached while write
16
17
  # queries bypass the cache and invalidate related cached entries.
17
18
  #
19
+ # Tables that are too write-heavy to benefit from caching can be listed
20
+ # via the +volatile:+ constructor parameter; any read whose FROM/JOIN
21
+ # set touches one of them bypasses the cache entirely.
22
+ #
18
23
  # Thread-safe with read-write locking.
19
24
  #
20
25
  # The implementation is very naive! Use it at your own risk.
@@ -67,11 +72,13 @@ class Pgtk::Stash
67
72
  # @param [Float] retirement Interval in seconds between retirement tasks
68
73
  # @param [Loog] loog Logger instance
69
74
  # @param [Concurrent::ReentrantReadWriteLock] entrance Read-write lock for thread-safe access
75
+ # @param [Array<String>] volatile Table names that must never be cached
70
76
  def initialize(
71
77
  pool,
72
78
  stash: { queries: {}, tables: {}, table_mod: {}, table_inflight: {} },
73
79
  loog: Loog::NULL,
74
80
  entrance: Concurrent::ReentrantReadWriteLock.new,
81
+ volatile: [],
75
82
  refill: 16,
76
83
  delay: 0,
77
84
  maxqueue: 128,
@@ -89,6 +96,7 @@ class Pgtk::Stash
89
96
  end
90
97
  @loog = loog
91
98
  @entrance = entrance
99
+ @volatile = Array(volatile).map(&:to_s).freeze
92
100
  @refill = refill
93
101
  @delay = delay
94
102
  @maxqueue = maxqueue
@@ -133,7 +141,7 @@ class Pgtk::Stash
133
141
  pure = (query.is_a?(Array) ? query.join(' ') : query).gsub(/\s+/, ' ').strip
134
142
  if MODS_RE.match?(pure) || (WITH_RE.match?(pure) && ALTS_RE.match?(pure))
135
143
  modify(pure, params, result)
136
- elsif /(^|\s)pg_[a-z_]+\(/.match?(pure)
144
+ elsif /(^|\s)pg_[a-z_]+\(/.match?(pure) || (!@volatile.empty? && @volatile.intersect?(pure.scan(READS_RE).flatten))
137
145
  @pool.exec(pure, params, result)
138
146
  else
139
147
  select(pure, params, result)
@@ -146,7 +154,7 @@ class Pgtk::Stash
146
154
  # @return [Object] The result of the block
147
155
  def transaction
148
156
  @pool.transaction do |t|
149
- yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance))
157
+ yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance, volatile: @volatile))
150
158
  end
151
159
  end
152
160
 
@@ -156,7 +164,7 @@ class Pgtk::Stash
156
164
  # @return [Object] The result of the block
157
165
  def session
158
166
  @pool.session do |t|
159
- yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance))
167
+ yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance, volatile: @volatile))
160
168
  end
161
169
  end
162
170
 
@@ -185,6 +193,7 @@ class Pgtk::Stash
185
193
  ' Not launched yet'
186
194
  end,
187
195
  " #{cached} queries cached (#{cached > @cap ? 'above' : 'below'} the cap)",
196
+ " ~#{footprint} bytes of RAM occupied by cache",
188
197
  " #{@stash[:tables].count} tables in cache",
189
198
  " #{list.sum { |a| a[:s] }} stale queries in cache:",
190
199
  stale(list),
@@ -327,6 +336,33 @@ class Pgtk::Stash
327
336
  end
328
337
  end
329
338
 
339
+ # Estimate the total heap footprint, in bytes, of everything held in
340
+ # +@stash[:queries]+.
341
+ #
342
+ # The count of cached entries alone is misleading: a single query with many
343
+ # parameter combinations keeps a distinct +PG::Result+ per combination, and
344
+ # the +cap+ limits the number of entries, not their weight. This gauge sums
345
+ # +ObjectSpace.memsize_of+ over each cached entry and its +:ret+, +:params+,
346
+ # and key strings, so an operator can tell whether the cache is about to
347
+ # exhaust memory. +Marshal+ is not an option here since neither +PG::Result+
348
+ # nor +Concurrent::AtomicFixnum+ is marshallable.
349
+ #
350
+ # The result is approximate: +memsize_of+ is shallow, so nested contents
351
+ # (rows inside a +PG::Result+) are only partially accounted for. A rough
352
+ # order of magnitude is enough.
353
+ #
354
+ # @return [Integer] Approximate total bytes of RAM held by the cache
355
+ def footprint
356
+ @entrance.with_read_lock do
357
+ @stash[:queries].sum do |q, kk|
358
+ ObjectSpace.memsize_of(q) +
359
+ kk.sum do |params, entry|
360
+ [params, entry, entry[:ret], entry[:params]].sum { |o| ObjectSpace.memsize_of(o) }
361
+ end
362
+ end
363
+ end
364
+ end
365
+
330
366
  # Discover ON DELETE CASCADE / ON UPDATE CASCADE foreign keys so that a
331
367
  # modify on the parent table also invalidates cached queries on children.
332
368
  def cascade!
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.32.8' unless defined?(VERSION)
13
+ VERSION = '0.33.0' 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.32.8
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko