readthis 0.5.0 → 0.5.1
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/CHANGELOG.md +9 -0
- data/PERFORMANCE.md +1 -1
- data/README.md +11 -7
- data/benchmarks/multi.rb +11 -0
- data/lib/readthis/cache.rb +71 -11
- data/lib/readthis/version.rb +1 -1
- data/spec/readthis/cache_spec.rb +21 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39c546b2720bf3e983c15c8fe9d7a60fea06cf75
|
4
|
+
data.tar.gz: 0a41d522ce9f5a096bf967a344d3e71ab1c01b56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 669ad6115ac86b13bb8ff8108a839d6c9890fbf4ca456ee8bd5f06dfe53578532559a8507a9cdd8a7ed7458341def6acee7e7e051b479fef2828c3312b0f32b8
|
7
|
+
data.tar.gz: 15ebfbe02678355846db403aa48b800212aeb5115c05b3b14107ba603db2e74445403ad24988b2161eaff7c5d8e0662b8c7fa1bab2a0927f290ccbf943fa5648
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## v0.5.1 2014-12-30
|
2
|
+
|
3
|
+
- Fixed: The `clear` method now accepts an argument for compatibility with other
|
4
|
+
caches. The argument is not actually used for anything.
|
5
|
+
- Changed: The `delete` method will always return a boolean value rather than an
|
6
|
+
integer.
|
7
|
+
- Changed: Avoid multiple instrumentation calls and pool checkouts within
|
8
|
+
`fetch_multi` calls.
|
9
|
+
|
1
10
|
## v0.5.0 2014-12-12
|
2
11
|
|
3
12
|
- Added: All read and write operations are marshalled to and from storage. This
|
data/PERFORMANCE.md
CHANGED
data/README.md
CHANGED
@@ -7,10 +7,14 @@
|
|
7
7
|
|
8
8
|
Readthis is a drop in replacement for any ActiveSupport compliant cache, but
|
9
9
|
emphasizes performance and simplicity. It takes some cues from Dalli (connection
|
10
|
-
pooling), the popular Memcache client.
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
pooling), the popular Memcache client.
|
11
|
+
|
12
|
+
For any new projects there isn't any reason to stick with Memcached. Redis is
|
13
|
+
as fast, if not faster in many scenarios, and is far more likely to be used
|
14
|
+
elsewhere in the stack. See [this Stack Overflow post][stackoverflow] for more
|
15
|
+
details.
|
16
|
+
|
17
|
+
[stackoverflow]: http://stackoverflow.com/questions/10558465/memcache-vs-redis
|
14
18
|
|
15
19
|
## Footprint & Performance
|
16
20
|
|
@@ -52,6 +56,8 @@ redis database, which defaults to 0. For example, using database 2:
|
|
52
56
|
REDIS_URL=redis://localhost:6379/2
|
53
57
|
```
|
54
58
|
|
59
|
+
[store]: http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html
|
60
|
+
|
55
61
|
### Compression
|
56
62
|
|
57
63
|
Compression can be enabled for all actions by passing the `compress` flag. By
|
@@ -72,7 +78,7 @@ config.cache_store = :readthis_store, ENV.fetch('REDIS_URL'), {
|
|
72
78
|
|
73
79
|
Readthis uses Ruby's `Marshal` module for dumping and loading all values by
|
74
80
|
default. This isn't always the fastest option, depending on your use case it may
|
75
|
-
be desirable to use a faster but
|
81
|
+
be desirable to use a faster but less flexible marshaller.
|
76
82
|
|
77
83
|
Use Oj for JSON marshalling, extremely fast, limited types:
|
78
84
|
|
@@ -93,5 +99,3 @@ Readthis supports all of standard cache methods except for the following:
|
|
93
99
|
* `cleanup` - redis does this with ttl for us already
|
94
100
|
* `delete_matched` - you really don't want to perform key matching operations
|
95
101
|
in redis. They are linear time and only support basic globbing.
|
96
|
-
|
97
|
-
[store]: http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html
|
data/benchmarks/multi.rb
CHANGED
@@ -5,10 +5,12 @@ Bundler.setup
|
|
5
5
|
require 'benchmark/ips'
|
6
6
|
require 'dalli'
|
7
7
|
require 'redis-activesupport'
|
8
|
+
require 'active_support/cache/memory_store'
|
8
9
|
require 'active_support/cache/dalli_store'
|
9
10
|
require 'readthis'
|
10
11
|
|
11
12
|
REDIS_URL = 'redis://localhost:6379/11'
|
13
|
+
memory = ActiveSupport::Cache::MemoryStore.new(expires_in: 60, namespace: 'mm')
|
12
14
|
dalli = ActiveSupport::Cache::DalliStore.new('localhost', namespace: 'da', pool_size: 5, expires_in: 60)
|
13
15
|
redisas = ActiveSupport::Cache::RedisStore.new(REDIS_URL + '/ra', expires_in: 60)
|
14
16
|
readthis = Readthis::Cache.new(REDIS_URL, namespace: 'rd', expires_in: 60)
|
@@ -16,12 +18,17 @@ readthis = Readthis::Cache.new(REDIS_URL, namespace: 'rd', expires_in: 60)
|
|
16
18
|
('a'..'z').each do |key|
|
17
19
|
value = key * 1024
|
18
20
|
|
21
|
+
memory.write(key, value)
|
19
22
|
dalli.write(key, value)
|
20
23
|
readthis.write(key, value)
|
21
24
|
redisas.write(key, value)
|
22
25
|
end
|
23
26
|
|
24
27
|
Benchmark.ips do |x|
|
28
|
+
x.report 'memory:read-multi' do
|
29
|
+
memory.read_multi(*('a'..'z'))
|
30
|
+
end
|
31
|
+
|
25
32
|
x.report 'readthis:read-multi' do
|
26
33
|
readthis.read_multi(*('a'..'z'))
|
27
34
|
end
|
@@ -38,6 +45,10 @@ Benchmark.ips do |x|
|
|
38
45
|
end
|
39
46
|
|
40
47
|
Benchmark.ips do |x|
|
48
|
+
x.report 'memory:fetch-multi' do
|
49
|
+
memory.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
50
|
+
end
|
51
|
+
|
41
52
|
x.report 'readthis:fetch-multi' do
|
42
53
|
readthis.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
43
54
|
end
|
data/lib/readthis/cache.rb
CHANGED
@@ -75,22 +75,41 @@ module Readthis
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
# Writes data to the cache using the given key. Will overwrite whatever
|
79
|
+
# value is already stored at that key.
|
80
|
+
#
|
81
|
+
# @param [String] Key for lookup
|
82
|
+
# @param [Hash] Optional overrides
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
#
|
86
|
+
# cache.write('some-key', 'a bunch of text') # => 'OK'
|
87
|
+
# cache.write('some-key', 'short lived', expires_in: 60) # => 'OK'
|
88
|
+
# cache.write('some-key', 'lives elsehwere', namespace: 'cache') # => 'OK'
|
89
|
+
#
|
78
90
|
def write(key, value, options = {})
|
79
|
-
options
|
80
|
-
namespaced = namespaced_key(key, options)
|
91
|
+
options = merged_options(options)
|
81
92
|
|
82
93
|
invoke(:write, key) do |store|
|
83
|
-
|
84
|
-
store.setex(namespaced, expiration, entity.dump(value))
|
85
|
-
else
|
86
|
-
store.set(namespaced, entity.dump(value))
|
87
|
-
end
|
94
|
+
write_entity(key, value, store, options)
|
88
95
|
end
|
89
96
|
end
|
90
97
|
|
98
|
+
# Delete the value stored at the specified key. Returns `true` if
|
99
|
+
# anything was deleted, `false` otherwise.
|
100
|
+
#
|
101
|
+
# @params [String] The key for lookup
|
102
|
+
# @params [Hash] Optional overrides
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
#
|
106
|
+
# cache.delete('existing-key') # => true
|
107
|
+
# cache.delete('random-key') # => false
|
91
108
|
def delete(key, options = {})
|
109
|
+
namespaced = namespaced_key(key, merged_options(options))
|
110
|
+
|
92
111
|
invoke(:delete, key) do |store|
|
93
|
-
store.del(
|
112
|
+
store.del(namespaced) > 0
|
94
113
|
end
|
95
114
|
end
|
96
115
|
|
@@ -162,9 +181,20 @@ module Readthis
|
|
162
181
|
# and filling in any cache misses. All read and write operations are
|
163
182
|
# executed atomically.
|
164
183
|
#
|
184
|
+
# @overload fetch_multi(keys)
|
185
|
+
# Return all values fro the given keys, applying the block to the key
|
186
|
+
# when a value is missing.
|
187
|
+
# @param [String] One or more keys to fetch
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
#
|
165
191
|
# cache.fetch_multi('alpha', 'beta') do |key|
|
166
192
|
# "#{key}-was-missing"
|
167
193
|
# end
|
194
|
+
#
|
195
|
+
# cache.fetch_multi('a', 'b', expires_in: 60) do |key|
|
196
|
+
# key * 2
|
197
|
+
# end
|
168
198
|
def fetch_multi(*keys)
|
169
199
|
results = read_multi(*keys)
|
170
200
|
options = merged_options(extract_options!(keys))
|
@@ -173,8 +203,8 @@ module Readthis
|
|
173
203
|
store.pipelined do
|
174
204
|
results.each do |key, value|
|
175
205
|
if value.nil?
|
176
|
-
value = yield
|
177
|
-
|
206
|
+
value = yield(key)
|
207
|
+
write_entity(key, value, store, options)
|
178
208
|
results[key] = value
|
179
209
|
end
|
180
210
|
end
|
@@ -184,16 +214,46 @@ module Readthis
|
|
184
214
|
end
|
185
215
|
end
|
186
216
|
|
217
|
+
# Returns `true` if the cache contains an entry for the given key.
|
218
|
+
#
|
219
|
+
# @param [String] Key for lookup
|
220
|
+
# @param [Hash] Optional overrides
|
221
|
+
#
|
222
|
+
# @example
|
223
|
+
#
|
224
|
+
# cache.exist?('some-key') # => false
|
225
|
+
# cache.exist?('some-key', namespace: 'cache') # => true
|
226
|
+
#
|
187
227
|
def exist?(key, options = {})
|
188
228
|
invoke(:exist?, key) do |store|
|
189
229
|
store.exists(namespaced_key(key, merged_options(options)))
|
190
230
|
end
|
191
231
|
end
|
192
232
|
|
193
|
-
|
233
|
+
# Clear the entire cache. This flushes the current database, no
|
234
|
+
# globbing is applied.
|
235
|
+
#
|
236
|
+
# @param [Hash] Options, only present for compatibility.
|
237
|
+
#
|
238
|
+
# @example
|
239
|
+
#
|
240
|
+
# cache.clear #=> 'OK'
|
241
|
+
def clear(options = {})
|
194
242
|
invoke(:clear, '*', &:flushdb)
|
195
243
|
end
|
196
244
|
|
245
|
+
protected
|
246
|
+
|
247
|
+
def write_entity(key, value, store, options)
|
248
|
+
namespaced = namespaced_key(key, options)
|
249
|
+
|
250
|
+
if expiration = options[:expires_in]
|
251
|
+
store.setex(namespaced, expiration, entity.dump(value))
|
252
|
+
else
|
253
|
+
store.set(namespaced, entity.dump(value))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
197
257
|
private
|
198
258
|
|
199
259
|
def alter(key, amount, options)
|
data/lib/readthis/version.rb
CHANGED
data/spec/readthis/cache_spec.rb
CHANGED
@@ -158,6 +158,22 @@ RSpec.describe Readthis::Cache do
|
|
158
158
|
'b' => 'bb',
|
159
159
|
'c' => 3,
|
160
160
|
)
|
161
|
+
|
162
|
+
expect(cache.read('b')).to eq('bb')
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'uses passed options' do
|
166
|
+
cache.write('a', 1, namespace: 'alph')
|
167
|
+
|
168
|
+
results = cache.fetch_multi('a', 'b', namespace: 'alph') { |key| key }
|
169
|
+
|
170
|
+
expect(results).to eq(
|
171
|
+
'a' => 1,
|
172
|
+
'b' => 'b'
|
173
|
+
)
|
174
|
+
|
175
|
+
expect(cache.read('b')).to be_nil
|
176
|
+
expect(cache.read('b', namespace: 'alph')).not_to be_nil
|
161
177
|
end
|
162
178
|
end
|
163
179
|
|
@@ -175,10 +191,14 @@ RSpec.describe Readthis::Cache do
|
|
175
191
|
describe '#delete' do
|
176
192
|
it 'deletes an existing key' do
|
177
193
|
cache.write('not-long', 'for this world')
|
178
|
-
cache.delete('not-long')
|
179
194
|
|
195
|
+
expect(cache.delete('not-long')).to be_truthy
|
180
196
|
expect(cache.read('not-long')).to be_nil
|
181
197
|
end
|
198
|
+
|
199
|
+
it 'safely returns false if nothing is deleted' do
|
200
|
+
expect(cache.delete('no-such-key')).to be_falsy
|
201
|
+
end
|
182
202
|
end
|
183
203
|
|
184
204
|
describe '#increment' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: readthis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Parker Selbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|