dalli 3.1.3 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dalli might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0905b56adf194401de7755ab22ebef6b57f6e673e8332f7cb99b3ef9ed1dde63'
4
- data.tar.gz: dac2014c748ef0c55fe171af0cec8dec807ae2468f758338c8968135acd47b92
3
+ metadata.gz: e687040436582dd13519490544b2b493c424dca476a2a9173a68dc216c61d7ba
4
+ data.tar.gz: 293d5d74a31562116c17a24b02192504483d066f03418fe44d99694092595f0e
5
5
  SHA512:
6
- metadata.gz: 85d8382dfd13c2353a61c74525e17bd81e000308e8d476851ed25fdb6ef81e9aff4276eb0b1484e30c83001301a3500140cb46a595081e1b21f0801ea32d7e28
7
- data.tar.gz: 7f0adfc09e31d435bbb3f6cff2f65392a58f81697e7025ca71d9423f9a536d9c984ed7ba0742d0c0f5de0e865a7ebd2dc5548a0406c86d7f1fe0c8135c7af363
6
+ metadata.gz: d47dc643fb3722b2718a6fd612525574ec1355889515b70499f56fb102f731a0be11ec010dec5e670bab1740f40e40b099347a5bf341c5754a97cf1a09206396
7
+ data.tar.gz: 6e993408f8ad08c275399d8f93542da58673207435fb171f9dcb39871f11d799bec412b721bb6c0bb3364d9d58fc1e1020533ed565e213db9b65cd2744505980
data/History.md CHANGED
@@ -4,6 +4,13 @@ Dalli Changelog
4
4
  Unreleased
5
5
  ==========
6
6
 
7
+ 3.1.4
8
+ ==========
9
+
10
+ - Improve response parsing performance (casperisfine)
11
+ - Reorganize binary protocol parsing a bit (petergoldstein)
12
+ - Fix handling of non-ASCII keys in get_multi (petergoldstein)
13
+
7
14
  3.1.3
8
15
  ==========
9
16
 
@@ -83,20 +83,20 @@ module Dalli
83
83
 
84
84
  response_buffer.read
85
85
 
86
- resp_header, key, value = pipeline_response
87
- # resp_header is not nil only if we have a full response to parse
86
+ status, cas, key, value = response_buffer.process_single_getk_response
87
+ # status is not nil only if we have a full response to parse
88
88
  # in the buffer
89
- while resp_header
89
+ until status.nil?
90
90
  # If the status is ok and key is nil, then this is the response
91
91
  # to the noop at the end of the pipeline
92
- finish_pipeline && break if resp_header.ok? && key.nil?
92
+ finish_pipeline && break if status && key.nil?
93
93
 
94
94
  # If the status is ok and the key is not nil, then this is a
95
95
  # getkq response with a value that we want to set in the response hash
96
- values[key] = [value, resp_header.cas] unless key.nil?
96
+ values[key] = [value, cas] unless key.nil?
97
97
 
98
98
  # Get the next response from the buffer
99
- resp_header, key, value = pipeline_response
99
+ status, cas, key, value = response_buffer.process_single_getk_response
100
100
  end
101
101
 
102
102
  values
@@ -207,10 +207,6 @@ module Dalli
207
207
  @response_buffer ||= ResponseBuffer.new(@connection_manager, response_processor)
208
208
  end
209
209
 
210
- def pipeline_response
211
- response_buffer.process_single_getk_response
212
- end
213
-
214
210
  # Called after the noop response is received at the end of a set
215
211
  # of pipelined gets
216
212
  def finish_pipeline
@@ -46,11 +46,13 @@ module Dalli
46
46
  [resp_header, body]
47
47
  end
48
48
 
49
- def unpack_response_body(extra_len, key_len, body, unpack)
50
- bitflags = extra_len.positive? ? body.byteslice(0, extra_len).unpack1('N') : 0x0
51
- key = body.byteslice(extra_len, key_len) if key_len.positive?
52
- value = body.byteslice(extra_len + key_len, body.bytesize - (extra_len + key_len))
53
- value = unpack ? @value_marshaller.retrieve(value, bitflags) : value
49
+ def unpack_response_body(resp_header, body, parse_as_stored_value)
50
+ extra_len = resp_header.extra_len
51
+ key_len = resp_header.key_len
52
+ bitflags = extra_len.positive? ? body.unpack1('N') : 0x0
53
+ key = body.byteslice(extra_len, key_len).force_encoding('UTF-8') if key_len.positive?
54
+ value = body.byteslice((extra_len + key_len)..-1)
55
+ value = parse_as_stored_value ? @value_marshaller.retrieve(value, bitflags) : value
54
56
  [key, value]
55
57
  end
56
58
 
@@ -64,7 +66,7 @@ module Dalli
64
66
  raise Dalli::DalliError, "Response error #{resp_header.status}: #{RESPONSE_CODES[resp_header.status]}"
65
67
  end
66
68
 
67
- def generic_response(unpack: false, cache_nils: false)
69
+ def get(cache_nils: false)
68
70
  resp_header, body = read_response
69
71
 
70
72
  return false if resp_header.not_stored? # Not stored, normal status for add operation
@@ -73,7 +75,7 @@ module Dalli
73
75
  raise_on_not_ok!(resp_header)
74
76
  return true unless body
75
77
 
76
- unpack_response_body(resp_header.extra_len, resp_header.key_len, body, unpack).last
78
+ unpack_response_body(resp_header, body, true).last
77
79
  end
78
80
 
79
81
  ##
@@ -89,7 +91,7 @@ module Dalli
89
91
  resp_header.cas
90
92
  end
91
93
 
92
- def delete_response
94
+ def delete
93
95
  resp_header, = read_response
94
96
  return false if resp_header.not_found? || resp_header.not_stored?
95
97
 
@@ -97,15 +99,7 @@ module Dalli
97
99
  true
98
100
  end
99
101
 
100
- def no_body_response
101
- resp_header, = read_response
102
- return false if resp_header.not_stored? # Not stored, possible status for append/prepend
103
-
104
- raise_on_not_ok!(resp_header)
105
- true
106
- end
107
-
108
- def data_cas_response(unpack: true)
102
+ def data_cas_response
109
103
  resp_header, body = read_response
110
104
  return [nil, resp_header.cas] if resp_header.not_found?
111
105
  return [nil, false] if resp_header.not_stored?
@@ -113,14 +107,16 @@ module Dalli
113
107
  raise_on_not_ok!(resp_header)
114
108
  return [nil, resp_header.cas] unless body
115
109
 
116
- [unpack_response_body(resp_header.extra_len, resp_header.key_len, body, unpack).last, resp_header.cas]
110
+ [unpack_response_body(resp_header, body, true).last, resp_header.cas]
117
111
  end
118
112
 
119
- def cas_response
120
- data_cas_response.last
113
+ # Returns the new value for the key, if found and updated
114
+ def decr_incr
115
+ body = generic_response
116
+ body ? body.unpack1('Q>') : body
121
117
  end
122
118
 
123
- def multi_with_keys_response
119
+ def stats
124
120
  hash = {}
125
121
  loop do
126
122
  resp_header, body = read_response
@@ -133,14 +129,49 @@ module Dalli
133
129
  # block to clear any error responses from inside the multi.
134
130
  next unless resp_header.ok?
135
131
 
136
- key, value = unpack_response_body(resp_header.extra_len, resp_header.key_len, body, true)
132
+ key, value = unpack_response_body(resp_header, body, true)
137
133
  hash[key] = value
138
134
  end
139
135
  end
140
136
 
141
- def decr_incr_response
142
- body = generic_response
143
- body ? body.unpack1('Q>') : body
137
+ def flush
138
+ no_body_response
139
+ end
140
+
141
+ def reset
142
+ generic_response
143
+ end
144
+
145
+ def version
146
+ generic_response
147
+ end
148
+
149
+ def consume_all_responses_until_noop
150
+ loop do
151
+ resp_header, = read_response
152
+ # This is the response to the terminating noop / end of stat
153
+ return true if resp_header.ok? && resp_header.key_len.zero?
154
+ end
155
+ end
156
+
157
+ def generic_response
158
+ resp_header, body = read_response
159
+
160
+ return false if resp_header.not_stored? # Not stored, normal status for add operation
161
+ return nil if resp_header.not_found?
162
+
163
+ raise_on_not_ok!(resp_header)
164
+ return true unless body
165
+
166
+ unpack_response_body(resp_header, body, false).last
167
+ end
168
+
169
+ def no_body_response
170
+ resp_header, = read_response
171
+ return false if resp_header.not_stored? # Not stored, possible status for append/prepend/delete
172
+
173
+ raise_on_not_ok!(resp_header)
174
+ true
144
175
  end
145
176
 
146
177
  def validate_auth_format(extra_len, count)
@@ -164,8 +195,7 @@ module Dalli
164
195
  end
165
196
 
166
197
  def response_header_from_buffer(buf)
167
- header = buf.slice(0, ResponseHeader::SIZE)
168
- ResponseHeader.new(header)
198
+ ResponseHeader.new(buf)
169
199
  end
170
200
 
171
201
  ##
@@ -180,7 +210,7 @@ module Dalli
180
210
  ##
181
211
  def getk_response_from_buffer(buf)
182
212
  # There's no header in the buffer, so don't advance
183
- return [0, nil, nil, nil] unless contains_header?(buf)
213
+ return [0, nil, nil, nil, nil] unless contains_header?(buf)
184
214
 
185
215
  resp_header = response_header_from_buffer(buf)
186
216
  body_len = resp_header.body_len
@@ -189,18 +219,18 @@ module Dalli
189
219
  # This is either the response to the terminating
190
220
  # noop or, if the status is not zero, an intermediate
191
221
  # error response that needs to be discarded.
192
- return [ResponseHeader::SIZE, resp_header, nil, nil] if body_len.zero?
222
+ return [ResponseHeader::SIZE, resp_header.ok?, resp_header.cas, nil, nil] if body_len.zero?
193
223
 
194
224
  resp_size = ResponseHeader::SIZE + body_len
195
225
  # The header is in the buffer, but the body is not. As we don't have
196
226
  # a complete response, don't advance the buffer
197
- return [0, nil, nil, nil] unless buf.bytesize >= resp_size
227
+ return [0, nil, nil, nil, nil] unless buf.bytesize >= resp_size
198
228
 
199
229
  # The full response is in our buffer, so parse it and return
200
230
  # the values
201
- body = buf.slice(ResponseHeader::SIZE, body_len)
202
- key, value = unpack_response_body(resp_header.extra_len, resp_header.key_len, body, true)
203
- [resp_size, resp_header, key, value]
231
+ body = buf.byteslice(ResponseHeader::SIZE, body_len)
232
+ key, value = unpack_response_body(resp_header, body, true)
233
+ [resp_size, resp_header.ok?, resp_header.cas, key, value]
204
234
  end
205
235
  end
206
236
  end
@@ -29,7 +29,7 @@ module Dalli
29
29
  def get(key, options = nil)
30
30
  req = RequestFormatter.standard_request(opkey: :get, key: key)
31
31
  write(req)
32
- response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
32
+ response_processor.get(cache_nils: cache_nils?(options))
33
33
  end
34
34
 
35
35
  def quiet_get_request(key)
@@ -40,7 +40,7 @@ module Dalli
40
40
  ttl = TtlSanitizer.sanitize(ttl)
41
41
  req = RequestFormatter.standard_request(opkey: :gat, key: key, ttl: ttl)
42
42
  write(req)
43
- response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
43
+ response_processor.get(cache_nils: cache_nils?(options))
44
44
  end
45
45
 
46
46
  def touch(key, ttl)
@@ -106,7 +106,7 @@ module Dalli
106
106
  opkey = quiet? ? :deleteq : :delete
107
107
  req = RequestFormatter.standard_request(opkey: opkey, key: key, cas: cas)
108
108
  write(req)
109
- response_processor.delete_response unless quiet?
109
+ response_processor.delete unless quiet?
110
110
  end
111
111
 
112
112
  # Arithmetic Commands
@@ -132,7 +132,7 @@ module Dalli
132
132
  initial ||= 0
133
133
  write(RequestFormatter.decr_incr_request(opkey: opkey, key: key,
134
134
  count: count, initial: initial, expiry: expiry))
135
- response_processor.decr_incr_response unless quiet?
135
+ response_processor.decr_incr unless quiet?
136
136
  end
137
137
 
138
138
  # Other Commands
@@ -146,23 +146,23 @@ module Dalli
146
146
  # We need to read all the responses at once.
147
147
  def noop
148
148
  write_noop
149
- response_processor.multi_with_keys_response
149
+ response_processor.consume_all_responses_until_noop
150
150
  end
151
151
 
152
152
  def stats(info = '')
153
153
  req = RequestFormatter.standard_request(opkey: :stat, key: info)
154
154
  write(req)
155
- response_processor.multi_with_keys_response
155
+ response_processor.stats
156
156
  end
157
157
 
158
158
  def reset_stats
159
159
  write(RequestFormatter.standard_request(opkey: :stat, key: 'reset'))
160
- response_processor.generic_response
160
+ response_processor.reset
161
161
  end
162
162
 
163
163
  def version
164
164
  write(RequestFormatter.standard_request(opkey: :version))
165
- response_processor.generic_response
165
+ response_processor.version
166
166
  end
167
167
 
168
168
  def write_noop
@@ -21,9 +21,9 @@ module Dalli
21
21
  # Attempts to process a single response from the buffer. Starts
22
22
  # by advancing the buffer to the specified start position
23
23
  def process_single_getk_response
24
- bytes, resp_header, key, value = @response_processor.getk_response_from_buffer(@buffer)
24
+ bytes, status, cas, key, value = @response_processor.getk_response_from_buffer(@buffer)
25
25
  advance(bytes)
26
- [resp_header, key, value]
26
+ [status, cas, key, value]
27
27
  end
28
28
 
29
29
  # Advances the internal response buffer by bytes_to_advance
@@ -31,13 +31,13 @@ module Dalli
31
31
  def advance(bytes_to_advance)
32
32
  return unless bytes_to_advance.positive?
33
33
 
34
- @buffer = @buffer[bytes_to_advance..-1]
34
+ @buffer = @buffer.byteslice(bytes_to_advance..-1)
35
35
  end
36
36
 
37
37
  # Resets the internal buffer to an empty state,
38
38
  # so that we're ready to read pipelined responses
39
39
  def reset
40
- @buffer = +''
40
+ @buffer = ''.b
41
41
  end
42
42
 
43
43
  # Clear the internal response buffer
data/lib/dalli/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dalli
4
- VERSION = '3.1.3'
4
+ VERSION = '3.1.4'
5
5
 
6
6
  MIN_SUPPORTED_MEMCACHED_VERSION = '1.4'
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: 3.1.3
4
+ version: 3.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-12-14 00:00:00.000000000 Z
12
+ date: 2021-12-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: connection_pool