zache 0.4.0 → 0.5.0

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: 91965defa678c5b684064d7b868b46f7f8b31c9192209d6eb2f659055e790056
4
- data.tar.gz: 35d397d7fa7179e0968b564cad219a8e1aedaf0c2efc92e4fb7079faaec36d49
3
+ metadata.gz: a1b2d35db53d59daaf2d281eb08c0381bc0d7302cbab9d817c39b22e8aec93b0
4
+ data.tar.gz: db7d2212ceea4cc6f7e2f8feb5954b720c16ed0fd12fab56ea50c2d2fed5621c
5
5
  SHA512:
6
- metadata.gz: 88c5c68c7438dd4a34abc24a529815abb2020a4fc2502bab0d374fcc75e79b5bfb447c1f4b82d72cc7787c5bd0c0cb2aae8176da9a332b33bb8880ef3c286c4d
7
- data.tar.gz: 734f9721d3e726ba433881a325a724e4e2cfa45c5b94962753879d61dc33d9ed763ec1bb144b2042c87673746cfd753a7b7b708b7c83ff610777caa1b5ed8ffa
6
+ metadata.gz: 63ffba8c6c32c96aabbf443b6faa94bcbe4b8e5a6fb2f2a39ac36bdc6a68906c7d0f46a8266d10d485ed4ec463104d38f65bfed4cb3bf246a8d4cfdbe2da545e
7
+ data.tar.gz: 9b46a730a46d6a177092b1499f3cd020796eb4c63782a17cb0e8c54ad55e1fabbaf9b9d96ff703ab41e502e41dcf8d338a184e9fad4aae29eaddd95a19555938
data/.rubocop.yml CHANGED
@@ -13,3 +13,7 @@ Metrics/AbcSize:
13
13
  Max: 30
14
14
  Metrics/MethodLength:
15
15
  Max: 30
16
+ Metrics/CyclomaticComplexity:
17
+ Max: 10
18
+ Metrics/PerceivedComplexity:
19
+ Max: 10
data/lib/zache.rb CHANGED
@@ -43,9 +43,13 @@ class Zache
43
43
  # "sync" is whether the hash is thread-safe (`true`)
44
44
  # or not (`false`); it is recommended to leave this parameter untouched,
45
45
  # unless you really know what you are doing.
46
- def initialize(sync: true)
46
+ #
47
+ # If the <tt>dirty</tt> argument is set to <tt>true</tt>, a previously
48
+ # calculated result will be returned if it exists.
49
+ def initialize(sync: true, dirty: false)
47
50
  @hash = {}
48
51
  @sync = sync
52
+ @dirty = dirty
49
53
  @monitor = Monitor.new
50
54
  end
51
55
 
@@ -54,8 +58,14 @@ class Zache
54
58
  # the block is not given, an exception will be raised. The lifetime
55
59
  # must be in seconds. The default lifetime is huge, which means that the
56
60
  # key will never be expired.
57
- def get(key, lifetime: 2**32)
61
+ #
62
+ # If the <tt>dirty</tt> argument is set to <tt>true</tt>, a previously
63
+ # calculated result will be returned if it exists.
64
+ def get(key, lifetime: 2**32, dirty: false)
58
65
  if block_given?
66
+ if (dirty || @dirty) && locked? && !key_expired?(key) && @hash.key?(key)
67
+ return @hash[key]
68
+ end
59
69
  synchronized { calc(key, lifetime) { yield } }
60
70
  else
61
71
  rec = @hash[key]
@@ -80,6 +90,11 @@ class Zache
80
90
  !rec.nil?
81
91
  end
82
92
 
93
+ # Is cache currently locked doing something?
94
+ def locked?
95
+ !@monitor.mon_try_enter { true }
96
+ end
97
+
83
98
  # Put a value into the cache.
84
99
  def put(key, value, lifetime: 2**32)
85
100
  synchronized do
@@ -124,7 +139,7 @@ class Zache
124
139
 
125
140
  def synchronized
126
141
  if @sync
127
- @monitor.synchronize { yield }
142
+ @monitor.mon_synchronize { yield }
128
143
  else
129
144
  yield
130
145
  end
data/test/test_zache.rb CHANGED
@@ -24,6 +24,7 @@
24
24
 
25
25
  require 'minitest/autorun'
26
26
  require 'threads'
27
+ require 'timeout'
27
28
  require_relative '../lib/zache'
28
29
 
29
30
  # Cache test.
@@ -168,4 +169,32 @@ class ZacheTest < Minitest::Test
168
169
  cache = Zache.new
169
170
  cache.get(:first) { cache.get(:second) { cache.get(:third) { 1 } } }
170
171
  end
172
+
173
+ def test_calculates_only_once
174
+ cache = Zache.new
175
+ long = Thread.start do
176
+ cache.get(:x) do
177
+ sleep 0.5
178
+ 'first'
179
+ end
180
+ end
181
+ sleep 0.1
182
+ assert(cache.locked?)
183
+ cache.get(:x) { 'second' }
184
+ assert(!cache.locked?)
185
+ long.kill
186
+ end
187
+
188
+ def test_returns_dirty_result
189
+ cache = Zache.new
190
+ cache.get(:first, lifetime: 10) { 1 }
191
+ long = Thread.start do
192
+ cache.get(:first) { sleep 1000 }
193
+ end
194
+ sleep 0.1
195
+ Timeout.timeout(1) do
196
+ assert_equal(1, cache.get(:first, dirty: true) { 2 })
197
+ end
198
+ long.kill
199
+ end
171
200
  end
data/zache.gemspec CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
31
31
  s.rubygems_version = '2.3.3'
32
32
  s.required_ruby_version = '>=2.3'
33
33
  s.name = 'zache'
34
- s.version = '0.4.0'
34
+ s.version = '0.5.0'
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.4.0
4
+ version: 0.5.0
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-01 00:00:00.000000000 Z
11
+ date: 2018-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest