dalli 3.2.3 → 3.2.7

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: f0ef39f4ff4e9e465b2522707f3c4eea85a94373ba0d3de4b9d940830001b118
4
- data.tar.gz: 35cb362ec6075818f062106769481e92c90752936ecaf9a00fae25725ee4ea94
3
+ metadata.gz: a98f25c5f6f750d72b83fdd0b6e45a9d693520a91b9b7d985bd26fd0abfac41e
4
+ data.tar.gz: 9e95098e69ece841757034d69cc2091e0b450feed17290bf5fffd527e6d45ac7
5
5
  SHA512:
6
- metadata.gz: 0c6b2b205551fb10fb2e49ab7c3c3eba3c552c0bc4b8132783b51f6cdc7a9ddd4c272bd24ed13f9d78e29353e3b84daec001b2691ad630bdfd517bb7af86fd54
7
- data.tar.gz: 6ef9f6733d8e6d5f8a6bf8fb7d782e99c450494e03d4e5fe46037b77665682df63eaa9a3eb05007d1720b175564c8e91524c0df92d0856dc1f68066501732a06
6
+ metadata.gz: 25368bee67a5fd00aa7795cc06839c366fb7c1c33386ca0304c1cdfee3a4c82729716128d8f452cb7e0c0e2c24e2c3aec384eb7e3e0ee68c3915d93e17917456
7
+ data.tar.gz: f0094059b3e7430b3b03a0a6d8795ba0e76bdf1622ba2531b3ceffa11ebb3fb2442a4512a5c98e27e00fba253a7241fb58f47e3f93c58944676c8cd5d0dfe123
data/CHANGELOG.md CHANGED
@@ -4,6 +4,32 @@ Dalli Changelog
4
4
  Unreleased
5
5
  ==========
6
6
 
7
+ 3.2.7
8
+ ==========
9
+
10
+ - Fix cascading error when there's an underlying network error in a pipelined get (eugeneius)
11
+ - Ruby 3.4/head compatibility by adding base64 to gemspec (tagliala)
12
+ - Add Ruby 3.3 to CI (m-nakamura145)
13
+ - Use Socket's connect_timeout when available, and pass timeout to the socket's send and receive timeouts (mlarraz)
14
+
15
+ 3.2.6
16
+ ==========
17
+
18
+ - Rescue IO::TimeoutError raised by Ruby since 3.2.0 on blocking reads/writes (skaes)
19
+ - Fix rubydoc link (JuanitoFatas)
20
+
21
+ 3.2.5
22
+ ==========
23
+
24
+ - Better handle memcached requests being interrupted by Thread#raise or Thread#kill (byroot)
25
+ - Unexpected errors are no longer treated as `Dalli::NetworkError`, including errors raised by `Timeout.timeout` (byroot)
26
+
27
+ 3.2.4
28
+ ==========
29
+
30
+ - Cache PID calls for performance since glibc no longer caches in recent versions (byroot)
31
+ - Preallocate the read buffer in Socket#readfull (byroot)
32
+
7
33
  3.2.3
8
34
  ==========
9
35
 
@@ -45,7 +71,7 @@ Unreleased
45
71
  3.1.4
46
72
  ==========
47
73
 
48
- - Improve response parsing performance (casperisfine)
74
+ - Improve response parsing performance (byroot)
49
75
  - Reorganize binary protocol parsing a bit (petergoldstein)
50
76
  - Fix handling of non-ASCII keys in get_multi (petergoldstein)
51
77
 
data/Gemfile CHANGED
@@ -4,6 +4,18 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
+ group :development, :test do
8
+ gem 'connection_pool'
9
+ gem 'minitest', '~> 5'
10
+ gem 'rack', '~> 2.0', '>= 2.2.0'
11
+ gem 'rake', '~> 13.0'
12
+ gem 'rubocop'
13
+ gem 'rubocop-minitest'
14
+ gem 'rubocop-performance'
15
+ gem 'rubocop-rake'
16
+ gem 'simplecov'
17
+ end
18
+
7
19
  group :test do
8
20
  gem 'ruby-prof', platform: :mri
9
21
  end
data/README.md CHANGED
@@ -23,7 +23,13 @@ The name is a variant of Salvador Dali for his famous painting [The Persistence
23
23
  * [Announcements](https://github.com/petergoldstein/dalli/discussions/categories/announcements) - Announcements of interest to the Dalli community will be posted here.
24
24
  * [Bug Reports](https://github.com/petergoldstein/dalli/issues) - If you discover a problem with Dalli, please submit a bug report in the tracker.
25
25
  * [Forum](https://github.com/petergoldstein/dalli/discussions/categories/q-a) - If you have questions about Dalli, please post them here.
26
- * [Client API](https://rubydoc.info/github/petergoldstein/dalli/Dalli/Client) - Ruby documentation for the `Dalli::Client` API
26
+ * [Client API](https://www.rubydoc.info/gems/dalli) - Ruby documentation for the `Dalli::Client` API
27
+
28
+ ## Development
29
+
30
+ After checking out the repo, run `bin/setup` to install dependencies. You can run `bin/console` for an interactive prompt that will allow you to experiment.
31
+
32
+ To install this gem onto your local machine, run `bundle exec rake install`.
27
33
 
28
34
  ## Contributing
29
35
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dalli
4
+ ##
5
+ # Dalli::PIDCache is a wrapper class for PID checking to avoid system calls when checking the PID.
6
+ ##
7
+ module PIDCache
8
+ if !Process.respond_to?(:fork) # JRuby or TruffleRuby
9
+ @pid = Process.pid
10
+ singleton_class.attr_reader(:pid)
11
+ elsif Process.respond_to?(:_fork) # Ruby 3.1+
12
+ class << self
13
+ attr_reader :pid
14
+
15
+ def update!
16
+ @pid = Process.pid
17
+ end
18
+ end
19
+ update!
20
+
21
+ ##
22
+ # Dalli::PIDCache::CoreExt hooks into Process to be able to reset the PID cache after fork
23
+ ##
24
+ module CoreExt
25
+ def _fork
26
+ child_pid = super
27
+ PIDCache.update! if child_pid.zero?
28
+ child_pid
29
+ end
30
+ end
31
+ Process.singleton_class.prepend(CoreExt)
32
+ else # Ruby 3.0 or older
33
+ class << self
34
+ def pid
35
+ Process.pid
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -60,7 +60,7 @@ module Dalli
60
60
  deleted = []
61
61
 
62
62
  servers.each do |server|
63
- next unless server.alive?
63
+ next unless server.connected?
64
64
 
65
65
  begin
66
66
  finish_query_for_server(server)
@@ -32,7 +32,13 @@ module Dalli
32
32
  verify_state(opkey)
33
33
 
34
34
  begin
35
- send(opkey, *args)
35
+ @connection_manager.start_request!
36
+ response = send(opkey, *args)
37
+
38
+ # pipelined_get emit query but doesn't read the response(s)
39
+ @connection_manager.finish_request! unless opkey == :pipelined_get
40
+
41
+ response
36
42
  rescue Dalli::MarshalError => e
37
43
  log_marshal_err(args.first, e)
38
44
  raise
@@ -40,7 +46,8 @@ module Dalli
40
46
  raise
41
47
  rescue StandardError => e
42
48
  log_unexpected_err(e)
43
- down!
49
+ close
50
+ raise
44
51
  end
45
52
  end
46
53
 
@@ -65,10 +72,9 @@ module Dalli
65
72
  #
66
73
  # Returns nothing.
67
74
  def pipeline_response_setup
68
- verify_state(:getkq)
75
+ verify_pipelined_state(:getkq)
69
76
  write_noop
70
77
  response_buffer.reset
71
- @connection_manager.start_request!
72
78
  end
73
79
 
74
80
  # Attempt to receive and parse as many key/value pairs as possible
@@ -100,7 +106,7 @@ module Dalli
100
106
  end
101
107
 
102
108
  values
103
- rescue SystemCallError, Timeout::Error, EOFError => e
109
+ rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
104
110
  @connection_manager.error_on_request!(e)
105
111
  end
106
112
 
@@ -169,6 +175,11 @@ module Dalli
169
175
  raise_down_error unless ensure_connected!
170
176
  end
171
177
 
178
+ def verify_pipelined_state(_opkey)
179
+ @connection_manager.confirm_in_progress!
180
+ raise_down_error unless connected?
181
+ end
182
+
172
183
  # The socket connection to the underlying server is initialized as a side
173
184
  # effect of this call. In fact, this is the ONLY place where that
174
185
  # socket connection is initialized.
@@ -197,8 +208,6 @@ module Dalli
197
208
  authenticate_connection if require_auth?
198
209
  @version = version # Connect socket if not authed
199
210
  up!
200
- rescue Dalli::DalliError
201
- raise
202
211
  end
203
212
 
204
213
  def pipelined_get(keys)
@@ -86,7 +86,7 @@ module Dalli
86
86
  touch: TTL_AND_KEY,
87
87
  gat: TTL_AND_KEY
88
88
  }.freeze
89
- FORMAT = BODY_FORMATS.transform_values { |v| REQ_HEADER_FORMAT + v; }
89
+ FORMAT = BODY_FORMATS.transform_values { |v| REQ_HEADER_FORMAT + v }
90
90
 
91
91
  # rubocop:disable Metrics/ParameterLists
92
92
  def self.standard_request(opkey:, key: nil, value: nil, opaque: 0, cas: 0, bitflags: nil, ttl: nil)
@@ -109,7 +109,7 @@ module Dalli
109
109
  end
110
110
 
111
111
  def self.as_8byte_uint(val)
112
- [val >> 32, 0xFFFFFFFF & val]
112
+ [val >> 32, val & 0xFFFFFFFF]
113
113
  end
114
114
  end
115
115
  end
@@ -50,9 +50,9 @@ module Dalli
50
50
  extra_len = resp_header.extra_len
51
51
  key_len = resp_header.key_len
52
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?
53
+ key = body.byteslice(extra_len, key_len).force_encoding(Encoding::UTF_8) if key_len.positive?
54
54
  value = body.byteslice((extra_len + key_len)..-1)
55
- value = parse_as_stored_value ? @value_marshaller.retrieve(value, bitflags) : value
55
+ value = @value_marshaller.retrieve(value, bitflags) if parse_as_stored_value
56
56
  [key, value]
57
57
  end
58
58
 
@@ -4,6 +4,8 @@ require 'English'
4
4
  require 'socket'
5
5
  require 'timeout'
6
6
 
7
+ require 'dalli/pid_cache'
8
+
7
9
  module Dalli
8
10
  module Protocol
9
11
  ##
@@ -51,7 +53,8 @@ module Dalli
51
53
  Dalli.logger.debug { "Dalli::Server#connect #{name}" }
52
54
 
53
55
  @sock = memcached_socket
54
- @pid = Process.pid
56
+ @pid = PIDCache.pid
57
+ @request_in_progress = false
55
58
  rescue SystemCallError, Timeout::Error, EOFError, SocketError => e
56
59
  # SocketError = DNS resolution failure
57
60
  error_on_request!(e)
@@ -96,7 +99,13 @@ module Dalli
96
99
  end
97
100
 
98
101
  def confirm_ready!
99
- error_on_request!(RuntimeError.new('Already writing to socket')) if request_in_progress?
102
+ close if request_in_progress?
103
+ close_on_fork if fork_detected?
104
+ end
105
+
106
+ def confirm_in_progress!
107
+ raise '[Dalli] No request in progress. This may be a bug in Dalli.' unless request_in_progress?
108
+
100
109
  close_on_fork if fork_detected?
101
110
  end
102
111
 
@@ -122,10 +131,14 @@ module Dalli
122
131
  end
123
132
 
124
133
  def start_request!
134
+ raise '[Dalli] Request already in progress. This may be a bug in Dalli.' if @request_in_progress
135
+
125
136
  @request_in_progress = true
126
137
  end
127
138
 
128
139
  def finish_request!
140
+ raise '[Dalli] No request in progress. This may be a bug in Dalli.' unless @request_in_progress
141
+
129
142
  @request_in_progress = false
130
143
  end
131
144
 
@@ -134,36 +147,26 @@ module Dalli
134
147
  end
135
148
 
136
149
  def read_line
137
- start_request!
138
150
  data = @sock.gets("\r\n")
139
151
  error_on_request!('EOF in read_line') if data.nil?
140
- finish_request!
141
152
  data
142
- rescue SystemCallError, Timeout::Error, EOFError => e
153
+ rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
143
154
  error_on_request!(e)
144
155
  end
145
156
 
146
157
  def read(count)
147
- start_request!
148
- data = @sock.readfull(count)
149
- finish_request!
150
- data
151
- rescue SystemCallError, Timeout::Error, EOFError => e
158
+ @sock.readfull(count)
159
+ rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
152
160
  error_on_request!(e)
153
161
  end
154
162
 
155
163
  def write(bytes)
156
- start_request!
157
- result = @sock.write(bytes)
158
- finish_request!
159
- result
160
- rescue SystemCallError, Timeout::Error => e
164
+ @sock.write(bytes)
165
+ rescue SystemCallError, *TIMEOUT_ERRORS => e
161
166
  error_on_request!(e)
162
167
  end
163
168
 
164
- # Non-blocking read. Should only be used in the context
165
- # of a caller who has called start_request!, but not yet
166
- # called finish_request!. Here to support the operation
169
+ # Non-blocking read. Here to support the operation
167
170
  # of the get_multi operation
168
171
  def read_nonblock
169
172
  @sock.read_available
@@ -226,7 +229,7 @@ module Dalli
226
229
  end
227
230
 
228
231
  def fork_detected?
229
- @pid && @pid != Process.pid
232
+ @pid && @pid != PIDCache.pid
230
233
  end
231
234
 
232
235
  def log_down_detected
@@ -23,7 +23,7 @@ module Dalli
23
23
  def self.decode(encoded_key, base64_encoded)
24
24
  return encoded_key unless base64_encoded
25
25
 
26
- Base64.strict_decode64(encoded_key).force_encoding('UTF-8')
26
+ Base64.strict_decode64(encoded_key).force_encoding(Encoding::UTF_8)
27
27
  end
28
28
  end
29
29
  end
@@ -1,8 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'timeout'
4
+
3
5
  module Dalli
4
6
  module Protocol
5
7
  # Preserved for backwards compatibility. Should be removed in 4.0
6
8
  NOT_FOUND = ::Dalli::NOT_FOUND
9
+
10
+ # Ruby 3.2 raises IO::TimeoutError on blocking reads/writes, but
11
+ # it is not defined in earlier Ruby versions.
12
+ TIMEOUT_ERRORS =
13
+ if defined?(IO::TimeoutError)
14
+ [Timeout::Error, IO::TimeoutError]
15
+ else
16
+ [Timeout::Error]
17
+ end
7
18
  end
8
19
  end
data/lib/dalli/socket.rb CHANGED
@@ -13,7 +13,7 @@ module Dalli
13
13
  ##
14
14
  module InstanceMethods
15
15
  def readfull(count)
16
- value = +''
16
+ value = String.new(capacity: count + 1)
17
17
  loop do
18
18
  result = read_nonblock(count - value.bytesize, exception: false)
19
19
  value << result if append_to_buffer?(result)
@@ -88,14 +88,24 @@ module Dalli
88
88
  # options - supports enhanced logging in the case of a timeout
89
89
  attr_accessor :options
90
90
 
91
- def self.open(host, port, options = {})
92
- Timeout.timeout(options[:socket_timeout]) do
93
- sock = new(host, port)
91
+ if RUBY_VERSION >= '3.0'
92
+ def self.open(host, port, options = {})
93
+ sock = new(host, port, connect_timeout: options[:socket_timeout])
94
94
  sock.options = { host: host, port: port }.merge(options)
95
95
  init_socket_options(sock, options)
96
96
 
97
97
  options[:ssl_context] ? wrapping_ssl_socket(sock, host, options[:ssl_context]) : sock
98
98
  end
99
+ else
100
+ def self.open(host, port, options = {})
101
+ Timeout.timeout(options[:socket_timeout]) do
102
+ sock = new(host, port)
103
+ sock.options = { host: host, port: port }.merge(options)
104
+ init_socket_options(sock, options)
105
+
106
+ options[:ssl_context] ? wrapping_ssl_socket(sock, host, options[:ssl_context]) : sock
107
+ end
108
+ end
99
109
  end
100
110
 
101
111
  def self.init_socket_options(sock, options)
@@ -103,6 +113,15 @@ module Dalli
103
113
  sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options[:keepalive]
104
114
  sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVBUF, options[:rcvbuf]) if options[:rcvbuf]
105
115
  sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDBUF, options[:sndbuf]) if options[:sndbuf]
116
+
117
+ return unless options[:socket_timeout]
118
+
119
+ seconds, fractional = options[:socket_timeout].divmod(1)
120
+ microseconds = fractional * 1_000_000
121
+ timeval = [seconds, microseconds].pack('l_2')
122
+
123
+ sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVTIMEO, timeval)
124
+ sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDTIMEO, timeval)
106
125
  end
107
126
 
108
127
  def self.wrapping_ssl_socket(tcp_socket, host, ssl_context)
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.2.3'
4
+ VERSION = '3.2.7'
5
5
 
6
6
  MIN_SUPPORTED_MEMCACHED_VERSION = '1.4'
7
7
  end
data/lib/dalli.rb CHANGED
@@ -34,7 +34,7 @@ module Dalli
34
34
  QUIET = :dalli_multi
35
35
 
36
36
  def self.logger
37
- @logger ||= (rails_logger || default_logger)
37
+ @logger ||= rails_logger || default_logger
38
38
  end
39
39
 
40
40
  def self.rails_logger
@@ -178,7 +178,7 @@ module Rack
178
178
  def with_dalli_client(result_on_error = nil, &block)
179
179
  @data.with(&block)
180
180
  rescue ::Dalli::DalliError, Errno::ECONNREFUSED
181
- raise if /undefined class/.match?($ERROR_INFO.message)
181
+ raise if $ERROR_INFO.message.include?('undefined class')
182
182
 
183
183
  if $VERBOSE
184
184
  warn "#{self} is unable to find memcached server."
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.2.3
4
+ version: 3.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein
@@ -9,134 +9,16 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-10-28 00:00:00.000000000 Z
12
+ date: 2024-01-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: connection_pool
15
+ name: base64
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
- type: :development
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
- - !ruby/object:Gem::Dependency
29
- name: minitest
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - "~>"
33
- - !ruby/object:Gem::Version
34
- version: '5'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: '5'
42
- - !ruby/object:Gem::Dependency
43
- name: rack
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '2.0'
49
- - - ">="
50
- - !ruby/object:Gem::Version
51
- version: 2.2.0
52
- type: :development
53
- prerelease: false
54
- version_requirements: !ruby/object:Gem::Requirement
55
- requirements:
56
- - - "~>"
57
- - !ruby/object:Gem::Version
58
- version: '2.0'
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: 2.2.0
62
- - !ruby/object:Gem::Dependency
63
- name: rake
64
- requirement: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '13.0'
69
- type: :development
70
- prerelease: false
71
- version_requirements: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '13.0'
76
- - !ruby/object:Gem::Dependency
77
- name: rubocop
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- - !ruby/object:Gem::Dependency
91
- name: rubocop-minitest
92
- requirement: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- type: :development
98
- prerelease: false
99
- version_requirements: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- - !ruby/object:Gem::Dependency
105
- name: rubocop-performance
106
- requirement: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- type: :development
112
- prerelease: false
113
- version_requirements: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- - !ruby/object:Gem::Dependency
119
- name: rubocop-rake
120
- requirement: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- type: :development
126
- prerelease: false
127
- version_requirements: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- - !ruby/object:Gem::Dependency
133
- name: simplecov
134
- requirement: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- type: :development
21
+ type: :runtime
140
22
  prerelease: false
141
23
  version_requirements: !ruby/object:Gem::Requirement
142
24
  requirements:
@@ -161,6 +43,7 @@ files:
161
43
  - lib/dalli/compressor.rb
162
44
  - lib/dalli/key_manager.rb
163
45
  - lib/dalli/options.rb
46
+ - lib/dalli/pid_cache.rb
164
47
  - lib/dalli/pipelined_getter.rb
165
48
  - lib/dalli/protocol.rb
166
49
  - lib/dalli/protocol/base.rb
@@ -206,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
89
  - !ruby/object:Gem::Version
207
90
  version: '0'
208
91
  requirements: []
209
- rubygems_version: 3.3.24
92
+ rubygems_version: 3.5.5
210
93
  signing_key:
211
94
  specification_version: 4
212
95
  summary: High performance memcached client for Ruby