dalli 2.6.2 → 2.6.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.

data/Gemfile CHANGED
@@ -1,10 +1,10 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
6
  gem 'kgio', :platform => :mri
7
- gem 'RubyInline', :platform => :mri
7
+ gem 'appraisal'
8
8
 
9
9
  group :test do
10
10
  gem 'simplecov'
data/History.md CHANGED
@@ -1,6 +1,14 @@
1
1
  Dalli Changelog
2
2
  =====================
3
3
 
4
+ 2.6.3
5
+ =======
6
+
7
+ - Support specific stats by passing `:items` or `:slabs` to `stats` method [bukhamseen]
8
+ - Fix 'can't modify frozen String' errors in `ActiveSupport::Cache::DalliStore` [dblock]
9
+ - Protect against objects with custom equality checking [theron17]
10
+ - Warn if value for key is too large to store [locriani]
11
+
4
12
  2.6.2
5
13
  =======
6
14
 
data/README.md CHANGED
@@ -114,7 +114,7 @@ Configuration
114
114
  ------------------------
115
115
  Dalli::Client accepts the following options. All times are in seconds.
116
116
 
117
- **expires_in**: Global default for key TTL. No default.
117
+ **expires_in**: Global default for key TTL. Default is 0, which means no expiry.
118
118
 
119
119
  **failover**: Boolean, if true Dalli will failover to another server if the main server for a key is down.
120
120
 
@@ -141,7 +141,7 @@ Default is Marshal.
141
141
 
142
142
  **password**: The password to use for authenticating this client instance against a SASL-enabled memcached server. Heroku users should not need to use this normally.
143
143
 
144
- **keepalive**: Boolean, if true Dalli will enable keep-alives on the socket so inactivity
144
+ **keepalive**: Boolean. If true, Dalli will enable keep-alive for socket connections. Default is false.
145
145
 
146
146
  **compressor**: The compressor to use for objects being stored.
147
147
  Default is zlib, implemented under `Dalli::Compressor`.
@@ -158,7 +158,7 @@ socket.
158
158
 
159
159
  Note that Dalli does not require ActiveSupport or Rails. You can safely use it in your own Ruby projects.
160
160
 
161
- ![View the API](http://www.ruby-doc.org/gems/docs/d/dalli-2.5.0/Dalli/Client.html)
161
+ [View the API](http://www.ruby-doc.org/gems/docs/d/dalli-2.6.2/Dalli/Client.html)
162
162
 
163
163
  Helping Out
164
164
  -------------
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'appraisal'
1
2
  require 'rake/testtask'
2
3
  Rake::TestTask.new(:test) do |test|
3
4
  test.libs << 'test'
@@ -63,8 +63,12 @@ module ActiveSupport
63
63
  if block_given?
64
64
  unless options[:force]
65
65
  entry = instrument(:read, name, options) do |payload|
66
- payload[:super_operation] = :fetch if payload
67
- read_entry(name, options)
66
+ read_entry(name, options).tap do |result|
67
+ if payload
68
+ payload[:super_operation] = :fetch
69
+ payload[:hit] = !!result
70
+ end
71
+ end
68
72
  end
69
73
  end
70
74
 
@@ -124,7 +128,6 @@ module ActiveSupport
124
128
  # servers for all keys. Keys must be Strings.
125
129
  def read_multi(*names)
126
130
  names.extract_options!
127
- names = names.flatten
128
131
  mapping = names.inject({}) { |memo, name| memo[expanded_key(name)] = name; memo }
129
132
  instrument(:read_multi, names) do
130
133
  results = {}
@@ -267,7 +270,10 @@ module ActiveSupport
267
270
  end
268
271
 
269
272
  key = key.to_param
270
- key.force_encoding('binary') if key.respond_to? :force_encoding
273
+ if key.respond_to? :force_encoding
274
+ key = key.dup
275
+ key.force_encoding('binary')
276
+ end
271
277
  key
272
278
  end
273
279
 
@@ -21,17 +21,27 @@ module Dalli
21
21
  # - :failover - if a server is down, look for and store values on another server in the ring. Default: true.
22
22
  # - :threadsafe - ensure that only one thread is actively using a socket at a time. Default: true.
23
23
  # - :expires_in - default TTL in seconds if you do not pass TTL as a parameter to an individual operation, defaults to 0 or forever
24
- # - :compress - defaults to false, if true Dalli will compress values larger than 1024 bytes before
24
+ # - :compress - defaults to false, if true Dalli will compress values larger than 1024 bytes before sending them to memcached.
25
25
  # - :serializer - defaults to Marshal
26
- # sending them to memcached.
27
26
  # - :compressor - defaults to zlib
28
27
  #
29
28
  def initialize(servers=nil, options={})
30
- @servers = servers || env_servers || '127.0.0.1:11211'
29
+ @servers = normalize_servers(servers || ENV["MEMCACHE_SERVERS"] || '127.0.0.1:11211')
31
30
  @options = normalize_options(options)
32
31
  @ring = nil
33
32
  end
34
33
 
34
+ ##
35
+ # Normalizes the argument into an array of servers. If the argument is a string, it's expected to be of
36
+ # the format "memcache1.example.com:11211[,memcache2.example.com:11211[,memcache3.example.com:11211[...]]]
37
+ def normalize_servers(servers)
38
+ if servers.is_a? String
39
+ return servers.split(",")
40
+ else
41
+ return servers
42
+ end
43
+ end
44
+
35
45
  #
36
46
  # The standard memcached instruction set
37
47
  #
@@ -50,7 +60,7 @@ module Dalli
50
60
 
51
61
  def get(key, options=nil)
52
62
  resp = perform(:get, key)
53
- resp.nil? || resp == 'Not found' ? nil : resp
63
+ resp.nil? || 'Not found' == resp ? nil : resp
54
64
  end
55
65
 
56
66
  ##
@@ -263,11 +273,13 @@ module Dalli
263
273
 
264
274
  ##
265
275
  # Collect the stats for each server.
276
+ # You can optionally pass a type including :items or :slabs to get specific stats
266
277
  # Returns a hash like { 'hostname:port' => { 'stat1' => 'value1', ... }, 'hostname2:port' => { ... } }
267
- def stats
278
+ def stats(type=nil)
279
+ type = nil if ![nil, :items,:slabs].include? type
268
280
  values = {}
269
281
  ring.servers.each do |server|
270
- values["#{server.hostname}:#{server.port}"] = server.alive? ? server.request(:stats) : nil
282
+ values["#{server.hostname}:#{server.port}"] = server.alive? ? server.request(:stats,type.to_s) : nil
271
283
  end
272
284
  values
273
285
  end
@@ -295,7 +307,7 @@ module Dalli
295
307
 
296
308
  def ring
297
309
  @ring ||= Dalli::Ring.new(
298
- Array(@servers).map do |s|
310
+ @servers.map do |s|
299
311
  server_options = {}
300
312
  if s =~ %r{\Amemcached://}
301
313
  uri = URI.parse(s)
@@ -308,10 +320,6 @@ module Dalli
308
320
  )
309
321
  end
310
322
 
311
- def env_servers
312
- ENV['MEMCACHE_SERVERS'] ? ENV['MEMCACHE_SERVERS'].split(',') : nil
313
- end
314
-
315
323
  # Chokepoint method for instrumentation
316
324
  def perform(op, key, *args)
317
325
  key = key.to_s
@@ -79,16 +79,18 @@ module Dalli
79
79
  inline do |builder|
80
80
  builder.c <<-EOM
81
81
  int binary_search(VALUE ary, unsigned int r) {
82
- int upper = RARRAY_LEN(ary) - 1;
83
- int lower = 0;
84
- int idx = 0;
82
+ long upper = RARRAY_LEN(ary) - 1;
83
+ long lower = 0;
84
+ long idx = 0;
85
85
  ID value = rb_intern("value");
86
+ VALUE continuumValue;
87
+ unsigned int l;
86
88
 
87
89
  while (lower <= upper) {
88
90
  idx = (lower + upper) / 2;
89
91
 
90
- VALUE continuumValue = rb_funcall(RARRAY_PTR(ary)[idx], value, 0);
91
- unsigned int l = NUM2UINT(continuumValue);
92
+ continuumValue = rb_funcall(RARRAY_PTR(ary)[idx], value, 0);
93
+ l = NUM2UINT(continuumValue);
92
94
  if (l == r) {
93
95
  return idx;
94
96
  }
@@ -43,6 +43,7 @@ module Dalli
43
43
  @options = DEFAULTS.merge(options)
44
44
  @sock = nil
45
45
  @msg = nil
46
+ @error = nil
46
47
  @pid = nil
47
48
  @inprogress = nil
48
49
  end
@@ -259,7 +260,7 @@ module Dalli
259
260
  def set(key, value, ttl, cas, options)
260
261
  (value, flags) = serialize(key, value, options)
261
262
 
262
- if under_max_value_size?(value)
263
+ if under_max_value_size?(key, value)
263
264
  req = [REQUEST, OPCODES[multi? ? :setq : :set], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, flags, ttl, key, value].pack(FORMAT[:set])
264
265
  write(req)
265
266
  generic_response unless multi?
@@ -271,7 +272,7 @@ module Dalli
271
272
  def add(key, value, ttl, options)
272
273
  (value, flags) = serialize(key, value, options)
273
274
 
274
- if under_max_value_size?(value)
275
+ if under_max_value_size?(key, value)
275
276
  req = [REQUEST, OPCODES[multi? ? :addq : :add], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:add])
276
277
  write(req)
277
278
  generic_response unless multi?
@@ -283,7 +284,7 @@ module Dalli
283
284
  def replace(key, value, ttl, options)
284
285
  (value, flags) = serialize(key, value, options)
285
286
 
286
- if under_max_value_size?(value)
287
+ if under_max_value_size?(key, value)
287
288
  req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, 0, flags, ttl, key, value].pack(FORMAT[:replace])
288
289
  write(req)
289
290
  generic_response unless multi?
@@ -450,8 +451,13 @@ module Dalli
450
451
  NORMAL_HEADER = '@4CCnN'
451
452
  KV_HEADER = '@2n@6nN'
452
453
 
453
- def under_max_value_size?(value)
454
- value.bytesize <= @options[:value_max_bytes]
454
+ def under_max_value_size?(key, value)
455
+ if value.bytesize <= @options[:value_max_bytes]
456
+ true
457
+ else
458
+ Dalli.logger.warn "Value for #{key} over max size"
459
+ false
460
+ end
455
461
  end
456
462
 
457
463
  def generic_response(unpack=false)
@@ -1,3 +1,3 @@
1
1
  module Dalli
2
- VERSION = '2.6.2'
2
+ VERSION = '2.6.3'
3
3
  end
@@ -63,7 +63,6 @@ module MemcachedMock
63
63
  end
64
64
 
65
65
  raise Errno::ENOENT, "Unable to find memcached 1.4+ locally"
66
- nil
67
66
  end
68
67
 
69
68
  def memcached(port=19122, args='', options={})
@@ -98,7 +98,9 @@ describe 'ActiveSupport' do
98
98
  assert_equal({}, @dalli.read_multi([x, y]))
99
99
  @dalli.write(x, '123')
100
100
  @dalli.write(y, 123)
101
- assert_equal({ x => '123', y => 123 }, @dalli.read_multi([x, y]))
101
+ assert_equal({}, @dalli.read_multi([x, y]))
102
+ @dalli.write([x, y], '123')
103
+ assert_equal({ [x, y] => '123' }, @dalli.read_multi([x, y]))
102
104
  end
103
105
  end
104
106
  end
@@ -328,6 +330,30 @@ describe 'ActiveSupport' do
328
330
  end
329
331
  end
330
332
 
333
+ should 'allow keys to be frozen' do
334
+ with_activesupport do
335
+ memcached do
336
+ connect
337
+ key = "foo"
338
+ key.freeze
339
+ assert_equal true, @dalli.write(key, "value")
340
+ end
341
+ end
342
+ end
343
+
344
+ should 'allow keys from a hash' do
345
+ with_activesupport do
346
+ memcached do
347
+ connect
348
+ map = { "one" => "one", "two" => "two" }
349
+ map.each_pair do |k, v|
350
+ assert_equal true, @dalli.write(k, v)
351
+ end
352
+ assert_equal map, @dalli.read_multi(*(map.keys))
353
+ end
354
+ end
355
+ end
356
+
331
357
  def connect
332
358
  @dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => lambda{33.to_s(36)})
333
359
  @dalli.clear
@@ -16,20 +16,24 @@ end
16
16
  describe 'Compressor' do
17
17
 
18
18
  should 'default to Dalli::Compressor' do
19
- memcache = Dalli::Client.new('127.0.0.1:11211')
20
- memcache.set 1,2
21
- assert_equal Dalli::Compressor, memcache.instance_variable_get('@ring').servers.first.compressor
19
+ memcached_kill(29199) do |dc|
20
+ memcache = Dalli::Client.new('127.0.0.1:29199')
21
+ memcache.set 1,2
22
+ assert_equal Dalli::Compressor, memcache.instance_variable_get('@ring').servers.first.compressor
23
+ end
22
24
  end
23
25
 
24
26
  should 'support a custom compressor' do
25
- memcache = Dalli::Client.new('127.0.0.1:11211', :compressor => NoopCompressor)
26
- memcache.set 1,2
27
- begin
28
- assert_equal NoopCompressor, memcache.instance_variable_get('@ring').servers.first.compressor
29
-
30
- memcached(19127) do |dc|
31
- assert dc.set("string-test", "a test string")
32
- assert_equal("a test string", dc.get("string-test"))
27
+ memcached_kill(29199) do |dc|
28
+ memcache = Dalli::Client.new('127.0.0.1:29199', :compressor => NoopCompressor)
29
+ memcache.set 1,2
30
+ begin
31
+ assert_equal NoopCompressor, memcache.instance_variable_get('@ring').servers.first.compressor
32
+
33
+ memcached(19127) do |dc|
34
+ assert dc.set("string-test", "a test string")
35
+ assert_equal("a test string", dc.get("string-test"))
36
+ end
33
37
  end
34
38
  end
35
39
  end
@@ -67,6 +67,24 @@ describe 'Dalli' do
67
67
  assert_equal s2, s3
68
68
  end
69
69
 
70
+ should "accept comma separated string" do
71
+ dc = Dalli::Client.new("server1.example.com:11211,server2.example.com:11211")
72
+ ring = dc.send(:ring)
73
+ assert_equal 2, ring.servers.size
74
+ s1,s2 = ring.servers.map(&:hostname)
75
+ assert_equal "server1.example.com", s1
76
+ assert_equal "server2.example.com", s2
77
+ end
78
+
79
+ should "accept array of servers" do
80
+ dc = Dalli::Client.new(["server1.example.com:11211","server2.example.com:11211"])
81
+ ring = dc.send(:ring)
82
+ assert_equal 2, ring.servers.size
83
+ s1,s2 = ring.servers.map(&:hostname)
84
+ assert_equal "server1.example.com", s1
85
+ assert_equal "server2.example.com", s2
86
+ end
87
+
70
88
  context 'using a live server' do
71
89
 
72
90
  should "support get/set" do
@@ -95,7 +113,23 @@ describe 'Dalli' do
95
113
  servers = stats.keys
96
114
  assert(servers.any? do |s|
97
115
  stats[s]["get_hits"].to_i != 0
98
- end)
116
+ end, "general stats failed")
117
+
118
+ stats_items = dc.stats(:items)
119
+ servers = stats_items.keys
120
+ assert(servers.all? do |s|
121
+ stats_items[s].keys.any? do |key|
122
+ key =~ /items:[0-9]+:number/
123
+ end
124
+ end, "stats items failed")
125
+
126
+ stats_slabs = dc.stats(:slabs)
127
+ servers = stats_slabs.keys
128
+ assert(servers.all? do |s|
129
+ stats_slabs[s].keys.any? do |key|
130
+ key == "active_slabs"
131
+ end
132
+ end, "stats slabs failed")
99
133
 
100
134
  # reset_stats test
101
135
  results = dc.reset_stats
@@ -6,20 +6,24 @@ require 'memcached_mock'
6
6
  describe 'Serializer' do
7
7
 
8
8
  should 'default to Marshal' do
9
- memcache = Dalli::Client.new('127.0.0.1:11211')
10
- memcache.set 1,2
11
- assert_equal Marshal, memcache.instance_variable_get('@ring').servers.first.serializer
9
+ memcached_kill(29198) do |dc|
10
+ memcache = Dalli::Client.new('127.0.0.1:29198')
11
+ memcache.set 1,2
12
+ assert_equal Marshal, memcache.instance_variable_get('@ring').servers.first.serializer
13
+ end
12
14
  end
13
15
 
14
16
  should 'support a custom serializer' do
15
- memcache = Dalli::Client.new('127.0.0.1:11211', :serializer => JSON)
16
- memcache.set 1,2
17
- begin
18
- assert_equal JSON, memcache.instance_variable_get('@ring').servers.first.serializer
17
+ memcached_kill(29198) do |dc|
18
+ memcache = Dalli::Client.new('127.0.0.1:29198', :serializer => JSON)
19
+ memcache.set 1,2
20
+ begin
21
+ assert_equal JSON, memcache.instance_variable_get('@ring').servers.first.serializer
19
22
 
20
- memcached(19128) do |dc|
21
- assert dc.set("json_test", {"foo" => "bar"})
22
- assert_equal({"foo" => "bar"}, dc.get("json_test"))
23
+ memcached(19128) do |dc|
24
+ assert dc.set("json_test", {"foo" => "bar"})
25
+ assert_equal({"foo" => "bar"}, dc.get("json_test"))
26
+ end
23
27
  end
24
28
  end
25
29
  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: 2.6.2
4
+ version: 2.6.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-25 00:00:00.000000000 Z
12
+ date: 2013-05-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mini_shoulda
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  version: '0'
120
120
  requirements: []
121
121
  rubyforge_project:
122
- rubygems_version: 1.8.24
122
+ rubygems_version: 1.8.23
123
123
  signing_key:
124
124
  specification_version: 3
125
125
  summary: High performance memcached client for Ruby