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 © 2018-2025 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.
233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/zache.rb', line 233 def clean synchronize_all do size_before = @hash.size @hash.delete_if do |key, _value| expired = expired_unsafe?(key) @locks.delete(key) if expired expired end size_before - @hash.size end end |
#empty? ⇒ Boolean
Returns TRUE if the cache is empty, FALSE otherwise.
248 249 250 |
# File 'lib/zache.rb', line 248 def empty? synchronize_all { @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) synchronize_all do rec = @hash[key] if expired_unsafe?(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) synchronize_all { expired_unsafe?(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 get_dirty_value(key) if should_return_dirty?(key, dirty) return get_eager(key, lifetime, placeholder, &block) if eager synchronize_one(key) { calc(key, lifetime, &block) } else get_without_block(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) synchronize_all { @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) synchronize_all 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 184 185 186 187 |
# File 'lib/zache.rb', line 179 def put(key, value, lifetime: 2**32) synchronize_one(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.
195 196 197 198 199 |
# File 'lib/zache.rb', line 195 def remove(key) result = synchronize_one(key) { @hash.delete(key) { yield if block_given? } } synchronize_all { @locks.delete(key) } result end |
#remove_all ⇒ Hash
Remove all keys from the cache.
204 205 206 207 208 209 |
# File 'lib/zache.rb', line 204 def remove_all synchronize_all do @hash = {} @locks = {} end end |
#remove_by {|key| ... } ⇒ Integer
Remove all keys that match the block.
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/zache.rb', line 216 def remove_by synchronize_all 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 synchronize_all { @hash.size } end |