Class: Readthis::Cache
- Inherits:
-
Object
- Object
- Readthis::Cache
- Defined in:
- lib/readthis/cache.rb
Overview
Readthis is a Redis backed cache client. It is a drop in replacement for any ‘ActiveSupport` compliant cache Above all Readthis emphasizes performance, simplicity, and explicitness.
Instance Attribute Summary collapse
-
#entity ⇒ Object
readonly
Returns the value of attribute entity.
-
#notifications ⇒ Object
readonly
Returns the value of attribute notifications.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#pool ⇒ Object
readonly
Returns the value of attribute pool.
-
#scripts ⇒ Object
readonly
Returns the value of attribute scripts.
Class Method Summary collapse
-
.notifications ⇒ Object
Provide a class level lookup of the proper notifications module.
Instance Method Summary collapse
-
#clear(options = {}) ⇒ Object
Clear the entire cache by flushing the current database.
-
#decrement(key, amount = 1, options = {}) ⇒ Object
Decrement a key in the store.
-
#delete(key, options = {}) ⇒ Object
Delete the value stored at the specified key.
-
#delete_matched(pattern, options = {}) ⇒ Object
Delete all values that match a given pattern.
-
#exist?(key, options = {}) ⇒ Boolean
Returns ‘true` if the cache contains an entry for the given key.
-
#fetch(key, options = {}) {|String| ... } ⇒ Object
Fetches data from the cache, using the given key.
-
#fetch_multi(keys) ⇒ Object
Fetches multiple keys from the cache using a single call to the server and filling in any cache misses.
-
#increment(key, amount = 1, options = {}) ⇒ Object
Increment a key in the store.
-
#initialize(options = {}) ⇒ Cache
constructor
Creates a new Readthis::Cache object with the given options.
-
#read(key, options = {}) ⇒ Object
Fetches data from the cache, using the given key.
-
#read_multi(keys) ⇒ Hash
Efficiently read multiple values at once from the cache.
-
#write(key, value, options = {}) ⇒ Object
Writes data to the cache using the given key.
-
#write_multi(hash, options = {}) ⇒ Object
Write multiple key value pairs simultaneously.
Constructor Details
#initialize(options = {}) ⇒ Cache
Creates a new Readthis::Cache object with the given options.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/readthis/cache.rb', line 55 def initialize( = {}) @options = @entity = Readthis::Entity.new( marshal: .fetch(:marshal, Marshal), compress: .fetch(:compress, false), threshold: .fetch(:compression_threshold, 1024) ) @pool = ConnectionPool.new(()) do Redis.new(.fetch(:redis, {})) end @scripts = Readthis::Scripts.new end |
Instance Attribute Details
#entity ⇒ Object (readonly)
Returns the value of attribute entity.
15 16 17 |
# File 'lib/readthis/cache.rb', line 15 def entity @entity end |
#notifications ⇒ Object (readonly)
Returns the value of attribute notifications.
15 16 17 |
# File 'lib/readthis/cache.rb', line 15 def notifications @notifications end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
15 16 17 |
# File 'lib/readthis/cache.rb', line 15 def @options end |
#pool ⇒ Object (readonly)
Returns the value of attribute pool.
15 16 17 |
# File 'lib/readthis/cache.rb', line 15 def pool @pool end |
#scripts ⇒ Object (readonly)
Returns the value of attribute scripts.
15 16 17 |
# File 'lib/readthis/cache.rb', line 15 def scripts @scripts end |
Class Method Details
.notifications ⇒ Object
Provide a class level lookup of the proper notifications module. Instrumention is expected to occur within applications that have ActiveSupport::Notifications available, but needs to work even when it isn’t.
21 22 23 |
# File 'lib/readthis/cache.rb', line 21 def self.notifications ActiveSupport::Notifications if defined?(ActiveSupport::Notifications) end |
Instance Method Details
#clear(options = {}) ⇒ Object
Clear the entire cache by flushing the current database.
This flushes everything in the current database, with no globbing applied. Data in other numbered databases will be preserved.
397 398 399 400 401 402 403 404 405 |
# File 'lib/readthis/cache.rb', line 397 def clear( = {}) invoke(:clear, '*') do |store| if [:async] store.flushdb(async: true) else store.flushdb end end end |
#decrement(key, amount = 1, options = {}) ⇒ Object
Decrement a key in the store.
If the key doesn’t exist it will be initialized at 0. If the key exists but it isn’t a Fixnum it will be coerced to 0. Like ‘increment`, this does not make use of the native `decr` or `decrby` commands.
270 271 272 273 274 |
# File 'lib/readthis/cache.rb', line 270 def decrement(key, amount = 1, = {}) invoke(:decrement, key) do |store| alter(store, key, -amount, ) end end |
#delete(key, options = {}) ⇒ Object
Delete the value stored at the specified key. Returns ‘true` if anything was deleted, `false` otherwise.
126 127 128 129 130 131 132 |
# File 'lib/readthis/cache.rb', line 126 def delete(key, = {}) namespaced = namespaced_key(key, ()) invoke(:delete, key) do |store| store.del(namespaced) > 0 end end |
#delete_matched(pattern, options = {}) ⇒ Object
Delete all values that match a given pattern. The pattern must be defined using Redis compliant globs. The following examples are borrowed from the ‘KEYS` documentation:
-
‘h?llo` matches hello, hallo and hxllo
-
‘h*llo` matches hllo and heeeello
-
‘hllo` matches hello and hallo, but not hillo
-
‘hllo` matches hallo, hbllo, … but not hello
-
‘hllo` matches hallo and hbllo
Note that ‘delete_matched` does not use the `KEYS` command, making it safe for use in production.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/readthis/cache.rb', line 156 def delete_matched(pattern, = {}) namespaced = namespaced_key(pattern, ()) invoke(:delete, pattern) do |store| cursor = nil count = .fetch(:count, 1000) deleted = 0 until cursor == '0' cursor, matched = store.scan(cursor || 0, match: namespaced, count: count) if matched.any? store.del(*matched) deleted += matched.length end end deleted end end |
#exist?(key, options = {}) ⇒ Boolean
Returns ‘true` if the cache contains an entry for the given key.
378 379 380 381 382 |
# File 'lib/readthis/cache.rb', line 378 def exist?(key, = {}) invoke(:exist?, key) do |store| store.exists(namespaced_key(key, ())) end end |
#fetch(key, options = {}) {|String| ... } ⇒ Object
Fetches data from the cache, using the given key. If there is data in the cache with the given key, then that data is returned.
If there is no such data in the cache (a cache miss), then ‘nil` will be returned. However, if a block has been passed, that block will be passed the key and executed in the event of a cache miss. The return value of the block will be written to the cache under the given cache key, and that return value will be returned.
211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/readthis/cache.rb', line 211 def fetch(key, = {}) ||= {} value = read(key, ) unless [:force] if value.nil? && block_given? value = yield(key) write(key, value, ) end value end |
#fetch_multi(keys) ⇒ Object
Fetches multiple keys from the cache using a single call to the server and filling in any cache misses. All read and write operations are executed atomically.
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/readthis/cache.rb', line 348 def fetch_multi(*keys) = (keys).merge(retain_nils: true) results = read_multi(*keys, ) missing = {} invoke(:fetch_multi, keys) do |_store| results.each do |key, value| next unless value.nil? value = yield(key) missing[key] = value results[key] = value end end write_multi(missing, ) if missing.any? results end |
#increment(key, amount = 1, options = {}) ⇒ Object
Increment a key in the store.
If the key doesn’t exist it will be initialized at 0. If the key exists but it isn’t a Fixnum it will be coerced to 0.
Note that this method does not use Redis’ native ‘incr` or `incrby` commands. Those commands only work with number-like strings, and are incompatible with the encoded values Readthis writes to the store. The behavior of `incrby` is preserved as much as possible, but incrementing is not an atomic action. If multiple clients are incrementing the same key there will be a “last write wins” race condition, causing incorrect counts.
If you absolutely require correct counts it is better to use the Redis client directly.
248 249 250 251 252 |
# File 'lib/readthis/cache.rb', line 248 def increment(key, amount = 1, = {}) invoke(:increment, key) do |store| alter(store, key, amount, ) end end |
#read(key, options = {}) ⇒ Object
Fetches data from the cache, using the given key. If there is data in the cache with the given key, then that data is returned. Otherwise, nil is returned.
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/readthis/cache.rb', line 83 def read(key, = {}) = () invoke(:read, key) do |store| key = namespaced_key(key, ) refresh_entity(key, store, ) entity.load(store.get(key)) end end |
#read_multi(keys) ⇒ Hash
Efficiently read multiple values at once from the cache. Options can be passed in the last argument.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/readthis/cache.rb', line 291 def read_multi(*keys) = ((keys)) mapping = keys.map { |key| namespaced_key(key, ) } return {} if keys.empty? invoke(:read_multi, keys) do |store| values = store.mget(*mapping).map { |value| entity.load(value) } refresh_entity(mapping, store, ) zipped_results(keys, values, ) end end |
#write(key, value, options = {}) ⇒ Object
Writes data to the cache using the given key. Will overwrite whatever value is already stored at that key.
107 108 109 110 111 112 113 |
# File 'lib/readthis/cache.rb', line 107 def write(key, value, = {}) = () invoke(:write, key) do |store| write_entity(key, value, store, ) end end |
#write_multi(hash, options = {}) ⇒ Object
Write multiple key value pairs simultaneously. This is an atomic operation that will always succeed and will overwrite existing values.
This is a non-standard, but useful, cache method.
319 320 321 322 323 324 325 326 327 |
# File 'lib/readthis/cache.rb', line 319 def write_multi(hash, = {}) = () invoke(:write_multi, hash.keys) do |store| store.multi do hash.each { |key, value| write_entity(key, value, store, ) } end end end |