sin_lru_redux 2.0.1 → 2.2.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 +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +78 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +17 -18
- data/README.md +24 -145
- data/Rakefile +1 -1
- data/lib/lru_redux/cache.rb +77 -47
- data/lib/lru_redux/ttl/cache.rb +120 -105
- data/lib/lru_redux/util/safe_sync.rb +2 -0
- data/lib/lru_redux/version.rb +1 -1
- metadata +10 -20
- data/.github/workflows/lint.yml +0 -19
- data/.github/workflows/test.yml +0 -21
- data/.gitignore +0 -19
- data/Gemfile +0 -19
- data/Guardfile +0 -6
- data/bench/bench.rb +0 -46
- data/bench/bench_ttl.rb +0 -35
- data/sin_lru_redux.gemspec +0 -35
- data/test/cache_test.rb +0 -146
- data/test/thread_safe_cache_test.rb +0 -19
- data/test/ttl/cache_test.rb +0 -93
- data/test/ttl/thread_safe_cache_test.rb +0 -20
data/Gemfile
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source 'https://rubygems.org'
|
4
|
-
|
5
|
-
gemspec
|
6
|
-
|
7
|
-
group :development, :test do
|
8
|
-
gem 'bundler'
|
9
|
-
gem 'guard'
|
10
|
-
gem 'guard-minitest'
|
11
|
-
gem 'minitest'
|
12
|
-
gem 'rake'
|
13
|
-
gem 'rb-inotify'
|
14
|
-
gem 'rubocop'
|
15
|
-
gem 'rubocop-minitest'
|
16
|
-
gem 'rubocop-performance'
|
17
|
-
gem 'rubocop-rake'
|
18
|
-
gem 'timecop'
|
19
|
-
end
|
data/Guardfile
DELETED
data/bench/bench.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler'
|
4
|
-
require 'benchmark'
|
5
|
-
require 'lru'
|
6
|
-
require 'lru_cache'
|
7
|
-
require 'threadsafe-lru'
|
8
|
-
|
9
|
-
Bundler.require
|
10
|
-
|
11
|
-
# Lru
|
12
|
-
lru = Cache::LRU.new(max_elements: 1_000)
|
13
|
-
|
14
|
-
# LruCache
|
15
|
-
lru_cache = LRUCache.new(1_000)
|
16
|
-
|
17
|
-
# ThreadSafeLru
|
18
|
-
thread_safe_lru = ThreadSafeLru::LruCache.new(1_000)
|
19
|
-
|
20
|
-
# LruRedux
|
21
|
-
redux = LruRedux::Cache.new(1_000)
|
22
|
-
redux_thread_safe = LruRedux::ThreadSafeCache.new(1_000)
|
23
|
-
|
24
|
-
puts '** LRU Benchmarks **'
|
25
|
-
|
26
|
-
Benchmark.bmbm do |bm|
|
27
|
-
bm.report 'ThreadSafeLru' do
|
28
|
-
1_000_000.times { thread_safe_lru.get(rand(2_000)) { :value } }
|
29
|
-
end
|
30
|
-
|
31
|
-
bm.report 'LRU' do
|
32
|
-
1_000_000.times { lru[rand(2_000)] ||= :value }
|
33
|
-
end
|
34
|
-
|
35
|
-
bm.report 'LRUCache' do
|
36
|
-
1_000_000.times { lru_cache[rand(2_000)] ||= :value }
|
37
|
-
end
|
38
|
-
|
39
|
-
bm.report 'LruRedux::Cache' do
|
40
|
-
1_000_000.times { redux.getset(rand(2_000)) { :value } }
|
41
|
-
end
|
42
|
-
|
43
|
-
bm.report 'LruRedux::ThreadSafeCache' do
|
44
|
-
1_000_000.times { redux_thread_safe.getset(rand(2_000)) { :value } }
|
45
|
-
end
|
46
|
-
end
|
data/bench/bench_ttl.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler'
|
4
|
-
require 'benchmark'
|
5
|
-
require 'fast_cache'
|
6
|
-
|
7
|
-
Bundler.require
|
8
|
-
|
9
|
-
# FastCache
|
10
|
-
fast_cache = FastCache::Cache.new(1_000, 5 * 60)
|
11
|
-
|
12
|
-
# LruRedux
|
13
|
-
redux_ttl = LruRedux::TTL::Cache.new(1_000, 5 * 60)
|
14
|
-
redux_ttl_thread_safe = LruRedux::TTL::ThreadSafeCache.new(1_000, 5 * 60)
|
15
|
-
redux_ttl_disabled = LruRedux::TTL::Cache.new(1_000, :none)
|
16
|
-
|
17
|
-
puts '** TTL Benchmarks **'
|
18
|
-
|
19
|
-
Benchmark.bmbm do |bm|
|
20
|
-
bm.report 'FastCache' do
|
21
|
-
1_000_000.times { fast_cache.fetch(rand(2_000)) { :value } } # rubocop:disable Style/RedundantFetchBlock
|
22
|
-
end
|
23
|
-
|
24
|
-
bm.report 'LruRedux::TTL::Cache' do
|
25
|
-
1_000_000.times { redux_ttl.getset(rand(2_000)) { :value } }
|
26
|
-
end
|
27
|
-
|
28
|
-
bm.report 'LruRedux::TTL::ThreadSafeCache' do
|
29
|
-
1_000_000.times { redux_ttl_thread_safe.getset(rand(2_000)) { :value } }
|
30
|
-
end
|
31
|
-
|
32
|
-
bm.report 'LruRedux::TTL::Cache (TTL disabled)' do
|
33
|
-
1_000_000.times { redux_ttl_disabled.getset(rand(2_000)) { :value } }
|
34
|
-
end
|
35
|
-
end
|
data/sin_lru_redux.gemspec
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'lru_redux/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'sin_lru_redux'
|
9
|
-
spec.version = LruRedux::VERSION
|
10
|
-
spec.description = <<~DESCRIPTION
|
11
|
-
Efficient and thread-safe LRU cache.
|
12
|
-
Forked from LruRedux.
|
13
|
-
DESCRIPTION
|
14
|
-
spec.summary = 'Efficient and thread-safe LRU cache.'
|
15
|
-
spec.authors = ['Masahiro']
|
16
|
-
spec.email = ['watanabe@cadenza-tech.com']
|
17
|
-
spec.license = 'MIT'
|
18
|
-
|
19
|
-
github_root_uri = 'https://github.com/cadenza-tech/sin_lru_redux'
|
20
|
-
spec.homepage = "#{github_root_uri}/tree/v#{spec.version}"
|
21
|
-
spec.metadata = {
|
22
|
-
'homepage_uri' => spec.homepage,
|
23
|
-
'source_code_uri' => spec.homepage,
|
24
|
-
'changelog_uri' => "#{github_root_uri}/blob/#{spec.version}#changelog",
|
25
|
-
'bug_tracker_uri' => "#{github_root_uri}/issues",
|
26
|
-
'documentation_uri' => "https://rubydoc.info/gems/#{spec.name}/#{spec.version}",
|
27
|
-
'rubygems_mfa_required' => 'true'
|
28
|
-
}
|
29
|
-
|
30
|
-
spec.required_ruby_version = '>= 2.3.0'
|
31
|
-
|
32
|
-
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
33
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
34
|
-
spec.require_paths = ['lib']
|
35
|
-
end
|
data/test/cache_test.rb
DELETED
@@ -1,146 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'lru_redux'
|
4
|
-
require 'minitest/autorun'
|
5
|
-
require 'minitest/pride'
|
6
|
-
|
7
|
-
class CacheTest < Minitest::Test
|
8
|
-
def setup
|
9
|
-
@c = LruRedux::Cache.new(3)
|
10
|
-
end
|
11
|
-
|
12
|
-
def teardown
|
13
|
-
assert @c.send(:valid?) # rubocop:disable Minitest/AssertionInLifecycleHook
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_drops_old
|
17
|
-
@c[:a] = 1
|
18
|
-
@c[:b] = 2
|
19
|
-
@c[:c] = 3
|
20
|
-
@c[:d] = 4
|
21
|
-
|
22
|
-
assert_equal [[:d, 4], [:c, 3], [:b, 2]], @c.to_a
|
23
|
-
assert_nil @c[:a]
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_fetch
|
27
|
-
@c[:a] = nil
|
28
|
-
@c[:b] = 2
|
29
|
-
|
30
|
-
assert_nil @c.fetch(:a) { 1 } # rubocop:disable Style/RedundantFetchBlock
|
31
|
-
assert_equal 3, @c.fetch(:c) { 3 } # rubocop:disable Style/RedundantFetchBlock
|
32
|
-
assert_equal [[:a, nil], [:b, 2]], @c.to_a
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_getset # rubocop:disable Minitest/MultipleAssertions
|
36
|
-
assert_equal 1, @c.getset(:a) { 1 }
|
37
|
-
@c.getset(:b) { 2 }
|
38
|
-
|
39
|
-
assert_equal 1, @c.getset(:a) { 11 }
|
40
|
-
@c.getset(:c) { 3 }
|
41
|
-
|
42
|
-
assert_equal 4, @c.getset(:d) { 4 }
|
43
|
-
assert_equal [[:d, 4], [:c, 3], [:a, 1]], @c.to_a
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_pushes_lru_to_back
|
47
|
-
@c[:a] = 1
|
48
|
-
@c[:b] = 2
|
49
|
-
@c[:c] = 3
|
50
|
-
|
51
|
-
@c[:a]
|
52
|
-
@c[:d] = 4
|
53
|
-
|
54
|
-
assert_equal [[:d, 4], [:a, 1], [:c, 3]], @c.to_a
|
55
|
-
assert_nil @c[:b]
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_delete # rubocop:disable Minitest/MultipleAssertions
|
59
|
-
@c[:a] = 1
|
60
|
-
@c[:b] = 2
|
61
|
-
@c[:c] = 3
|
62
|
-
@c.delete(:a)
|
63
|
-
|
64
|
-
assert_equal [[:c, 3], [:b, 2]], @c.to_a
|
65
|
-
assert_nil @c[:a]
|
66
|
-
|
67
|
-
# Regression test for a bug in the legacy delete method
|
68
|
-
@c.delete(:b)
|
69
|
-
@c[:d] = 4
|
70
|
-
@c[:e] = 5
|
71
|
-
@c[:f] = 6
|
72
|
-
|
73
|
-
assert_equal [[:f, 6], [:e, 5], [:d, 4]], @c.to_a
|
74
|
-
assert_nil @c[:b]
|
75
|
-
end
|
76
|
-
|
77
|
-
def test_key?
|
78
|
-
@c[:a] = 1
|
79
|
-
@c[:b] = 2
|
80
|
-
|
81
|
-
assert @c.key?(:a)
|
82
|
-
refute @c.key?(:c)
|
83
|
-
end
|
84
|
-
|
85
|
-
def test_update
|
86
|
-
@c[:a] = 1
|
87
|
-
@c[:b] = 2
|
88
|
-
@c[:c] = 3
|
89
|
-
@c[:a] = 99
|
90
|
-
|
91
|
-
assert_equal [[:a, 99], [:c, 3], [:b, 2]], @c.to_a
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_clear
|
95
|
-
@c[:a] = 1
|
96
|
-
@c[:b] = 2
|
97
|
-
@c[:c] = 3
|
98
|
-
|
99
|
-
@c.clear
|
100
|
-
|
101
|
-
assert_empty @c.to_a
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_grow
|
105
|
-
@c[:a] = 1
|
106
|
-
@c[:b] = 2
|
107
|
-
@c[:c] = 3
|
108
|
-
@c.max_size = 4
|
109
|
-
@c[:d] = 4
|
110
|
-
|
111
|
-
assert_equal [[:d, 4], [:c, 3], [:b, 2], [:a, 1]], @c.to_a
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_shrink
|
115
|
-
@c[:a] = 1
|
116
|
-
@c[:b] = 2
|
117
|
-
@c[:c] = 3
|
118
|
-
@c.max_size = 1
|
119
|
-
|
120
|
-
assert_equal [[:c, 3]], @c.to_a
|
121
|
-
end
|
122
|
-
|
123
|
-
def test_each
|
124
|
-
@c.max_size = 2
|
125
|
-
@c[:a] = 1
|
126
|
-
@c[:b] = 2
|
127
|
-
@c[:c] = 3
|
128
|
-
|
129
|
-
pairs = []
|
130
|
-
@c.each do |pair| # rubocop:disable Style/MapIntoArray
|
131
|
-
pairs << pair
|
132
|
-
end
|
133
|
-
|
134
|
-
assert_equal [[:c, 3], [:b, 2]], pairs
|
135
|
-
end
|
136
|
-
|
137
|
-
def test_values
|
138
|
-
@c[:a] = 1
|
139
|
-
@c[:b] = 2
|
140
|
-
@c[:c] = 3
|
141
|
-
@c[:d] = 4
|
142
|
-
|
143
|
-
assert_equal [4, 3, 2], @c.values
|
144
|
-
assert_nil @c[:a]
|
145
|
-
end
|
146
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/cache_test'
|
4
|
-
|
5
|
-
class ThreadSafeCacheTest < CacheTest
|
6
|
-
def setup
|
7
|
-
@c = LruRedux::ThreadSafeCache.new(3)
|
8
|
-
end
|
9
|
-
|
10
|
-
def test_recursion
|
11
|
-
@c[:a] = 1
|
12
|
-
@c[:b] = 2
|
13
|
-
|
14
|
-
# should not blow up
|
15
|
-
@c.each do |k, _| # rubocop:disable Style/HashEachMethods
|
16
|
-
@c[k]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/test/ttl/cache_test.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'timecop'
|
4
|
-
require './test/cache_test'
|
5
|
-
|
6
|
-
class TTLCacheTest < CacheTest
|
7
|
-
def setup
|
8
|
-
Timecop.freeze(Time.now)
|
9
|
-
@c = LruRedux::TTL::Cache.new 3, 5 * 60
|
10
|
-
end
|
11
|
-
|
12
|
-
def teardown
|
13
|
-
Timecop.return
|
14
|
-
|
15
|
-
assert @c.send(:valid?) # rubocop:disable Minitest/AssertionInLifecycleHook
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_ttl
|
19
|
-
assert_equal 300, @c.ttl
|
20
|
-
|
21
|
-
@c.ttl = 10 * 60
|
22
|
-
|
23
|
-
assert_equal 600, @c.ttl
|
24
|
-
end
|
25
|
-
|
26
|
-
# TTL tests using Timecop
|
27
|
-
def test_ttl_eviction_on_access
|
28
|
-
@c[:a] = 1
|
29
|
-
@c[:b] = 2
|
30
|
-
|
31
|
-
Timecop.freeze(Time.now + 330)
|
32
|
-
|
33
|
-
@c[:c] = 3
|
34
|
-
|
35
|
-
assert_equal([[:c, 3]], @c.to_a)
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_ttl_eviction_on_expire
|
39
|
-
@c[:a] = 1
|
40
|
-
@c[:b] = 2
|
41
|
-
|
42
|
-
Timecop.freeze(Time.now + 330)
|
43
|
-
|
44
|
-
@c.expire
|
45
|
-
|
46
|
-
assert_empty @c.to_a
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_ttl_eviction_on_new_max_size
|
50
|
-
@c[:a] = 1
|
51
|
-
@c[:b] = 2
|
52
|
-
|
53
|
-
Timecop.freeze(Time.now + 330)
|
54
|
-
|
55
|
-
@c.max_size = 10
|
56
|
-
|
57
|
-
assert_empty @c.to_a
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_ttl_eviction_on_new_ttl
|
61
|
-
@c[:a] = 1
|
62
|
-
@c[:b] = 2
|
63
|
-
|
64
|
-
Timecop.freeze(Time.now + 330)
|
65
|
-
|
66
|
-
@c.ttl = 10 * 60
|
67
|
-
|
68
|
-
assert_equal([[:b, 2], [:a, 1]], @c.to_a)
|
69
|
-
|
70
|
-
@c.ttl = 2 * 60
|
71
|
-
|
72
|
-
assert_empty @c.to_a
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_ttl_precedence_over_lru
|
76
|
-
@c[:a] = 1
|
77
|
-
|
78
|
-
Timecop.freeze(Time.now + 60)
|
79
|
-
|
80
|
-
@c[:b] = 2
|
81
|
-
@c[:c] = 3
|
82
|
-
|
83
|
-
@c[:a]
|
84
|
-
|
85
|
-
assert_equal [[:a, 1], [:c, 3], [:b, 2]], @c.to_a
|
86
|
-
|
87
|
-
Timecop.freeze(Time.now + 270)
|
88
|
-
|
89
|
-
@c[:d] = 4
|
90
|
-
|
91
|
-
assert_equal [[:d, 4], [:c, 3], [:b, 2]], @c.to_a
|
92
|
-
end
|
93
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require './test/ttl/cache_test'
|
4
|
-
|
5
|
-
class TTLThreadSafeCacheTest < TTLCacheTest
|
6
|
-
def setup
|
7
|
-
Timecop.freeze(Time.now)
|
8
|
-
@c = LruRedux::TTL::ThreadSafeCache.new 3, 5 * 60
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_recursion
|
12
|
-
@c[:a] = 1
|
13
|
-
@c[:b] = 2
|
14
|
-
|
15
|
-
# should not blow up
|
16
|
-
@c.each do |k, _| # rubocop:disable Style/HashEachMethods
|
17
|
-
@c[k]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|