double_write_cache_stores 0.3.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 +5 -5
- data/.codeclimate.yml +7 -0
- data/.github/workflows/test.yml +60 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +91 -0
- data/.ruby-version +1 -0
- data/Appraisals +18 -0
- data/Gemfile +1 -1
- data/README.md +27 -12
- data/Rakefile +6 -1
- data/activesupport.gemfile +7 -0
- data/activesupport.gemfile.lock +62 -0
- data/compose.yaml +9 -0
- data/double_write_cache_stores.gemspec +13 -11
- data/gemfiles/activesupport_5_2.gemfile +7 -0
- data/gemfiles/activesupport_6_0.gemfile +7 -0
- data/gemfiles/activesupport_6_1.gemfile +7 -0
- data/gemfiles/activesupport_7_0.gemfile +7 -0
- data/gemfiles/without_activesupport.gemfile +5 -0
- data/lib/double_write_cache_stores/client.rb +171 -179
- data/lib/double_write_cache_stores/version.rb +1 -1
- data/lib/double_write_cache_stores.rb +22 -3
- data/lib/mem_cache_store_patch.rb +13 -0
- data/spec/double_write_cache_stores/client_spec.rb +238 -154
- data/spec/double_write_cache_stores_spec.rb +2 -2
- data/spec/spec_helper.rb +5 -26
- metadata +50 -39
- data/.travis.yml +0 -3
- data/lib/dalli_store_patch.rb +0 -41
|
@@ -1,217 +1,209 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
module DoubleWriteCacheStores
|
|
2
|
+
class Client # rubocop:disable Metrics/ClassLength
|
|
3
|
+
attr_accessor :read_and_write_store, :write_only_store
|
|
4
|
+
|
|
5
|
+
def initialize(read_and_write_store_servers, write_only_store_servers = nil)
|
|
6
|
+
@read_and_write_store = read_and_write_store_servers
|
|
7
|
+
if write_only_store_servers
|
|
8
|
+
if read_and_write_store_servers.class != write_only_store_servers.class
|
|
9
|
+
raise "different cache store instance. #{read_and_write_store_servers.class} != #{write_only_store_servers.class}"
|
|
10
|
+
end
|
|
11
|
+
@write_only_store = write_only_store_servers
|
|
12
|
+
end
|
|
9
13
|
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def [](key)
|
|
13
|
-
get key
|
|
14
|
-
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def get_multi(*keys)
|
|
21
|
-
get_multi_or_read_multi_method_call *keys
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def get_cas(key)
|
|
25
|
-
if @read_and_write_store.respond_to? :get_cas
|
|
26
|
-
@read_and_write_store.get_cas key
|
|
27
|
-
elsif @read_and_write_store.respond_to? :read_cas
|
|
28
|
-
@read_and_write_store.read_cas key
|
|
15
|
+
def [](key)
|
|
16
|
+
get key
|
|
29
17
|
end
|
|
30
|
-
end
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if @write_only_store && cas_unique
|
|
42
|
-
set_or_write_method_call @write_only_store, key, value, options
|
|
19
|
+
def get_cas(key)
|
|
20
|
+
if @read_and_write_store.respond_to? :get_cas
|
|
21
|
+
@read_and_write_store.get_cas key
|
|
22
|
+
elsif @read_and_write_store.respond_to? :read_cas
|
|
23
|
+
@read_and_write_store.read_cas key
|
|
24
|
+
elsif @read_and_write_store.respond_to? :dalli
|
|
25
|
+
@read_and_write_store.dalli.get_cas key
|
|
26
|
+
end
|
|
43
27
|
end
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
end
|
|
29
|
+
def set_cas(key, value, cas = 0, options = nil)
|
|
30
|
+
cas_unique = if @read_and_write_store.respond_to? :set_cas
|
|
31
|
+
@read_and_write_store.set_cas key, value, cas, options
|
|
32
|
+
elsif @read_and_write_store.respond_to? :read_cas
|
|
33
|
+
options ||= {}
|
|
34
|
+
options[:cas] = cas
|
|
35
|
+
@read_and_write_store.write_cas key, value, options
|
|
36
|
+
elsif @read_and_write_store.respond_to? :dalli
|
|
37
|
+
@read_and_write_store.dalli.set_cas key, value, cas, options
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if @write_only_store && cas_unique
|
|
41
|
+
set_or_write_method_call @write_only_store, key, value, options
|
|
42
|
+
end
|
|
60
43
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
44
|
+
cas_unique
|
|
45
|
+
end
|
|
64
46
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
47
|
+
def delete(key)
|
|
48
|
+
result = @read_and_write_store.delete key
|
|
49
|
+
@write_only_store.delete key if @write_only_store
|
|
50
|
+
result
|
|
51
|
+
end
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
def []=(key, value)
|
|
54
|
+
set key, value
|
|
55
|
+
end
|
|
72
56
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
57
|
+
def touch(key, ttl = nil)
|
|
58
|
+
result = if @read_and_write_store.respond_to? :touch
|
|
59
|
+
@read_and_write_store.touch key, ttl
|
|
60
|
+
elsif @read_and_write_store.respond_to? :dalli
|
|
61
|
+
@read_and_write_store.dalli.touch key, ttl
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if @write_only_store
|
|
65
|
+
if @write_only_store.respond_to? :touch
|
|
66
|
+
@write_only_store.touch key, ttl
|
|
67
|
+
elsif @write_only_store.respond_to? :dalli
|
|
68
|
+
@write_only_store.dalli.touch key, ttl
|
|
69
|
+
end
|
|
82
70
|
end
|
|
83
|
-
end
|
|
84
|
-
result
|
|
85
|
-
end
|
|
86
71
|
|
|
87
|
-
|
|
88
|
-
if flush_cache_store || flush_cache_store(:clear)
|
|
89
|
-
true
|
|
90
|
-
else
|
|
91
|
-
false
|
|
72
|
+
result
|
|
92
73
|
end
|
|
93
|
-
end
|
|
94
74
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if block_given?
|
|
99
|
-
result = @read_and_write_store.fetch(name, options = nil) { yield }
|
|
100
|
-
@write_only_store.fetch(name, options = nil) { yield } if @write_only_store
|
|
101
|
-
result
|
|
75
|
+
def flush
|
|
76
|
+
if flush_cache_store || flush_cache_store(:clear)
|
|
77
|
+
true
|
|
102
78
|
else
|
|
103
|
-
|
|
104
|
-
@write_only_store.fetch(name, options = nil) if @write_only_store
|
|
105
|
-
result
|
|
79
|
+
false
|
|
106
80
|
end
|
|
107
|
-
else
|
|
108
|
-
raise UnSupportException.new "Unsupported #fetch from client object."
|
|
109
81
|
end
|
|
110
|
-
end
|
|
111
82
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
end
|
|
115
|
-
alias_method :incr, :increment
|
|
83
|
+
def fetch(name, options = {}, &_block)
|
|
84
|
+
raise UnSupportException "Unsupported #fetch from client object." unless @read_and_write_store.respond_to?(:fetch)
|
|
116
85
|
|
|
117
|
-
|
|
118
|
-
decrement_cache_store key, amount, options
|
|
119
|
-
end
|
|
120
|
-
alias_method :decr, :decrement
|
|
121
|
-
|
|
122
|
-
private
|
|
123
|
-
|
|
124
|
-
def write_cache_store(key, value, options = nil)
|
|
125
|
-
set_or_write_method_call @read_and_write_store, key, value, options
|
|
126
|
-
set_or_write_method_call @write_only_store, key, value, options if @write_only_store
|
|
127
|
-
end
|
|
86
|
+
delete name if options[:force]
|
|
128
87
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if defined?(Dalli) && cache_store.is_a?(Dalli::Client)
|
|
132
|
-
ttl = options[:expires_in] if options
|
|
133
|
-
cache_store.set key, value, ttl, options
|
|
88
|
+
if options[:race_condition_ttl]
|
|
89
|
+
fetch_race_condition name, options { yield }
|
|
134
90
|
else
|
|
135
|
-
|
|
91
|
+
unless value = get_or_read_method_call(name)
|
|
92
|
+
value = yield
|
|
93
|
+
write_cache_store name, value, options
|
|
94
|
+
end
|
|
95
|
+
value
|
|
136
96
|
end
|
|
137
|
-
elsif cache_store.respond_to? :write
|
|
138
|
-
cache_store.write key, value, options
|
|
139
97
|
end
|
|
140
|
-
end
|
|
141
98
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
@read_and_write_store.get key
|
|
145
|
-
elsif @read_and_write_store.respond_to? :read
|
|
146
|
-
@read_and_write_store.read key
|
|
99
|
+
def increment(key, amount = 1, options = {})
|
|
100
|
+
increment_cache_store key, amount, options
|
|
147
101
|
end
|
|
148
|
-
|
|
102
|
+
alias_method :incr, :increment
|
|
149
103
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
@read_and_write_store.get_multi *keys
|
|
153
|
-
elsif @read_and_write_store.respond_to? :read_multi
|
|
154
|
-
@read_and_write_store.read_multi *keys
|
|
155
|
-
else
|
|
156
|
-
raise UnSupportException.new "Unsupported multi keys get or read from client object."
|
|
104
|
+
def decrement(key, amount = 1, options = {})
|
|
105
|
+
decrement_cache_store key, amount, options
|
|
157
106
|
end
|
|
158
|
-
|
|
107
|
+
alias_method :decr, :decrement
|
|
159
108
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
109
|
+
def write_cache_store(key, value, options = nil)
|
|
110
|
+
set_or_write_method_call @read_and_write_store, key, value, options
|
|
111
|
+
set_or_write_method_call @write_only_store, key, value, options if @write_only_store
|
|
112
|
+
end
|
|
113
|
+
alias_method :set, :write_cache_store
|
|
114
|
+
alias_method :write, :write_cache_store
|
|
115
|
+
|
|
116
|
+
def get_or_read_method_call(key)
|
|
117
|
+
if @read_and_write_store.respond_to? :get
|
|
118
|
+
@read_and_write_store.get key
|
|
119
|
+
elsif @read_and_write_store.respond_to? :read
|
|
120
|
+
@read_and_write_store.read key
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
alias_method :get, :get_or_read_method_call
|
|
124
|
+
alias_method :read, :get_or_read_method_call
|
|
125
|
+
|
|
126
|
+
def get_multi_or_read_multi_method_call(*keys)
|
|
127
|
+
if @read_and_write_store.respond_to? :get_multi
|
|
128
|
+
@read_and_write_store.get_multi(*keys)
|
|
129
|
+
elsif @read_and_write_store.respond_to? :read_multi
|
|
130
|
+
@read_and_write_store.read_multi(*keys)
|
|
131
|
+
else
|
|
132
|
+
raise UnSupportException "Unsupported multi keys get or read from client object."
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
alias_method :get_multi, :get_multi_or_read_multi_method_call
|
|
136
|
+
alias_method :read_multi, :get_multi_or_read_multi_method_call
|
|
165
137
|
|
|
166
|
-
|
|
167
|
-
rw_store_value = decr_or_decrement_method_call @read_and_write_store, key, amount, options
|
|
168
|
-
return rw_store_value unless @write_only_store
|
|
169
|
-
decr_or_decrement_method_call @write_only_store, key, amount, options
|
|
170
|
-
end
|
|
138
|
+
private
|
|
171
139
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
elsif cache_store.respond_to? :increment
|
|
178
|
-
options[:initial] = amount unless options.has_key?(:initial)
|
|
179
|
-
cache_store.increment key, amount, options
|
|
180
|
-
end
|
|
181
|
-
end
|
|
140
|
+
def fetch_race_condition(key, options, &_block)
|
|
141
|
+
result = fetch_to_cache_store(@read_and_write_store, key, options) { yield }
|
|
142
|
+
fetch_to_cache_store(@write_only_store, key, options) { result } if @write_only_store && @write_only_store.respond_to?(:fetch)
|
|
143
|
+
result
|
|
144
|
+
end
|
|
182
145
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
end
|
|
192
|
-
end
|
|
146
|
+
def fetch_to_cache_store(cache_store, key, options, &_block)
|
|
147
|
+
if cache_store.is_a? Dalli::Client
|
|
148
|
+
ttl = options[:expires_in]
|
|
149
|
+
cache_store.fetch key, ttl, options { yield }
|
|
150
|
+
else
|
|
151
|
+
cache_store.fetch key, options { yield }
|
|
152
|
+
end
|
|
153
|
+
end
|
|
193
154
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
155
|
+
def set_or_write_method_call(cache_store, key, value, options)
|
|
156
|
+
if cache_store.respond_to? :set
|
|
157
|
+
ttl = options[:expires_in] if options
|
|
158
|
+
cache_store.set key, value, ttl, options
|
|
159
|
+
elsif cache_store.respond_to? :write
|
|
160
|
+
cache_store.write key, value, options
|
|
161
|
+
end
|
|
198
162
|
end
|
|
199
|
-
@read_and_write_store.send method
|
|
200
|
-
else
|
|
201
|
-
false
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
163
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
@write_only_store
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
164
|
+
def increment_cache_store(key, amount, options)
|
|
165
|
+
rw_store_value = incr_or_increment_method_call @read_and_write_store, key, amount, options
|
|
166
|
+
return rw_store_value unless @write_only_store
|
|
167
|
+
incr_or_increment_method_call @write_only_store, key, amount, options
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def decrement_cache_store(key, amount, options)
|
|
171
|
+
rw_store_value = decr_or_decrement_method_call @read_and_write_store, key, amount, options
|
|
172
|
+
return rw_store_value unless @write_only_store
|
|
173
|
+
decr_or_decrement_method_call @write_only_store, key, amount, options
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def incr_or_increment_method_call(cache_store, key, amount, options)
|
|
177
|
+
ttl = options[:expires_in] if options
|
|
178
|
+
default = options.key?(:initial) ? options[:initial] : amount
|
|
179
|
+
if cache_store.is_a? Dalli::Client
|
|
180
|
+
cache_store.incr key, amount, ttl, default
|
|
181
|
+
elsif cache_store.respond_to? :increment
|
|
182
|
+
options[:initial] = amount unless options.key?(:initial)
|
|
183
|
+
cache_store.increment key, amount, **options
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def decr_or_decrement_method_call(cache_store, key, amount, options)
|
|
188
|
+
if cache_store.is_a?(Dalli::Client)
|
|
189
|
+
ttl = options[:expires_in] if options
|
|
190
|
+
default = options.key?(:initial) ? options[:initial] : 0
|
|
191
|
+
cache_store.decr key, amount, ttl, default
|
|
192
|
+
elsif cache_store.respond_to? :decrement
|
|
193
|
+
options[:initial] = 0 unless options.key?(:initial)
|
|
194
|
+
cache_store.decrement key, amount, **options
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def flush_cache_store(method = :flush)
|
|
199
|
+
if @read_and_write_store.respond_to? method
|
|
200
|
+
if @write_only_store && @write_only_store.respond_to?(method)
|
|
201
|
+
@write_only_store.send method
|
|
202
|
+
end
|
|
203
|
+
@read_and_write_store.send method
|
|
204
|
+
else
|
|
205
|
+
false
|
|
213
206
|
end
|
|
214
207
|
end
|
|
215
|
-
end
|
|
216
208
|
end
|
|
217
209
|
end
|
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
module DoubleWriteCacheStores
|
|
2
|
+
loaded_active_support = false
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require "active_support"
|
|
6
|
+
loaded_active_support = true
|
|
7
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
loaded_active_support.freeze
|
|
11
|
+
|
|
12
|
+
LOADED_ACTIVE_SUPPORT = loaded_active_support
|
|
13
|
+
|
|
14
|
+
def self.loaded_active_support?
|
|
15
|
+
LOADED_ACTIVE_SUPPORT
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
1
19
|
require "double_write_cache_stores/version"
|
|
2
20
|
require "double_write_cache_stores/client"
|
|
3
21
|
require "double_write_cache_stores/base_exception"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
22
|
+
|
|
23
|
+
require "dalli"
|
|
24
|
+
|
|
25
|
+
require "mem_cache_store_patch" if DoubleWriteCacheStores.loaded_active_support?
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# monky patch
|
|
2
|
+
module MemCacheStorePatch
|
|
3
|
+
def dalli
|
|
4
|
+
@data
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
begin
|
|
9
|
+
require "active_support/cache/mem_cache_store"
|
|
10
|
+
|
|
11
|
+
ActiveSupport::Cache::MemCacheStore.include MemCacheStorePatch
|
|
12
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
13
|
+
end
|