zache 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 257081764cc35a64985d251872770a52136ad5bdab0a11c6183e61af038e2eed
4
- data.tar.gz: 8fcdeb45bdb0471b97b3706ad0c82b6779a11fc7d930b9e2d7706691f400acb1
3
+ metadata.gz: 60df3e71e2b231946894808553577fa3877e865f1556858d195e0d49957b75d0
4
+ data.tar.gz: 2d64c893d7bf7dd43d5788b9a3ad155df595dc8ad22b48f536ed4484b037dd4f
5
5
  SHA512:
6
- metadata.gz: 0a232c9be3072ade8f8d83c647f67b85d7506cc34a2c17bd3ce6b85af5cf0cd8c5aed420d0019264ad62c73855ec28bbe7443b170f006dede7eec3d5dfb077f5
7
- data.tar.gz: b0eb1264f9ad527ec8fa36f12b2911dfcdfb62c9add06c7de088401a546bb96836279692e7138a0e51e74c74b2f4e80b60a5e2d31007a1d9bf406463710abe91
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. You turn that off by using `sync` argument:
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
- @monitor = Monitor.new
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
- !@monitor.mon_try_enter { true }
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
- @monitor.synchronize do
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 test_sync_zache_is_reentrant
171
+ def test_sync_zache_is_not_reentrant
172
172
  cache = Zache.new
173
- cache.get(:first) { cache.get(:second) { cache.get(:third) { 1 } } }
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 test_fetches_multiple_keys_in_many_threads
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.2'
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.2
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-18 00:00:00.000000000 Z
11
+ date: 2018-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby