paquito 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -6
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +7 -9
- data/README.md +22 -0
- data/Rakefile +1 -2
- data/benchmark/flat-entry-coder.rb +50 -0
- data/dev.yml +2 -2
- data/lib/paquito/active_record_coder.rb +1 -0
- data/lib/paquito/cache_entry_coder.rb +4 -11
- data/lib/paquito/codec_factory.rb +1 -1
- data/lib/paquito/compressor.rb +17 -0
- data/lib/paquito/flat_cache_entry_coder.rb +48 -0
- data/lib/paquito/version.rb +1 -1
- data/lib/paquito.rb +4 -1
- data/paquito.gemspec +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2882e208a7d6cc2c9b98f748578ea1c8e91133a5ecc71fdc4e41861bb7788f7e
|
4
|
+
data.tar.gz: 8376bc939c974028dd6957e1d98467594c33807cdf13fc0470b216aa2476f9ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bb6ab11609d478cae8993c65fb12db8ea22363064401c718f6e6915ccdd75ad9ddd5c3f7a5a88a8c0562e943c2fda44c4dab101a3db4266f26134ae2ac0e26f
|
7
|
+
data.tar.gz: 268549cd0b872b554397b7d685e0ba9f8db9572690091ebaa4936e7a488a26569e9691ad0bfdf2447d1521a36aa5c26b8a7acf96a04271d449c0a6036de7d777
|
data/.github/workflows/ci.yml
CHANGED
@@ -13,7 +13,7 @@ jobs:
|
|
13
13
|
- name: Set up Ruby
|
14
14
|
uses: ruby/setup-ruby@v1
|
15
15
|
with:
|
16
|
-
ruby-version: '2.
|
16
|
+
ruby-version: '2.7'
|
17
17
|
bundler-cache: true
|
18
18
|
- name: Run test
|
19
19
|
run: bundle exec rubocop
|
@@ -23,18 +23,17 @@ jobs:
|
|
23
23
|
strategy:
|
24
24
|
fail-fast: false
|
25
25
|
matrix:
|
26
|
-
ruby: [ ruby-head, '3.1', '3.0', '2.7'
|
26
|
+
ruby: [ ruby-head, '3.1', '3.0', '2.7' ]
|
27
27
|
steps:
|
28
28
|
- name: Checkout
|
29
29
|
uses: actions/checkout@v3
|
30
|
+
- name: Remove Gemfile.lock
|
31
|
+
run: rm Gemfile.lock
|
30
32
|
- name: Set up Ruby
|
31
33
|
uses: ruby/setup-ruby@v1
|
32
34
|
with:
|
33
35
|
ruby-version: ${{ matrix.ruby }}
|
34
|
-
|
35
|
-
run: |
|
36
|
-
rm Gemfile.lock
|
37
|
-
bundle install
|
36
|
+
bundler-cache: true
|
38
37
|
- name: Run test
|
39
38
|
run: bundle exec rake
|
40
39
|
- name: Install gem
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
paquito (0.
|
4
|
+
paquito (0.9.0)
|
5
5
|
msgpack (>= 1.5.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (
|
11
|
-
activesupport (=
|
12
|
-
activerecord (
|
13
|
-
activemodel (=
|
14
|
-
activesupport (=
|
15
|
-
activesupport (
|
10
|
+
activemodel (7.0.4)
|
11
|
+
activesupport (= 7.0.4)
|
12
|
+
activerecord (7.0.4)
|
13
|
+
activemodel (= 7.0.4)
|
14
|
+
activesupport (= 7.0.4)
|
15
|
+
activesupport (7.0.4)
|
16
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
17
|
i18n (>= 1.6, < 2)
|
18
18
|
minitest (>= 5.1)
|
19
19
|
tzinfo (~> 2.0)
|
20
|
-
zeitwerk (~> 2.3)
|
21
20
|
ast (2.4.2)
|
22
21
|
benchmark-ips (2.10.0)
|
23
22
|
byebug (11.1.3)
|
@@ -52,7 +51,6 @@ GEM
|
|
52
51
|
tzinfo (2.0.5)
|
53
52
|
concurrent-ruby (~> 1.0)
|
54
53
|
unicode-display_width (2.2.0)
|
55
|
-
zeitwerk (2.6.0)
|
56
54
|
|
57
55
|
PLATFORMS
|
58
56
|
ruby
|
data/README.md
CHANGED
@@ -161,6 +161,28 @@ Example:
|
|
161
161
|
ActiveSupport::Cache::FileStore.new("tmp/cache", coder: Paquito.chain(Paquito::CacheEntryCoder, JSON))
|
162
162
|
```
|
163
163
|
|
164
|
+
### `FlatCacheEntryCoder`
|
165
|
+
|
166
|
+
`Paquito::FlatCacheEntryCoder` is a variation of `Paquito::CacheEntryCoder`. Instead of encoding `ActiveSupport::Cache::Entry`
|
167
|
+
into an Array of three members, it serializes the entry metadata itself and adds it as a prefix to the serialized payload.
|
168
|
+
|
169
|
+
This allows to leverage `Paquito::SingleBytePrefixVersionWithStringBypass` effectively.
|
170
|
+
|
171
|
+
Example:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
ActiveSupport::Cache::FileStore.new(
|
175
|
+
"tmp/cache",
|
176
|
+
coder: Paquito::FlatCacheEntryCoder.new(
|
177
|
+
Paquito::SingleBytePrefixVersionWithStringBypass.new(
|
178
|
+
1,
|
179
|
+
0 => Marshal,
|
180
|
+
1 => JSON,
|
181
|
+
)
|
182
|
+
)
|
183
|
+
)
|
184
|
+
```
|
185
|
+
|
164
186
|
### `SerializedColumn`
|
165
187
|
|
166
188
|
`Paquito::SerializedColumn` allows you to decorate any encoder to behave like Rails's builtin `YAMLColumn`
|
data/Rakefile
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/testtask"
|
5
5
|
|
6
|
-
suites = [:vanilla, :activesupport]
|
7
|
-
suites << :activerecord if RUBY_VERSION >= "2.7"
|
6
|
+
suites = [:vanilla, :activesupport, :activerecord]
|
8
7
|
namespace :test do
|
9
8
|
suites.each do |suite|
|
10
9
|
Rake::TestTask.new(suite) do |t|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "paquito"
|
6
|
+
require "active_support"
|
7
|
+
require "benchmark/ips"
|
8
|
+
|
9
|
+
CODEC = Paquito::CodecFactory.build
|
10
|
+
ORIGINAL = Paquito::SingleBytePrefixVersion.new(
|
11
|
+
0,
|
12
|
+
0 => Paquito.chain(
|
13
|
+
Paquito::CacheEntryCoder,
|
14
|
+
CODEC,
|
15
|
+
),
|
16
|
+
)
|
17
|
+
FLAT = Paquito::FlatCacheEntryCoder.new(
|
18
|
+
Paquito::SingleBytePrefixVersionWithStringBypass.new(
|
19
|
+
0,
|
20
|
+
0 => CODEC,
|
21
|
+
)
|
22
|
+
)
|
23
|
+
|
24
|
+
entries = {
|
25
|
+
small_string: "Hello World!",
|
26
|
+
bytes_1mb: Random.bytes(1_000_000),
|
27
|
+
int_array: 1000.times.to_a,
|
28
|
+
}
|
29
|
+
|
30
|
+
entries.each do |name, object|
|
31
|
+
entry = ActiveSupport::Cache::Entry.new(object, expires_at: 15.minutes.from_now.to_f)
|
32
|
+
original_payload = ORIGINAL.dump(entry).freeze
|
33
|
+
flat_payload = FLAT.dump(entry).freeze
|
34
|
+
|
35
|
+
puts " === Read #{name} ==="
|
36
|
+
Benchmark.ips do |x|
|
37
|
+
x.report("original") { ORIGINAL.load(original_payload) }
|
38
|
+
x.report("flat") { FLAT.load(flat_payload) }
|
39
|
+
x.compare!(order: :baseline)
|
40
|
+
end
|
41
|
+
|
42
|
+
puts " === Write #{name} ==="
|
43
|
+
Benchmark.ips do |x|
|
44
|
+
x.report("original") { ORIGINAL.dump(entry) }
|
45
|
+
x.report("flat") { FLAT.dump(entry) }
|
46
|
+
x.compare!(order: :baseline)
|
47
|
+
end
|
48
|
+
|
49
|
+
puts
|
50
|
+
end
|
data/dev.yml
CHANGED
@@ -1,22 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
gem "activesupport", ">= 7.0"
|
4
|
+
|
3
5
|
module Paquito
|
4
6
|
module CacheEntryCoder
|
5
7
|
def self.dump(entry)
|
6
|
-
|
7
|
-
# drop any trailing nil values to save a couple bytes
|
8
|
-
attrs.pop until !attrs.last.nil? || attrs.empty?
|
9
|
-
attrs
|
8
|
+
entry.pack
|
10
9
|
end
|
11
10
|
|
12
11
|
def self.load(payload)
|
13
|
-
|
14
|
-
value, expires_in, version = payload
|
15
|
-
entry.instance_variable_set(:@value, value)
|
16
|
-
entry.instance_variable_set(:@expires_in, expires_in)
|
17
|
-
entry.instance_variable_set(:@created_at, 0.0)
|
18
|
-
entry.instance_variable_set(:@version, version)
|
19
|
-
entry
|
12
|
+
::ActiveSupport::Cache::Entry.unpack(payload)
|
20
13
|
end
|
21
14
|
end
|
22
15
|
end
|
@@ -5,7 +5,7 @@ require "paquito/coder_chain"
|
|
5
5
|
|
6
6
|
module Paquito
|
7
7
|
class CodecFactory
|
8
|
-
def self.build(types, freeze: false, serializable_type: false, pool: 1)
|
8
|
+
def self.build(types = [], freeze: false, serializable_type: false, pool: 1)
|
9
9
|
factory = if types.empty? && !serializable_type
|
10
10
|
MessagePack::DefaultFactory
|
11
11
|
else
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Paquito
|
4
|
+
class Compressor
|
5
|
+
def initialize(compressor)
|
6
|
+
@compressor = compressor
|
7
|
+
end
|
8
|
+
|
9
|
+
def dump(serial)
|
10
|
+
@compressor.compress(serial)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(payload)
|
14
|
+
@compressor.decompress(payload)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
gem "activesupport", ">= 7.0"
|
4
|
+
|
5
|
+
module Paquito
|
6
|
+
class FlatCacheEntryCoder
|
7
|
+
METADATA_CODEC = CodecFactory.build
|
8
|
+
|
9
|
+
EXPIRES_AT_FORMAT = "E" # Float double-precision, little-endian byte order (8 bytes)
|
10
|
+
VERSION_SIZE_FORMAT = "l<" # 32-bit signed, little-endian byte order (int32_t) (4 bytes)
|
11
|
+
PREFIX_FORMAT = -(EXPIRES_AT_FORMAT + VERSION_SIZE_FORMAT)
|
12
|
+
VERSION_SIZE_OFFSET = [0.0].pack(EXPIRES_AT_FORMAT).bytesize # should be 8
|
13
|
+
VERSION_OFFSET = [0.0, 0].pack(PREFIX_FORMAT).bytesize # Should be 12
|
14
|
+
VERSION_SIZE_UNPACK = -"@#{VERSION_SIZE_OFFSET}#{VERSION_SIZE_FORMAT}"
|
15
|
+
|
16
|
+
def initialize(value_coder)
|
17
|
+
@value_coder = value_coder
|
18
|
+
end
|
19
|
+
|
20
|
+
def dump(entry)
|
21
|
+
version = entry.version
|
22
|
+
payload = [
|
23
|
+
entry.expires_at || 0.0,
|
24
|
+
version ? version.bytesize : -1,
|
25
|
+
].pack(PREFIX_FORMAT)
|
26
|
+
payload << version if version
|
27
|
+
payload << @value_coder.dump(entry.value)
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(payload)
|
31
|
+
expires_at = payload.unpack1(EXPIRES_AT_FORMAT)
|
32
|
+
expires_at = nil if expires_at == 0.0
|
33
|
+
|
34
|
+
version_size = payload.unpack1(VERSION_SIZE_UNPACK)
|
35
|
+
if version_size < 0
|
36
|
+
version_size = 0
|
37
|
+
else
|
38
|
+
version = payload.byteslice(VERSION_OFFSET, version_size)
|
39
|
+
end
|
40
|
+
|
41
|
+
::ActiveSupport::Cache::Entry.new(
|
42
|
+
@value_coder.load(payload.byteslice((VERSION_OFFSET + version_size)..-1).freeze),
|
43
|
+
expires_at: expires_at,
|
44
|
+
version: version,
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/paquito/version.rb
CHANGED
data/lib/paquito.rb
CHANGED
@@ -14,7 +14,6 @@ require "paquito/allow_nil"
|
|
14
14
|
require "paquito/translate_errors"
|
15
15
|
require "paquito/safe_yaml"
|
16
16
|
require "paquito/conditional_compressor"
|
17
|
-
require "paquito/cache_entry_coder"
|
18
17
|
require "paquito/single_byte_prefix_version"
|
19
18
|
require "paquito/single_byte_prefix_version_with_string_bypass"
|
20
19
|
require "paquito/comment_prefix_version"
|
@@ -25,6 +24,8 @@ require "paquito/typed_struct"
|
|
25
24
|
require "paquito/serialized_column"
|
26
25
|
|
27
26
|
module Paquito
|
27
|
+
autoload :CacheEntryCoder, "paquito/cache_entry_coder"
|
28
|
+
autoload :FlatCacheEntryCoder, "paquito/flat_cache_entry_coder"
|
28
29
|
autoload :ActiveRecordCoder, "paquito/active_record_coder"
|
29
30
|
|
30
31
|
class << self
|
@@ -33,6 +34,8 @@ module Paquito
|
|
33
34
|
coder
|
34
35
|
elsif coder.respond_to?(:deflate) && coder.respond_to?(:inflate)
|
35
36
|
Deflater.new(coder)
|
37
|
+
elsif coder.respond_to?(:compress) && coder.respond_to?(:decompress)
|
38
|
+
Compressor.new(coder)
|
36
39
|
else
|
37
40
|
raise TypeError, "Coders must respond to #dump and #load, #{coder.inspect} doesn't"
|
38
41
|
end
|
data/paquito.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = "Framework for defining efficient and extendable serializers"
|
13
13
|
spec.homepage = "https://github.com/Shopify/paquito"
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">= 2.
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
16
16
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
18
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paquito
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- LICENSE.txt
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
|
+
- benchmark/flat-entry-coder.rb
|
43
44
|
- benchmark/msgpack-pooling.rb
|
44
45
|
- benchmark/string-bypass.rb
|
45
46
|
- bin/console
|
@@ -52,9 +53,11 @@ files:
|
|
52
53
|
- lib/paquito/codec_factory.rb
|
53
54
|
- lib/paquito/coder_chain.rb
|
54
55
|
- lib/paquito/comment_prefix_version.rb
|
56
|
+
- lib/paquito/compressor.rb
|
55
57
|
- lib/paquito/conditional_compressor.rb
|
56
58
|
- lib/paquito/deflater.rb
|
57
59
|
- lib/paquito/errors.rb
|
60
|
+
- lib/paquito/flat_cache_entry_coder.rb
|
58
61
|
- lib/paquito/safe_yaml.rb
|
59
62
|
- lib/paquito/serialized_column.rb
|
60
63
|
- lib/paquito/single_byte_prefix_version.rb
|
@@ -81,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
84
|
requirements:
|
82
85
|
- - ">="
|
83
86
|
- !ruby/object:Gem::Version
|
84
|
-
version: 2.
|
87
|
+
version: 2.7.0
|
85
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
89
|
requirements:
|
87
90
|
- - ">="
|