readthis 1.0.0.pre.beta → 1.0.0.pre.rc.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: b0b93b4402db2eaaff687eb60a40296bb618dd4e
4
- data.tar.gz: 81f108e00b2b7dfe0ce92d9209c1160e3cc59a6f
3
+ metadata.gz: c641f0b14297f5f65cc9e2a36dc525c92e2f4a48
4
+ data.tar.gz: cf5625a9a3b874f5f715979c615ee0db5c27daad
5
5
  SHA512:
6
- metadata.gz: d8e81b60017904895db2c2d2666f9f9d2fdad7fa2178c6bbca617abc0d49e5d8934c3128e0f8dba1014c5b30f02d2101fcf3102d2ecee441d5f43f9be9a35282
7
- data.tar.gz: 1b8c28d2a8fdcff75d38bc565dceaf14fb442a1d14ca2c547c53e315d5d6eae08f35f96dbf3f97e268f71774ab27eb9afa5faf4266a1f3becf8af7303c92eee9
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
- ### Marshalling
99
+ ### Serializing
100
100
 
101
- Readthis uses Ruby's `Marshal` module for dumping and loading all values by
102
- default. This isn't always the fastest option, and depending on your use case it
103
- may be desirable to use a faster but less flexible marshaller.
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 for marshalling:
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 marshaller:
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 marshals by configuring `serializers` on
119
- the Readthis module. For example, if you wanted to use Oj for JSON marshalling,
120
- it is extremely fast, but supports limited types:
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
@@ -2,6 +2,6 @@ require 'readthis'
2
2
 
3
3
  module ActiveSupport
4
4
  module Cache
5
- ReadthisStore ||= Readthis::Cache
5
+ ReadthisStore ||= Readthis::Cache # rubocop:disable Style/ConstantName
6
6
  end
7
7
  end
@@ -7,7 +7,7 @@ require 'connection_pool'
7
7
 
8
8
  module Readthis
9
9
  class Cache
10
- attr_reader :entity, :expires_in, :namespace, :options, :pool
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 = 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 |store|
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 |store|
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 |store|
272
+ invoke(:fetch_multi, keys) do |_store|
275
273
  results.each do |key, value|
276
- if value.nil?
277
- value = yield(key)
278
- missing[key] = value
279
- results[key] = value
280
- end
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 = 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)
@@ -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 & MARSHAL_FLAG)
107
+ marshal = serializers.rassoc(flags)
109
108
  compress = (flags & COMPRESSED_FLAG) != 0
110
109
 
111
110
  [marshal, compress, string[1..-1]]
@@ -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 { |key, _| key.to_s }.map { |key, val| "#{key}=#{val}" }.join('/')
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
@@ -2,8 +2,9 @@ require 'json'
2
2
  require 'readthis/passthrough'
3
3
 
4
4
  module Readthis
5
- SerializersFrozenError = Class.new(Exception)
6
- SerializersLimitError = Class.new(Exception)
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
- raise SerializersFrozenError
42
+ fail SerializersFrozenError
42
43
  when serializers.length > SERIALIZER_LIMIT
43
- raise SerializersLimitError
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 by the marshal object.
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 marshal object
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(Marshal) #=> 1
76
+ # serializers.assoc(JSON) #=> 1
74
77
  #
75
- def assoc(marshal)
76
- serializers[marshal]
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 marshal object by flag value.
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
- # @param [Number] Flag to look up the marshal object by
82
- # @return [Module] The marshal object
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
- # The current list of marshal objects.
89
- #
101
+ # @private
90
102
  def marshals
91
103
  serializers.keys
92
104
  end
93
105
 
94
- # The current list of flags.
95
- #
106
+ # @private
96
107
  def flags
97
108
  serializers.values
98
109
  end
@@ -1,3 +1,3 @@
1
1
  module Readthis
2
- VERSION = '1.0.0-beta'
2
+ VERSION = '1.0.0-rc.1'
3
3
  end
@@ -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
- 'dumped'
80
+ def self.dump(value)
81
+ value
94
82
  end
95
83
 
96
- def self.load(_)
97
- 'dumped'
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', 'overwrite me', marshal: custom)
91
+ cache.write('customized', 'some value', marshal: custom)
104
92
 
105
- expect(cache.read('customized')).to include('dumped')
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({ 'a' => 1, 'b' => 2 }, namespace: 'multi', expires_in: 1)
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(['alpha', 'beta'])).to eq('alpha/beta')
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((1..4).to_a)
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
- }.to raise_error(Readthis::SerializersLimitError)
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
- }.to raise_error(Readthis::SerializersFrozenError)
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.marshals.length).to eq(3)
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.beta
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-18 00:00:00.000000000 Z
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: Pooled active support compliant caching with redis
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
@@ -1,15 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.bundle
11
- *.so
12
- *.o
13
- *.a
14
- mkmf.log
15
- TODO
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --require spec_helper
data/.travis.yml DELETED
@@ -1,15 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.1.0
5
- - 2.2.2
6
- - ruby-head
7
- - rbx-2
8
- matrix:
9
- allow_failures:
10
- - rvm: ruby-head
11
- - rvm: rbx-2
12
- services:
13
- - redis-server
14
- script: bin/rspec
15
- bundler_args: --without benchmarking
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
@@ -1,14 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- gem 'coveralls', require: false
6
-
7
- group :benchmarking do
8
- gem 'benchmark-ips'
9
- gem 'dalli'
10
- gem 'oj'
11
- gem 'msgpack'
12
- gem 'redis-activesupport'
13
- gem 'stackprof'
14
- end
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
@@ -1,2 +0,0 @@
1
- require "bundler/gem_tasks"
2
-
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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