dalli 5.0.12 → 5.0.14

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
  SHA256:
3
- metadata.gz: 237c6d61c07c784fab08e871f5ec95e05a56f280a738bd2a060176ea49885198
4
- data.tar.gz: 846bb56b3ce9e7a7c1b9c2bfd91faa907c5b8974e686a0767d4437343dadd2b3
3
+ metadata.gz: 1b52725fdd6dd9e4e890f506cca29a520e12e5458b29d9e315b6bb8805d749c7
4
+ data.tar.gz: 504b5d320f3802d5aeb98608ffbc1ff629a89c76ba48957440b3403b40a5a69e
5
5
  SHA512:
6
- metadata.gz: 8ef4bca995d5ed6d1d0d47b460a21f9ac99db727d3a60fe60f168760b11e7b1c2e139903b5d2b3b8d8ce0869ff252b5b77acdf422db8d07456301e83e87e9e94
7
- data.tar.gz: 5b272117c00c7ce7e077ad5137a708a9ce06a842408b75f8efd1248c72a29b3fc739cfe7347dd475229158c3cd0869989c89b57f51d91bc8794c277a4324a0a9
6
+ metadata.gz: 1d258b16c57f90309b60867fac9e1aa03fd9ae6a67607d04f2cfd76c205e5f096e8322c532ecf4404d74895dd8a6deca766fac2ca3bb5fff17b646e321e6962f
7
+ data.tar.gz: 430cc33100948d985f373247848122dc79c6ab6cfc1fa295c7fe8fbcc1463cf91e26a17a93d91145ef9c06d57e887aad592d2a437ccc79868886f7b4a40a0cd5
data/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ Dalli Changelog
4
4
  Unreleased
5
5
  ==========
6
6
 
7
+ 5.0.14
8
+ ==========
9
+
10
+ Bug fixes:
11
+
12
+ - Raw values in an encoding that isn't ASCII-compatible, such as UTF-16, raised `Encoding::CompatibilityError` from `set`, `add`, `replace`, `append`, `prepend` and `set_multi`, as did a single-server `set_multi` mixing non-ASCII UTF-8 values with binary ones (such as raw Strings of both kinds, or with a JSON serializer, a value containing `é` next to a compressed one). The error also closed the connection, so in a `quiet` block, or within one server's part of a multi-server `set_multi`, writes buffered before it were silently lost. Values are now sent as their bytes, which is what memcached stores (#1269)
13
+
14
+ 5.0.13
15
+ ==========
16
+
17
+ Bug fixes:
18
+
19
+ - `set_multi` across more than one server stored `nil` for a Symbol key or a key over 250 bytes, in place of the value given
20
+
7
21
  5.0.12
8
22
  ==========
9
23
 
@@ -41,9 +41,12 @@ module Dalli
41
41
 
42
42
  private
43
43
 
44
+ # Values are looked up by each key as sent. The caller's key can't be
45
+ # rebuilt from it: a long key is digested, and a Symbol becomes a String.
44
46
  def setup_requests(hash, ttl, req_options)
45
- groups = groups_for_keys(hash.keys)
46
- make_set_requests(groups, hash, ttl, req_options)
47
+ pairs = hash.transform_keys { |k| @key_manager.validate_key(k.to_s) }
48
+ groups = groups_for_keys(pairs.keys)
49
+ make_set_requests(groups, pairs, ttl, req_options)
47
50
  groups.keys
48
51
  end
49
52
 
@@ -51,12 +54,10 @@ module Dalli
51
54
  # Loop through the server-grouped sets of keys, writing
52
55
  # the corresponding quiet set requests to the appropriate servers
53
56
  ##
54
- def make_set_requests(groups, hash, ttl, req_options)
57
+ def make_set_requests(groups, pairs, ttl, req_options)
55
58
  groups.each do |server, keys_for_server|
56
59
  keys_for_server.each do |key|
57
- original_key = @key_manager.key_without_namespace(key)
58
- value = hash[original_key]
59
- server.request(:pipelined_set, key, value, ttl, req_options)
60
+ server.request(:pipelined_set, key, pairs[key], ttl, req_options)
60
61
  rescue Dalli::MarshalError, Dalli::ValueOverMaxSize => e
61
62
  # Nothing was written for this key, so the server's other keys are
62
63
  # unaffected; raised by #process once the batch is complete
@@ -81,8 +82,7 @@ module Dalli
81
82
  end
82
83
 
83
84
  def groups_for_keys(keys)
84
- validated_keys = keys.map { |k| @key_manager.validate_key(k.to_s) }
85
- groups = @ring.keys_grouped_by_server(validated_keys)
85
+ groups = @ring.keys_grouped_by_server(keys)
86
86
 
87
87
  if (unfound_keys = groups.delete(nil))
88
88
  Dalli.logger.debug do
@@ -138,7 +138,7 @@ module Dalli
138
138
  req = RequestFormatter.meta_set(key: key, value: value,
139
139
  bitflags: bitflags, cas: cas,
140
140
  ttl: ttl, mode: mode, quiet: quiet)
141
- write("#{req}#{value}#{TERMINATOR}")
141
+ write(request_with_value(req, value))
142
142
  @connection_manager.flush unless quiet
143
143
  end
144
144
  # rubocop:enable Metrics/ParameterLists
@@ -158,10 +158,20 @@ module Dalli
158
158
  ttl = TtlSanitizer.sanitize(ttl) if ttl
159
159
  req = RequestFormatter.meta_set(key: key, value: value,
160
160
  cas: cas, ttl: ttl, mode: mode, quiet: quiet?)
161
- write("#{req}#{value}#{TERMINATOR}")
161
+ write(request_with_value(req, value))
162
162
  @connection_manager.flush unless quiet?
163
163
  end
164
164
 
165
+ # Ruby refuses to join Strings whose encodings clash, such as a raw
166
+ # UTF-16 value next to the ASCII request line. memcached stores bytes,
167
+ # so join the bytes then. Joining the Strings first keeps the common
168
+ # case free of extra checks.
169
+ def request_with_value(req, value)
170
+ "#{req}#{value}#{TERMINATOR}"
171
+ rescue Encoding::CompatibilityError
172
+ "#{req.b}#{value.b}#{TERMINATOR}"
173
+ end
174
+
165
175
  # Delete Commands
166
176
  def delete(key, cas)
167
177
  req = RequestFormatter.meta_delete(key: key, cas: cas, quiet: quiet?)
@@ -95,11 +95,29 @@ module Dalli
95
95
  buffer << ' b' if base64
96
96
  buffer << " F#{bitflags}" if bitflags
97
97
  buffer << " T#{ttl}" if ttl
98
- buffer << ' MS q' << TERMINATOR << value << TERMINATOR
98
+ buffer << ' MS q' << TERMINATOR
99
+ append_bytes(buffer, value)
100
+ buffer << TERMINATOR
99
101
  end
100
102
  buffer << META_NOOP
101
103
  end
102
104
 
105
+ # Values are appended as bytes. One batch can hold UTF-8 and binary
106
+ # values, which String#<< refuses to combine, and a raw value can be in
107
+ # an encoding that isn't ASCII-compatible, such as UTF-16.
108
+ # Don't chain on the result: TruffleRuby's append_as_bytes returns its
109
+ # arguments rather than the buffer.
110
+ if String.method_defined?(:append_as_bytes)
111
+ def append_bytes(buffer, value)
112
+ buffer.append_as_bytes(value)
113
+ end
114
+ else
115
+ def append_bytes(buffer, value)
116
+ buffer << (value.encoding == Encoding::BINARY ? value : value.b)
117
+ end
118
+ end
119
+ private :append_bytes
120
+
103
121
  # Thundering herd protection flag:
104
122
  # - stale (I flag): Instead of deleting the item, mark it as stale. Other clients
105
123
  # using N/R flags will see the X flag and know the item is being regenerated.
data/lib/dalli/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dalli
4
- VERSION = '5.0.12'
4
+ VERSION = '5.0.14'
5
5
 
6
6
  MIN_SUPPORTED_MEMCACHED_VERSION = '1.6'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dalli
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.12
4
+ version: 5.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein