Parent

Included Modules

Class Index [+]

Quicksearch

Sequel::Postgres::StatementCache::StatementCache

The backbone of the block, a modified LRU (least recently used) cache mapping SQL query strings to Statement objects.

Public Class Methods

new(opts={}, &block) click to toggle source

Set the options for the statement cache. These are generally set at the database level using the :statement_cache_opts Database option.

:max_size

The maximum size (high water mark) for the cache. If an entry is added when the current size of the cache is equal to the maximum size, the cache is cleaned up to reduce the number of entries to the :min_size. Defaults to 1000.

:min_size

The minimum size (low water mark) for the cache. On cleanup, the size of the cache is reduced to this number. Note that there could be fewer than this number of entries in the cache. Defaults to :max_size/2.

:prepare_after

The number of executions to wait for before preparing

             the query server-side.  If set to 1, prepares all executed
             queries server-side.  If set to 5, does not attempt to
             prepare the query until the 5th execution.  Defaults to 2.
:sorter

A callable object that takes two arguments, the current time and the related Statement instance, and should return some Comparable (usually a numeric) such that the lowest values returned are the first to be removed when it comes time to clean the pool. The default is basically:

 
  lambda{|t, stmt| (stmt.last_seen - t)/stmt.num_executes}

so that it doesn’t remove statements that have been executed many times just because many less-frequently executed statements have been executed recently.

The block passed is called with the Statement object’s name, only for statements that have been prepared, and should be used to deallocate the statements.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 108
108:         def initialize(opts={}, &block)
109:           @cleanup_proc = block
110:           @prepare_after = opts.fetch(:prepare_after, 2)
111:           @max_size = opts.fetch(:max_size, 1000)
112:           @min_size = opts.fetch(:min_size, @max_size/2)
113:           @sorter = opts.fetch(:sorter){method(:default_sorter)}
114:           @ids = (1..@max_size).to_a.reverse
115:           @hash = {}
116:           #
117:           # We add one so that when we clean the cache, the entry
118:           # about to be added brings us to the min_size.
119:           @size_diff = @max_size - @min_size + 1
120:         end

Public Instance Methods

clear() click to toggle source

Completely clear the statement cache, deallocating on the server side all statements that have been prepared.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 124
124:         def clear
125:           @hash.keys.each{|k| remove(k)}
126:         end
each(&block) click to toggle source

Yield each SQL string and Statement instance in the cache to the block.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 130
130:         def each(&block)
131:           @hash.each(&block)
132:         end
fetch(sql) click to toggle source

Get the related statement name from the cache. If the entry is already in the cache, just bump it’s last seen time and the number of executions. Otherwise, add it to the cache. If the cache is already full, clean it up before adding it.

If the num of executions has passed the threshhold, yield the statement name to the block, which should be used to prepare the statement on the server side.

This method should return the prepared statment name if the statement has been prepared, and nil if the query has not been prepared and the statement should be executed normally.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 148
148:         def fetch(sql)
149:           unless stmt = @hash[sql]
150:             # Get the next id from the id pool.
151:             unless id = @ids.pop
152:               # No id left, cache must be full, so cleanup and then
153:               # get the next id from the id pool.
154:               cleanup
155:               id = @ids.pop
156:             end
157:             @hash[sql] = stmt = Statement.new(id)
158:           end
159: 
160:           stmt.last_seen = Time.now
161:           stmt.num_executes += 1
162: 
163:           if stmt.num_executes >= @prepare_after
164:             if stmt.num_executes == @prepare_after
165:               begin
166:                 yield(stmt.name)
167:               rescue PGError
168:                 # An error occurred while preparing the statement,
169:                 # execute it normally (which will probably raise
170:                 # the error again elsewhere), but decrement the
171:                 # number of executions so we don't think we've
172:                 # prepared the statement when we haven't.
173:                 stmt.num_executes -= 1
174:                 return nil
175:               end
176:             end
177:             stmt.name
178:           end
179:         end
size() click to toggle source

The current size of the statement cache.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 182
182:         def size
183:           @hash.length
184:         end

Private Instance Methods

cleanup() click to toggle source

After sorting the cache appropriately (so that the least important items are first), reduce the number of entries in the cache to the low water mark by removing the related query. Should only be called when the cache is full.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 201
201:         def cleanup
202:           t = Time.now
203:           @hash.sort_by{|k,v| @sorter.call(t, v)}.first(@size_diff).each{|sql, stmt| remove(sql)}
204:         end
default_sorter(t, stmt) click to toggle source

Sort by time since last execution and number of executions. We don’t want to throw stuff out of the cache if it has been executed a lot, but a bunch of queries that were executed only once came in more recently.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 193
193:         def default_sorter(t, stmt)
194:           (stmt.last_seen - t)/stmt.num_executes
195:         end
remove(sql) click to toggle source

Remove the query from the cache. If it has been prepared, call the cleanup_proc to deallocate the statement.

     # File lib/sequel/extensions/pg_statement_cache.rb, line 208
208:         def remove(sql)
209:           stmt = @hash.delete(sql)
210:           if stmt.num_executes >= @prepare_after
211:             @cleanup_proc.call(stmt.name)
212:           end
213: 
214:           # Return id to the pool of ids
215:           @ids.push(stmt.cache_id)
216:         end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.