readthis 0.8.1 → 1.2.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.
data/CHANGELOG.md DELETED
@@ -1,114 +0,0 @@
1
- ## v0.8.1 2015-09-04
2
-
3
- - Changed: `Readthis::Cache` now has an accessor for the options that were
4
- passed during initialization. This is primarily to support the session store
5
- middleware provided by `ActionDispatch`. See [readthis#16][issue-16].
6
- - Fixed: Caching `nil` values is now possible. Previously the value would be
7
- converted into a blank string, causing a Marshal error when loading the data.
8
- There is still some non-standard handling of `nil` within `fetch` or
9
- `fetch_multi`, where a cached `nil` value will always result in a cache miss.
10
- See [readthis#15][issue-15].
11
- - Fixed: Entity compression was broken, it wouldn't unload data when the
12
- compressed size was below the compression limit. Data is now decompressed
13
- when it can the value looks to be compressed, falling back to the initial
14
- value when decompression fails. See [readthis#13][issue-13] for details.
15
-
16
- [issue-13]: https://github.com/sorentwo/readthis/pull/13
17
- [issue-15]: https://github.com/sorentwo/readthis/pull/15
18
- [issue-16]: https://github.com/sorentwo/readthis/pull/16
19
-
20
- ## v0.8.0 2015-08-26
21
-
22
- - Breaking: The initializer now takes a single options argument instead of a
23
- `url` and `options` separately. This allows the underlying redis client to
24
- accept any options, rather than just the driver. For example, it's now
25
- possible to use Readthis with sentinel directly through the configuration.
26
- - Changed: The `hiredis` driver is *no longer the default*. In order to use the
27
- vastly faster `hiredis` driver you need to pass it in during construction.
28
- See [readthis#9][issue-9] for more discussion.
29
-
30
- [issue-9]: https://github.com/sorentwo/readthis/issues/9
31
-
32
- ## v0.7.0 2015-08-11
33
-
34
- - Changed: Entity initialization uses an options hash rather than keyword
35
- arguments. This allows flexibility with older Ruby versions (1.9) that aren't
36
- officially supported.
37
- - Changed: There is no longer a hard dependency on `hiredis`, though it is the
38
- default. The redis driver can be configured by passing a `driver: :ruby`
39
- option through to the constructor.
40
-
41
- ## v0.6.2 2015-04-28
42
-
43
- - Fixed: Set expiration during `write_multi`, primarily effecting `fetch_multi`.
44
- This fixes the real issue underlying the change in `v0.6.1`.
45
-
46
- ## v0.6.1 2015-04-28
47
-
48
- - Changed: Expiration values are always cast to an integer before use in write
49
- operations. This prevents subtle ActiveSupport bugs where the value would be
50
- ignored by `setex`.
51
-
52
- ## v0.6.0 2015-03-09
53
-
54
- - Fixed: Safely handle calling `read_multi` without any keys. [Michael Rykov]
55
- - Fixed: Pointed `redis-activesupport` at master. Only effected development and
56
- testing.
57
- - Added: A `write_multi` method is no available to bulk set keys and values. It
58
- is used by `fetch_multi` internally to ensure that there are at most two Redis
59
- calls.
60
-
61
- ## v0.5.2 2015-01-09
62
-
63
- - Fixed: Remove the `pipeline` around `fetch_multi` writing. This will slow down
64
- `fetch_multi` in cache miss situations for now. It prevents a difficult to
65
- track down exception in multi-threaded situations.
66
-
67
- ## v0.5.1 2014-12-30
68
-
69
- - Fixed: The `clear` method now accepts an argument for compatibility with other
70
- caches. The argument is not actually used for anything.
71
- - Changed: The `delete` method will always return a boolean value rather than an
72
- integer.
73
- - Changed: Avoid multiple instrumentation calls and pool checkouts within
74
- `fetch_multi` calls.
75
-
76
- ## v0.5.0 2014-12-12
77
-
78
- - Added: All read and write operations are marshalled to and from storage. This
79
- allows hashes, arrays, etc. to be restored instead of always returning a
80
- string. Unlike `ActiveSupport::Store::Entity`, no new objects are allocated
81
- for each entity, reducing GC and improving performance.
82
- - Fixed: Increment/Decrement interface was only accepting two params instead of
83
- three. Now accepts `amount` as the second parameter.
84
- - Changed: Increment/Decrement no longer use `incby` and `decby`, as they don't
85
- work with marshalled values. This means they are not entirely atomic, so race
86
- conditions are possible.
87
-
88
- ## v0.4.0 2014-12-11
89
-
90
- - Added: Force the use of `hiredis` as the adapter. It is dramatically faster,
91
- but prevents the project from being used in `jruby`. If we get interest from
92
- some `jruby` projects we can soften the requirement.
93
- - Added: Compression! Adheres to the `ActiveSupport::Store` documentation.
94
- - Fixed: Gracefully handle `nil` passed as `options` to any cache method.
95
-
96
- ## v0.3.0 2014-12-01
97
-
98
- - Added: Use `to_param` for key expansion, only when available. Makes it
99
- possible to extract a key from any object when ActiveSupport is loaded.
100
- - Added: Expand hashes as cache keys.
101
- - Changed: Use `mget` for `read_multi`, faster and more synchronous than relying on
102
- `pipelined`.
103
- - Changed: Delimit compound objects with a slash rather than a colon.
104
-
105
- ## v0.2.0 2014-11-24
106
-
107
- - Added: Instrument all caching methods. Will use `ActiveSupport::Notifications`
108
- if available, otherwise falls back to a polyfill.
109
- - Added: Expand objects with a `cache_key` method and arrays of strings or objects into
110
- consistent naespaced keys.
111
-
112
- ## v0.1.0 2014-11-22
113
-
114
- - 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,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,40 +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
- OPTIONS = { compressed: false }
13
-
14
- readthis_pass = Readthis::Cache.new(OPTIONS.merge(marshal: Readthis::Passthrough))
15
- readthis_oj = Readthis::Cache.new(OPTIONS.merge(marshal: Oj))
16
- readthis_msgpack = Readthis::Cache.new(OPTIONS.merge(marshal: MessagePack))
17
- readthis_json = Readthis::Cache.new(OPTIONS.merge(marshal: JSON))
18
- readthis_ruby = Readthis::Cache.new(OPTIONS.merge(marshal: Marshal))
19
-
20
- HASH = ('a'..'z').each_with_object({}) { |key, memo| memo[key] = key }
21
-
22
- Benchmark.ips do |x|
23
- x.report('pass:hash:dump') { readthis_pass.write('pass', HASH) }
24
- x.report('oj:hash:dump') { readthis_oj.write('oj', HASH) }
25
- x.report('json:hash:dump') { readthis_json.write('json', HASH) }
26
- x.report('msgpack:hash:dump') { readthis_msgpack.write('msgpack', HASH) }
27
- x.report('ruby:hash:dump') { readthis_ruby.write('ruby', HASH) }
28
-
29
- x.compare!
30
- end
31
-
32
- Benchmark.ips do |x|
33
- x.report('pass:hash:load') { readthis_pass.read('pass') }
34
- x.report('oj:hash:load') { readthis_oj.read('oj') }
35
- x.report('json:hash:load') { readthis_json.read('json') }
36
- x.report('msgpack:hash:load') { readthis_msgpack.read('msgpack') }
37
- x.report('ruby:hash:load') { readthis_ruby.read('ruby') }
38
-
39
- x.compare!
40
- 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,64 +0,0 @@
1
- require 'bundler'
2
-
3
- Bundler.setup
4
-
5
- require 'benchmark/ips'
6
- require 'dalli'
7
- require 'redis-activesupport'
8
- require 'active_support/cache/memory_store'
9
- require 'active_support/cache/dalli_store'
10
- require 'readthis'
11
-
12
- memory = ActiveSupport::Cache::MemoryStore.new(expires_in: 60, namespace: 'mm')
13
- dalli = ActiveSupport::Cache::DalliStore.new('localhost', namespace: 'da', pool_size: 5, expires_in: 60)
14
- redisas = ActiveSupport::Cache::RedisStore.new('redis://localhost:6379/11/ra', expires_in: 60)
15
- readthis = Readthis::Cache.new(namespace: 'rd', expires_in: 60)
16
-
17
- ('a'..'z').each do |key|
18
- value = key * 1024
19
-
20
- memory.write(key, value)
21
- dalli.write(key, value)
22
- readthis.write(key, value)
23
- redisas.write(key, value)
24
- end
25
-
26
- Benchmark.ips do |x|
27
- x.report 'memory:read-multi' do
28
- memory.read_multi(*('a'..'z'))
29
- end
30
-
31
- x.report 'readthis:read-multi' do
32
- readthis.read_multi(*('a'..'z'))
33
- end
34
-
35
- x.report 'redisas:read-multi' do
36
- redisas.read_multi(*('a'..'z'))
37
- end
38
-
39
- x.report 'dalli:read-multi' do
40
- dalli.read_multi(*('a'..'z'))
41
- end
42
-
43
- x.compare!
44
- end
45
-
46
- Benchmark.ips do |x|
47
- x.report 'memory:fetch-multi' do
48
- memory.fetch_multi(*('a'..'z')) { |_| 'missing' }
49
- end
50
-
51
- x.report 'readthis:fetch-multi' do
52
- readthis.fetch_multi(*('a'..'z')) { |_| 'missing' }
53
- end
54
-
55
- x.report 'redisas:fetch-multi' do
56
- redisas.fetch_multi(*('a'..'z')) { |_| 'missing' }
57
- end
58
-
59
- x.report 'dalli:fetch-multi' do
60
- dalli.fetch_multi(*('a'..'z')) { |_| 'missing' }
61
- end
62
-
63
- x.compare!
64
- 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('redis://localhost:6379/11')
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')
@@ -1,7 +0,0 @@
1
- module Readthis
2
- module Notifications
3
- def self.instrument(_name, payload)
4
- yield(payload)
5
- end
6
- end
7
- end
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
@@ -1,15 +0,0 @@
1
- require 'readthis/notifications'
2
-
3
- RSpec.describe Readthis::Notifications do
4
- describe '#instrument' do
5
- it 'yields the provided block' do
6
- inner = double(:inner)
7
-
8
- expect(inner).to receive(:call)
9
-
10
- Readthis::Notifications.instrument('operation', key: 'key') do
11
- inner.call
12
- end
13
- end
14
- end
15
- end