readthis 0.3.0 → 0.4.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/CHANGELOG.md +8 -0
- data/PERFORMANCE.md +73 -0
- data/README.md +16 -41
- data/benchmarks/compressed.rb +73 -0
- data/benchmarks/multi.rb +9 -7
- data/lib/readthis/cache.rb +62 -8
- data/lib/readthis/compressor.rb +41 -0
- data/lib/readthis/expanders.rb +22 -14
- data/lib/readthis/version.rb +1 -1
- data/readthis.gemspec +1 -0
- data/spec/readthis/cache_spec.rb +48 -0
- data/spec/readthis/compressor_spec.rb +38 -0
- data/spec/readthis/expanders_spec.rb +1 -1
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5a03b37918d41dfd0e30151cb3049638df50aa8
|
4
|
+
data.tar.gz: 9c80690714866bc6992eafa9c137e785cf72a88d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9297ce7d8525ecdc2715399b3b657fb3cc12e581e4e9d067d762f7e9a134ffe6a35e48f6867bf7a26902f5dc48b6106e5c6dd012bc5e16372ad1b715fa6faa60
|
7
|
+
data.tar.gz: d431742cd9f908aabdd06dfeaab2ed99b7165158fff51c57c947d9857d336e2a5c82fe42edae15a41c7cdd8043b3fc950c09e6fd60feb4d69c571fb71e2fe6e3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## v0.4.0 2014-12-11
|
2
|
+
|
3
|
+
- Added: Force the use of `hiredis` as the adapter. It is dramatically faster,
|
4
|
+
but prevents the project from being used in `jruby`. If we get interest from
|
5
|
+
some `jruby` projects we can soften the requirement.
|
6
|
+
- Added: Compression! Adheres to the `ActiveSupport::Store` documentation.
|
7
|
+
- Fixed: Gracefully handle `nil` passed as `options` to any cache method.
|
8
|
+
|
1
9
|
## v0.3.0 2014-12-01
|
2
10
|
|
3
11
|
- Added: Use `to_param` for key expansion, only when available. Makes it
|
data/PERFORMANCE.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Results from the various benchmarks in `./bencharks`. Hardware doesnt't matter
|
2
|
+
much, as we're simply looking for a comparison against other libraries and prior
|
3
|
+
verions.
|
4
|
+
|
5
|
+
## Footprint
|
6
|
+
|
7
|
+
Footprint compared to `redis-activesupport`:
|
8
|
+
|
9
|
+
```
|
10
|
+
# Total allocated objects after require
|
11
|
+
readthis: 20602
|
12
|
+
redis-activesupport: 78630
|
13
|
+
```
|
14
|
+
|
15
|
+
## Performance
|
16
|
+
|
17
|
+
Performance compared to `dalli` and `redis-activesupport`:
|
18
|
+
|
19
|
+
```
|
20
|
+
Raw Read Multi:
|
21
|
+
Calculating -------------------------------------
|
22
|
+
readthis:read-multi 500.000 i/100ms
|
23
|
+
redisas:read-multi 95.000 i/100ms
|
24
|
+
dalli:read-multi 97.000 i/100ms
|
25
|
+
-------------------------------------------------
|
26
|
+
readthis:read-multi 5.286k (± 2.7%) i/s - 26.500k
|
27
|
+
redisas:read-multi 959.405 (± 4.2%) i/s - 4.845k
|
28
|
+
dalli:read-multi 978.803 (± 2.1%) i/s - 4.947k
|
29
|
+
|
30
|
+
Comparison:
|
31
|
+
readthis:read-multi: 5286.0 i/s
|
32
|
+
dalli:read-multi: 978.8 i/s - 5.40x slower
|
33
|
+
redisas:read-multi: 959.4 i/s - 5.51x slower
|
34
|
+
|
35
|
+
Raw Fetch Multi:
|
36
|
+
Calculating -------------------------------------
|
37
|
+
readthis:fetch-multi 448.000 i/100ms
|
38
|
+
redisas:fetch-multi 84.000 i/100ms
|
39
|
+
dalli:fetch-multi 99.000 i/100ms
|
40
|
+
-------------------------------------------------
|
41
|
+
readthis:fetch-multi 4.682k (± 2.4%) i/s - 23.744k
|
42
|
+
redisas:fetch-multi 848.101 (± 3.2%) i/s - 4.284k
|
43
|
+
dalli:fetch-multi 1.006k (± 2.4%) i/s - 5.049k
|
44
|
+
|
45
|
+
Comparison:
|
46
|
+
readthis:fetch-multi: 4682.4 i/s
|
47
|
+
dalli:fetch-multi: 1005.6 i/s - 4.66x slower
|
48
|
+
redisas:fetch-multi: 848.1 i/s - 5.52x slower
|
49
|
+
|
50
|
+
Compressed Writes:
|
51
|
+
Calculating -------------------------------------
|
52
|
+
readthis:write 1.003k i/100ms
|
53
|
+
dalli:write 913.000 i/100ms
|
54
|
+
-------------------------------------------------
|
55
|
+
readthis:write 11.095k (± 5.7%) i/s - 56.168k
|
56
|
+
dalli:write 9.829k (± 1.8%) i/s - 49.302k
|
57
|
+
|
58
|
+
Comparison:
|
59
|
+
readthis:write: 11095.5 i/s
|
60
|
+
dalli:write: 9828.8 i/s - 1.13x slower
|
61
|
+
|
62
|
+
Compressed Read Multi:
|
63
|
+
Calculating -------------------------------------
|
64
|
+
readthis:read_multi 446.000 i/100ms
|
65
|
+
dalli:read_multi 97.000 i/100ms
|
66
|
+
-------------------------------------------------
|
67
|
+
readthis:read_multi 4.728k (± 4.6%) i/s - 23.638k
|
68
|
+
dalli:read_multi 985.986 (± 3.9%) i/s - 4.947k
|
69
|
+
|
70
|
+
Comparison:
|
71
|
+
readthis:read_multi: 4728.3 i/s
|
72
|
+
dalli:read_multi: 986.0 i/s - 4.80x slower
|
73
|
+
```
|
data/README.md
CHANGED
@@ -13,46 +13,7 @@ behavior for `fetch_multi`.
|
|
13
13
|
|
14
14
|
## Footprint & Performance
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
```
|
19
|
-
# Total allocated objects after require
|
20
|
-
readthis: 19,964
|
21
|
-
redis-activesupport: 78,630
|
22
|
-
```
|
23
|
-
|
24
|
-
Performance compared to `dalli` and `redis-activesupport` for \*multi
|
25
|
-
operations:
|
26
|
-
|
27
|
-
```
|
28
|
-
Calculating -------------------------------------
|
29
|
-
readthis:read-multi 118.000 i/100ms
|
30
|
-
redisas:read-multi 94.000 i/100ms
|
31
|
-
dalli:read-multi 92.000 i/100ms
|
32
|
-
-------------------------------------------------
|
33
|
-
readthis:read-multi 1.206k (± 4.6%) i/s - 6.018k
|
34
|
-
redisas:read-multi 973.086 (± 4.4%) i/s - 4.888k
|
35
|
-
dalli:read-multi 949.348 (± 4.1%) i/s - 4.784k
|
36
|
-
|
37
|
-
Comparison:
|
38
|
-
readthis:read-multi: 1206.0 i/s
|
39
|
-
redisas:read-multi: 973.1 i/s - 1.24x slower
|
40
|
-
dalli:read-multi: 949.3 i/s - 1.27x slower
|
41
|
-
|
42
|
-
Calculating -------------------------------------
|
43
|
-
readthis:fetch-multi 114.000 i/100ms
|
44
|
-
redisas:fetch-multi 82.000 i/100ms
|
45
|
-
dalli:fetch-multi 97.000 i/100ms
|
46
|
-
-------------------------------------------------
|
47
|
-
readthis:fetch-multi 1.157k (± 5.0%) i/s - 5.814k
|
48
|
-
redisas:fetch-multi 829.211 (± 4.2%) i/s - 4.182k
|
49
|
-
dalli:fetch-multi 979.081 (± 3.8%) i/s - 4.947k
|
50
|
-
|
51
|
-
Comparison:
|
52
|
-
readthis:fetch-multi: 1157.2 i/s
|
53
|
-
dalli:fetch-multi: 979.1 i/s - 1.18x slower
|
54
|
-
redisas:fetch-multi: 829.2 i/s - 1.40x slower
|
55
|
-
```
|
16
|
+
See [Performance][PERFORMANCE.md]
|
56
17
|
|
57
18
|
## Installation
|
58
19
|
|
@@ -86,10 +47,24 @@ You'll want to use a specific database for caching, just in case you need to
|
|
86
47
|
clear the cache entirely. Appending a number between 0 and 15 will specify the
|
87
48
|
redis database, which defaults to 0. For example, using database 2:
|
88
49
|
|
89
|
-
```
|
50
|
+
```bash
|
90
51
|
REDIS_URL=redis://localhost:6379/2
|
91
52
|
```
|
92
53
|
|
54
|
+
Compression can be enabled for all actions by passing the `compress` flag. By
|
55
|
+
default all values greater than 1024k will be compressed automatically. If there
|
56
|
+
is any content has not been stored with compression, or perhaps was compressed
|
57
|
+
but is beneath the compression threshold, it will be passed through as is. This
|
58
|
+
means it is safe to enable or change compression with an existing cache. There
|
59
|
+
will be a decoding performance penalty in this case, but it should be minor.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
config.cache_store = :readthis_store, ENV.fetch('REDIS_URL'), {
|
63
|
+
compress: true,
|
64
|
+
compression_threshold: 2.kilobytes
|
65
|
+
}
|
66
|
+
```
|
67
|
+
|
93
68
|
## Differences
|
94
69
|
|
95
70
|
Readthis supports all of standard cache methods except for the following:
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'benchmark/ips'
|
6
|
+
require 'dalli'
|
7
|
+
require 'active_support'
|
8
|
+
require 'active_support/cache/dalli_store'
|
9
|
+
require 'readthis'
|
10
|
+
|
11
|
+
dalli = ActiveSupport::Cache::DalliStore.new(
|
12
|
+
'localhost',
|
13
|
+
pool_size: 5,
|
14
|
+
compressed: true,
|
15
|
+
compression_threshold: 8
|
16
|
+
)
|
17
|
+
|
18
|
+
readthis = Readthis::Cache.new(
|
19
|
+
'redis://localhost:6379/11',
|
20
|
+
pool_size: 5,
|
21
|
+
compressed: true,
|
22
|
+
compression_threshold: 128
|
23
|
+
)
|
24
|
+
|
25
|
+
KEY = 'key'
|
26
|
+
TEXT = <<-TEXT
|
27
|
+
An abstract cache store class. There are multiple cache store implementations, each having its own additional features. See the classes under the ActiveSupport::Cache module, e.g. ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most popular cache store for large production websites.
|
28
|
+
Some implementations may not support all methods beyond the basic cache methods of fetch, write, read, exist?, and delete.
|
29
|
+
ActiveSupport::Cache::Store can store any serializable Ruby object.
|
30
|
+
cache = ActiveSupport::Cache::MemoryStore.new
|
31
|
+
cache.read('city') # => nil
|
32
|
+
cache.write('city', "Duckburgh")
|
33
|
+
cache.read('city') # => "Duckburgh"
|
34
|
+
Keys are always translated into Strings and are case sensitive. When an object is specified as a key and has a cache_key method defined, this method will be called to define the key. Otherwise, the to_param method will be called. Hashes and Arrays can also be used as keys. The elements will be delimited by slashes, and the elements within a Hash will be sorted by key so they are consistent.
|
35
|
+
cache.read('city') == cache.read(:city) # => true
|
36
|
+
Nil values can be cached.
|
37
|
+
If your cache is on a shared infrastructure, you can define a namespace for your cache entries. If a namespace is defined, it will be prefixed on to every key. The namespace can be either a static value or a Proc. If it is a Proc, it will be invoked when each key is evaluated so that you can use application logic to invalidate keys.
|
38
|
+
cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
39
|
+
@last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
40
|
+
Caches can also store values in a compressed format to save space and reduce time spent sending data. Since there is overhead, values must be large enough to warrant compression. To turn on compression either pass compress: true in the initializer or as an option to fetch or write. To specify the threshold at which to compress values, set the :compress_threshold option. The default threshold is 16K.
|
41
|
+
TEXT
|
42
|
+
|
43
|
+
puts 'Compressed Writes:'
|
44
|
+
Benchmark.ips do |x|
|
45
|
+
x.report 'readthis:write' do
|
46
|
+
readthis.write(KEY, TEXT)
|
47
|
+
end
|
48
|
+
|
49
|
+
x.report 'dalli:write' do
|
50
|
+
dalli.write(KEY, TEXT)
|
51
|
+
end
|
52
|
+
|
53
|
+
x.compare!
|
54
|
+
end
|
55
|
+
|
56
|
+
puts 'Compressed Read Multi:'
|
57
|
+
MULTI_KEY = (1..30).to_a
|
58
|
+
MULTI_KEY.each do |key|
|
59
|
+
readthis.write(key, TEXT)
|
60
|
+
dalli.write(key, TEXT)
|
61
|
+
end
|
62
|
+
|
63
|
+
Benchmark.ips do |x|
|
64
|
+
x.report 'readthis:read_multi' do
|
65
|
+
readthis.read_multi(*MULTI_KEY)
|
66
|
+
end
|
67
|
+
|
68
|
+
x.report 'dalli:read_multi' do
|
69
|
+
dalli.read_multi(*MULTI_KEY)
|
70
|
+
end
|
71
|
+
|
72
|
+
x.compare!
|
73
|
+
end
|
data/benchmarks/multi.rb
CHANGED
@@ -8,15 +8,17 @@ require 'redis-activesupport'
|
|
8
8
|
require 'active_support/cache/dalli_store'
|
9
9
|
require 'readthis'
|
10
10
|
|
11
|
-
|
12
|
-
dalli = ActiveSupport::Cache::DalliStore.new('localhost', namespace: 'da', pool_size: 5)
|
13
|
-
redisas = ActiveSupport::Cache::RedisStore.new(
|
14
|
-
readthis = Readthis::Cache.new(
|
11
|
+
REDIS_URL = 'redis://localhost:6379/11'
|
12
|
+
dalli = ActiveSupport::Cache::DalliStore.new('localhost', namespace: 'da', pool_size: 5, expires_in: 60)
|
13
|
+
redisas = ActiveSupport::Cache::RedisStore.new(REDIS_URL + '/ra', expires_in: 60)
|
14
|
+
readthis = Readthis::Cache.new(REDIS_URL, namespace: 'rd', expires_in: 60)
|
15
15
|
|
16
16
|
('a'..'z').each do |key|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
value = key * 1024
|
18
|
+
|
19
|
+
dalli.write(key, value)
|
20
|
+
readthis.write(key, value)
|
21
|
+
redisas.write(key, value)
|
20
22
|
end
|
21
23
|
|
22
24
|
Benchmark.ips do |x|
|
data/lib/readthis/cache.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
|
+
require 'readthis/compressor'
|
1
2
|
require 'readthis/expanders'
|
2
3
|
require 'readthis/notifications'
|
3
4
|
require 'redis'
|
5
|
+
require 'hiredis'
|
4
6
|
require 'connection_pool'
|
5
7
|
|
6
8
|
module Readthis
|
7
9
|
class Cache
|
8
|
-
attr_reader :
|
10
|
+
attr_reader :compress,
|
11
|
+
:compression_threshold,
|
12
|
+
:expires_in,
|
13
|
+
:namespace,
|
14
|
+
:pool
|
15
|
+
|
16
|
+
alias_method :compress?, :compress
|
9
17
|
|
10
18
|
# Provide a class level lookup of the proper notifications module.
|
11
19
|
# Instrumention is expected to occur within applications that have
|
@@ -22,19 +30,34 @@ module Readthis
|
|
22
30
|
# Creates a new Readthis::Cache object with the given redis URL. The URL
|
23
31
|
# is parsed by the redis client directly.
|
24
32
|
#
|
33
|
+
# @param url [String] A redis compliant url with necessary connection details
|
34
|
+
# @option options [String] :namespace Prefix used to namespace entries
|
35
|
+
# @option options [Number] :expires_in The number of seconds until an entry expires
|
36
|
+
# @option options [Boolean] :compress Enable or disable automatic compression
|
37
|
+
# @option options [Number] :compression_threshold The size a string must be for compression
|
38
|
+
#
|
39
|
+
# @example Create a new cache instance
|
25
40
|
# Readthis::Cache.new('redis://localhost:6379/0', namespace: 'cache')
|
41
|
+
#
|
42
|
+
# @example Create a compressed cache instance
|
43
|
+
# Readthis::Cache.new('redis://localhost:6379/0', compress: true, compression_threshold: 2048)
|
44
|
+
#
|
26
45
|
def initialize(url, options = {})
|
27
46
|
@expires_in = options.fetch(:expires_in, nil)
|
28
|
-
@namespace = options.fetch(:namespace,
|
47
|
+
@namespace = options.fetch(:namespace, nil)
|
48
|
+
@compress = options.fetch(:compress, false)
|
49
|
+
@compression_threshold = options.fetch(:compression_threshold, 1024)
|
29
50
|
|
30
51
|
@pool = ConnectionPool.new(pool_options(options)) do
|
31
|
-
Redis.new(url: url)
|
52
|
+
Redis.new(url: url, driver: :hiredis)
|
32
53
|
end
|
33
54
|
end
|
34
55
|
|
35
56
|
def read(key, options = {})
|
36
57
|
invoke(:read, key) do |store|
|
37
|
-
store.get(namespaced_key(key, merged_options(options)))
|
58
|
+
value = store.get(namespaced_key(key, merged_options(options)))
|
59
|
+
|
60
|
+
decompressed(value)
|
38
61
|
end
|
39
62
|
end
|
40
63
|
|
@@ -44,9 +67,9 @@ module Readthis
|
|
44
67
|
|
45
68
|
invoke(:write, key) do |store|
|
46
69
|
if expiration = options[:expires_in]
|
47
|
-
store.setex(namespaced, expiration, value)
|
70
|
+
store.setex(namespaced, expiration, compressed(value))
|
48
71
|
else
|
49
|
-
store.set(namespaced, value)
|
72
|
+
store.set(namespaced, compressed(value))
|
50
73
|
end
|
51
74
|
end
|
52
75
|
end
|
@@ -85,7 +108,9 @@ module Readthis
|
|
85
108
|
mapping = keys.map { |key| namespaced_key(key, options) }
|
86
109
|
|
87
110
|
invoke(:read_multi, keys) do |store|
|
88
|
-
|
111
|
+
values = decompressed_multi(store.mget(mapping))
|
112
|
+
|
113
|
+
keys.zip(values).to_h
|
89
114
|
end
|
90
115
|
end
|
91
116
|
|
@@ -127,6 +152,34 @@ module Readthis
|
|
127
152
|
|
128
153
|
private
|
129
154
|
|
155
|
+
def compressed(value)
|
156
|
+
if compress?
|
157
|
+
compressor.compress(value)
|
158
|
+
else
|
159
|
+
value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def decompressed(value)
|
164
|
+
if compress?
|
165
|
+
compressor.decompress(value)
|
166
|
+
else
|
167
|
+
value
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def decompressed_multi(values)
|
172
|
+
if compress?
|
173
|
+
values.map { |value| compressor.decompress(value) }
|
174
|
+
else
|
175
|
+
values
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def compressor
|
180
|
+
@compressor ||= Readthis::Compressor.new(threshold: compression_threshold)
|
181
|
+
end
|
182
|
+
|
130
183
|
def instrument(operation, key)
|
131
184
|
name = "cache_#{operation}.active_support"
|
132
185
|
payload = { key: key }
|
@@ -145,6 +198,7 @@ module Readthis
|
|
145
198
|
end
|
146
199
|
|
147
200
|
def merged_options(options)
|
201
|
+
options = options || {}
|
148
202
|
options[:namespace] ||= namespace
|
149
203
|
options[:expires_in] ||= expires_in
|
150
204
|
options
|
@@ -156,7 +210,7 @@ module Readthis
|
|
156
210
|
end
|
157
211
|
|
158
212
|
def namespaced_key(key, options)
|
159
|
-
Readthis::Expanders.
|
213
|
+
Readthis::Expanders.namespace_key(key, options[:namespace])
|
160
214
|
end
|
161
215
|
end
|
162
216
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
|
3
|
+
module Readthis
|
4
|
+
class Compressor
|
5
|
+
attr_reader :threshold
|
6
|
+
|
7
|
+
# Create a new Readthis::Compressor object that pivots on the provided
|
8
|
+
# threshold value.
|
9
|
+
#
|
10
|
+
# @param threshold [Number] the threshold size required for compression
|
11
|
+
def initialize(threshold: 1024)
|
12
|
+
@threshold = threshold
|
13
|
+
end
|
14
|
+
|
15
|
+
# Compress a value if its size is greater or equal to the current threshold.
|
16
|
+
#
|
17
|
+
# @param value [String] a string to compress
|
18
|
+
def compress(value)
|
19
|
+
if value.size >= threshold
|
20
|
+
Zlib::Deflate.deflate(value)
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Decompress a previously compressed object. It will attempt to decode a
|
27
|
+
# value regardless of whether it has been compressed, but will rescue
|
28
|
+
# decoding errors.
|
29
|
+
#
|
30
|
+
# @param value [String] a possibly compressed string to decompress
|
31
|
+
def decompress(value)
|
32
|
+
if value.size >= threshold
|
33
|
+
Zlib::Inflate.inflate(value)
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
rescue Zlib::Error
|
38
|
+
value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/readthis/expanders.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
module Readthis
|
2
2
|
module Expanders
|
3
|
-
def self.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
3
|
+
def self.expand_key(key)
|
4
|
+
case
|
5
|
+
when key.respond_to?(:cache_key)
|
6
|
+
key.cache_key
|
7
|
+
when key.is_a?(Array)
|
8
|
+
key.flat_map { |elem| expand_key(elem) }.join('/')
|
9
|
+
when key.is_a?(Hash)
|
10
|
+
key.sort_by { |key, _| key.to_s }.map { |key, val| "#{key}=#{val}" }.join('/')
|
11
|
+
when key.respond_to?(:to_param)
|
12
|
+
key.to_param
|
13
|
+
else
|
14
|
+
key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.namespace_key(key, namespace)
|
19
|
+
expanded = expand_key(key)
|
16
20
|
|
17
|
-
|
21
|
+
if namespace
|
22
|
+
"#{namespace}:#{expanded}"
|
23
|
+
else
|
24
|
+
expanded
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
20
28
|
end
|
data/lib/readthis/version.rb
CHANGED
data/readthis.gemspec
CHANGED
data/spec/readthis/cache_spec.rb
CHANGED
@@ -20,6 +20,17 @@ RSpec.describe Readthis::Cache do
|
|
20
20
|
|
21
21
|
expect(cache.expires_in).to eq(10)
|
22
22
|
end
|
23
|
+
|
24
|
+
it 'stores compression parameters' do
|
25
|
+
cache = Readthis::Cache.new(
|
26
|
+
url,
|
27
|
+
compress: true,
|
28
|
+
compression_threshold: 8
|
29
|
+
)
|
30
|
+
|
31
|
+
expect(cache.compress).to be_truthy
|
32
|
+
expect(cache.compression_threshold).to eq(8)
|
33
|
+
end
|
23
34
|
end
|
24
35
|
|
25
36
|
describe '#write' do
|
@@ -53,6 +64,43 @@ RSpec.describe Readthis::Cache do
|
|
53
64
|
end
|
54
65
|
end
|
55
66
|
|
67
|
+
describe '#read' do
|
68
|
+
it 'gracefully handles nil options' do
|
69
|
+
expect { cache.read('whatever', nil) }.not_to raise_error
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#compress' do
|
74
|
+
it 'round trips entries when compression is enabled' do
|
75
|
+
com_cache = Readthis::Cache.new(url, compress: true, compression_threshold: 8)
|
76
|
+
raw_cache = Readthis::Cache.new(url)
|
77
|
+
value = 'enough text that it should be compressed'
|
78
|
+
|
79
|
+
com_cache.write('compressed', value)
|
80
|
+
|
81
|
+
expect(raw_cache.read('compressed')).not_to eq(value)
|
82
|
+
expect(com_cache.read('compressed')).to eq(value)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'round trips bulk entries when compression is enabled' do
|
86
|
+
cache = Readthis::Cache.new(url, compress: true, compression_threshold: 8)
|
87
|
+
value = 'also enough text to compress'
|
88
|
+
|
89
|
+
cache.write('comp-a', value)
|
90
|
+
cache.write('comp-b', value)
|
91
|
+
|
92
|
+
expect(cache.read_multi('comp-a', 'comp-b')).to eq(
|
93
|
+
'comp-a' => value,
|
94
|
+
'comp-b' => value
|
95
|
+
)
|
96
|
+
|
97
|
+
expect(cache.fetch_multi('comp-a', 'comp-b')).to eq(
|
98
|
+
'comp-a' => value,
|
99
|
+
'comp-b' => value
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
56
104
|
describe '#fetch' do
|
57
105
|
it 'gets an existing value' do
|
58
106
|
cache.write('great-key', 'great')
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'readthis/compressor'
|
2
|
+
|
3
|
+
RSpec.describe Readthis::Compressor do
|
4
|
+
describe '#compress' do
|
5
|
+
it 'compresses the input' do
|
6
|
+
compressor = Readthis::Compressor.new(threshold: 0)
|
7
|
+
input = 'aaa bbb ccc'
|
8
|
+
output = compressor.compress(input)
|
9
|
+
|
10
|
+
expect(input).not_to eq(output)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'passes input below the threshold size through uncompressed' do
|
14
|
+
compressor = Readthis::Compressor.new(threshold: 1024)
|
15
|
+
input = 'abcdefg'
|
16
|
+
|
17
|
+
expect(compressor.compress(input)).to eq(input)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#decompress' do
|
22
|
+
it 'decompresses compressed data' do
|
23
|
+
compressor = Readthis::Compressor.new(threshold: 0)
|
24
|
+
input = 'aaa bbb ccc'
|
25
|
+
compressed = compressor.compress(input)
|
26
|
+
decompressed = compressor.decompress(compressed)
|
27
|
+
|
28
|
+
expect(decompressed).to eq(input)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'passes through decompression failures' do
|
32
|
+
compressor = Readthis::Compressor.new(threshold: 0)
|
33
|
+
input = 'abcdefg'
|
34
|
+
|
35
|
+
expect(compressor.decompress(input)).to eq(input)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
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.
|
4
|
+
version: 0.4.0
|
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-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hiredis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.5'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: connection_pool
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,19 +108,23 @@ files:
|
|
94
108
|
- CONTRIBUTING.md
|
95
109
|
- Gemfile
|
96
110
|
- LICENSE.txt
|
111
|
+
- PERFORMANCE.md
|
97
112
|
- README.md
|
98
113
|
- Rakefile
|
114
|
+
- benchmarks/compressed.rb
|
99
115
|
- benchmarks/memory.rb
|
100
116
|
- benchmarks/multi.rb
|
101
117
|
- bin/rspec
|
102
118
|
- lib/active_support/cache/readthis_store.rb
|
103
119
|
- lib/readthis.rb
|
104
120
|
- lib/readthis/cache.rb
|
121
|
+
- lib/readthis/compressor.rb
|
105
122
|
- lib/readthis/expanders.rb
|
106
123
|
- lib/readthis/notifications.rb
|
107
124
|
- lib/readthis/version.rb
|
108
125
|
- readthis.gemspec
|
109
126
|
- spec/readthis/cache_spec.rb
|
127
|
+
- spec/readthis/compressor_spec.rb
|
110
128
|
- spec/readthis/expanders_spec.rb
|
111
129
|
- spec/readthis/notifications_spec.rb
|
112
130
|
- spec/spec_helper.rb
|
@@ -136,6 +154,7 @@ specification_version: 4
|
|
136
154
|
summary: Pooled active support compliant caching with redis
|
137
155
|
test_files:
|
138
156
|
- spec/readthis/cache_spec.rb
|
157
|
+
- spec/readthis/compressor_spec.rb
|
139
158
|
- spec/readthis/expanders_spec.rb
|
140
159
|
- spec/readthis/notifications_spec.rb
|
141
160
|
- spec/spec_helper.rb
|