readthis 1.0.0.pre.beta → 1.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -9
- data/lib/active_support/cache/readthis_store.rb +1 -1
- data/lib/readthis/cache.rb +11 -16
- data/lib/readthis/entity.rb +1 -2
- data/lib/readthis/expanders.rb +1 -1
- data/lib/readthis/serializers.rb +28 -17
- data/lib/readthis/version.rb +1 -1
- data/spec/readthis/cache_spec.rb +14 -22
- data/spec/readthis/entity_spec.rb +0 -10
- data/spec/readthis/expanders_spec.rb +1 -1
- data/spec/readthis/serializers_spec.rb +21 -6
- data/spec/spec_helper.rb +1 -3
- metadata +3 -23
- data/.gitignore +0 -15
- data/.rspec +0 -2
- data/.travis.yml +0 -15
- data/CHANGELOG.md +0 -135
- data/CONTRIBUTING.md +0 -14
- data/Gemfile +0 -14
- data/LICENSE.txt +0 -22
- data/PERFORMANCE.md +0 -73
- data/Rakefile +0 -2
- data/benchmarks/composing.rb +0 -43
- data/benchmarks/compressed.rb +0 -74
- data/benchmarks/driver.rb +0 -18
- data/benchmarks/generic.rb +0 -30
- data/benchmarks/marshalling.rb +0 -38
- data/benchmarks/memory.rb +0 -11
- data/benchmarks/multi.rb +0 -60
- data/benchmarks/parsing.rb +0 -42
- data/benchmarks/profile.rb +0 -20
- data/bin/rspec +0 -16
- data/readthis.gemspec +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c641f0b14297f5f65cc9e2a36dc525c92e2f4a48
|
4
|
+
data.tar.gz: cf5625a9a3b874f5f715979c615ee0db5c27daad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3774c714c24caa36cdb07b8ce5b39f1694ed2e9b9b116b2b3c463fc516e2b2bfebf68e1481c5181502fddd76e3690ae3af7bfcf7ef3210c5ae8ca634ad3f16c9
|
7
|
+
data.tar.gz: 274020a823960b9f4b7efdf101d02b3cc6a08074c508a6b32d4c990de0ccacf47571d98a1e74796f2d12d417971c297dffdc81abc1e24b3a770a74c64874810a
|
data/README.md
CHANGED
@@ -96,28 +96,28 @@ config.cache_store = :readthis_store, {
|
|
96
96
|
}
|
97
97
|
```
|
98
98
|
|
99
|
-
###
|
99
|
+
### Serializing
|
100
100
|
|
101
|
-
Readthis uses Ruby's `Marshal` module for
|
102
|
-
|
103
|
-
|
101
|
+
Readthis uses Ruby's `Marshal` module for serializing all values by default.
|
102
|
+
This isn't always the fastest option, and depending on your use case it may be
|
103
|
+
desirable to use a faster but less flexible serializer.
|
104
104
|
|
105
|
-
By default Readthis knows about 3 different serializers
|
105
|
+
By default Readthis knows about 3 different serializers:
|
106
106
|
|
107
107
|
* Marshal
|
108
108
|
* JSON
|
109
109
|
* Passthrough
|
110
110
|
|
111
111
|
If all cached data can safely be represented as a string then use the
|
112
|
-
pass-through
|
112
|
+
pass-through serializer:
|
113
113
|
|
114
114
|
```ruby
|
115
115
|
Readthis::Cache.new(marshal: Readthis::Passthrough)
|
116
116
|
```
|
117
117
|
|
118
|
-
You can introduce up to four additional
|
119
|
-
the Readthis module. For example, if you wanted to use
|
120
|
-
|
118
|
+
You can introduce up to four additional serializers by configuring `serializers`
|
119
|
+
on the Readthis module. For example, if you wanted to use the extremely fast Oj
|
120
|
+
library for JSON serialization:
|
121
121
|
|
122
122
|
```ruby
|
123
123
|
Readthis.serializers << Oj
|
data/lib/readthis/cache.rb
CHANGED
@@ -7,7 +7,7 @@ require 'connection_pool'
|
|
7
7
|
|
8
8
|
module Readthis
|
9
9
|
class Cache
|
10
|
-
attr_reader :entity, :
|
10
|
+
attr_reader :entity, :options, :pool
|
11
11
|
|
12
12
|
# Provide a class level lookup of the proper notifications module.
|
13
13
|
# Instrumention is expected to occur within applications that have
|
@@ -39,9 +39,7 @@ module Readthis
|
|
39
39
|
# Readthis::Cache.new(compress: true, compression_threshold: 2048)
|
40
40
|
#
|
41
41
|
def initialize(options = {})
|
42
|
-
@options
|
43
|
-
@expires_in = options.fetch(:expires_in, nil)
|
44
|
-
@namespace = options.fetch(:namespace, nil)
|
42
|
+
@options = options
|
45
43
|
|
46
44
|
@entity = Readthis::Entity.new(
|
47
45
|
marshal: options.fetch(:marshal, Marshal),
|
@@ -171,7 +169,7 @@ module Readthis
|
|
171
169
|
# cache.increment('counter', 2) # => 3
|
172
170
|
#
|
173
171
|
def increment(key, amount = 1, options = {})
|
174
|
-
invoke(:increment, key) do |
|
172
|
+
invoke(:increment, key) do |_store|
|
175
173
|
alter(key, amount, options)
|
176
174
|
end
|
177
175
|
end
|
@@ -192,7 +190,7 @@ module Readthis
|
|
192
190
|
# cache.decrement('counter', 2) # => 17
|
193
191
|
#
|
194
192
|
def decrement(key, amount = 1, options = {})
|
195
|
-
invoke(:decrement, key) do |
|
193
|
+
invoke(:decrement, key) do |_store|
|
196
194
|
alter(key, amount * -1, options)
|
197
195
|
end
|
198
196
|
end
|
@@ -271,13 +269,13 @@ module Readthis
|
|
271
269
|
extracted = extract_options!(keys)
|
272
270
|
missing = {}
|
273
271
|
|
274
|
-
invoke(:fetch_multi, keys) do |
|
272
|
+
invoke(:fetch_multi, keys) do |_store|
|
275
273
|
results.each do |key, value|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
274
|
+
next unless value.nil?
|
275
|
+
|
276
|
+
value = yield(key)
|
277
|
+
missing[key] = value
|
278
|
+
results[key] = value
|
281
279
|
end
|
282
280
|
end
|
283
281
|
|
@@ -354,10 +352,7 @@ module Readthis
|
|
354
352
|
end
|
355
353
|
|
356
354
|
def merged_options(options)
|
357
|
-
options
|
358
|
-
options[:namespace] ||= namespace
|
359
|
-
options[:expires_in] ||= expires_in
|
360
|
-
options
|
355
|
+
(options || {}).merge!(@options)
|
361
356
|
end
|
362
357
|
|
363
358
|
def pool_options(options)
|
data/lib/readthis/entity.rb
CHANGED
@@ -9,7 +9,6 @@ module Readthis
|
|
9
9
|
}.freeze
|
10
10
|
|
11
11
|
COMPRESSED_FLAG = 0x8
|
12
|
-
MARSHAL_FLAG = 0x3
|
13
12
|
|
14
13
|
# Creates a Readthis::Entity with default options. Each option can be
|
15
14
|
# overridden later when entities are being dumped.
|
@@ -105,7 +104,7 @@ module Readthis
|
|
105
104
|
flags = string[0].unpack('C').first
|
106
105
|
|
107
106
|
if flags < 16
|
108
|
-
marshal = serializers.rassoc(flags
|
107
|
+
marshal = serializers.rassoc(flags)
|
109
108
|
compress = (flags & COMPRESSED_FLAG) != 0
|
110
109
|
|
111
110
|
[marshal, compress, string[1..-1]]
|
data/lib/readthis/expanders.rb
CHANGED
@@ -7,7 +7,7 @@ module Readthis
|
|
7
7
|
when key.is_a?(Array)
|
8
8
|
key.flat_map { |elem| expand_key(elem) }.join('/')
|
9
9
|
when key.is_a?(Hash)
|
10
|
-
key.sort_by { |
|
10
|
+
key.sort_by { |hkey, _| hkey.to_s }.map { |hkey, val| "#{hkey}=#{val}" }.join('/')
|
11
11
|
when key.respond_to?(:to_param)
|
12
12
|
key.to_param
|
13
13
|
else
|
data/lib/readthis/serializers.rb
CHANGED
@@ -2,8 +2,9 @@ require 'json'
|
|
2
2
|
require 'readthis/passthrough'
|
3
3
|
|
4
4
|
module Readthis
|
5
|
-
SerializersFrozenError = Class.new(
|
6
|
-
SerializersLimitError = Class.new(
|
5
|
+
SerializersFrozenError = Class.new(StandardError)
|
6
|
+
SerializersLimitError = Class.new(StandardError)
|
7
|
+
UnknownSerializerError = Class.new(StandardError)
|
7
8
|
|
8
9
|
class Serializers
|
9
10
|
BASE_SERIALIZERS = {
|
@@ -38,9 +39,9 @@ module Readthis
|
|
38
39
|
def <<(serializer)
|
39
40
|
case
|
40
41
|
when serializers.frozen?
|
41
|
-
|
42
|
+
fail SerializersFrozenError
|
42
43
|
when serializers.length > SERIALIZER_LIMIT
|
43
|
-
|
44
|
+
fail SerializersLimitError
|
44
45
|
else
|
45
46
|
@serializers[serializer] = flags.max.succ
|
46
47
|
@inverted = @serializers.invert
|
@@ -63,36 +64,46 @@ module Readthis
|
|
63
64
|
@inverted = @serializers.invert
|
64
65
|
end
|
65
66
|
|
66
|
-
# Find a flag
|
67
|
+
# Find a flag for a serializer object.
|
67
68
|
#
|
68
69
|
# @param [Object] Look up a flag by object
|
69
|
-
# @return [Number] Corresponding flag for the
|
70
|
+
# @return [Number] Corresponding flag for the serializer object
|
71
|
+
# @raise [UnknownSerializerError] Indicates that a serializer was
|
72
|
+
# specified, but hasn't been configured for usage.
|
70
73
|
#
|
71
74
|
# @example
|
72
75
|
#
|
73
|
-
# serializers.assoc(
|
76
|
+
# serializers.assoc(JSON) #=> 1
|
74
77
|
#
|
75
|
-
def assoc(
|
76
|
-
serializers[
|
78
|
+
def assoc(serializer)
|
79
|
+
flag = serializers[serializer]
|
80
|
+
|
81
|
+
unless flag
|
82
|
+
fail UnknownSerializerError, "'#{serializer}' hasn't been configured"
|
83
|
+
end
|
84
|
+
|
85
|
+
flag
|
77
86
|
end
|
78
87
|
|
79
|
-
# Find a
|
88
|
+
# Find a serializer object by flag value.
|
89
|
+
#
|
90
|
+
# @param [Number] Flag to look up the serializer object by
|
91
|
+
# @return [Module] The serializer object
|
80
92
|
#
|
81
|
-
# @
|
82
|
-
#
|
93
|
+
# @example
|
94
|
+
#
|
95
|
+
# serializers.rassoc(1) #=> Marshal
|
83
96
|
#
|
84
97
|
def rassoc(flag)
|
85
|
-
inverted[flag]
|
98
|
+
inverted[flag & inverted.length]
|
86
99
|
end
|
87
100
|
|
88
|
-
#
|
89
|
-
#
|
101
|
+
# @private
|
90
102
|
def marshals
|
91
103
|
serializers.keys
|
92
104
|
end
|
93
105
|
|
94
|
-
#
|
95
|
-
#
|
106
|
+
# @private
|
96
107
|
def flags
|
97
108
|
serializers.values
|
98
109
|
end
|
data/lib/readthis/version.rb
CHANGED
data/spec/readthis/cache_spec.rb
CHANGED
@@ -8,18 +8,6 @@ RSpec.describe Readthis::Cache do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '#initialize' do
|
11
|
-
it 'accepts and persists a namespace' do
|
12
|
-
cache = Readthis::Cache.new(namespace: 'kash')
|
13
|
-
|
14
|
-
expect(cache.namespace).to eq('kash')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'accepts and persists an expiration' do
|
18
|
-
cache = Readthis::Cache.new(expires_in: 10)
|
19
|
-
|
20
|
-
expect(cache.expires_in).to eq(10)
|
21
|
-
end
|
22
|
-
|
23
11
|
it 'makes options available' do
|
24
12
|
cache = Readthis::Cache.new(namespace: 'cache', expires_in: 1)
|
25
13
|
|
@@ -89,20 +77,20 @@ RSpec.describe Readthis::Cache do
|
|
89
77
|
|
90
78
|
it 'uses globally configured serializers' do
|
91
79
|
custom = Class.new do
|
92
|
-
def self.dump(
|
93
|
-
|
80
|
+
def self.dump(value)
|
81
|
+
value
|
94
82
|
end
|
95
83
|
|
96
|
-
def self.load(
|
97
|
-
|
84
|
+
def self.load(value)
|
85
|
+
value
|
98
86
|
end
|
99
87
|
end
|
100
88
|
|
101
89
|
Readthis.serializers << custom
|
102
90
|
|
103
|
-
cache.write('customized', '
|
91
|
+
cache.write('customized', 'some value', marshal: custom)
|
104
92
|
|
105
|
-
expect(cache.read('customized')).to
|
93
|
+
expect(cache.read('customized')).to eq('some value')
|
106
94
|
end
|
107
95
|
end
|
108
96
|
|
@@ -179,7 +167,7 @@ RSpec.describe Readthis::Cache do
|
|
179
167
|
expect(cache.read_multi('a', 'b', 'c')).to eq(
|
180
168
|
'a' => 1,
|
181
169
|
'b' => 2,
|
182
|
-
'c' => '3'
|
170
|
+
'c' => '3'
|
183
171
|
)
|
184
172
|
end
|
185
173
|
|
@@ -189,7 +177,7 @@ RSpec.describe Readthis::Cache do
|
|
189
177
|
|
190
178
|
expect(cache.read_multi('d', 'e', namespace: 'cache')).to eq(
|
191
179
|
'd' => 1,
|
192
|
-
'e' => 2
|
180
|
+
'e' => 2
|
193
181
|
)
|
194
182
|
end
|
195
183
|
|
@@ -208,7 +196,11 @@ RSpec.describe Readthis::Cache do
|
|
208
196
|
end
|
209
197
|
|
210
198
|
it 'respects passed options' do
|
211
|
-
cache.write_multi(
|
199
|
+
cache.write_multi(
|
200
|
+
{ 'a' => 1, 'b' => 2 },
|
201
|
+
namespace: 'multi',
|
202
|
+
expires_in: 1
|
203
|
+
)
|
212
204
|
|
213
205
|
expect(cache.read('a')).to be_nil
|
214
206
|
expect(cache.read('a', namespace: 'multi')).to eq(1)
|
@@ -227,7 +219,7 @@ RSpec.describe Readthis::Cache do
|
|
227
219
|
expect(results).to eq(
|
228
220
|
'a' => 1,
|
229
221
|
'b' => 'bb',
|
230
|
-
'c' => 3
|
222
|
+
'c' => 3
|
231
223
|
)
|
232
224
|
|
233
225
|
expect(cache.read('b')).to eq('bb')
|
@@ -131,16 +131,6 @@ RSpec.describe Readthis::Entity do
|
|
131
131
|
expect(value).to eq(string)
|
132
132
|
end
|
133
133
|
|
134
|
-
it 'can reconstruct longer qualified module names' do
|
135
|
-
string = 'a' * 30
|
136
|
-
entity = Readthis::Entity.new
|
137
|
-
marked = entity.compose(string, Readthis::Passthrough, false)
|
138
|
-
|
139
|
-
marshal, _, _ = entity.decompose(marked)
|
140
|
-
|
141
|
-
expect(marshal).to eq(Readthis::Passthrough)
|
142
|
-
end
|
143
|
-
|
144
134
|
it 'returns the original string without a marker' do
|
145
135
|
string = 'the quick brown fox'
|
146
136
|
entity = Readthis::Entity.new
|
@@ -19,7 +19,7 @@ RSpec.describe Readthis::Expanders do
|
|
19
19
|
it 'expands an array of objects' do
|
20
20
|
object = double(cache_key: 'gamma')
|
21
21
|
|
22
|
-
expect(expand([
|
22
|
+
expect(expand(%w[alpha beta])).to eq('alpha/beta')
|
23
23
|
expect(expand([object, object])).to eq('gamma/gamma')
|
24
24
|
end
|
25
25
|
|
@@ -11,7 +11,7 @@ RSpec.describe Readthis::Serializers do
|
|
11
11
|
serializers << CustomSerializer
|
12
12
|
|
13
13
|
expect(serializers.marshals).to include(CustomSerializer)
|
14
|
-
expect(serializers.flags).to eq(
|
14
|
+
expect(serializers.flags).to eq([1, 2, 3, 4])
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'increments flags' do
|
@@ -25,9 +25,9 @@ RSpec.describe Readthis::Serializers do
|
|
25
25
|
it 'prevents more than seven serializers' do
|
26
26
|
serializers = Readthis::Serializers.new
|
27
27
|
|
28
|
-
expect
|
28
|
+
expect do
|
29
29
|
10.times { serializers << Class.new }
|
30
|
-
|
30
|
+
end.to raise_error(Readthis::SerializersLimitError)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -37,6 +37,14 @@ RSpec.describe Readthis::Serializers do
|
|
37
37
|
|
38
38
|
expect(serializers.assoc(Marshal)).to eq(0x1)
|
39
39
|
end
|
40
|
+
|
41
|
+
it 'raises a helpful error when the serializer is unknown' do
|
42
|
+
serializers = Readthis::Serializers.new
|
43
|
+
|
44
|
+
expect do
|
45
|
+
serializers.assoc(CustomSerializer)
|
46
|
+
end.to raise_error(Readthis::UnknownSerializerError)
|
47
|
+
end
|
40
48
|
end
|
41
49
|
|
42
50
|
describe '#rassoc' do
|
@@ -45,6 +53,13 @@ RSpec.describe Readthis::Serializers do
|
|
45
53
|
|
46
54
|
expect(serializers.rassoc(1)).to eq(Marshal)
|
47
55
|
end
|
56
|
+
|
57
|
+
it 'returns custom serializers' do
|
58
|
+
serializers = Readthis::Serializers.new
|
59
|
+
serializers << CustomSerializer
|
60
|
+
|
61
|
+
expect(serializers.rassoc(4)).to eq(CustomSerializer)
|
62
|
+
end
|
48
63
|
end
|
49
64
|
|
50
65
|
describe '#freeze!' do
|
@@ -53,9 +68,9 @@ RSpec.describe Readthis::Serializers do
|
|
53
68
|
|
54
69
|
serializers.freeze!
|
55
70
|
|
56
|
-
expect
|
71
|
+
expect do
|
57
72
|
serializers << CustomSerializer
|
58
|
-
|
73
|
+
end.to raise_error(Readthis::SerializersFrozenError)
|
59
74
|
end
|
60
75
|
end
|
61
76
|
|
@@ -66,7 +81,7 @@ RSpec.describe Readthis::Serializers do
|
|
66
81
|
serializers << Class.new
|
67
82
|
serializers.reset!
|
68
83
|
|
69
|
-
expect(serializers.
|
84
|
+
expect(serializers.serializers.length).to eq(3)
|
70
85
|
end
|
71
86
|
end
|
72
87
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,9 +16,7 @@ RSpec.configure do |config|
|
|
16
16
|
|
17
17
|
config.disable_monkey_patching!
|
18
18
|
|
19
|
-
if config.files_to_run.one?
|
20
|
-
config.default_formatter = 'doc'
|
21
|
-
end
|
19
|
+
config.default_formatter = 'doc' if config.files_to_run.one?
|
22
20
|
|
23
21
|
config.order = :random
|
24
22
|
Kernel.srand config.seed
|
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: 1.0.0.pre.
|
4
|
+
version: 1.0.0.pre.rc.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: 2015-09-
|
11
|
+
date: 2015-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -94,33 +94,14 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '3.1'
|
97
|
-
description:
|
97
|
+
description:
|
98
98
|
email:
|
99
99
|
- parker@sorentwo.com
|
100
100
|
executables: []
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
-
- ".gitignore"
|
105
|
-
- ".rspec"
|
106
|
-
- ".travis.yml"
|
107
|
-
- CHANGELOG.md
|
108
|
-
- CONTRIBUTING.md
|
109
|
-
- Gemfile
|
110
|
-
- LICENSE.txt
|
111
|
-
- PERFORMANCE.md
|
112
104
|
- README.md
|
113
|
-
- Rakefile
|
114
|
-
- benchmarks/composing.rb
|
115
|
-
- benchmarks/compressed.rb
|
116
|
-
- benchmarks/driver.rb
|
117
|
-
- benchmarks/generic.rb
|
118
|
-
- benchmarks/marshalling.rb
|
119
|
-
- benchmarks/memory.rb
|
120
|
-
- benchmarks/multi.rb
|
121
|
-
- benchmarks/parsing.rb
|
122
|
-
- benchmarks/profile.rb
|
123
|
-
- bin/rspec
|
124
105
|
- lib/active_support/cache/readthis_store.rb
|
125
106
|
- lib/readthis.rb
|
126
107
|
- lib/readthis/cache.rb
|
@@ -130,7 +111,6 @@ files:
|
|
130
111
|
- lib/readthis/passthrough.rb
|
131
112
|
- lib/readthis/serializers.rb
|
132
113
|
- lib/readthis/version.rb
|
133
|
-
- readthis.gemspec
|
134
114
|
- spec/readthis/cache_spec.rb
|
135
115
|
- spec/readthis/entity_spec.rb
|
136
116
|
- spec/readthis/expanders_spec.rb
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
data/CHANGELOG.md
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
## v1.0.0-beta
|
2
|
-
|
3
|
-
- Breaking: This change is necessary for the consistency and portability of
|
4
|
-
values going forward. All entities are now written with a set of option flags
|
5
|
-
as the initial byte. This flag is later used to determine whether the entity
|
6
|
-
was compressed and what was used to marshal it. There are a number of
|
7
|
-
advantages to this approach, consistency and reliability being the most
|
8
|
-
important. See [readthis#17][pull-17] for additional background.
|
9
|
-
- Added: Per-entity options can be passed through to any cache method that
|
10
|
-
writes a value (`write`, `fetch`, etc). For example, this allows certain
|
11
|
-
entities to be cached as JSON while all other entities are cached using
|
12
|
-
Marshal. Thanks to @fabn.
|
13
|
-
- Fixed: A hash containing the cache key is passed as the payload for
|
14
|
-
`ActiveSupport::Notifications` instrumentation, rather than the key directly.
|
15
|
-
This moves the implementation in-line with the tests for the code, and
|
16
|
-
prevents errors from being masked when an error occurs inside an instrumented
|
17
|
-
block. [readthis#20][pull-20]. Discovered by @banister and fixed by @workmad3.
|
18
|
-
|
19
|
-
[pull-17]: https://github.com/sorentwo/readthis/pull/17
|
20
|
-
[pull-20]: https://github.com/sorentwo/readthis/pull/20
|
21
|
-
|
22
|
-
## v0.8.1 2015-09-04
|
23
|
-
|
24
|
-
- Changed: `Readthis::Cache` now has an accessor for the options that were
|
25
|
-
passed during initialization. This is primarily to support the session store
|
26
|
-
middleware provided by `ActionDispatch`. See [readthis#16][issue-16].
|
27
|
-
- Fixed: Caching `nil` values is now possible. Previously the value would be
|
28
|
-
converted into a blank string, causing a Marshal error when loading the data.
|
29
|
-
There is still some non-standard handling of `nil` within `fetch` or
|
30
|
-
`fetch_multi`, where a cached `nil` value will always result in a cache miss.
|
31
|
-
See [readthis#15][issue-15].
|
32
|
-
- Fixed: Entity compression was broken, it wouldn't unload data when the
|
33
|
-
compressed size was below the compression limit. Data is now decompressed
|
34
|
-
when it can the value looks to be compressed, falling back to the initial
|
35
|
-
value when decompression fails. See [readthis#13][issue-13] for details.
|
36
|
-
|
37
|
-
[issue-13]: https://github.com/sorentwo/readthis/issues/13
|
38
|
-
[issue-15]: https://github.com/sorentwo/readthis/issues/15
|
39
|
-
[issue-16]: https://github.com/sorentwo/readthis/issues/16
|
40
|
-
|
41
|
-
## v0.8.0 2015-08-26
|
42
|
-
|
43
|
-
- Breaking: The initializer now takes a single options argument instead of a
|
44
|
-
`url` and `options` separately. This allows the underlying redis client to
|
45
|
-
accept any options, rather than just the driver. For example, it's now
|
46
|
-
possible to use Readthis with sentinel directly through the configuration.
|
47
|
-
- Changed: The `hiredis` driver is *no longer the default*. In order to use the
|
48
|
-
vastly faster `hiredis` driver you need to pass it in during construction.
|
49
|
-
See [readthis#9][issue-9] for more discussion.
|
50
|
-
|
51
|
-
[issue-9]: https://github.com/sorentwo/readthis/issues/9
|
52
|
-
|
53
|
-
## v0.7.0 2015-08-11
|
54
|
-
|
55
|
-
- Changed: Entity initialization uses an options hash rather than keyword
|
56
|
-
arguments. This allows flexibility with older Ruby versions (1.9) that aren't
|
57
|
-
officially supported.
|
58
|
-
- Changed: There is no longer a hard dependency on `hiredis`, though it is the
|
59
|
-
default. The redis driver can be configured by passing a `driver: :ruby`
|
60
|
-
option through to the constructor.
|
61
|
-
|
62
|
-
## v0.6.2 2015-04-28
|
63
|
-
|
64
|
-
- Fixed: Set expiration during `write_multi`, primarily effecting `fetch_multi`.
|
65
|
-
This fixes the real issue underlying the change in `v0.6.1`.
|
66
|
-
|
67
|
-
## v0.6.1 2015-04-28
|
68
|
-
|
69
|
-
- Changed: Expiration values are always cast to an integer before use in write
|
70
|
-
operations. This prevents subtle ActiveSupport bugs where the value would be
|
71
|
-
ignored by `setex`.
|
72
|
-
|
73
|
-
## v0.6.0 2015-03-09
|
74
|
-
|
75
|
-
- Fixed: Safely handle calling `read_multi` without any keys. [Michael Rykov]
|
76
|
-
- Fixed: Pointed `redis-activesupport` at master. Only effected development and
|
77
|
-
testing.
|
78
|
-
- Added: A `write_multi` method is no available to bulk set keys and values. It
|
79
|
-
is used by `fetch_multi` internally to ensure that there are at most two Redis
|
80
|
-
calls.
|
81
|
-
|
82
|
-
## v0.5.2 2015-01-09
|
83
|
-
|
84
|
-
- Fixed: Remove the `pipeline` around `fetch_multi` writing. This will slow down
|
85
|
-
`fetch_multi` in cache miss situations for now. It prevents a difficult to
|
86
|
-
track down exception in multi-threaded situations.
|
87
|
-
|
88
|
-
## v0.5.1 2014-12-30
|
89
|
-
|
90
|
-
- Fixed: The `clear` method now accepts an argument for compatibility with other
|
91
|
-
caches. The argument is not actually used for anything.
|
92
|
-
- Changed: The `delete` method will always return a boolean value rather than an
|
93
|
-
integer.
|
94
|
-
- Changed: Avoid multiple instrumentation calls and pool checkouts within
|
95
|
-
`fetch_multi` calls.
|
96
|
-
|
97
|
-
## v0.5.0 2014-12-12
|
98
|
-
|
99
|
-
- Added: All read and write operations are marshalled to and from storage. This
|
100
|
-
allows hashes, arrays, etc. to be restored instead of always returning a
|
101
|
-
string. Unlike `ActiveSupport::Store::Entity`, no new objects are allocated
|
102
|
-
for each entity, reducing GC and improving performance.
|
103
|
-
- Fixed: Increment/Decrement interface was only accepting two params instead of
|
104
|
-
three. Now accepts `amount` as the second parameter.
|
105
|
-
- Changed: Increment/Decrement no longer use `incby` and `decby`, as they don't
|
106
|
-
work with marshalled values. This means they are not entirely atomic, so race
|
107
|
-
conditions are possible.
|
108
|
-
|
109
|
-
## v0.4.0 2014-12-11
|
110
|
-
|
111
|
-
- Added: Force the use of `hiredis` as the adapter. It is dramatically faster,
|
112
|
-
but prevents the project from being used in `jruby`. If we get interest from
|
113
|
-
some `jruby` projects we can soften the requirement.
|
114
|
-
- Added: Compression! Adheres to the `ActiveSupport::Store` documentation.
|
115
|
-
- Fixed: Gracefully handle `nil` passed as `options` to any cache method.
|
116
|
-
|
117
|
-
## v0.3.0 2014-12-01
|
118
|
-
|
119
|
-
- Added: Use `to_param` for key expansion, only when available. Makes it
|
120
|
-
possible to extract a key from any object when ActiveSupport is loaded.
|
121
|
-
- Added: Expand hashes as cache keys.
|
122
|
-
- Changed: Use `mget` for `read_multi`, faster and more synchronous than relying on
|
123
|
-
`pipelined`.
|
124
|
-
- Changed: Delimit compound objects with a slash rather than a colon.
|
125
|
-
|
126
|
-
## v0.2.0 2014-11-24
|
127
|
-
|
128
|
-
- Added: Instrument all caching methods. Will use `ActiveSupport::Notifications`
|
129
|
-
if available, otherwise falls back to a polyfill.
|
130
|
-
- Added: Expand objects with a `cache_key` method and arrays of strings or objects into
|
131
|
-
consistent naespaced keys.
|
132
|
-
|
133
|
-
## v0.1.0 2014-11-22
|
134
|
-
|
135
|
-
- Initial release! Working as a drop in replacement for `redis_store`.
|
data/CONTRIBUTING.md
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# Contributing
|
2
|
-
|
3
|
-
## Open an Issue
|
4
|
-
|
5
|
-
Let us know about bugs. Include your version of Readthis, Ruby, and the
|
6
|
-
environment you are using.
|
7
|
-
|
8
|
-
## Submit a Pull Request
|
9
|
-
|
10
|
-
1. Fork it ( https://github.com/sorentwo/readthis/fork )
|
11
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
12
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
13
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
14
|
-
5. Create a new Pull Request
|
data/Gemfile
DELETED
data/LICENSE.txt
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Copyright (c) 2014 Parker Selbert
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/PERFORMANCE.md
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
Results from the various benchmarks in `./bencharks`. Hardware doesn'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 358.000 i/100ms
|
23
|
-
redisas:read-multi 94.000 i/100ms
|
24
|
-
dalli:read-multi 99.000 i/100ms
|
25
|
-
-------------------------------------------------
|
26
|
-
readthis:read-multi 3.800k (± 2.3%) i/s - 19.332k
|
27
|
-
redisas:read-multi 962.199 (± 3.6%) i/s - 4.888k
|
28
|
-
dalli:read-multi 995.353 (± 1.1%) i/s - 5.049k
|
29
|
-
|
30
|
-
Comparison:
|
31
|
-
readthis:read-multi: 3799.8 i/s
|
32
|
-
dalli:read-multi: 995.4 i/s - 3.82x slower
|
33
|
-
redisas:read-multi: 962.2 i/s - 3.95x slower
|
34
|
-
|
35
|
-
Raw Fetch Multi:
|
36
|
-
Calculating -------------------------------------
|
37
|
-
readthis:fetch-multi 336.000 i/100ms
|
38
|
-
redisas:fetch-multi 86.000 i/100ms
|
39
|
-
dalli:fetch-multi 102.000 i/100ms
|
40
|
-
-------------------------------------------------
|
41
|
-
readthis:fetch-multi 3.424k (± 2.6%) i/s - 17.136k
|
42
|
-
redisas:fetch-multi 874.803 (± 2.7%) i/s - 4.386k
|
43
|
-
dalli:fetch-multi 1.028k (± 1.2%) i/s - 5.202k
|
44
|
-
|
45
|
-
Comparison:
|
46
|
-
readthis:fetch-multi: 3424.2 i/s
|
47
|
-
dalli:fetch-multi: 1027.7 i/s - 3.33x slower
|
48
|
-
redisas:fetch-multi: 874.8 i/s - 3.91x slower
|
49
|
-
|
50
|
-
Compressed Writes:
|
51
|
-
Calculating -------------------------------------
|
52
|
-
readthis:write 924.000 i/100ms
|
53
|
-
dalli:write 903.000 i/100ms
|
54
|
-
-------------------------------------------------
|
55
|
-
readthis:write 10.105k (± 4.9%) i/s - 50.820k
|
56
|
-
dalli:write 9.662k (± 1.6%) i/s - 48.762k
|
57
|
-
|
58
|
-
Comparison:
|
59
|
-
readthis:write: 10105.3 i/s
|
60
|
-
dalli:write: 9662.4 i/s - 1.05x slower
|
61
|
-
|
62
|
-
Compressed Read Multi:
|
63
|
-
Calculating -------------------------------------
|
64
|
-
readthis:read_multi 325.000 i/100ms
|
65
|
-
dalli:read_multi 100.000 i/100ms
|
66
|
-
-------------------------------------------------
|
67
|
-
readthis:read_multi 3.357k (± 2.3%) i/s - 16.900k
|
68
|
-
dalli:read_multi 1.014k (± 3.1%) i/s - 5.100k
|
69
|
-
|
70
|
-
Comparison:
|
71
|
-
readthis:read_multi: 3356.5 i/s
|
72
|
-
dalli:read_multi: 1014.1 i/s - 3.31x slower
|
73
|
-
```
|
data/Rakefile
DELETED
data/benchmarks/composing.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
|
3
|
-
def compose_a(marshal, compress)
|
4
|
-
prefix = ''
|
5
|
-
prefix << 'R|'.freeze
|
6
|
-
prefix << marshal.name.ljust(24)
|
7
|
-
prefix << (compress ? '1'.freeze : '0'.freeze)
|
8
|
-
prefix << 1
|
9
|
-
prefix << '|R'.freeze
|
10
|
-
end
|
11
|
-
|
12
|
-
def compose_b(marshal, compress)
|
13
|
-
"R|#{marshal.name.ljust(24)}#{compress ? '1'.freeze : '0'.freeze}1|R"
|
14
|
-
end
|
15
|
-
|
16
|
-
def compose_c(marshal, compress)
|
17
|
-
name = marshal.name.ljust(24)
|
18
|
-
comp = compress ? '1'.freeze : '0'.freeze
|
19
|
-
|
20
|
-
"R|#{name}#{comp}1|R"
|
21
|
-
end
|
22
|
-
|
23
|
-
SERIALIZER_FLAG = { Marshal => 0x1 }.freeze
|
24
|
-
COMPRESSED_FLAG = 0x8
|
25
|
-
|
26
|
-
# | 0000 | 0 | 000 |
|
27
|
-
# four unused bits, # 1 compression bit, 3 bits for serializer, allow up to 8
|
28
|
-
# different marshalers
|
29
|
-
def compose_d(marshal, compress)
|
30
|
-
flags = SERIALIZER_FLAG[marshal]
|
31
|
-
flags |= COMPRESSED_FLAG if compress
|
32
|
-
|
33
|
-
[flags].pack('C')
|
34
|
-
end
|
35
|
-
|
36
|
-
Benchmark.ips do |x|
|
37
|
-
x.report('a') { compose_a(Marshal, true) }
|
38
|
-
x.report('b') { compose_b(Marshal, true) }
|
39
|
-
x.report('c') { compose_c(Marshal, true) }
|
40
|
-
x.report('d') { compose_d(Marshal, true) }
|
41
|
-
|
42
|
-
x.compare!
|
43
|
-
end
|
data/benchmarks/compressed.rb
DELETED
@@ -1,74 +0,0 @@
|
|
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
|
-
pool_size: 5,
|
20
|
-
compressed: true,
|
21
|
-
compression_threshold: 128
|
22
|
-
)
|
23
|
-
|
24
|
-
KEY = 'key'
|
25
|
-
TEXT = <<-TEXT
|
26
|
-
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.
|
27
|
-
Some implementations may not support all methods beyond the basic cache methods of fetch, write, read, exist?, and delete.
|
28
|
-
ActiveSupport::Cache::Store can store any serializable Ruby object.
|
29
|
-
cache = ActiveSupport::Cache::MemoryStore.new
|
30
|
-
cache.read('city') # => nil
|
31
|
-
cache.write('city', "Duckburgh")
|
32
|
-
cache.read('city') # => "Duckburgh"
|
33
|
-
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.
|
34
|
-
cache.read('city') == cache.read(:city) # => true
|
35
|
-
Nil values can be cached.
|
36
|
-
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.
|
37
|
-
cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
38
|
-
@last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
39
|
-
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.
|
40
|
-
TEXT
|
41
|
-
|
42
|
-
puts 'Compressed Write/Read:'
|
43
|
-
Benchmark.ips do |x|
|
44
|
-
x.report 'readthis:write/read' do
|
45
|
-
readthis.write(KEY, TEXT)
|
46
|
-
readthis.read(KEY)
|
47
|
-
end
|
48
|
-
|
49
|
-
x.report 'dalli:write/read' do
|
50
|
-
dalli.write(KEY, TEXT)
|
51
|
-
dalli.read(KEY)
|
52
|
-
end
|
53
|
-
|
54
|
-
x.compare!
|
55
|
-
end
|
56
|
-
|
57
|
-
puts 'Compressed Read Multi:'
|
58
|
-
MULTI_KEY = (1..30).to_a
|
59
|
-
MULTI_KEY.each do |key|
|
60
|
-
readthis.write(key, TEXT)
|
61
|
-
dalli.write(key, TEXT)
|
62
|
-
end
|
63
|
-
|
64
|
-
Benchmark.ips do |x|
|
65
|
-
x.report 'readthis:read_multi' do
|
66
|
-
readthis.read_multi(*MULTI_KEY)
|
67
|
-
end
|
68
|
-
|
69
|
-
x.report 'dalli:read_multi' do
|
70
|
-
dalli.read_multi(*MULTI_KEY)
|
71
|
-
end
|
72
|
-
|
73
|
-
x.compare!
|
74
|
-
end
|
data/benchmarks/driver.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
|
3
|
-
Bundler.setup
|
4
|
-
|
5
|
-
require 'benchmark/ips'
|
6
|
-
require 'readthis'
|
7
|
-
|
8
|
-
native = Readthis::Cache.new(redis: { driver: :ruby }, expires_in: 60)
|
9
|
-
hiredis = Readthis::Cache.new(redis: { driver: :hiredis }, expires_in: 60)
|
10
|
-
|
11
|
-
('a'..'z').each { |key| native.write(key, key * 1024) }
|
12
|
-
|
13
|
-
Benchmark.ips do |x|
|
14
|
-
x.report('native:read-multi') { native.read_multi(*('a'..'z')) }
|
15
|
-
x.report('hiredis:read-multi') { hiredis.read_multi(*('a'..'z')) }
|
16
|
-
|
17
|
-
x.compare!
|
18
|
-
end
|
data/benchmarks/generic.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
require 'json'
|
3
|
-
require 'readthis'
|
4
|
-
|
5
|
-
READTHIS = Readthis::Cache.new(
|
6
|
-
expires_in: 120,
|
7
|
-
marshal: JSON,
|
8
|
-
compress: true
|
9
|
-
)
|
10
|
-
|
11
|
-
def write_key(key)
|
12
|
-
READTHIS.write(key, key.to_s * 2048)
|
13
|
-
end
|
14
|
-
|
15
|
-
KEYS = (1..1_000).to_a
|
16
|
-
KEYS.each { |key| write_key(key) }
|
17
|
-
|
18
|
-
Benchmark.ips do |x|
|
19
|
-
x.report 'readthis:write' do
|
20
|
-
write_key(KEYS.sample)
|
21
|
-
end
|
22
|
-
|
23
|
-
x.report 'readthis:read' do
|
24
|
-
READTHIS.read(KEYS.sample)
|
25
|
-
end
|
26
|
-
|
27
|
-
x.report 'readthis:read_multi' do
|
28
|
-
READTHIS.read(KEYS.sample(30))
|
29
|
-
end
|
30
|
-
end
|
data/benchmarks/marshalling.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
|
3
|
-
Bundler.setup
|
4
|
-
|
5
|
-
require 'benchmark/ips'
|
6
|
-
require 'json'
|
7
|
-
require 'oj'
|
8
|
-
require 'msgpack'
|
9
|
-
require 'readthis'
|
10
|
-
require 'readthis/passthrough'
|
11
|
-
|
12
|
-
Readthis.serializers << Oj
|
13
|
-
Readthis.serializers << MessagePack
|
14
|
-
|
15
|
-
readthis_oj = Readthis::Cache.new(marshal: Oj)
|
16
|
-
readthis_msgpack = Readthis::Cache.new(marshal: MessagePack)
|
17
|
-
readthis_json = Readthis::Cache.new(marshal: JSON)
|
18
|
-
readthis_ruby = Readthis::Cache.new(marshal: Marshal)
|
19
|
-
|
20
|
-
HASH = ('a'..'z').each_with_object({}) { |key, memo| memo[key] = key }
|
21
|
-
|
22
|
-
Benchmark.ips do |x|
|
23
|
-
x.report('oj:hash:dump') { readthis_oj.write('oj', HASH) }
|
24
|
-
x.report('json:hash:dump') { readthis_json.write('json', HASH) }
|
25
|
-
x.report('msgpack:hash:dump') { readthis_msgpack.write('msgpack', HASH) }
|
26
|
-
x.report('ruby:hash:dump') { readthis_ruby.write('ruby', HASH) }
|
27
|
-
|
28
|
-
x.compare!
|
29
|
-
end
|
30
|
-
|
31
|
-
Benchmark.ips do |x|
|
32
|
-
x.report('oj:hash:load') { readthis_oj.read('oj') }
|
33
|
-
x.report('json:hash:load') { readthis_json.read('json') }
|
34
|
-
x.report('msgpack:hash:load') { readthis_msgpack.read('msgpack') }
|
35
|
-
x.report('ruby:hash:load') { readthis_ruby.read('ruby') }
|
36
|
-
|
37
|
-
x.compare!
|
38
|
-
end
|
data/benchmarks/memory.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'bundler'; Bundler.setup
|
2
|
-
a = GC.stat(:total_allocated_objects)
|
3
|
-
|
4
|
-
require 'readthis'
|
5
|
-
b = GC.stat(:total_allocated_objects)
|
6
|
-
|
7
|
-
require 'redis-activesupport'
|
8
|
-
c = GC.stat(:total_allocated_objects)
|
9
|
-
|
10
|
-
puts "readthis: #{b - a}"
|
11
|
-
puts "redis-activesupport: #{c - b}"
|
data/benchmarks/multi.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
require 'dalli'
|
3
|
-
require 'redis-activesupport'
|
4
|
-
require 'active_support/cache/memory_store'
|
5
|
-
require 'active_support/cache/dalli_store'
|
6
|
-
require 'readthis'
|
7
|
-
|
8
|
-
memory = ActiveSupport::Cache::MemoryStore.new(expires_in: 60, namespace: 'mm')
|
9
|
-
dalli = ActiveSupport::Cache::DalliStore.new('localhost', namespace: 'da', pool_size: 5, expires_in: 60)
|
10
|
-
redisas = ActiveSupport::Cache::RedisStore.new('redis://localhost:6379/11/ra', expires_in: 60)
|
11
|
-
readthis = Readthis::Cache.new(namespace: 'rd', expires_in: 60)
|
12
|
-
|
13
|
-
('a'..'z').each do |key|
|
14
|
-
value = key * 1024
|
15
|
-
|
16
|
-
memory.write(key, value)
|
17
|
-
dalli.write(key, value)
|
18
|
-
readthis.write(key, value)
|
19
|
-
redisas.write(key, value)
|
20
|
-
end
|
21
|
-
|
22
|
-
Benchmark.ips do |x|
|
23
|
-
x.report 'memory:read-multi' do
|
24
|
-
memory.read_multi(*('a'..'z'))
|
25
|
-
end
|
26
|
-
|
27
|
-
x.report 'readthis:read-multi' do
|
28
|
-
readthis.read_multi(*('a'..'z'))
|
29
|
-
end
|
30
|
-
|
31
|
-
x.report 'redisas:read-multi' do
|
32
|
-
redisas.read_multi(*('a'..'z'))
|
33
|
-
end
|
34
|
-
|
35
|
-
x.report 'dalli:read-multi' do
|
36
|
-
dalli.read_multi(*('a'..'z'))
|
37
|
-
end
|
38
|
-
|
39
|
-
x.compare!
|
40
|
-
end
|
41
|
-
|
42
|
-
Benchmark.ips do |x|
|
43
|
-
x.report 'memory:fetch-multi' do
|
44
|
-
memory.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
45
|
-
end
|
46
|
-
|
47
|
-
x.report 'readthis:fetch-multi' do
|
48
|
-
readthis.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
49
|
-
end
|
50
|
-
|
51
|
-
x.report 'redisas:fetch-multi' do
|
52
|
-
redisas.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
53
|
-
end
|
54
|
-
|
55
|
-
x.report 'dalli:fetch-multi' do
|
56
|
-
dalli.fetch_multi(*('a'..'z')) { |_| 'missing' }
|
57
|
-
end
|
58
|
-
|
59
|
-
x.compare!
|
60
|
-
end
|
data/benchmarks/parsing.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
|
3
|
-
def parse_a(string)
|
4
|
-
marshal = string[2, 12].strip
|
5
|
-
compress = string[15] == '1'.freeze
|
6
|
-
|
7
|
-
[Kernel.const_get(marshal), compress, string[18..-1]]
|
8
|
-
end
|
9
|
-
|
10
|
-
def parse_b(marked)
|
11
|
-
prefix = marked[0, 32].scrub('*'.freeze)[/R\|(.*)\|R/, 1]
|
12
|
-
offset = prefix.size + 4
|
13
|
-
|
14
|
-
marshal, c_name, _ = prefix.split(' '.freeze)
|
15
|
-
|
16
|
-
compress = c_name == 'true'.freeze
|
17
|
-
|
18
|
-
[Kernel.const_get(marshal), compress, marked[offset..-1]]
|
19
|
-
end
|
20
|
-
|
21
|
-
SERIALIZERS = { Marshal => 0x1 }.freeze
|
22
|
-
DESERIALIZERS = SERIALIZERS.invert.freeze
|
23
|
-
COMPRESSED_FLAG = 0x8
|
24
|
-
MARSHAL_FLAG = 0x3
|
25
|
-
BINARY_FLAG = [SERIALIZERS[Marshal] | COMPRESSED_FLAG].pack('C')
|
26
|
-
|
27
|
-
def parse_c(binary_string)
|
28
|
-
flags = binary_string[0].unpack('C').first
|
29
|
-
|
30
|
-
[DESERIALIZERS[flags & MARSHAL_FLAG], flags & COMPRESSED_FLAG, binary_string[1..-1]]
|
31
|
-
end
|
32
|
-
|
33
|
-
STR = 'R|Marshal 0|Rafdlkadfjadfj asdlkfjasdlfkj asdlfkjdasflkjadsflkjadslkjfadslkjfasdlkjfadlskjf laksdjflkajsdflkjadsflkadjsfladskjf laksjflakdjfalsdkjfadlskjf laksdjflkajdsflk j'
|
34
|
-
STR2 = BINARY_FLAG << 'Rafdlkadfjadfj asdlkfjasdlfkj asdlfkjdasflkjadsflkjadslkjfadslkjfasdlkjfadlskjf laksdjflkajsdflkjadsflkadjsfladskjf laksjflakdjfalsdkjfadlskjf laksdjflkajdsflk j'
|
35
|
-
|
36
|
-
Benchmark.ips do |x|
|
37
|
-
x.report('a') { parse_a(STR) }
|
38
|
-
x.report('b') { parse_b(STR) }
|
39
|
-
x.report('c') { parse_c(STR2) }
|
40
|
-
|
41
|
-
x.compare!
|
42
|
-
end
|
data/benchmarks/profile.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'bundler'
|
2
|
-
|
3
|
-
Bundler.setup
|
4
|
-
|
5
|
-
require 'fileutils'
|
6
|
-
require 'stackprof'
|
7
|
-
require 'readthis'
|
8
|
-
|
9
|
-
readthis = Readthis::Cache.new
|
10
|
-
|
11
|
-
FileUtils.mkdir_p('tmp')
|
12
|
-
readthis.clear
|
13
|
-
|
14
|
-
('a'..'z').each { |key| readthis.write(key, key * 1024) }
|
15
|
-
|
16
|
-
StackProf.run(mode: :object, interval: 500, out: "tmp/stackprof-object.dump") do
|
17
|
-
1000.times do
|
18
|
-
readthis.read_multi(*('a'..'z'))
|
19
|
-
end
|
20
|
-
end
|
data/bin/rspec
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This file was generated by Bundler.
|
4
|
-
#
|
5
|
-
# The application 'rspec' is installed as part of a gem, and
|
6
|
-
# this file is here to facilitate running it.
|
7
|
-
#
|
8
|
-
|
9
|
-
require 'pathname'
|
10
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
-
Pathname.new(__FILE__).realpath)
|
12
|
-
|
13
|
-
require 'rubygems'
|
14
|
-
require 'bundler/setup'
|
15
|
-
|
16
|
-
load Gem.bin_path('rspec-core', 'rspec')
|
data/readthis.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'readthis/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = 'readthis'
|
8
|
-
spec.version = Readthis::VERSION
|
9
|
-
spec.authors = ['Parker Selbert']
|
10
|
-
spec.email = ['parker@sorentwo.com']
|
11
|
-
spec.summary = 'Pooled active support compliant caching with redis'
|
12
|
-
spec.description = 'Pooled active support compliant caching with redis'
|
13
|
-
spec.homepage = 'https://github.com/sorentwo/readthis'
|
14
|
-
spec.license = 'MIT'
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.test_files = spec.files.grep(%r{^(spec)/})
|
18
|
-
spec.require_paths = ['lib']
|
19
|
-
|
20
|
-
spec.add_dependency 'redis', '~> 3.0'
|
21
|
-
spec.add_dependency 'connection_pool', '~> 2.1'
|
22
|
-
|
23
|
-
spec.add_development_dependency 'bundler'
|
24
|
-
spec.add_development_dependency 'hiredis', '~> 0.5'
|
25
|
-
spec.add_development_dependency 'rake'
|
26
|
-
spec.add_development_dependency 'rspec', '~> 3.1'
|
27
|
-
end
|