zache 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/lib/zache.rb +3 -5
- data/test/test_zache.rb +24 -3
- data/zache.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60df3e71e2b231946894808553577fa3877e865f1556858d195e0d49957b75d0
|
4
|
+
data.tar.gz: 2d64c893d7bf7dd43d5788b9a3ad155df595dc8ad22b48f536ed4484b037dd4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27bb7605e2618a94c0bcc2d6978a19055bbced16b7f398a1ad232009d091259c7846efde96975bb0929940f9fc52a47345a62007b3b6fccaed7870eaf04cc267
|
7
|
+
data.tar.gz: 7101a0956069c62e85dfcc7796033e0133303a0f3b8ee87a46b90316991db1d2fd41ff1375c3b7fd1985412e7c301d9b876576d2f41b5876bc8550c3ad673441
|
data/README.md
CHANGED
@@ -25,13 +25,21 @@ zache = Zache.new
|
|
25
25
|
v = zache.get(:count, lifetime: 5 * 60) { expensive() }
|
26
26
|
```
|
27
27
|
|
28
|
-
By default `Zache` is thread-safe.
|
28
|
+
By default `Zache` is thread-safe. It locks the entire cache on each
|
29
|
+
`get` call. You turn that off by using `sync` argument:
|
29
30
|
|
30
31
|
```ruby
|
31
32
|
zache = Zache.new(sync: false)
|
32
33
|
v = zache.get(:count) { expensive() }
|
33
34
|
```
|
34
35
|
|
36
|
+
You may use "dirty" mode, which will return you an expired value, while
|
37
|
+
calculation is waiting. Say, you have something in the cache, but it's
|
38
|
+
expired. Then, you call `get` with a long running block. The thread waits,
|
39
|
+
while another one calls `get` again. That second thread won't wait, but will
|
40
|
+
receive what's left in the cache. This is a very convenient mode for situations
|
41
|
+
when you don't really care about data accuracy, but performance is an issue.
|
42
|
+
|
35
43
|
That's it.
|
36
44
|
|
37
45
|
# How to contribute
|
data/lib/zache.rb
CHANGED
@@ -22,8 +22,6 @@
|
|
22
22
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
23
|
# SOFTWARE.
|
24
24
|
|
25
|
-
require 'monitor'
|
26
|
-
|
27
25
|
# It is a very simple thread-safe in-memory cache with an ability to expire
|
28
26
|
# keys automatically, when their lifetime is over. Use it like this:
|
29
27
|
#
|
@@ -50,7 +48,7 @@ class Zache
|
|
50
48
|
@hash = {}
|
51
49
|
@sync = sync
|
52
50
|
@dirty = dirty
|
53
|
-
@
|
51
|
+
@mutex = Mutex.new
|
54
52
|
end
|
55
53
|
|
56
54
|
# Gets the value from the cache by the provided key. If the value is not
|
@@ -92,7 +90,7 @@ class Zache
|
|
92
90
|
|
93
91
|
# Is cache currently locked doing something?
|
94
92
|
def locked?
|
95
|
-
|
93
|
+
@mutex.locked?
|
96
94
|
end
|
97
95
|
|
98
96
|
# Put a value into the cache.
|
@@ -139,7 +137,7 @@ class Zache
|
|
139
137
|
|
140
138
|
def synchronized
|
141
139
|
if @sync
|
142
|
-
@
|
140
|
+
@mutex.synchronize do
|
143
141
|
# I don't know why, but if you remove this line, the tests will
|
144
142
|
# break. It seems to me that there is a bug in Ruby. Let's try to
|
145
143
|
# fix it or find a workaround and remove this line.
|
data/test/test_zache.rb
CHANGED
@@ -168,9 +168,11 @@ class ZacheTest < Minitest::Test
|
|
168
168
|
assert_equal(123, cache.get(:hey))
|
169
169
|
end
|
170
170
|
|
171
|
-
def
|
171
|
+
def test_sync_zache_is_not_reentrant
|
172
172
|
cache = Zache.new
|
173
|
-
|
173
|
+
assert_raises ThreadError do
|
174
|
+
cache.get(:first) { cache.get(:second) { 1 } }
|
175
|
+
end
|
174
176
|
end
|
175
177
|
|
176
178
|
def test_calculates_only_once
|
@@ -188,6 +190,15 @@ class ZacheTest < Minitest::Test
|
|
188
190
|
long.kill
|
189
191
|
end
|
190
192
|
|
193
|
+
def test_checks_locked_status_from_inside
|
194
|
+
cache = Zache.new
|
195
|
+
cache.get(:x) do
|
196
|
+
assert(cache.locked?)
|
197
|
+
'done'
|
198
|
+
end
|
199
|
+
assert(!cache.locked?)
|
200
|
+
end
|
201
|
+
|
191
202
|
def test_returns_dirty_result
|
192
203
|
cache = Zache.new
|
193
204
|
cache.get(:x, lifetime: 0) { 1 }
|
@@ -204,10 +215,20 @@ class ZacheTest < Minitest::Test
|
|
204
215
|
long.kill
|
205
216
|
end
|
206
217
|
|
207
|
-
def
|
218
|
+
def test_fetches_multiple_keys_in_many_threads_in_dirty_mode
|
208
219
|
cache = Zache.new(dirty: true)
|
209
220
|
set = Concurrent::Set.new
|
210
221
|
threads = 50
|
222
|
+
Threads.new(threads).assert(threads * 2) do |i|
|
223
|
+
set << cache.get(i, lifetime: 0.001) { i }
|
224
|
+
end
|
225
|
+
assert_equal(threads, set.size)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_fetches_multiple_keys_in_many_threads
|
229
|
+
cache = Zache.new
|
230
|
+
set = Concurrent::Set.new
|
231
|
+
threads = 50
|
211
232
|
Threads.new(threads).assert(threads * 2) do |i|
|
212
233
|
set << cache.get(i) { i }
|
213
234
|
end
|
data/zache.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.rubygems_version = '2.5'
|
32
32
|
s.required_ruby_version = '>=2.5'
|
33
33
|
s.name = 'zache'
|
34
|
-
s.version = '0.5.
|
34
|
+
s.version = '0.5.3'
|
35
35
|
s.license = 'MIT'
|
36
36
|
s.summary = 'In-memory Cache'
|
37
37
|
s.description = 'Zero-footprint in-memory thread-safe cache'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|