dalli 3.1.2 → 3.1.3

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: 74310302432b6cdf905f2e581145a10a3dc1c08f97b47e3a8e1b91a113920d4d
4
- data.tar.gz: b62f80ba194b9feba95ac7db0fac632381bdf5b2d0ecd24ec3b7a748c79e9d26
3
+ metadata.gz: '0905b56adf194401de7755ab22ebef6b57f6e673e8332f7cb99b3ef9ed1dde63'
4
+ data.tar.gz: dac2014c748ef0c55fe171af0cec8dec807ae2468f758338c8968135acd47b92
5
5
  SHA512:
6
- metadata.gz: ccf0a1722111940e132879abc0e4bb1899f6e337b8ef0ded051bd50eac76bbd9f79a50b22584b8893ed97ff99df0687edb5734ab958b56ed437adbed15176389
7
- data.tar.gz: ba43861323882292b98e8dc12ea96cd42ca76ee146df523726e23dc1bca27fbc8e659d1a67bfbfcf529597626562d1731e7c5ee2dd56497e905cc594f6ed9569
6
+ metadata.gz: 85d8382dfd13c2353a61c74525e17bd81e000308e8d476851ed25fdb6ef81e9aff4276eb0b1484e30c83001301a3500140cb46a595081e1b21f0801ea32d7e28
7
+ data.tar.gz: 7f0adfc09e31d435bbb3f6cff2f65392a58f81697e7025ca71d9423f9a536d9c984ed7ba0742d0c0f5de0e865a7ebd2dc5548a0406c86d7f1fe0c8135c7af363
data/History.md CHANGED
@@ -4,6 +4,11 @@ Dalli Changelog
4
4
  Unreleased
5
5
  ==========
6
6
 
7
+ 3.1.3
8
+ ==========
9
+
10
+ - Restore falsey behavior on delete/delete_cas for nonexistent key (petergoldstein)
11
+
7
12
  3.1.2
8
13
  ==========
9
14
 
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'socket'
5
+ require 'timeout'
6
+
7
+ module Dalli
8
+ module Protocol
9
+ ##
10
+ # Base class for a single Memcached server, containing logic common to all
11
+ # protocols. Contains logic for managing connection state to the server and value
12
+ # handling.
13
+ ##
14
+ class Base
15
+ extend Forwardable
16
+
17
+ attr_accessor :weight, :options
18
+
19
+ def_delegators :@value_marshaller, :serializer, :compressor, :compression_min_size, :compress_by_default?
20
+ def_delegators :@connection_manager, :name, :sock, :hostname, :port, :close, :connected?, :socket_timeout,
21
+ :socket_type, :up!, :down!, :write, :reconnect_down_server?, :raise_down_error
22
+
23
+ def initialize(attribs, client_options = {})
24
+ hostname, port, socket_type, @weight, user_creds = ServerConfigParser.parse(attribs)
25
+ @options = client_options.merge(user_creds)
26
+ @value_marshaller = ValueMarshaller.new(@options)
27
+ @connection_manager = ConnectionManager.new(hostname, port, socket_type, @options)
28
+ end
29
+
30
+ # Chokepoint method for error handling and ensuring liveness
31
+ def request(opkey, *args)
32
+ verify_state(opkey)
33
+
34
+ begin
35
+ send(opkey, *args)
36
+ rescue Dalli::MarshalError => e
37
+ log_marshal_err(args.first, e)
38
+ raise
39
+ rescue Dalli::DalliError
40
+ raise
41
+ rescue StandardError => e
42
+ log_unexpected_err(e)
43
+ down!
44
+ end
45
+ end
46
+
47
+ ##
48
+ # Boolean method used by clients of this class to determine if this
49
+ # particular memcached instance is available for use.
50
+ def alive?
51
+ ensure_connected!
52
+ rescue Dalli::NetworkError
53
+ # ensure_connected! raises a NetworkError if connection fails. We
54
+ # want to capture that error and convert it to a boolean value here.
55
+ false
56
+ end
57
+
58
+ def lock!; end
59
+
60
+ def unlock!; end
61
+
62
+ # Start reading key/value pairs from this connection. This is usually called
63
+ # after a series of GETKQ commands. A NOOP is sent, and the server begins
64
+ # flushing responses for kv pairs that were found.
65
+ #
66
+ # Returns nothing.
67
+ def pipeline_response_setup
68
+ verify_state(:getkq)
69
+ write_noop
70
+ response_buffer.reset
71
+ @connection_manager.start_request!
72
+ end
73
+
74
+ # Attempt to receive and parse as many key/value pairs as possible
75
+ # from this server. After #pipeline_response_setup, this should be invoked
76
+ # repeatedly whenever this server's socket is readable until
77
+ # #pipeline_complete?.
78
+ #
79
+ # Returns a Hash of kv pairs received.
80
+ def pipeline_next_responses
81
+ reconnect_on_pipeline_complete!
82
+ values = {}
83
+
84
+ response_buffer.read
85
+
86
+ resp_header, key, value = pipeline_response
87
+ # resp_header is not nil only if we have a full response to parse
88
+ # in the buffer
89
+ while resp_header
90
+ # If the status is ok and key is nil, then this is the response
91
+ # to the noop at the end of the pipeline
92
+ finish_pipeline && break if resp_header.ok? && key.nil?
93
+
94
+ # If the status is ok and the key is not nil, then this is a
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?
97
+
98
+ # Get the next response from the buffer
99
+ resp_header, key, value = pipeline_response
100
+ end
101
+
102
+ values
103
+ rescue SystemCallError, Timeout::Error, EOFError => e
104
+ @connection_manager.error_on_request!(e)
105
+ end
106
+
107
+ # Abort current pipelined get. Generally used to signal an external
108
+ # timeout during pipelined get. The underlying socket is
109
+ # disconnected, and the exception is swallowed.
110
+ #
111
+ # Returns nothing.
112
+ def pipeline_abort
113
+ response_buffer.clear
114
+ @connection_manager.abort_request!
115
+ return true unless connected?
116
+
117
+ # Closes the connection, which ensures that our connection
118
+ # is in a clean state for future requests
119
+ @connection_manager.error_on_request!('External timeout')
120
+ rescue NetworkError
121
+ true
122
+ end
123
+
124
+ # Did the last call to #pipeline_response_setup complete successfully?
125
+ def pipeline_complete?
126
+ !response_buffer.in_progress?
127
+ end
128
+
129
+ def username
130
+ @options[:username] || ENV['MEMCACHE_USERNAME']
131
+ end
132
+
133
+ def password
134
+ @options[:password] || ENV['MEMCACHE_PASSWORD']
135
+ end
136
+
137
+ def require_auth?
138
+ !username.nil?
139
+ end
140
+
141
+ def quiet?
142
+ Thread.current[::Dalli::QUIET]
143
+ end
144
+ alias multi? quiet?
145
+
146
+ # NOTE: Additional public methods should be overridden in Dalli::Threadsafe
147
+
148
+ private
149
+
150
+ ##
151
+ # Checks to see if we can execute the specified operation. Checks
152
+ # whether the connection is in use, and whether the command is allowed
153
+ ##
154
+ def verify_state(opkey)
155
+ @connection_manager.confirm_ready!
156
+ verify_allowed_quiet!(opkey) if quiet?
157
+
158
+ # The ensure_connected call has the side effect of connecting the
159
+ # underlying socket if it is not connected, or there's been a disconnect
160
+ # because of timeout or other error. Method raises an error
161
+ # if it can't connect
162
+ raise_down_error unless ensure_connected!
163
+ end
164
+
165
+ # The socket connection to the underlying server is initialized as a side
166
+ # effect of this call. In fact, this is the ONLY place where that
167
+ # socket connection is initialized.
168
+ #
169
+ # Both this method and connect need to be in this class so we can do auth
170
+ # as required
171
+ #
172
+ # Since this is invoked exclusively in verify_state!, we don't need to worry about
173
+ # thread safety. Using it elsewhere may require revisiting that assumption.
174
+ def ensure_connected!
175
+ return true if connected?
176
+ return false unless reconnect_down_server?
177
+
178
+ connect # This call needs to be in this class so we can do auth
179
+ connected?
180
+ end
181
+
182
+ def cache_nils?(opts)
183
+ return false unless opts.is_a?(Hash)
184
+
185
+ opts[:cache_nils] ? true : false
186
+ end
187
+
188
+ def connect
189
+ @connection_manager.establish_connection
190
+ authenticate_connection if require_auth?
191
+ @version = version # Connect socket if not authed
192
+ up!
193
+ rescue Dalli::DalliError
194
+ raise
195
+ end
196
+
197
+ def pipelined_get(keys)
198
+ req = +''
199
+ keys.each do |key|
200
+ req << quiet_get_request(key)
201
+ end
202
+ # Could send noop here instead of in pipeline_response_setup
203
+ write(req)
204
+ end
205
+
206
+ def response_buffer
207
+ @response_buffer ||= ResponseBuffer.new(@connection_manager, response_processor)
208
+ end
209
+
210
+ def pipeline_response
211
+ response_buffer.process_single_getk_response
212
+ end
213
+
214
+ # Called after the noop response is received at the end of a set
215
+ # of pipelined gets
216
+ def finish_pipeline
217
+ response_buffer.clear
218
+ @connection_manager.finish_request!
219
+
220
+ true # to simplify response
221
+ end
222
+
223
+ def reconnect_on_pipeline_complete!
224
+ @connection_manager.reconnect! 'pipelined get has completed' if pipeline_complete?
225
+ end
226
+
227
+ def log_marshal_err(key, err)
228
+ Dalli.logger.error "Marshalling error for key '#{key}': #{err.message}"
229
+ Dalli.logger.error 'You are trying to cache a Ruby object which cannot be serialized to memcached.'
230
+ end
231
+
232
+ def log_unexpected_err(err)
233
+ Dalli.logger.error "Unexpected exception during Dalli request: #{err.class.name}: #{err.message}"
234
+ Dalli.logger.error err.backtrace.join("\n\t")
235
+ end
236
+ end
237
+ end
238
+ end
@@ -89,6 +89,14 @@ module Dalli
89
89
  resp_header.cas
90
90
  end
91
91
 
92
+ def delete_response
93
+ resp_header, = read_response
94
+ return false if resp_header.not_found? || resp_header.not_stored?
95
+
96
+ raise_on_not_ok!(resp_header)
97
+ true
98
+ end
99
+
92
100
  def no_body_response
93
101
  resp_header, = read_response
94
102
  return false if resp_header.not_stored? # Not stored, possible status for append/prepend
@@ -10,7 +10,7 @@ module Dalli
10
10
  def perform_auth_negotiation
11
11
  write(RequestFormatter.standard_request(opkey: :auth_negotiation))
12
12
 
13
- status, content = @response_processor.auth_response
13
+ status, content = response_processor.auth_response
14
14
  return [status, []] if content.nil?
15
15
 
16
16
  # Substitute spaces for the \x00 returned by
@@ -4,11 +4,6 @@ require 'forwardable'
4
4
  require 'socket'
5
5
  require 'timeout'
6
6
 
7
- require_relative 'binary/request_formatter'
8
- require_relative 'binary/response_header'
9
- require_relative 'binary/response_processor'
10
- require_relative 'binary/sasl_authentication'
11
-
12
7
  module Dalli
13
8
  module Protocol
14
9
  ##
@@ -16,175 +11,13 @@ module Dalli
16
11
  # protocol. Contains logic for managing connection state to the server (retries, etc),
17
12
  # formatting requests to the server, and unpacking responses.
18
13
  ##
19
- class Binary
20
- extend Forwardable
21
-
22
- attr_accessor :weight, :options
23
-
24
- def_delegators :@value_marshaller, :serializer, :compressor, :compression_min_size, :compress_by_default?
25
- def_delegators :@connection_manager, :name, :sock, :hostname, :port, :close, :connected?, :socket_timeout,
26
- :socket_type, :up!, :down!, :write, :reconnect_down_server?, :raise_down_error
27
-
28
- def initialize(attribs, client_options = {})
29
- hostname, port, socket_type, @weight, user_creds = ServerConfigParser.parse(attribs)
30
- @options = client_options.merge(user_creds)
31
- @value_marshaller = ValueMarshaller.new(@options)
32
- @connection_manager = ConnectionManager.new(hostname, port, socket_type, @options)
33
- @response_processor = ResponseProcessor.new(@connection_manager, @value_marshaller)
34
- end
35
-
36
- # Chokepoint method for error handling and ensuring liveness
37
- def request(opkey, *args)
38
- verify_state(opkey)
39
-
40
- begin
41
- send(opkey, *args)
42
- rescue Dalli::MarshalError => e
43
- log_marshal_err(args.first, e)
44
- raise
45
- rescue Dalli::DalliError
46
- raise
47
- rescue StandardError => e
48
- log_unexpected_err(e)
49
- down!
50
- end
51
- end
52
-
53
- ##
54
- # Boolean method used by clients of this class to determine if this
55
- # particular memcached instance is available for use.
56
- def alive?
57
- ensure_connected!
58
- rescue Dalli::NetworkError
59
- # ensure_connected! raises a NetworkError if connection fails. We
60
- # want to capture that error and convert it to a boolean value here.
61
- false
62
- end
63
-
64
- def lock!; end
65
-
66
- def unlock!; end
67
-
68
- # Start reading key/value pairs from this connection. This is usually called
69
- # after a series of GETKQ commands. A NOOP is sent, and the server begins
70
- # flushing responses for kv pairs that were found.
71
- #
72
- # Returns nothing.
73
- def pipeline_response_setup
74
- verify_state(:getkq)
75
- write_noop
76
- response_buffer.reset
77
- @connection_manager.start_request!
78
- end
79
-
80
- # Attempt to receive and parse as many key/value pairs as possible
81
- # from this server. After #pipeline_response_setup, this should be invoked
82
- # repeatedly whenever this server's socket is readable until
83
- # #pipeline_complete?.
84
- #
85
- # Returns a Hash of kv pairs received.
86
- def pipeline_next_responses
87
- reconnect_on_pipeline_complete!
88
- values = {}
89
-
90
- response_buffer.read
91
-
92
- resp_header, key, value = pipeline_response
93
- # resp_header is not nil only if we have a full response to parse
94
- # in the buffer
95
- while resp_header
96
- # If the status is ok and key is nil, then this is the response
97
- # to the noop at the end of the pipeline
98
- finish_pipeline && break if resp_header.ok? && key.nil?
99
-
100
- # If the status is ok and the key is not nil, then this is a
101
- # getkq response with a value that we want to set in the response hash
102
- values[key] = [value, resp_header.cas] unless key.nil?
103
-
104
- # Get the next response from the buffer
105
- resp_header, key, value = pipeline_response
106
- end
107
-
108
- values
109
- rescue SystemCallError, Timeout::Error, EOFError => e
110
- @connection_manager.error_on_request!(e)
111
- end
112
-
113
- # Abort current pipelined get. Generally used to signal an external
114
- # timeout during pipelined get. The underlying socket is
115
- # disconnected, and the exception is swallowed.
116
- #
117
- # Returns nothing.
118
- def pipeline_abort
119
- response_buffer.clear
120
- @connection_manager.abort_request!
121
- return true unless connected?
122
-
123
- # Closes the connection, which ensures that our connection
124
- # is in a clean state for future requests
125
- @connection_manager.error_on_request!('External timeout')
126
- rescue NetworkError
127
- true
128
- end
129
-
130
- # Did the last call to #pipeline_response_setup complete successfully?
131
- def pipeline_complete?
132
- !response_buffer.in_progress?
133
- end
134
-
135
- def username
136
- @options[:username] || ENV['MEMCACHE_USERNAME']
137
- end
138
-
139
- def password
140
- @options[:password] || ENV['MEMCACHE_PASSWORD']
141
- end
142
-
143
- def require_auth?
144
- !username.nil?
14
+ class Binary < Base
15
+ def response_processor
16
+ @response_processor ||= ResponseProcessor.new(@connection_manager, @value_marshaller)
145
17
  end
146
18
 
147
- def quiet?
148
- Thread.current[::Dalli::QUIET]
149
- end
150
- alias multi? quiet?
151
-
152
- # NOTE: Additional public methods should be overridden in Dalli::Threadsafe
153
-
154
19
  private
155
20
 
156
- ##
157
- # Checks to see if we can execute the specified operation. Checks
158
- # whether the connection is in use, and whether the command is allowed
159
- ##
160
- def verify_state(opkey)
161
- @connection_manager.confirm_ready!
162
- verify_allowed_quiet!(opkey) if quiet?
163
-
164
- # The ensure_connected call has the side effect of connecting the
165
- # underlying socket if it is not connected, or there's been a disconnect
166
- # because of timeout or other error. Method raises an error
167
- # if it can't connect
168
- raise_down_error unless ensure_connected!
169
- end
170
-
171
- # The socket connection to the underlying server is initialized as a side
172
- # effect of this call. In fact, this is the ONLY place where that
173
- # socket connection is initialized.
174
- #
175
- # Both this method and connect need to be in this class so we can do auth
176
- # as required
177
- #
178
- # Since this is invoked exclusively in verify_state!, we don't need to worry about
179
- # thread safety. Using it elsewhere may require revisiting that assumption.
180
- def ensure_connected!
181
- return true if connected?
182
- return false unless reconnect_down_server?
183
-
184
- connect # This call needs to be in this class so we can do auth
185
- connected?
186
- end
187
-
188
21
  ALLOWED_QUIET_OPS = %i[add replace set delete incr decr append prepend flush noop].freeze
189
22
  def verify_allowed_quiet!(opkey)
190
23
  return if ALLOWED_QUIET_OPS.include?(opkey)
@@ -192,30 +25,28 @@ module Dalli
192
25
  raise Dalli::NotPermittedMultiOpError, "The operation #{opkey} is not allowed in a quiet block."
193
26
  end
194
27
 
195
- def cache_nils?(opts)
196
- return false unless opts.is_a?(Hash)
197
-
198
- opts[:cache_nils] ? true : false
199
- end
200
-
201
28
  # Retrieval Commands
202
29
  def get(key, options = nil)
203
30
  req = RequestFormatter.standard_request(opkey: :get, key: key)
204
31
  write(req)
205
- @response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
32
+ response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
33
+ end
34
+
35
+ def quiet_get_request(key)
36
+ RequestFormatter.standard_request(opkey: :getkq, key: key)
206
37
  end
207
38
 
208
39
  def gat(key, ttl, options = nil)
209
40
  ttl = TtlSanitizer.sanitize(ttl)
210
41
  req = RequestFormatter.standard_request(opkey: :gat, key: key, ttl: ttl)
211
42
  write(req)
212
- @response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
43
+ response_processor.generic_response(unpack: true, cache_nils: cache_nils?(options))
213
44
  end
214
45
 
215
46
  def touch(key, ttl)
216
47
  ttl = TtlSanitizer.sanitize(ttl)
217
48
  write(RequestFormatter.standard_request(opkey: :touch, key: key, ttl: ttl))
218
- @response_processor.generic_response
49
+ response_processor.generic_response
219
50
  end
220
51
 
221
52
  # TODO: This is confusing, as there's a cas command in memcached
@@ -223,7 +54,7 @@ module Dalli
223
54
  def cas(key)
224
55
  req = RequestFormatter.standard_request(opkey: :get, key: key)
225
56
  write(req)
226
- @response_processor.data_cas_response
57
+ response_processor.data_cas_response
227
58
  end
228
59
 
229
60
  # Storage Commands
@@ -251,7 +82,7 @@ module Dalli
251
82
  value: value, bitflags: bitflags,
252
83
  ttl: ttl, cas: cas)
253
84
  write(req)
254
- @response_processor.storage_response unless quiet?
85
+ response_processor.storage_response unless quiet?
255
86
  end
256
87
  # rubocop:enable Metrics/ParameterLists
257
88
 
@@ -267,7 +98,7 @@ module Dalli
267
98
 
268
99
  def write_append_prepend(opkey, key, value)
269
100
  write(RequestFormatter.standard_request(opkey: opkey, key: key, value: value))
270
- @response_processor.no_body_response unless quiet?
101
+ response_processor.no_body_response unless quiet?
271
102
  end
272
103
 
273
104
  # Delete Commands
@@ -275,7 +106,7 @@ module Dalli
275
106
  opkey = quiet? ? :deleteq : :delete
276
107
  req = RequestFormatter.standard_request(opkey: opkey, key: key, cas: cas)
277
108
  write(req)
278
- @response_processor.no_body_response unless quiet?
109
+ response_processor.delete_response unless quiet?
279
110
  end
280
111
 
281
112
  # Arithmetic Commands
@@ -301,37 +132,37 @@ module Dalli
301
132
  initial ||= 0
302
133
  write(RequestFormatter.decr_incr_request(opkey: opkey, key: key,
303
134
  count: count, initial: initial, expiry: expiry))
304
- @response_processor.decr_incr_response unless quiet?
135
+ response_processor.decr_incr_response unless quiet?
305
136
  end
306
137
 
307
138
  # Other Commands
308
139
  def flush(ttl = 0)
309
140
  opkey = quiet? ? :flushq : :flush
310
141
  write(RequestFormatter.standard_request(opkey: opkey, ttl: ttl))
311
- @response_processor.no_body_response unless quiet?
142
+ response_processor.no_body_response unless quiet?
312
143
  end
313
144
 
314
145
  # Noop is a keepalive operation but also used to demarcate the end of a set of pipelined commands.
315
146
  # We need to read all the responses at once.
316
147
  def noop
317
148
  write_noop
318
- @response_processor.multi_with_keys_response
149
+ response_processor.multi_with_keys_response
319
150
  end
320
151
 
321
152
  def stats(info = '')
322
153
  req = RequestFormatter.standard_request(opkey: :stat, key: info)
323
154
  write(req)
324
- @response_processor.multi_with_keys_response
155
+ response_processor.multi_with_keys_response
325
156
  end
326
157
 
327
158
  def reset_stats
328
159
  write(RequestFormatter.standard_request(opkey: :stat, key: 'reset'))
329
- @response_processor.generic_response
160
+ response_processor.generic_response
330
161
  end
331
162
 
332
163
  def version
333
164
  write(RequestFormatter.standard_request(opkey: :version))
334
- @response_processor.generic_response
165
+ response_processor.generic_response
335
166
  end
336
167
 
337
168
  def write_noop
@@ -339,55 +170,10 @@ module Dalli
339
170
  write(req)
340
171
  end
341
172
 
342
- def connect
343
- @connection_manager.establish_connection
344
- authenticate_connection if require_auth?
345
- @version = version # Connect socket if not authed
346
- up!
347
- rescue Dalli::DalliError
348
- raise
349
- end
350
-
351
- def pipelined_get(keys)
352
- req = +''
353
- keys.each do |key|
354
- req << RequestFormatter.standard_request(opkey: :getkq, key: key)
355
- end
356
- # Could send noop here instead of in pipeline_response_setup
357
- write(req)
358
- end
359
-
360
- def response_buffer
361
- @response_buffer ||= ResponseBuffer.new(@connection_manager, @response_processor)
362
- end
363
-
364
- def pipeline_response
365
- response_buffer.process_single_getk_response
366
- end
367
-
368
- # Called after the noop response is received at the end of a set
369
- # of pipelined gets
370
- def finish_pipeline
371
- response_buffer.clear
372
- @connection_manager.finish_request!
373
-
374
- true # to simplify response
375
- end
376
-
377
- def reconnect_on_pipeline_complete!
378
- @connection_manager.reconnect! 'pipelined get has completed' if pipeline_complete?
379
- end
380
-
381
- def log_marshal_err(key, err)
382
- Dalli.logger.error "Marshalling error for key '#{key}': #{err.message}"
383
- Dalli.logger.error 'You are trying to cache a Ruby object which cannot be serialized to memcached.'
384
- end
385
-
386
- def log_unexpected_err(err)
387
- Dalli.logger.error "Unexpected exception during Dalli request: #{err.class.name}: #{err.message}"
388
- Dalli.logger.error err.backtrace.join("\n\t")
389
- end
390
-
173
+ require_relative 'binary/request_formatter'
174
+ require_relative 'binary/response_header'
175
+ require_relative 'binary/response_processor'
176
+ require_relative 'binary/sasl_authentication'
391
177
  include SaslAuthentication
392
178
  end
393
179
  end
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.2'
4
+ VERSION = '3.1.3'
5
5
 
6
6
  MIN_SUPPORTED_MEMCACHED_VERSION = '1.4'
7
7
  end
data/lib/dalli.rb CHANGED
@@ -62,6 +62,7 @@ require_relative 'dalli/key_manager'
62
62
  require_relative 'dalli/pipelined_getter'
63
63
  require_relative 'dalli/ring'
64
64
  require_relative 'dalli/protocol'
65
+ require_relative 'dalli/protocol/base'
65
66
  require_relative 'dalli/protocol/binary'
66
67
  require_relative 'dalli/protocol/connection_manager'
67
68
  require_relative 'dalli/protocol/response_buffer'
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.2
4
+ version: 3.1.3
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-13 00:00:00.000000000 Z
12
+ date: 2021-12-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: connection_pool
@@ -121,6 +121,7 @@ files:
121
121
  - lib/dalli/options.rb
122
122
  - lib/dalli/pipelined_getter.rb
123
123
  - lib/dalli/protocol.rb
124
+ - lib/dalli/protocol/base.rb
124
125
  - lib/dalli/protocol/binary.rb
125
126
  - lib/dalli/protocol/binary/request_formatter.rb
126
127
  - lib/dalli/protocol/binary/response_header.rb