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.
88 89 90 91 92 93 94 |
# File 'lib/zache.rb', line 88 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.
251 252 253 254 255 256 257 |
# File 'lib/zache.rb', line 251 def clean synchronize_all do size_before = @hash.size @hash.delete_if { |key, _value| expired?(key) } size_before - @hash.size end end |
#empty? ⇒ Boolean
Returns TRUE if the cache is empty, FALSE otherwise.
262 263 264 |
# File 'lib/zache.rb', line 262 def empty? @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.
159 160 161 162 163 164 165 166 |
# File 'lib/zache.rb', line 159 def exists?(key, dirty: false) rec = @hash[key] if expired?(key) && !dirty && !@dirty @hash.delete(key) rec = nil end !rec.nil? end |
#expired?(key) ⇒ Boolean
Checks whether the key exists in the cache and is expired. If the key is absent FALSE is returned.
173 174 175 176 |
# File 'lib/zache.rb', line 173 def expired?(key) rec = @hash[key] !rec.nil? && rec[:start] < Time.now - rec[:lifetime] 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.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/zache.rb', line 123 def get(key, lifetime: 2**32, dirty: false, placeholder: nil, eager: false, &block) if block_given? return @hash[key][:value] if (dirty || @dirty) && locked?(key) && expired?(key) && @hash.key?(key) if eager return @hash[key][:value] if @hash.key?(key) put(key, placeholder, lifetime: 0) Thread.new do synchronize_one(key) do calc(key, lifetime, &block) end end placeholder else synchronize_one(key) do calc(key, lifetime, &block) end end else rec = @hash[key] if expired?(key) return rec[:value] if dirty || @dirty @hash.delete(key) rec = nil end raise 'The key is absent in the cache' if rec.nil? rec[:value] end end |
#locked?(key) ⇒ Boolean
Is key currently locked doing something?
192 193 194 |
# File 'lib/zache.rb', line 192 def locked?(key) @locks[key]&.locked? end |
#mtime(key) ⇒ Time
Returns the modification time of the key, if it exists. If not, current time is returned.
183 184 185 186 |
# File 'lib/zache.rb', line 183 def mtime(key) rec = @hash[key] rec.nil? ? Time.now : rec[:start] end |
#put(key, value, lifetime: 2**32) ⇒ Object
Put a value into the cache.
202 203 204 205 206 207 208 209 210 |
# File 'lib/zache.rb', line 202 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.
218 219 220 |
# File 'lib/zache.rb', line 218 def remove(key) synchronize_one(key) { @hash.delete(key) { yield if block_given? } } end |
#remove_all ⇒ Hash
Remove all keys from the cache.
225 226 227 |
# File 'lib/zache.rb', line 225 def remove_all synchronize_all { @hash = {} } end |
#remove_by {|key| ... } ⇒ Integer
Remove all keys that match the block.
234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/zache.rb', line 234 def remove_by synchronize_all do count = 0 @hash.each_key do |k| if yield(k) @hash.delete(k) count += 1 end end count end end |
#size ⇒ Integer
Total number of keys currently in cache.
99 100 101 |
# File 'lib/zache.rb', line 99 def size @hash.size end |