rails-brotli-cache 0.6.0 → 0.6.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 +4 -4
- data/README.md +13 -2
- data/benchmarks/Gemfile +2 -0
- data/benchmarks/main.rb +61 -2
- data/lib/rails-brotli-cache/store.rb +4 -2
- data/lib/rails-brotli-cache/version.rb +1 -1
- data/spec/rails-brotli-cache/compatibility_spec.rb +9 -6
- data/spec/rails-brotli-cache/store_spec.rb +15 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e109b9b356474fb8085b1cceaa892695de997465db4c90872556f76419da8f86
|
|
4
|
+
data.tar.gz: c8422310e9fed160052637a40dc7b1150b938c0f891b3b7b011eacdd11b8e4bb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b435443fbf3a6a09baed87b124429e43dcd4d3fbd06cab175a15818b397285aeab96ad0694dc8a2f0e0d91c3478400ba0e3081045e93ca63e275e62626f0e0d
|
|
7
|
+
data.tar.gz: 95af20d56721fbe1e9118b29a0fa1f7dc3fe5825d8c7ee04d77b783b96b405d6b1e765f4d8b63e8668d9414ca1e716cc010e3201d7a93340d35251ebd966f9e8
|
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@ You can check out [this blog post](https://pawelurbanek.com/rails-brotli-cache)
|
|
|
9
9
|
`Gemfile`
|
|
10
10
|
|
|
11
11
|
```ruby
|
|
12
|
-
gem 'brotli' #
|
|
12
|
+
gem 'brotli' # an optional dependency, other compressors are supported
|
|
13
13
|
gem 'rails-brotli-cache'
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -139,10 +139,21 @@ config.cache_store = RailsBrotliCache::Store.new(
|
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
```ruby
|
|
142
|
+
|
|
143
|
+
class ZSTDCompressor
|
|
144
|
+
def self.deflate(payload)
|
|
145
|
+
::Zstd.compress(payload, 10)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.inflate(payload)
|
|
149
|
+
::Zstd.decompress(payload)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
142
153
|
Rails.cache.write('test-key', json, compressor_class: Snappy)
|
|
143
154
|
```
|
|
144
155
|
|
|
145
|
-
This config expects a class
|
|
156
|
+
This config expects a class that defines two methods, `inflate` and `deflate`. It allows to use, for example, a [ZSTD by Facebook](https://github.com/SpringMT/zstd-ruby), offering even better performance and compression.
|
|
146
157
|
|
|
147
158
|
## Testing
|
|
148
159
|
|
data/benchmarks/Gemfile
CHANGED
data/benchmarks/main.rb
CHANGED
|
@@ -1,31 +1,62 @@
|
|
|
1
1
|
require 'active_support'
|
|
2
2
|
require 'active_support/core_ext/hash'
|
|
3
3
|
require 'net/http'
|
|
4
|
+
require 'brotli'
|
|
4
5
|
require 'rails-brotli-cache'
|
|
5
6
|
require 'benchmark'
|
|
7
|
+
require 'zstd-ruby'
|
|
8
|
+
|
|
9
|
+
class ZSTDCompressor
|
|
10
|
+
def self.deflate(payload)
|
|
11
|
+
::Zstd.compress(payload, 10)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.inflate(payload)
|
|
15
|
+
::Zstd.decompress(payload)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
6
18
|
|
|
7
19
|
memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
|
|
8
20
|
brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
|
|
21
|
+
zstd_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
|
22
|
+
|
|
9
23
|
redis_cache = ActiveSupport::Cache::RedisCacheStore.new
|
|
10
24
|
brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
|
|
25
|
+
zstd_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
|
26
|
+
|
|
11
27
|
memcached_cache = ActiveSupport::Cache::MemCacheStore.new
|
|
12
28
|
brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
|
|
29
|
+
zstd_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
|
30
|
+
|
|
13
31
|
file_cache = ActiveSupport::Cache::FileStore.new('/tmp')
|
|
14
32
|
brotli_file_cache = RailsBrotliCache::Store.new(file_cache)
|
|
33
|
+
zstd_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
|
|
15
34
|
|
|
16
35
|
json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
|
|
17
36
|
json = Net::HTTP.get(json_uri)
|
|
18
37
|
|
|
19
38
|
puts "Uncompressed JSON size: #{json.size}"
|
|
20
39
|
redis_cache.write("gz-json", json)
|
|
21
|
-
gzip_json_size = redis_cache.redis.
|
|
40
|
+
gzip_json_size = redis_cache.redis.with do |conn|
|
|
41
|
+
conn.get("gz-json").size
|
|
42
|
+
end
|
|
22
43
|
puts "Gzip JSON size: #{gzip_json_size}"
|
|
23
44
|
brotli_redis_cache.write("json", json)
|
|
24
|
-
br_json_size = redis_cache.redis.
|
|
45
|
+
br_json_size = redis_cache.redis.with do |conn|
|
|
46
|
+
conn.get("br-json").size
|
|
47
|
+
end
|
|
25
48
|
puts "Brotli JSON size: #{br_json_size}"
|
|
26
49
|
puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
|
|
27
50
|
puts ""
|
|
28
51
|
|
|
52
|
+
zstd_redis_cache.write("json", json)
|
|
53
|
+
zs_json_size = redis_cache.redis.with do |conn|
|
|
54
|
+
conn.get("zs-json").size
|
|
55
|
+
end
|
|
56
|
+
puts "ZSTD JSON size: #{zs_json_size}"
|
|
57
|
+
puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
|
|
58
|
+
puts ""
|
|
59
|
+
|
|
29
60
|
iterations = 100
|
|
30
61
|
|
|
31
62
|
Benchmark.bm do |x|
|
|
@@ -43,6 +74,13 @@ Benchmark.bm do |x|
|
|
|
43
74
|
end
|
|
44
75
|
end
|
|
45
76
|
|
|
77
|
+
x.report("zstd_memory_cache") do
|
|
78
|
+
iterations.times do
|
|
79
|
+
zstd_memory_cache.write("test", json)
|
|
80
|
+
zstd_memory_cache.read("test")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
46
84
|
x.report("redis_cache") do
|
|
47
85
|
iterations.times do
|
|
48
86
|
redis_cache.write("test", json)
|
|
@@ -57,6 +95,13 @@ Benchmark.bm do |x|
|
|
|
57
95
|
end
|
|
58
96
|
end
|
|
59
97
|
|
|
98
|
+
x.report("zstd_redis_cache") do
|
|
99
|
+
iterations.times do
|
|
100
|
+
zstd_redis_cache.write("test", json)
|
|
101
|
+
zstd_redis_cache.read("test")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
60
105
|
x.report("memcached_cache") do
|
|
61
106
|
iterations.times do
|
|
62
107
|
memcached_cache.write("test", json)
|
|
@@ -71,6 +116,13 @@ Benchmark.bm do |x|
|
|
|
71
116
|
end
|
|
72
117
|
end
|
|
73
118
|
|
|
119
|
+
x.report("zstd_memcached_cache") do
|
|
120
|
+
iterations.times do
|
|
121
|
+
zstd_memcached_cache.write("test", json)
|
|
122
|
+
zstd_memcached_cache.read("test")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
74
126
|
x.report("file_cache") do
|
|
75
127
|
iterations.times do
|
|
76
128
|
file_cache.write("test", json)
|
|
@@ -84,4 +136,11 @@ Benchmark.bm do |x|
|
|
|
84
136
|
brotli_file_cache.read("test")
|
|
85
137
|
end
|
|
86
138
|
end
|
|
139
|
+
|
|
140
|
+
x.report("zstd_file_cache") do
|
|
141
|
+
iterations.times do
|
|
142
|
+
zstd_file_cache.write("test", json)
|
|
143
|
+
zstd_file_cache.read("test")
|
|
144
|
+
end
|
|
145
|
+
end
|
|
87
146
|
end
|
|
@@ -115,8 +115,10 @@ module RailsBrotliCache
|
|
|
115
115
|
@core_store.fetch_multi(
|
|
116
116
|
*names, options.merge(compress: false)
|
|
117
117
|
) do |name|
|
|
118
|
-
compressed(yield(name), options)
|
|
119
|
-
end
|
|
118
|
+
compressed(yield(source_cache_key(name)), options)
|
|
119
|
+
end.map do |key, val|
|
|
120
|
+
[source_cache_key(key), uncompressed(val, options)]
|
|
121
|
+
end.to_h
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def exist?(name, options = {})
|
|
@@ -13,6 +13,10 @@ describe RailsBrotliCache do
|
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
CACHE_STORE_TYPES.each do |cache_store_types|
|
|
16
|
+
let(:big_enough_to_compress_value) do
|
|
17
|
+
SecureRandom.hex(2048)
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
describe "Brotli cache has the same API as #{cache_store_types[0].class}" do
|
|
17
21
|
subject(:brotli_store) do
|
|
18
22
|
RailsBrotliCache::Store.new(cache_store_types[0])
|
|
@@ -32,7 +36,7 @@ describe RailsBrotliCache do
|
|
|
32
36
|
|
|
33
37
|
it "for #read and #write" do
|
|
34
38
|
int_val = 123
|
|
35
|
-
expect(brotli_store.write("int_val_key",
|
|
39
|
+
expect(brotli_store.write("int_val_key", big_enough_to_compress_value).class).to eq(standard_cache.write("int_val_key", big_enough_to_compress_value).class)
|
|
36
40
|
expect(brotli_store.read("int_val_key")).to eq(standard_cache.read("int_val_key"))
|
|
37
41
|
|
|
38
42
|
str_val = "str"
|
|
@@ -55,16 +59,15 @@ describe RailsBrotliCache do
|
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
it "for #fetch" do
|
|
58
|
-
|
|
59
|
-
expect(brotli_store.fetch("val_key") {
|
|
60
|
-
expect(brotli_store.fetch("val_key", force: true) { val }).to eq(standard_cache.fetch("val_key", force: true) { val })
|
|
62
|
+
expect(brotli_store.fetch("val_key") { big_enough_to_compress_value }).to eq(standard_cache.fetch("val_key") { big_enough_to_compress_value })
|
|
63
|
+
expect(brotli_store.fetch("val_key", force: true) { big_enough_to_compress_value }).to eq(standard_cache.fetch("val_key", force: true) { big_enough_to_compress_value })
|
|
61
64
|
expect(brotli_store.fetch("val_key")).to eq(standard_cache.fetch("val_key"))
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
it "for #write_multi and #read_multi" do
|
|
65
68
|
values = {
|
|
66
69
|
"key_1" => "val_1",
|
|
67
|
-
"key_2" =>
|
|
70
|
+
"key_2" => big_enough_to_compress_value
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
brotli_store.write_multi(values)
|
|
@@ -78,7 +81,7 @@ describe RailsBrotliCache do
|
|
|
78
81
|
|
|
79
82
|
it "for #fetch_multi" do
|
|
80
83
|
values = {
|
|
81
|
-
"key_1" =>
|
|
84
|
+
"key_1" => big_enough_to_compress_value,
|
|
82
85
|
"key_2" => "val_2"
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -98,9 +98,22 @@ describe RailsBrotliCache do
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
describe "fetch_multi" do
|
|
101
|
+
subject do
|
|
102
|
+
cache_store.fetch_multi(*keys) do |key|
|
|
103
|
+
big_enough_to_compress_value + key
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
let(:keys) { %w[key_1 key_2] }
|
|
108
|
+
let(:response) do
|
|
109
|
+
{
|
|
110
|
+
'key_1' => big_enough_to_compress_value + 'key_1',
|
|
111
|
+
'key_2' => big_enough_to_compress_value + 'key_2'
|
|
112
|
+
}
|
|
113
|
+
end
|
|
114
|
+
|
|
101
115
|
it "works" do
|
|
102
|
-
|
|
103
|
-
expect(cache_store.read("key_1")).to eq big_enough_to_compress_value
|
|
116
|
+
expect(subject).to eq response
|
|
104
117
|
end
|
|
105
118
|
end
|
|
106
119
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-brotli-cache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pawurb
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-10-
|
|
11
|
+
date: 2023-10-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -226,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
226
226
|
- !ruby/object:Gem::Version
|
|
227
227
|
version: '0'
|
|
228
228
|
requirements: []
|
|
229
|
-
rubygems_version: 3.
|
|
229
|
+
rubygems_version: 3.3.7
|
|
230
230
|
signing_key:
|
|
231
231
|
specification_version: 4
|
|
232
232
|
summary: Drop-in enhancement for Rails cache, offering better performance and compression
|