dalli 2.7.0 → 2.7.1
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 +4 -4
- data/History.md +10 -0
- data/README.md +19 -0
- data/dalli.gemspec +1 -1
- data/lib/action_dispatch/middleware/session/dalli_store.rb +1 -1
- data/lib/active_support/cache/dalli_store.rb +2 -0
- data/lib/dalli/cas/client.rb +4 -4
- data/lib/dalli/client.rb +10 -3
- data/lib/dalli/server.rb +57 -53
- data/lib/dalli/version.rb +1 -1
- data/lib/rack/session/dalli.rb +3 -1
- data/test/test_active_support.rb +12 -0
- data/test/test_dalli.rb +24 -0
- data/test/test_rack_session.rb +48 -28
- data/test/test_server.rb +80 -0
- metadata +24 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b95a4fab254be40a050b417698b0551ffeb5e81d
|
4
|
+
data.tar.gz: c15ffb9b9e417e8188855394a5af9384cc090cc1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d837cb9c4869b6035a271585e4fbd1a41cd91d6d4f19ff910b99e4364d8c401ebb8a8f366c077e4ef70a2809d3d0f49122a9cae8d90ce81490d58e2b13381dd
|
7
|
+
data.tar.gz: b8f5499ad63ff4e357557d2a68b32a07251da67244c35c3281b3a90afab928bacdef17842ff4cf4cde938920f4f7210f46eb6e8e0795d8eb3381b15ebe92afd5
|
data/History.md
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
Dalli Changelog
|
2
2
|
=====================
|
3
3
|
|
4
|
+
2.7.1
|
5
|
+
==========
|
6
|
+
|
7
|
+
- Rack session will check if servers are up on initialization (arthurnn, #423)
|
8
|
+
- Add support for IPv6 addresses in hex form, ie: "[::1]:11211" (dplummer, #428)
|
9
|
+
- Add symbol support for namespace (jingkai #431)
|
10
|
+
- Support expiration intervals longer than 30 days (leonid-shevtsov #436)
|
11
|
+
|
4
12
|
2.7.0
|
5
13
|
==========
|
6
14
|
|
15
|
+
- BREAKING CHANGE:
|
16
|
+
Dalli::Client#add and #replace now return a truthy value, not boolean true or false.
|
7
17
|
- Multithreading support with dalli\_store:
|
8
18
|
Use :pool\_size to create a pool of shared, threadsafe Dalli clients in Rails:
|
9
19
|
```ruby
|
data/README.md
CHANGED
@@ -94,6 +94,12 @@ config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
|
|
94
94
|
{ :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
|
95
95
|
```
|
96
96
|
|
97
|
+
If your servers are specified in `ENV["MEMCACHE_SERVERS"]` (e.g. on Heroku when using a third-party hosted addon), simply provide `nil` for the servers:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
config.cache_store = :dalli_store, nil, { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
|
101
|
+
```
|
102
|
+
|
97
103
|
To use Dalli for Rails session storage that times out after 20 minutes, in `config/initializers/session_store.rb`:
|
98
104
|
|
99
105
|
For Rails >= 3.2.4:
|
@@ -124,6 +130,19 @@ add :pool\_size to your `dalli_store` config:
|
|
124
130
|
config.cache_store = :dalli_store, 'cache-1.example.com', { :pool_size => 5 }
|
125
131
|
```
|
126
132
|
|
133
|
+
You can then use the Rails cache as normal or check out a Dalli client directly from the pool:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
Rails.cache.fetch('foo', :expires_in => 300) do
|
137
|
+
'bar'
|
138
|
+
end
|
139
|
+
|
140
|
+
Rails.cache.dalli.with do |client|
|
141
|
+
# client is a Dalli::Client instance which you can
|
142
|
+
# use ONLY within this block
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
127
146
|
|
128
147
|
Configuration
|
129
148
|
------------------------
|
data/dalli.gemspec
CHANGED
@@ -24,6 +24,6 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.test_files = Dir.glob("test/**/*")
|
25
25
|
s.add_development_dependency(%q<minitest>, [">= 4.2.0"])
|
26
26
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
27
|
-
s.add_development_dependency(%q<rails>, ["~>
|
27
|
+
s.add_development_dependency(%q<rails>, ["~> 4"])
|
28
28
|
end
|
29
29
|
|
@@ -54,6 +54,8 @@ module ActiveSupport
|
|
54
54
|
pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
|
55
55
|
|
56
56
|
@options[:compress] ||= @options[:compression]
|
57
|
+
|
58
|
+
addresses.compact!
|
57
59
|
servers = if addresses.empty?
|
58
60
|
nil # use the default from Dalli::Client
|
59
61
|
else
|
data/lib/dalli/cas/client.rb
CHANGED
@@ -33,7 +33,7 @@ module Dalli
|
|
33
33
|
|
34
34
|
##
|
35
35
|
# Set the key-value pair, verifying existing CAS.
|
36
|
-
# Returns the resulting CAS value if succeeded, and
|
36
|
+
# Returns the resulting CAS value if succeeded, and falsy otherwise.
|
37
37
|
def set_cas(key, value, cas, ttl=nil, options=nil)
|
38
38
|
ttl ||= @options[:expires_in].to_i
|
39
39
|
perform(:set, key, value, ttl, cas, options)
|
@@ -42,17 +42,17 @@ module Dalli
|
|
42
42
|
##
|
43
43
|
# Conditionally add a key/value pair, verifying existing CAS, only if the
|
44
44
|
# key already exists on the server. Returns the new CAS value if the
|
45
|
-
# operation succeeded, or
|
45
|
+
# operation succeeded, or falsy otherwise.
|
46
46
|
def replace_cas(key, value, cas, ttl=nil, options=nil)
|
47
47
|
ttl ||= @options[:expires_in].to_i
|
48
48
|
perform(:replace, key, value, ttl, cas, options)
|
49
49
|
end
|
50
50
|
|
51
51
|
# Delete a key/value pair, verifying existing CAS.
|
52
|
-
# Returns true if succeeded, and
|
52
|
+
# Returns true if succeeded, and falsy otherwise.
|
53
53
|
def delete_cas(key, cas=0)
|
54
54
|
perform(:delete, key, cas)
|
55
55
|
end
|
56
56
|
|
57
57
|
end
|
58
|
-
end
|
58
|
+
end
|
data/lib/dalli/client.rb
CHANGED
@@ -105,7 +105,7 @@ module Dalli
|
|
105
105
|
|
106
106
|
##
|
107
107
|
# Conditionally add a key/value pair, if the key does not already exist
|
108
|
-
# on the server. Returns
|
108
|
+
# on the server. Returns truthy if the operation succeeded.
|
109
109
|
def add(key, value, ttl=nil, options=nil)
|
110
110
|
ttl ||= @options[:expires_in].to_i
|
111
111
|
perform(:add, key, value, ttl, options)
|
@@ -113,7 +113,7 @@ module Dalli
|
|
113
113
|
|
114
114
|
##
|
115
115
|
# Conditionally add a key/value pair, only if the key already exists
|
116
|
-
# on the server. Returns
|
116
|
+
# on the server. Returns truthy if the operation succeeded.
|
117
117
|
def replace(key, value, ttl=nil, options=nil)
|
118
118
|
ttl ||= @options[:expires_in].to_i
|
119
119
|
perform(:replace, key, value, ttl, 0, options)
|
@@ -212,6 +212,12 @@ module Dalli
|
|
212
212
|
end
|
213
213
|
end
|
214
214
|
|
215
|
+
##
|
216
|
+
## Make sure memcache servers are alive, or raise an Dalli::RingError
|
217
|
+
def alive!
|
218
|
+
ring.server_for_key("")
|
219
|
+
end
|
220
|
+
|
215
221
|
##
|
216
222
|
## Version of the memcache servers.
|
217
223
|
def version
|
@@ -348,7 +354,8 @@ module Dalli
|
|
348
354
|
end
|
349
355
|
|
350
356
|
def namespace
|
351
|
-
|
357
|
+
return nil unless @options[:namespace]
|
358
|
+
@options[:namespace].is_a?(Proc) ? @options[:namespace].call.to_s : @options[:namespace].to_s
|
352
359
|
end
|
353
360
|
|
354
361
|
def normalize_options(opts)
|
data/lib/dalli/server.rb
CHANGED
@@ -32,7 +32,7 @@ module Dalli
|
|
32
32
|
}
|
33
33
|
|
34
34
|
def initialize(attribs, options = {})
|
35
|
-
(@hostname, @port, @weight) = attribs
|
35
|
+
(@hostname, @port, @weight) = parse_hostname(attribs)
|
36
36
|
@port ||= 11211
|
37
37
|
@port = Integer(@port)
|
38
38
|
@weight ||= 1
|
@@ -268,6 +268,7 @@ module Dalli
|
|
268
268
|
|
269
269
|
def set(key, value, ttl, cas, options)
|
270
270
|
(value, flags) = serialize(key, value, options)
|
271
|
+
ttl = sanitize_ttl(ttl)
|
271
272
|
|
272
273
|
guard_max_value(key, value) do
|
273
274
|
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])
|
@@ -278,6 +279,7 @@ module Dalli
|
|
278
279
|
|
279
280
|
def add(key, value, ttl, options)
|
280
281
|
(value, flags) = serialize(key, value, options)
|
282
|
+
ttl = sanitize_ttl(ttl)
|
281
283
|
|
282
284
|
guard_max_value(key, value) do
|
283
285
|
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])
|
@@ -288,6 +290,7 @@ module Dalli
|
|
288
290
|
|
289
291
|
def replace(key, value, ttl, cas, options)
|
290
292
|
(value, flags) = serialize(key, value, options)
|
293
|
+
ttl = sanitize_ttl(ttl)
|
291
294
|
|
292
295
|
guard_max_value(key, value) do
|
293
296
|
req = [REQUEST, OPCODES[multi? ? :replaceq : :replace], key.bytesize, 8, 0, 0, value.bytesize + key.bytesize + 8, 0, cas, flags, ttl, key, value].pack(FORMAT[:replace])
|
@@ -308,26 +311,32 @@ module Dalli
|
|
308
311
|
generic_response
|
309
312
|
end
|
310
313
|
|
311
|
-
def
|
312
|
-
expiry = default ? ttl : 0xFFFFFFFF
|
314
|
+
def decr_incr(opcode, key, count, ttl, default)
|
315
|
+
expiry = default ? sanitize_ttl(ttl) : 0xFFFFFFFF
|
313
316
|
default ||= 0
|
314
317
|
(h, l) = split(count)
|
315
318
|
(dh, dl) = split(default)
|
316
|
-
req = [REQUEST, OPCODES[
|
319
|
+
req = [REQUEST, OPCODES[opcode], key.bytesize, 20, 0, 0, key.bytesize + 20, 0, 0, h, l, dh, dl, expiry, key].pack(FORMAT[opcode])
|
317
320
|
write(req)
|
318
321
|
body = generic_response
|
319
|
-
body ?
|
322
|
+
body ? body.unpack('Q>').first : body
|
323
|
+
end
|
324
|
+
|
325
|
+
def decr(key, count, ttl, default)
|
326
|
+
decr_incr :decr, key, count, ttl, default
|
320
327
|
end
|
321
328
|
|
322
329
|
def incr(key, count, ttl, default)
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
330
|
+
decr_incr :incr, key, count, ttl, default
|
331
|
+
end
|
332
|
+
|
333
|
+
def write_append_prepend(opcode, key, value)
|
334
|
+
write_generic [REQUEST, OPCODES[opcode], key.bytesize, 0, 0, 0, value.bytesize + key.bytesize, 0, 0, key, value].pack(FORMAT[opcode])
|
335
|
+
end
|
336
|
+
|
337
|
+
def write_generic(bytes)
|
338
|
+
write(bytes)
|
339
|
+
generic_response
|
331
340
|
end
|
332
341
|
|
333
342
|
def write_noop
|
@@ -343,15 +352,11 @@ module Dalli
|
|
343
352
|
end
|
344
353
|
|
345
354
|
def append(key, value)
|
346
|
-
|
347
|
-
write(req)
|
348
|
-
generic_response
|
355
|
+
write_append_prepend :append, key, value
|
349
356
|
end
|
350
357
|
|
351
358
|
def prepend(key, value)
|
352
|
-
|
353
|
-
write(req)
|
354
|
-
generic_response
|
359
|
+
write_append_prepend :prepend, key, value
|
355
360
|
end
|
356
361
|
|
357
362
|
def stats(info='')
|
@@ -361,9 +366,7 @@ module Dalli
|
|
361
366
|
end
|
362
367
|
|
363
368
|
def reset_stats
|
364
|
-
|
365
|
-
write(req)
|
366
|
-
generic_response
|
369
|
+
write_generic [REQUEST, OPCODES[:stat], 'reset'.bytesize, 0, 0, 0, 'reset'.bytesize, 0, 0, 'reset'].pack(FORMAT[:stat])
|
367
370
|
end
|
368
371
|
|
369
372
|
def cas(key)
|
@@ -373,15 +376,12 @@ module Dalli
|
|
373
376
|
end
|
374
377
|
|
375
378
|
def version
|
376
|
-
|
377
|
-
write(req)
|
378
|
-
generic_response
|
379
|
+
write_generic [REQUEST, OPCODES[:version], 0, 0, 0, 0, 0, 0, 0].pack(FORMAT[:noop])
|
379
380
|
end
|
380
381
|
|
381
382
|
def touch(key, ttl)
|
382
|
-
|
383
|
-
|
384
|
-
generic_response
|
383
|
+
ttl = sanitize_ttl(ttl)
|
384
|
+
write_generic [REQUEST, OPCODES[:touch], key.bytesize, 4, 0, 0, key.bytesize + 4, 0, 0, ttl, key].pack(FORMAT[:touch])
|
385
385
|
end
|
386
386
|
|
387
387
|
# http://www.hjp.at/zettel/m/memcached_flags.rxml
|
@@ -434,9 +434,7 @@ module Dalli
|
|
434
434
|
end
|
435
435
|
|
436
436
|
def data_cas_response
|
437
|
-
|
438
|
-
raise Dalli::NetworkError, 'No response' if !header
|
439
|
-
(extras, _, status, count, _, cas) = header.unpack(CAS_HEADER)
|
437
|
+
(extras, _, status, count, _, cas) = read_header.unpack(CAS_HEADER)
|
440
438
|
data = read(count) if count > 0
|
441
439
|
if status == 1
|
442
440
|
nil
|
@@ -463,10 +461,20 @@ module Dalli
|
|
463
461
|
end
|
464
462
|
end
|
465
463
|
|
464
|
+
# https://code.google.com/p/memcached/wiki/NewCommands#Standard_Protocol
|
465
|
+
# > An expiration time, in seconds. Can be up to 30 days. After 30 days, is treated as a unix timestamp of an exact date.
|
466
|
+
MAX_ACCEPTABLE_EXPIRATION_INTERVAL = 30*24*60*60 # 30 days
|
467
|
+
def sanitize_ttl(ttl)
|
468
|
+
if ttl > MAX_ACCEPTABLE_EXPIRATION_INTERVAL
|
469
|
+
Dalli.logger.debug "Expiration interval too long for Memcached, converting to an expiration timestamp"
|
470
|
+
Time.now.to_i + ttl
|
471
|
+
else
|
472
|
+
ttl
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
466
476
|
def generic_response(unpack=false)
|
467
|
-
|
468
|
-
raise Dalli::NetworkError, 'No response' if !header
|
469
|
-
(extras, _, status, count) = header.unpack(NORMAL_HEADER)
|
477
|
+
(extras, _, status, count) = read_header.unpack(NORMAL_HEADER)
|
470
478
|
data = read(count) if count > 0
|
471
479
|
if status == 1
|
472
480
|
nil
|
@@ -484,9 +492,7 @@ module Dalli
|
|
484
492
|
end
|
485
493
|
|
486
494
|
def cas_response
|
487
|
-
|
488
|
-
raise Dalli::NetworkError, 'No response' if !header
|
489
|
-
(_, _, status, count, _, cas) = header.unpack(CAS_HEADER)
|
495
|
+
(_, _, status, count, _, cas) = read_header.unpack(CAS_HEADER)
|
490
496
|
read(count) if count > 0 # this is potential data that we don't care about
|
491
497
|
if status == 1
|
492
498
|
nil
|
@@ -502,9 +508,7 @@ module Dalli
|
|
502
508
|
def keyvalue_response
|
503
509
|
hash = {}
|
504
510
|
loop do
|
505
|
-
|
506
|
-
raise Dalli::NetworkError, 'No response' if !header
|
507
|
-
(key_length, _, body_length, _) = header.unpack(KV_HEADER)
|
511
|
+
(key_length, _, body_length, _) = read_header.unpack(KV_HEADER)
|
508
512
|
return hash if key_length == 0
|
509
513
|
key = read(key_length)
|
510
514
|
value = read(body_length - key_length) if body_length - key_length > 0
|
@@ -515,9 +519,7 @@ module Dalli
|
|
515
519
|
def multi_response
|
516
520
|
hash = {}
|
517
521
|
loop do
|
518
|
-
|
519
|
-
raise Dalli::NetworkError, 'No response' if !header
|
520
|
-
(key_length, _, body_length, _) = header.unpack(KV_HEADER)
|
522
|
+
(key_length, _, body_length, _) = read_header.unpack(KV_HEADER)
|
521
523
|
return hash if key_length == 0
|
522
524
|
flags = read(4).unpack('N')[0]
|
523
525
|
key = read(key_length)
|
@@ -548,6 +550,10 @@ module Dalli
|
|
548
550
|
end
|
549
551
|
end
|
550
552
|
|
553
|
+
def read_header
|
554
|
+
read(24) || raise(Dalli::NetworkError, 'No response')
|
555
|
+
end
|
556
|
+
|
551
557
|
def connect
|
552
558
|
Dalli.logger.debug { "Dalli::Server#connect #{hostname}:#{port}" }
|
553
559
|
|
@@ -569,10 +575,6 @@ module Dalli
|
|
569
575
|
[n >> 32, 0xFFFFFFFF & n]
|
570
576
|
end
|
571
577
|
|
572
|
-
def longlong(a, b)
|
573
|
-
(a << 32) | b
|
574
|
-
end
|
575
|
-
|
576
578
|
REQUEST = 0x80
|
577
579
|
RESPONSE = 0x81
|
578
580
|
|
@@ -661,9 +663,8 @@ module Dalli
|
|
661
663
|
# negotiate
|
662
664
|
req = [REQUEST, OPCODES[:auth_negotiation], 0, 0, 0, 0, 0, 0, 0].pack(FORMAT[:noop])
|
663
665
|
write(req)
|
664
|
-
|
665
|
-
|
666
|
-
(extras, type, status, count) = header.unpack(NORMAL_HEADER)
|
666
|
+
|
667
|
+
(extras, type, status, count) = read_header.unpack(NORMAL_HEADER)
|
667
668
|
raise Dalli::NetworkError, "Unexpected message format: #{extras} #{count}" unless extras == 0 && count > 0
|
668
669
|
content = read(count)
|
669
670
|
return (Dalli.logger.debug("Authentication not required/supported by server")) if status == 0x81
|
@@ -676,9 +677,7 @@ module Dalli
|
|
676
677
|
req = [REQUEST, OPCODES[:auth_request], mechanism.bytesize, 0, 0, 0, mechanism.bytesize + msg.bytesize, 0, 0, mechanism, msg].pack(FORMAT[:auth_request])
|
677
678
|
write(req)
|
678
679
|
|
679
|
-
|
680
|
-
raise Dalli::NetworkError, 'No response' if !header
|
681
|
-
(extras, type, status, count) = header.unpack(NORMAL_HEADER)
|
680
|
+
(extras, type, status, count) = read_header.unpack(NORMAL_HEADER)
|
682
681
|
raise Dalli::NetworkError, "Unexpected message format: #{extras} #{count}" unless extras == 0 && count > 0
|
683
682
|
content = read(count)
|
684
683
|
return Dalli.logger.info("Dalli/SASL: #{content}") if status == 0
|
@@ -688,5 +687,10 @@ module Dalli
|
|
688
687
|
# (step, msg) = sasl.receive('challenge', content)
|
689
688
|
# raise Dalli::NetworkError, "Authentication failed" if sasl.failed? || step != 'response'
|
690
689
|
end
|
690
|
+
|
691
|
+
def parse_hostname(str)
|
692
|
+
res = str.match(/\A(\[([\h:]+)\]|[^:]+)(:(\d+))?(:(\d+))?\z/)
|
693
|
+
return res[2] || res[1], res[4], res[6]
|
694
|
+
end
|
691
695
|
end
|
692
696
|
end
|
data/lib/dalli/version.rb
CHANGED
data/lib/rack/session/dalli.rb
CHANGED
@@ -16,6 +16,7 @@ module Rack
|
|
16
16
|
mserv = @default_options[:memcache_server]
|
17
17
|
mopts = @default_options.reject{|k,v| !DEFAULT_OPTIONS.include? k }
|
18
18
|
@pool = options[:cache] || ::Dalli::Client.new(mserv, mopts)
|
19
|
+
@pool.alive!
|
19
20
|
end
|
20
21
|
|
21
22
|
def generate_sid
|
@@ -27,7 +28,7 @@ module Rack
|
|
27
28
|
|
28
29
|
def get_session(env, sid)
|
29
30
|
with_lock(env, [nil, {}]) do
|
30
|
-
unless sid and session = @pool.get(sid)
|
31
|
+
unless sid and !sid.empty? and session = @pool.get(sid)
|
31
32
|
sid, session = generate_sid, {}
|
32
33
|
unless @pool.add(sid, session)
|
33
34
|
raise "Session collision on '#{sid.inspect}'"
|
@@ -38,6 +39,7 @@ module Rack
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def set_session(env, session_id, new_session, options)
|
42
|
+
return false unless session_id
|
41
43
|
expiry = options[:expire_after]
|
42
44
|
expiry = expiry.nil? ? 0 : expiry + 1
|
43
45
|
|
data/test/test_active_support.rb
CHANGED
@@ -371,6 +371,18 @@ describe 'ActiveSupport' do
|
|
371
371
|
@dalli = ActiveSupport::Cache::DalliStore.new('localhost:19122', :expires_in => 1, :namespace => 'foo', :compress => true)
|
372
372
|
assert_equal 1, @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:expires_in]
|
373
373
|
assert_equal 'foo', @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:namespace]
|
374
|
+
assert_equal ["localhost:19122"], @dalli.instance_variable_get(:@data).instance_variable_get(:@servers)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'handles nil server with additional options' do
|
380
|
+
with_activesupport do
|
381
|
+
memcached do
|
382
|
+
@dalli = ActiveSupport::Cache::DalliStore.new(nil, :expires_in => 1, :namespace => 'foo', :compress => true)
|
383
|
+
assert_equal 1, @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:expires_in]
|
384
|
+
assert_equal 'foo', @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:namespace]
|
385
|
+
assert_equal ["127.0.0.1:11211"], @dalli.instance_variable_get(:@data).instance_variable_get(:@servers)
|
374
386
|
end
|
375
387
|
end
|
376
388
|
end
|
data/test/test_dalli.rb
CHANGED
@@ -23,6 +23,16 @@ describe 'Dalli' do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
it 'return string type for namespace attribute' do
|
28
|
+
dc = Dalli::Client.new('foo', :namespace => :wunderschoen)
|
29
|
+
assert_equal "wunderschoen", dc.send(:namespace)
|
30
|
+
dc.close
|
31
|
+
|
32
|
+
dc = Dalli::Client.new('foo', :namespace => Proc.new{:wunderschoen})
|
33
|
+
assert_equal "wunderschoen", dc.send(:namespace)
|
34
|
+
dc.close
|
35
|
+
end
|
26
36
|
end
|
27
37
|
|
28
38
|
describe 'key validation' do
|
@@ -42,6 +52,13 @@ describe 'Dalli' do
|
|
42
52
|
end
|
43
53
|
end
|
44
54
|
end
|
55
|
+
|
56
|
+
it 'allow namespace to be a symbol' do
|
57
|
+
memcached(19122, '', :namespace => :wunderschoen) do |dc|
|
58
|
+
dc.set "x" * 251, 1
|
59
|
+
assert 1, dc.get("#{'x' * 200}:md5:#{Digest::MD5.hexdigest('x' * 251)}")
|
60
|
+
end
|
61
|
+
end
|
45
62
|
end
|
46
63
|
|
47
64
|
it "default to localhost:11211" do
|
@@ -515,6 +532,13 @@ describe 'Dalli' do
|
|
515
532
|
end
|
516
533
|
end
|
517
534
|
|
535
|
+
it "handle nil namespace" do
|
536
|
+
memcached do |dc|
|
537
|
+
dc = Dalli::Client.new('localhost:19122', :namespace => nil)
|
538
|
+
assert_equal 'key', dc.send(:validate_key, 'key')
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
518
542
|
it 'truncate cache keys that are too long' do
|
519
543
|
memcached do
|
520
544
|
dc = Dalli::Client.new('localhost:19122', :namespace => 'some:namspace')
|
data/test/test_rack_session.rb
CHANGED
@@ -11,40 +11,51 @@ describe Rack::Session::Dalli do
|
|
11
11
|
before do
|
12
12
|
memcached(19129) do
|
13
13
|
end
|
14
|
+
|
15
|
+
# test memcache connection
|
16
|
+
Rack::Session::Dalli.new(incrementor)
|
14
17
|
end
|
15
18
|
|
16
|
-
session_key
|
17
|
-
session_match
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
let(:session_key) { Rack::Session::Dalli::DEFAULT_OPTIONS[:key] }
|
20
|
+
let(:session_match) do
|
21
|
+
/#{session_key}=([0-9a-fA-F]+);/
|
22
|
+
end
|
23
|
+
let(:incrementor_proc) do
|
24
|
+
lambda do |env|
|
25
|
+
env["rack.session"]["counter"] ||= 0
|
26
|
+
env["rack.session"]["counter"] += 1
|
27
|
+
Rack::Response.new(env["rack.session"].inspect).to_a
|
28
|
+
end
|
29
|
+
end
|
30
|
+
let(:drop_session) do
|
31
|
+
Rack::Lint.new(proc do |env|
|
32
|
+
env['rack.session.options'][:drop] = true
|
33
|
+
incrementor_proc.call(env)
|
34
|
+
end)
|
35
|
+
end
|
36
|
+
let(:renew_session) do
|
37
|
+
Rack::Lint.new(proc do |env|
|
38
|
+
env['rack.session.options'][:renew] = true
|
39
|
+
incrementor_proc.call(env)
|
40
|
+
end)
|
41
|
+
end
|
42
|
+
let(:defer_session) do
|
43
|
+
Rack::Lint.new(proc do |env|
|
44
|
+
env['rack.session.options'][:defer] = true
|
45
|
+
incrementor_proc.call(env)
|
46
|
+
end)
|
47
|
+
end
|
48
|
+
let(:skip_session) do
|
49
|
+
Rack::Lint.new(proc do |env|
|
50
|
+
env['rack.session.options'][:skip] = true
|
51
|
+
incrementor_proc.call(env)
|
52
|
+
end)
|
22
53
|
end
|
23
|
-
|
24
|
-
env['rack.session.options'][:drop] = true
|
25
|
-
incrementor.call(env)
|
26
|
-
end)
|
27
|
-
renew_session = Rack::Lint.new(proc do |env|
|
28
|
-
env['rack.session.options'][:renew] = true
|
29
|
-
incrementor.call(env)
|
30
|
-
end)
|
31
|
-
defer_session = Rack::Lint.new(proc do |env|
|
32
|
-
env['rack.session.options'][:defer] = true
|
33
|
-
incrementor.call(env)
|
34
|
-
end)
|
35
|
-
skip_session = Rack::Lint.new(proc do |env|
|
36
|
-
env['rack.session.options'][:skip] = true
|
37
|
-
incrementor.call(env)
|
38
|
-
end)
|
39
|
-
incrementor = Rack::Lint.new(incrementor)
|
40
|
-
|
41
|
-
# test memcache connection
|
42
|
-
Rack::Session::Dalli.new(incrementor)
|
54
|
+
let(:incrementor) { Rack::Lint.new(incrementor_proc) }
|
43
55
|
|
44
56
|
it "faults on no connection" do
|
45
57
|
assert_raises Dalli::RingError do
|
46
|
-
|
47
|
-
rsd.pool.set('ping', '')
|
58
|
+
Rack::Session::Dalli.new(incrementor, :memcache_server => 'nosuchserver')
|
48
59
|
end
|
49
60
|
end
|
50
61
|
|
@@ -104,6 +115,15 @@ describe Rack::Session::Dalli do
|
|
104
115
|
refute_match(/#{bad_cookie}/, cookie)
|
105
116
|
end
|
106
117
|
|
118
|
+
it "survives nonexistant blank cookies" do
|
119
|
+
bad_cookie = "rack.session="
|
120
|
+
rsd = Rack::Session::Dalli.new(incrementor)
|
121
|
+
res = Rack::MockRequest.new(rsd).
|
122
|
+
get("/", "HTTP_COOKIE" => bad_cookie)
|
123
|
+
cookie = res["Set-Cookie"][session_match]
|
124
|
+
refute_match(/#{bad_cookie}$/, cookie)
|
125
|
+
end
|
126
|
+
|
107
127
|
it "maintains freshness" do
|
108
128
|
rsd = Rack::Session::Dalli.new(incrementor, :expire_after => 3)
|
109
129
|
res = Rack::MockRequest.new(rsd).get('/')
|
data/test/test_server.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Dalli::Server do
|
4
|
+
describe 'hostname parsing' do
|
5
|
+
it 'handles no port or weight' do
|
6
|
+
s = Dalli::Server.new('localhost')
|
7
|
+
assert_equal 'localhost', s.hostname
|
8
|
+
assert_equal 11211, s.port
|
9
|
+
assert_equal 1, s.weight
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'handles a port, but no weight' do
|
13
|
+
s = Dalli::Server.new('localhost:11212')
|
14
|
+
assert_equal 'localhost', s.hostname
|
15
|
+
assert_equal 11212, s.port
|
16
|
+
assert_equal 1, s.weight
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'handles a port and a weight' do
|
20
|
+
s = Dalli::Server.new('localhost:11212:2')
|
21
|
+
assert_equal 'localhost', s.hostname
|
22
|
+
assert_equal 11212, s.port
|
23
|
+
assert_equal 2, s.weight
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'handles ipv4 addresses' do
|
27
|
+
s = Dalli::Server.new('127.0.0.1')
|
28
|
+
assert_equal '127.0.0.1', s.hostname
|
29
|
+
assert_equal 11211, s.port
|
30
|
+
assert_equal 1, s.weight
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'handles ipv6 addresses' do
|
34
|
+
s = Dalli::Server.new('[::1]')
|
35
|
+
assert_equal '::1', s.hostname
|
36
|
+
assert_equal 11211, s.port
|
37
|
+
assert_equal 1, s.weight
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'handles ipv6 addresses with port' do
|
41
|
+
s = Dalli::Server.new('[::1]:11212')
|
42
|
+
assert_equal '::1', s.hostname
|
43
|
+
assert_equal 11212, s.port
|
44
|
+
assert_equal 1, s.weight
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'handles ipv6 addresses with port and weight' do
|
48
|
+
s = Dalli::Server.new('[::1]:11212:2')
|
49
|
+
assert_equal '::1', s.hostname
|
50
|
+
assert_equal 11212, s.port
|
51
|
+
assert_equal 2, s.weight
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'handles a FQDN' do
|
55
|
+
s = Dalli::Server.new('my.fqdn.com')
|
56
|
+
assert_equal 'my.fqdn.com', s.hostname
|
57
|
+
assert_equal 11211, s.port
|
58
|
+
assert_equal 1, s.weight
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'handles a FQDN with port and weight' do
|
62
|
+
s = Dalli::Server.new('my.fqdn.com:11212:2')
|
63
|
+
assert_equal 'my.fqdn.com', s.hostname
|
64
|
+
assert_equal 11212, s.port
|
65
|
+
assert_equal 2, s.weight
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'ttl translation' do
|
70
|
+
it 'does not translate ttls under 30 days' do
|
71
|
+
s = Dalli::Server.new('localhost')
|
72
|
+
assert_equal s.send(:sanitize_ttl, 30*24*60*60), 30*24*60*60
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'translates ttls over 30 days into timestamps' do
|
76
|
+
s = Dalli::Server.new('localhost')
|
77
|
+
assert_equal s.send(:sanitize_ttl, 30*24*60*60 + 1), Time.now.to_i + 30*24*60*60+1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,65 +1,73 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dalli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 4.2.0
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 4.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: mocha
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rails
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '4'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '4'
|
55
55
|
description: High performance memcached client for Ruby
|
56
56
|
email: mperham@gmail.com
|
57
57
|
executables: []
|
58
58
|
extensions: []
|
59
59
|
extra_rdoc_files: []
|
60
60
|
files:
|
61
|
+
- Gemfile
|
62
|
+
- History.md
|
63
|
+
- LICENSE
|
64
|
+
- Performance.md
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- dalli.gemspec
|
61
68
|
- lib/action_dispatch/middleware/session/dalli_store.rb
|
62
69
|
- lib/active_support/cache/dalli_store.rb
|
70
|
+
- lib/dalli.rb
|
63
71
|
- lib/dalli/cas/client.rb
|
64
72
|
- lib/dalli/client.rb
|
65
73
|
- lib/dalli/compressor.rb
|
@@ -69,15 +77,7 @@ files:
|
|
69
77
|
- lib/dalli/server.rb
|
70
78
|
- lib/dalli/socket.rb
|
71
79
|
- lib/dalli/version.rb
|
72
|
-
- lib/dalli.rb
|
73
80
|
- lib/rack/session/dalli.rb
|
74
|
-
- LICENSE
|
75
|
-
- README.md
|
76
|
-
- History.md
|
77
|
-
- Rakefile
|
78
|
-
- Gemfile
|
79
|
-
- dalli.gemspec
|
80
|
-
- Performance.md
|
81
81
|
- test/benchmark_test.rb
|
82
82
|
- test/helper.rb
|
83
83
|
- test/memcached_mock.rb
|
@@ -93,28 +93,29 @@ files:
|
|
93
93
|
- test/test_ring.rb
|
94
94
|
- test/test_sasl.rb
|
95
95
|
- test/test_serializer.rb
|
96
|
+
- test/test_server.rb
|
96
97
|
homepage: http://github.com/mperham/dalli
|
97
98
|
licenses:
|
98
99
|
- MIT
|
99
100
|
metadata: {}
|
100
101
|
post_install_message:
|
101
102
|
rdoc_options:
|
102
|
-
- --charset=UTF-8
|
103
|
+
- "--charset=UTF-8"
|
103
104
|
require_paths:
|
104
105
|
- lib
|
105
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
107
|
requirements:
|
107
|
-
- -
|
108
|
+
- - ">="
|
108
109
|
- !ruby/object:Gem::Version
|
109
110
|
version: '0'
|
110
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
112
|
requirements:
|
112
|
-
- -
|
113
|
+
- - ">="
|
113
114
|
- !ruby/object:Gem::Version
|
114
115
|
version: '0'
|
115
116
|
requirements: []
|
116
117
|
rubyforge_project:
|
117
|
-
rubygems_version: 2.
|
118
|
+
rubygems_version: 2.2.2
|
118
119
|
signing_key:
|
119
120
|
specification_version: 4
|
120
121
|
summary: High performance memcached client for Ruby
|
@@ -134,3 +135,4 @@ test_files:
|
|
134
135
|
- test/test_ring.rb
|
135
136
|
- test/test_sasl.rb
|
136
137
|
- test/test_serializer.rb
|
138
|
+
- test/test_server.rb
|