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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d1763594017ac9b87a099ca476d01c9f3823a0b0
4
- data.tar.gz: 23e9363a5cc0c997c70f923f0ea21c50477843ff
3
+ metadata.gz: 39c546b2720bf3e983c15c8fe9d7a60fea06cf75
4
+ data.tar.gz: 0a41d522ce9f5a096bf967a344d3e71ab1c01b56
5
5
  SHA512:
6
- metadata.gz: 0c3868ec4afab92154c4a9bc542de628224086760a6c8c5275d9ba83ede290b4800f209eb3c3b5349d11cd2f2f63e0aa5858e587308ac9d2988ecc6a35989511
7
- data.tar.gz: 3ffd2cc9546da805453a27d5ca33a4a35525582eb7905973a45293e4093ed47c70ebe37b4e3fb8f16035074cb558de08e271b2de712b8f52e237a8f386db9ca3
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
@@ -1,4 +1,4 @@
1
- Results from the various benchmarks in `./bencharks`. Hardware doesnt't matter
1
+ Results from the various benchmarks in `./bencharks`. Hardware doesn't matter
2
2
  much, as we're simply looking for a comparison against other libraries and prior
3
3
  verions.
4
4
 
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. Below are some performance comparisons
11
- against the only other notable redis cache implementation, `redis-activesupport`,
12
- which has been abandoned and doesn't actually comply to Rails 4.2 cache store
13
- behavior for `fetch_multi`.
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 more flexible marshaller.
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
@@ -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 = merged_options(options)
80
- namespaced = namespaced_key(key, options)
91
+ options = merged_options(options)
81
92
 
82
93
  invoke(:write, key) do |store|
83
- if expiration = options[:expires_in]
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(namespaced_key(key, merged_options(options)))
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 key
177
- write(key, value, options)
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
- def clear
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)
@@ -1,3 +1,3 @@
1
1
  module Readthis
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
@@ -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.0
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-12 00:00:00.000000000 Z
11
+ date: 2014-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis