Class: Zache
- Inherits:
-
Object
- Object
- Zache
- Defined in:
- lib/zache.rb
Overview
It is a very simple thread-safe in-memory cache with an ability to expire keys automatically, when their lifetime is over. Use it like this:
require 'zache' zache = Zache.new
Expires in 5 minutes
v = zache.get(:count, lifetime: 5 * 60) { expensive() }
For more information read README file.
- Author
Yegor Bugayenko ([email protected])
- Copyright
Copyright (c) 2018-2026 Yegor Bugayenko
- License
MIT
Defined Under Namespace
Classes: Fake
Instance Method Summary collapse
-
#clean ⇒ Integer
Remove keys that are expired.
-
#empty? ⇒ Boolean
Returns TRUE if the cache is empty, FALSE otherwise.
-
#exists?(key, dirty: false) ⇒ Boolean
Checks whether the value exists in the cache by the provided key.
-
#expired?(key) ⇒ Boolean
Checks whether the key exists in the cache and is expired.
-
#get(key, lifetime: 2**32, dirty: false, placeholder: nil, eager: false) { ... } ⇒ Object
Gets the value from the cache by the provided key.
-
#initialize(sync: true, dirty: false) ⇒ Zache
constructor
Makes a new object of the cache.
-
#locked?(key) ⇒ Boolean
Is key currently locked doing something?.
-
#mtime(key) ⇒ Time
Returns the modification time of the key, if it exists.
-
#put(key, value, lifetime: 2**32) ⇒ Object
Put a value into the cache.
-
#remove(key) { ... } ⇒ Object
Removes the value from the cache, by the provided key.
-
#remove_all ⇒ Hash
Remove all keys from the cache.
-
#remove_by {|key| ... } ⇒ Integer
Remove all keys that match the block.
-
#size ⇒ Integer
Total number of keys currently in cache.
Constructor Details
#initialize(sync: true, dirty: false) ⇒ Zache
Makes a new object of the cache.
"sync" is whether the hash is thread-safe (true)
or not (false); it is recommended to leave this parameter untouched,
unless you really know what you are doing.
If the dirty argument is set to true, a previously calculated result will be returned if it exists, even if it is already expired.
81 82 83 84 85 86 87 |
# File 'lib/zache.rb', line 81 def initialize(sync: true, dirty: false) @hash = {} @sync = sync @dirty = dirty @mutex = Mutex.new @locks = {} end |
Instance Method Details
#clean ⇒ Integer
Remove keys that are expired. This cleans up the cache by removing all keys where the lifetime has been exceeded.
228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/zache.rb', line 228 def clean sync do count = 0 @hash.delete_if do |key, _value| expired = overdue?(key) if expired @locks.delete(key) count += 1 end expired end count end end |
#empty? ⇒ Boolean
Returns TRUE if the cache is empty, FALSE otherwise.
246 247 248 |
# File 'lib/zache.rb', line 246 def empty? sync { @hash.empty? } end |
#exists?(key, dirty: false) ⇒ Boolean
Checks whether the value exists in the cache by the provided key. Returns TRUE if the value is here. If the key is already expired in the cache, it will be removed by this method and the result will be FALSE.
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/zache.rb', line 133 def exists?(key, dirty: false) sync do rec = @hash[key] if overdue?(key) && !dirty && !@dirty @hash.delete(key) rec = nil end !rec.nil? end end |
#expired?(key) ⇒ Boolean
Checks whether the key exists in the cache and is expired. If the key is absent FALSE is returned.
149 150 151 |
# File 'lib/zache.rb', line 149 def expired?(key) sync { overdue?(key) } end |
#get(key, lifetime: 2**32, dirty: false, placeholder: nil, eager: false) { ... } ⇒ Object
Gets the value from the cache by the provided key.
If the value is not found in the cache, it will be calculated via the provided block. If the block is not given and the key doesn't exist or is expired, an exception will be raised (unless dirty is set to true). The lifetime must be in seconds. The default lifetime is huge, which means that the key will never be expired.
If the dirty argument is set to true, a previously calculated result will be returned if it exists, even if it is already expired.
116 117 118 119 120 121 122 123 124 |
# File 'lib/zache.rb', line 116 def get(key, lifetime: 2**32, dirty: false, placeholder: nil, eager: false, &block) if block_given? return cached(key) if dirt?(key, dirty) return eager(key, lifetime, placeholder, &block) if eager lock(key) { calc(key, lifetime, &block) } else fetch(key, dirty) end end |
#locked?(key) ⇒ Boolean
Is key currently locked doing something?
169 170 171 |
# File 'lib/zache.rb', line 169 def locked?(key) sync { @locks[key]&.locked? } end |
#mtime(key) ⇒ Time
Returns the modification time of the key, if it exists. If not, current time is returned.
158 159 160 161 162 163 |
# File 'lib/zache.rb', line 158 def mtime(key) sync do rec = @hash[key] rec.nil? ? Time.now : rec[:start] end end |
#put(key, value, lifetime: 2**32) ⇒ Object
Put a value into the cache.
179 180 181 182 183 |
# File 'lib/zache.rb', line 179 def put(key, value, lifetime: 2**32) lock(key) do @hash[key] = { value: value, start: Time.now, lifetime: lifetime } end end |
#remove(key) { ... } ⇒ Object
Removes the value from the cache, by the provided key. If the key is absent and the block is provided, the block will be called.
191 192 193 194 |
# File 'lib/zache.rb', line 191 def remove(key) lock(key) { @hash.delete(key) { yield if block_given? } } sync { @locks.delete(key) } end |
#remove_all ⇒ Hash
Remove all keys from the cache.
199 200 201 202 203 204 |
# File 'lib/zache.rb', line 199 def remove_all sync do @hash = {} @locks = {} end end |
#remove_by {|key| ... } ⇒ Integer
Remove all keys that match the block.
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/zache.rb', line 211 def remove_by sync do count = 0 @hash.each_key do |k| next unless yield(k) @hash.delete(k) @locks.delete(k) count += 1 end count end end |
#size ⇒ Integer
Total number of keys currently in cache.
92 93 94 |
# File 'lib/zache.rb', line 92 def size sync { @hash.size } end |