Class: Pgtk::Stash
- Inherits:
-
Object
- Object
- Pgtk::Stash
- Defined in:
- lib/pgtk/stash.rb
Overview
Database query cache implementation.
Provides a caching layer for PostgreSQL queries, automatically invalidating the cache when tables are modified. Read queries are cached while write queries bypass the cache and invalidate related cached entries.
Tables that are too write-heavy to benefit from caching can be listed
via the volatile: constructor parameter; any read whose FROM/JOIN
set touches one of them bypasses the cache entirely.
Thread-safe with read-write locking.
The implementation is very naive! Use it at your own risk.
- Author
Yegor Bugayenko (yegor256@gmail.com)
- Copyright
Copyright (c) 2019-2026 Yegor Bugayenko
- License
MIT
Instance Method Summary collapse
-
#dump ⇒ String
Convert internal state into text.
-
#exec(query, params = [], result = 0) ⇒ PG::Result
Execute a SQL query with optional caching.
-
#initialize(pool, stash: { queries: {}, tables: {}, table_mod: {}, table_inflight: {} }, loog: Loog::NULL, entrance: Concurrent::ReentrantReadWriteLock.new, volatile: [], refill: 16, delay: 0, maxqueue: 128, threads: 4, cap: 10_000, capping: 60, retire: 15 * 60, retirement: 60) ⇒ Stash
constructor
Initialize a new Stash with query caching.
-
#session {|Pgtk::Stash| ... } ⇒ Object
Run statements on a single connection, without a transaction.
-
#start! ⇒ void
Start the connection pool and launch background cache management tasks.
-
#transaction {|Pgtk::Stash| ... } ⇒ Object
Execute a database transaction.
-
#version ⇒ String
Get the PostgreSQL server version.
Constructor Details
#initialize(pool, stash: { queries: {}, tables: {}, table_mod: {}, table_inflight: {} }, loog: Loog::NULL, entrance: Concurrent::ReentrantReadWriteLock.new, volatile: [], refill: 16, delay: 0, maxqueue: 128, threads: 4, cap: 10_000, capping: 60, retire: 15 * 60, retirement: 60) ⇒ Stash
Initialize a new Stash with query caching.
Set any of the intervals to nil to disable the cron.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/pgtk/stash.rb', line 76 def initialize( pool, stash: { queries: {}, tables: {}, table_mod: {}, table_inflight: {} }, loog: Loog::NULL, entrance: Concurrent::ReentrantReadWriteLock.new, volatile: [], refill: 16, delay: 0, maxqueue: 128, threads: 4, cap: 10_000, capping: 60, retire: 15 * 60, retirement: 60 ) @pool = pool @stash = stash @stash[:table_mod] ||= {} unless @stash[:table_inflight].default_proc @stash[:table_inflight] = Hash.new { |h, k| h[k] = Concurrent::AtomicFixnum.new(0) } end @loog = loog @entrance = entrance @volatile = Array(volatile).map(&:to_s).freeze @refill = refill @delay = delay @maxqueue = maxqueue @threads = threads @cap = cap @capping = capping @retire = retire @retirement = retirement end |
Instance Method Details
#dump ⇒ String
Convert internal state into text.
128 129 130 131 132 |
# File 'lib/pgtk/stash.rb', line 128 def dump @entrance.with_read_lock do body(queries) end end |
#exec(query, params = [], result = 0) ⇒ PG::Result
Execute a SQL query with optional caching.
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/pgtk/stash.rb', line 140 def exec(query, params = [], result = 0) pure = (query.is_a?(Array) ? query.join(' ') : query).gsub(/\s+/, ' ').strip if MODS_RE.match?(pure) || (WITH_RE.match?(pure) && ALTS_RE.match?(pure)) modify(pure, params, result) elsif /(^|\s)pg_[a-z_]+\(/.match?(pure) || (!@volatile.empty? && @volatile.intersect?(pure.scan(READS_RE).flatten)) @pool.exec(pure, params, result) else select(pure, params, result) end end |
#session {|Pgtk::Stash| ... } ⇒ Object
Run statements on a single connection, without a transaction.
165 166 167 168 169 |
# File 'lib/pgtk/stash.rb', line 165 def session @pool.session do |t| yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance, volatile: @volatile)) end end |
#start! ⇒ void
This method returns an undefined value.
Start the connection pool and launch background cache management tasks.
113 114 115 116 117 |
# File 'lib/pgtk/stash.rb', line 113 def start! @pool.start! cascade! launch! end |
#transaction {|Pgtk::Stash| ... } ⇒ Object
Execute a database transaction.
155 156 157 158 159 |
# File 'lib/pgtk/stash.rb', line 155 def transaction @pool.transaction do |t| yield(Pgtk::Stash.new(t, stash: @stash, loog: @loog, entrance: @entrance, volatile: @volatile)) end end |
#version ⇒ String
Get the PostgreSQL server version.
121 122 123 |
# File 'lib/pgtk/stash.rb', line 121 def version @pool.version end |