dalli 1.1.5 → 2.0.0
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 +0 -2
- data/History.md +23 -5
- data/Performance.md +26 -69
- data/README.md +13 -22
- data/dalli.gemspec +1 -4
- data/lib/active_support/cache/dalli_store.rb +121 -104
- data/lib/dalli.rb +0 -6
- data/lib/dalli/client.rb +23 -28
- data/lib/dalli/server.rb +9 -14
- data/lib/dalli/socket.rb +19 -113
- data/lib/dalli/version.rb +1 -1
- data/test/helper.rb +0 -1
- data/test/memcached_mock.rb +2 -15
- data/test/test_active_support.rb +9 -52
- data/test/test_dalli.rb +67 -56
- metadata +10 -29
- data/Upgrade.md +0 -45
- data/lib/active_support/cache/dalli_store23.rb +0 -172
- data/lib/dalli/compatibility.rb +0 -52
- data/lib/dalli/memcache-client.rb +0 -1
- data/test/test_compatibility.rb +0 -33
- data/test/test_synchrony.rb +0 -175
data/Gemfile
CHANGED
data/History.md
CHANGED
@@ -1,11 +1,29 @@
|
|
1
1
|
Dalli Changelog
|
2
2
|
=====================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
2.0.0
|
5
|
+
=======
|
6
|
+
|
7
|
+
- Reimplemented the Rails' dalli\_store to remove use of
|
8
|
+
ActiveSupport::Cache::Entry which added 109 bytes overhead to every
|
9
|
+
value stored, was a performance bottleneck and duplicated a lot of
|
10
|
+
functionality already in Dalli. One benchmark went from 4.0 sec to 3.0
|
11
|
+
sec with the new dalli\_store. [#173]
|
12
|
+
- Added reset\_stats operation [#155]
|
13
|
+
- Added support for configuring keepalive on TCP connections to memcached servers (@bianster, #180)
|
14
|
+
|
15
|
+
Notes:
|
16
|
+
|
17
|
+
* data stored with dalli\_store 2.x is NOT backwards compatible with 1.x.
|
18
|
+
Upgraders are advised to namespace their keys and roll out the 2.x
|
19
|
+
upgrade slowly so keys do not clash and caches are warmed.
|
20
|
+
`config.cache_store = :dalli_store, :expires_in => 24.hours.to_i, :namespace => 'myapp2'`
|
21
|
+
* data stored with plain Dalli::Client API is unchanged.
|
22
|
+
* removed support for dalli\_store's race\_condition\_ttl option.
|
23
|
+
* removed support for em-synchrony and unix socket connection options.
|
24
|
+
* removed support for Ruby 1.8.6
|
25
|
+
* removed memcache-client compability layer and upgrade documentation.
|
7
26
|
|
8
|
-
gem 'dalli', '~> 1.1'
|
9
27
|
|
10
28
|
1.1.5
|
11
29
|
=======
|
@@ -84,7 +102,7 @@ v1.1.0 was a bad release. Yanked.
|
|
84
102
|
- Allow browser session cookies (blindsey)
|
85
103
|
- Compatibility fixes (mwynholds)
|
86
104
|
- Add backwards compatibility module for memcache-client, require 'dalli/memcache-client'. It makes
|
87
|
-
Dalli more compatible with memcache-client and prints out a warning any time you do something that
|
105
|
+
Dalli more compatible with memcache-client and prints out a warning any time you do something that
|
88
106
|
is no longer supported so you can fix your code.
|
89
107
|
|
90
108
|
1.0.1
|
data/Performance.md
CHANGED
@@ -2,84 +2,41 @@ Performance
|
|
2
2
|
====================
|
3
3
|
|
4
4
|
Caching is all about performance, so I carefully track Dalli performance to ensure no regressions.
|
5
|
-
|
5
|
+
You can optionally use kgio to give Dalli a 10-20% performance boost: `gem install kgio`.
|
6
6
|
|
7
|
-
|
7
|
+
Note I've added some benchmarks over time to Dalli that the other libraries don't necessarily have.
|
8
8
|
|
9
9
|
memcache-client
|
10
10
|
---------------
|
11
11
|
|
12
|
-
Testing 1.8.5 with ruby 1.9.
|
12
|
+
Testing 1.8.5 with ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
incr:ruby:memcache 0.700000 0.120000 0.820000 ( 0.842896)
|
14
|
+
user system total real
|
15
|
+
set:plain:memcache-client 1.860000 0.310000 2.170000 ( 2.188030)
|
16
|
+
set:ruby:memcache-client 1.830000 0.290000 2.120000 ( 2.130212)
|
17
|
+
get:plain:memcache-client 1.830000 0.340000 2.170000 ( 2.176156)
|
18
|
+
get:ruby:memcache-client 1.900000 0.330000 2.230000 ( 2.235045)
|
19
|
+
multiget:ruby:memcache-client 0.860000 0.120000 0.980000 ( 0.987348)
|
20
|
+
missing:ruby:memcache-client 1.630000 0.320000 1.950000 ( 1.954867)
|
21
|
+
mixed:ruby:memcache-client 3.690000 0.670000 4.360000 ( 4.364469)
|
23
22
|
|
24
|
-
libmemcached
|
25
|
-
------------
|
26
|
-
|
27
|
-
Testing 1.1.2 with ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-darwin10.6.0]
|
28
|
-
|
29
|
-
user system total real
|
30
|
-
set:plain:libm 0.120000 0.220000 0.340000 ( 0.847521)
|
31
|
-
setq:plain:libm 0.030000 0.000000 0.030000 ( 0.126944)
|
32
|
-
set:ruby:libm 0.220000 0.250000 0.470000 ( 1.102789)
|
33
|
-
get:plain:libm 0.140000 0.230000 0.370000 ( 0.813998)
|
34
|
-
get:ruby:libm 0.210000 0.240000 0.450000 ( 1.025994)
|
35
|
-
multiget:ruby:libm 0.100000 0.080000 0.180000 ( 0.322217)
|
36
|
-
missing:ruby:libm 0.250000 0.240000 0.490000 ( 1.049972)
|
37
|
-
mixed:ruby:libm 0.400000 0.410000 0.810000 ( 2.172349)
|
38
|
-
mixedq:ruby:libm 0.410000 0.360000 0.770000 ( 1.516718)
|
39
|
-
incr:ruby:libm 0.080000 0.340000 0.420000 ( 1.685931)
|
40
23
|
|
41
24
|
dalli
|
42
25
|
-----
|
43
26
|
|
27
|
+
Testing with Rails 3.2.1
|
44
28
|
Using kgio socket IO
|
45
|
-
Testing
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
Testing 1.0.2 with rubinius 1.3.0dev (1.8.7 382e813f xxxx-xx-xx JI) [x86_64-apple-darwin10.6.0]
|
60
|
-
|
61
|
-
user system total real
|
62
|
-
set:plain:dalli 2.800581 0.329360 3.129941 ( 5.186546)
|
63
|
-
setq:plain:dalli 1.064253 0.138044 1.202297 ( 1.280355)
|
64
|
-
set:ruby:dalli 2.220885 0.262619 2.483504 ( 2.778118)
|
65
|
-
get:plain:dalli 2.291344 0.280490 2.571834 ( 2.948004)
|
66
|
-
get:ruby:dalli 2.148900 0.274477 2.423377 ( 2.425808)
|
67
|
-
multiget:ruby:dalli 1.724193 0.249145 1.973338 ( 2.158673)
|
68
|
-
missing:ruby:dalli 1.881502 0.272610 2.154112 ( 2.208384)
|
69
|
-
mixed:ruby:dalli 4.292620 0.533768 4.826388 ( 4.830238)
|
70
|
-
mixedq:ruby:dalli 4.076032 0.501442 4.577474 ( 4.583800)
|
71
|
-
incr:ruby:dalli 0.691467 0.091475 0.782942 ( 0.931674)
|
72
|
-
|
73
|
-
Testing 1.0.2 with rubinius 1.2.0 (1.8.7 release 2010-12-21 JI) [x86_64-apple-darwin10.6.0]
|
74
|
-
|
75
|
-
user system total real
|
76
|
-
set:plain:dalli 6.586927 0.331545 6.918472 ( 4.628652)
|
77
|
-
setq:plain:dalli 0.930905 0.129008 1.059913 ( 1.016105)
|
78
|
-
set:ruby:dalli 2.702486 0.283004 2.985490 ( 2.690442)
|
79
|
-
get:plain:dalli 2.740202 0.291353 3.031555 ( 2.722746)
|
80
|
-
get:ruby:dalli 1.979379 0.282986 2.262365 ( 2.264118)
|
81
|
-
multiget:ruby:dalli 1.887086 0.249799 2.136885 ( 1.803230)
|
82
|
-
missing:ruby:dalli 1.882662 0.278019 2.160681 ( 2.113429)
|
83
|
-
mixed:ruby:dalli 3.969242 0.553361 4.522603 ( 4.524504)
|
84
|
-
mixedq:ruby:dalli 3.520755 0.475669 3.996424 ( 3.997405)
|
85
|
-
incr:ruby:dalli 0.849998 0.094012 0.944010 ( 0.884001)
|
29
|
+
Testing 2.0.0 with ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.3.0]
|
30
|
+
|
31
|
+
user system total real
|
32
|
+
mixed:rails:dalli 1.580000 0.570000 2.150000 ( 3.008839)
|
33
|
+
set:plain:dalli 0.730000 0.300000 1.030000 ( 1.567098)
|
34
|
+
setq:plain:dalli 0.520000 0.120000 0.640000 ( 0.634402)
|
35
|
+
set:ruby:dalli 0.800000 0.300000 1.100000 ( 1.640348)
|
36
|
+
get:plain:dalli 0.840000 0.330000 1.170000 ( 1.668425)
|
37
|
+
get:ruby:dalli 0.850000 0.330000 1.180000 ( 1.665716)
|
38
|
+
multiget:ruby:dalli 0.700000 0.260000 0.960000 ( 0.965423)
|
39
|
+
missing:ruby:dalli 0.720000 0.320000 1.040000 ( 1.511720)
|
40
|
+
mixed:ruby:dalli 1.660000 0.640000 2.300000 ( 3.320743)
|
41
|
+
mixedq:ruby:dalli 1.630000 0.510000 2.140000 ( 2.629734)
|
42
|
+
incr:ruby:dalli 0.270000 0.100000 0.370000 ( 0.547618)
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Dalli
|
2
2
|
=========
|
3
3
|
|
4
|
-
Dalli is a high performance pure Ruby client for accessing memcached servers. It works with memcached 1.4+ only as it uses the newer binary protocol. It should be considered a replacement for the memcache-client gem.
|
4
|
+
Dalli is a high performance pure Ruby client for accessing memcached servers. It works with memcached 1.4+ only as it uses the newer binary protocol. It should be considered a replacement for the memcache-client gem.
|
5
5
|
|
6
6
|
The name is a variant of Salvador Dali for his famous painting [The Persistence of Memory](http://en.wikipedia.org/wiki/The_Persistence_of_Memory).
|
7
7
|
|
@@ -25,10 +25,8 @@ So a few notes. Dalli:
|
|
25
25
|
0. uses the exact same algorithm to choose a server so existing memcached clusters with TBs of data will work identically to memcache-client.
|
26
26
|
1. is approximately 20% faster than memcache-client (which itself was heavily optimized) in Ruby 1.9.2.
|
27
27
|
2. contains explicit "chokepoint" methods which handle all requests; these can be hooked into by monitoring tools (NewRelic, Rack::Bug, etc) to track memcached usage.
|
28
|
-
3.
|
29
|
-
4.
|
30
|
-
5. provides proper failover with recovery and adjustable timeouts
|
31
|
-
6. has a backwards-compatibility mode for people migrating from memcache-client (see Upgrade.md).
|
28
|
+
3. supports SASL for use in managed environments, e.g. Heroku.
|
29
|
+
4. provides proper failover with recovery and adjustable timeouts
|
32
30
|
|
33
31
|
|
34
32
|
Supported Ruby versions and implementations
|
@@ -47,8 +45,7 @@ If you have problems, please enter an issue.
|
|
47
45
|
Installation and Usage
|
48
46
|
------------------------
|
49
47
|
|
50
|
-
Remember, Dalli **requires** memcached 1.4+. You can check the version with `memcached -h`. Please note that memcached that Mac OS X Snow Leopard ships with is 1.2.8 and
|
51
|
-
won't work. Install 1.4.x using Homebrew with
|
48
|
+
Remember, Dalli **requires** memcached 1.4+. You can check the version with `memcached -h`. Please note that memcached that Mac OS X Snow Leopard ships with is 1.2.8 and won't work. Install 1.4.x using Homebrew with
|
52
49
|
|
53
50
|
brew install memcached
|
54
51
|
|
@@ -65,7 +62,7 @@ You can verify your installation using this piece of code:
|
|
65
62
|
The test suite requires memcached 1.4.3+ with SASL enabled (brew install memcached --enable-sasl ; mv /usr/bin/memcached /usr/bin/memcached.old). Currently only supports the PLAIN mechanism.
|
66
63
|
|
67
64
|
Dalli has no runtime dependencies and never will. You can optionally install the 'kgio' gem to
|
68
|
-
give Dalli a
|
65
|
+
give Dalli a 20-30% performance boost.
|
69
66
|
|
70
67
|
|
71
68
|
Usage with Rails 3.x
|
@@ -79,21 +76,17 @@ In `config/environments/production.rb`:
|
|
79
76
|
|
80
77
|
config.cache_store = :dalli_store
|
81
78
|
|
82
|
-
|
79
|
+
Here's a more comprehensive example that sets a reasonable default for maximum cache entry lifetime (one day), enables compression for large values and namespaces all entries for this rails app. Remove the namespace if you have multiple apps which share cached values.
|
83
80
|
|
84
81
|
config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
|
85
|
-
{ :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :
|
82
|
+
{ :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
|
86
83
|
|
87
84
|
To use Dalli for Rails session storage, in `config/initializers/session_store.rb`:
|
88
85
|
|
89
86
|
require 'action_dispatch/middleware/session/dalli_store'
|
90
87
|
Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 30.minutes
|
91
88
|
|
92
|
-
|
93
|
-
Usage with Rails 2.3.x
|
94
|
-
----------------------------
|
95
|
-
|
96
|
-
Dalli v1.1+ does not support Rails 2.3. Please use an earlier version: gem install dalli -v "~> 1.0.4"
|
89
|
+
Dalli does not support Rails 2.x any longer.
|
97
90
|
|
98
91
|
|
99
92
|
Usage with Passenger
|
@@ -122,7 +115,7 @@ Dalli::Client accepts the following options. All times are in seconds.
|
|
122
115
|
|
123
116
|
**failover**: Boolean, if true Dalli will failover to another server if the main server for a key is down.
|
124
117
|
|
125
|
-
**
|
118
|
+
**compress**: Boolean, if true Dalli will gzip-compress values larger than 1K.
|
126
119
|
|
127
120
|
**socket_timeout**: Timeout for all socket operations (connect, read, write). Default is 0.5.
|
128
121
|
|
@@ -138,17 +131,13 @@ Dalli::Client accepts the following options. All times are in seconds.
|
|
138
131
|
|
139
132
|
**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.
|
140
133
|
|
141
|
-
**
|
134
|
+
**keepalive**: Boolean, if true Dalli will enable keep-alives on the socket so inactivity
|
142
135
|
|
143
136
|
Features and Changes
|
144
137
|
------------------------
|
145
138
|
|
146
|
-
Dalli is **NOT** 100% API compatible with memcache-client. If you have code which uses the MemCache API directly, it will likely need small tweaks. Method parameters and return values changed slightly. See Upgrade.md for more detail.
|
147
|
-
|
148
139
|
By default, Dalli is thread-safe. Disable thread-safety at your own peril.
|
149
140
|
|
150
|
-
Multi-threaded use will fail if used with EventMachine.
|
151
|
-
|
152
141
|
Note that Dalli does not require ActiveSupport or Rails. You can safely use it in your own Ruby projects.
|
153
142
|
|
154
143
|
|
@@ -171,7 +160,9 @@ Brian Mitchell - for his remix-stash project which was helpful when implementing
|
|
171
160
|
Author
|
172
161
|
----------
|
173
162
|
|
174
|
-
Mike Perham, mperham@gmail.com, [mikeperham.com](http://mikeperham.com), [@mperham](http://twitter.com/mperham) If you like and use this project, please give me a recommendation at [WWR](http://workingwithrails.com/person/10797-mike-perham). Happy caching!
|
163
|
+
Mike Perham, mperham@gmail.com, [mikeperham.com](http://mikeperham.com), [@mperham](http://twitter.com/mperham) If you like and use this project, please give me a recommendation at [WWR](http://workingwithrails.com/person/10797-mike-perham) or send a few bucks my way via my Pledgie page below. Happy caching!
|
164
|
+
|
165
|
+
<a href='http://www.pledgie.com/campaigns/16623'><img alt='Click here to lend your support to Open Source and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/16623.png?skin_name=chrome' border='0' /></a>
|
175
166
|
|
176
167
|
|
177
168
|
Copyright
|
data/dalli.gemspec
CHANGED
@@ -5,7 +5,6 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.version = Dalli::VERSION
|
6
6
|
|
7
7
|
s.authors = ["Mike Perham"]
|
8
|
-
s.date = Time.now.utc.strftime("%Y-%m-%d")
|
9
8
|
s.description = %q{High performance memcached client for Ruby}
|
10
9
|
s.email = %q{mperham@gmail.com}
|
11
10
|
s.files = Dir.glob("lib/**/*") + [
|
@@ -16,7 +15,6 @@ Gem::Specification.new do |s|
|
|
16
15
|
"Gemfile",
|
17
16
|
"dalli.gemspec",
|
18
17
|
"Performance.md",
|
19
|
-
"Upgrade.md",
|
20
18
|
]
|
21
19
|
s.homepage = %q{http://github.com/mperham/dalli}
|
22
20
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -25,7 +23,6 @@ Gem::Specification.new do |s|
|
|
25
23
|
s.test_files = Dir.glob("test/**/*")
|
26
24
|
s.add_development_dependency(%q<mini_shoulda>, [">= 0"])
|
27
25
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
28
|
-
s.add_development_dependency(%q<rails>, ["
|
29
|
-
s.add_development_dependency(%q<memcache-client>, [">= 1.8.5"])
|
26
|
+
s.add_development_dependency(%q<rails>, ["~> 3"])
|
30
27
|
end
|
31
28
|
|
@@ -1,24 +1,12 @@
|
|
1
1
|
# encoding: ascii
|
2
|
-
|
3
|
-
require 'dalli'
|
4
|
-
rescue LoadError => e
|
5
|
-
$stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
6
|
-
raise e
|
7
|
-
end
|
2
|
+
require 'dalli'
|
8
3
|
require 'digest/md5'
|
9
|
-
require 'active_support/cache'
|
10
4
|
|
11
5
|
module ActiveSupport
|
12
6
|
module Cache
|
13
|
-
|
14
|
-
# http://www.memcached.org
|
15
|
-
#
|
16
|
-
# DalliStore implements the Strategy::LocalCache strategy which implements
|
17
|
-
# an in memory cache inside of a block.
|
18
|
-
class DalliStore < Store
|
7
|
+
class DalliStore
|
19
8
|
|
20
9
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/
|
21
|
-
RAW = { :raw => true }
|
22
10
|
|
23
11
|
# Creates a new DalliStore object, with the given memcached server
|
24
12
|
# addresses. Each address is either a host name, or a host-with-port string
|
@@ -32,33 +20,73 @@ module ActiveSupport
|
|
32
20
|
def initialize(*addresses)
|
33
21
|
addresses = addresses.flatten
|
34
22
|
options = addresses.extract_options!
|
35
|
-
|
36
|
-
|
23
|
+
options[:compression] = options.delete(:compress) || options[:compression]
|
37
24
|
addresses << 'localhost:11211' if addresses.empty?
|
38
|
-
options = options.dup
|
39
|
-
options.delete(:namespace)
|
40
|
-
# Extend expiry by stale TTL or else memcached will never return stale data.
|
41
|
-
# See ActiveSupport::Cache#fetch.
|
42
|
-
options[:expires_in] += options[:race_condition_ttl] if options[:expires_in] && options[:race_condition_ttl]
|
43
25
|
@data = Dalli::Client.new(addresses, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch(name, options={})
|
29
|
+
if block_given?
|
30
|
+
unless options[:force]
|
31
|
+
entry = instrument(:read, name, options) do |payload|
|
32
|
+
payload[:super_operation] = :fetch if payload
|
33
|
+
read_entry(name, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if entry
|
38
|
+
instrument(:fetch_hit, name, options) { |payload| }
|
39
|
+
entry
|
40
|
+
else
|
41
|
+
result = instrument(:generate, name, options) do |payload|
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
write(name, result, options)
|
45
|
+
result
|
46
|
+
end
|
47
|
+
else
|
48
|
+
read(name, options)
|
49
|
+
end
|
50
|
+
end
|
44
51
|
|
45
|
-
|
46
|
-
|
52
|
+
def read(name, options={})
|
53
|
+
instrument(:read, name, options) do |payload|
|
54
|
+
entry = read_entry(name, options)
|
55
|
+
payload[:hit] = !!entry if payload
|
56
|
+
entry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def write(name, value, options={})
|
61
|
+
instrument(:write, name, options) do |payload|
|
62
|
+
write_entry(name, value, options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def exist?(name, options={})
|
67
|
+
!!read_entry(name, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def delete(name, options={})
|
71
|
+
@data.delete(name)
|
47
72
|
end
|
48
73
|
|
49
74
|
# Reads multiple keys from the cache using a single call to the
|
50
|
-
# servers for all keys.
|
75
|
+
# servers for all keys. Keys must be Strings.
|
51
76
|
def read_multi(*names)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
77
|
+
names.extract_options!
|
78
|
+
names = names.flatten
|
79
|
+
|
80
|
+
mapping = names.inject({}) { |memo, name| memo[escape(name)] = name; memo }
|
81
|
+
instrument(:read_multi, names) do
|
82
|
+
results = @data.get_multi(mapping.keys)
|
83
|
+
results.inject({}) do |memo, (inner, value)|
|
84
|
+
entry = results[inner]
|
85
|
+
# NB Backwards data compatibility, to be removed at some point
|
86
|
+
memo[mapping[inner]] = (entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry)
|
87
|
+
memo
|
88
|
+
end
|
60
89
|
end
|
61
|
-
values
|
62
90
|
end
|
63
91
|
|
64
92
|
# Increment a cached value. This method uses the memcached incr atomic
|
@@ -66,12 +94,11 @@ module ActiveSupport
|
|
66
94
|
# Calling it on a value not stored with :raw will fail.
|
67
95
|
# :initial defaults to the amount passed in, as if the counter was initially zero.
|
68
96
|
# memcached counters cannot hold negative values.
|
69
|
-
def increment(name, amount = 1, options
|
70
|
-
options = merged_options(options)
|
97
|
+
def increment(name, amount = 1, options={}) # :nodoc:
|
71
98
|
initial = options[:initial] || amount
|
72
|
-
expires_in = options[:expires_in]
|
73
|
-
|
74
|
-
@data.incr(
|
99
|
+
expires_in = options[:expires_in]
|
100
|
+
instrument(:increment, name, :amount => amount) do
|
101
|
+
@data.incr(name, amount, expires_in, initial)
|
75
102
|
end
|
76
103
|
rescue Dalli::DalliError => e
|
77
104
|
logger.error("DalliError: #{e.message}") if logger
|
@@ -83,12 +110,11 @@ module ActiveSupport
|
|
83
110
|
# Calling it on a value not stored with :raw will fail.
|
84
111
|
# :initial defaults to zero, as if the counter was initially zero.
|
85
112
|
# memcached counters cannot hold negative values.
|
86
|
-
def decrement(name, amount = 1, options
|
87
|
-
options = merged_options(options)
|
113
|
+
def decrement(name, amount = 1, options={}) # :nodoc:
|
88
114
|
initial = options[:initial] || 0
|
89
|
-
expires_in = options[:expires_in]
|
90
|
-
|
91
|
-
@data.decr(
|
115
|
+
expires_in = options[:expires_in]
|
116
|
+
instrument(:decrement, name, :amount => amount) do
|
117
|
+
@data.decr(name, amount, expires_in, initial)
|
92
118
|
end
|
93
119
|
rescue Dalli::DalliError => e
|
94
120
|
logger.error("DalliError: #{e.message}") if logger
|
@@ -97,7 +123,7 @@ module ActiveSupport
|
|
97
123
|
|
98
124
|
# Clear the entire cache on all memcached servers. This method should
|
99
125
|
# be used with care when using a shared cache.
|
100
|
-
def clear(options
|
126
|
+
def clear(options=nil)
|
101
127
|
@data.flush_all
|
102
128
|
end
|
103
129
|
|
@@ -112,74 +138,65 @@ module ActiveSupport
|
|
112
138
|
|
113
139
|
protected
|
114
140
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
nil
|
125
|
-
end
|
141
|
+
# Read an entry from the cache.
|
142
|
+
def read_entry(key, options) # :nodoc:
|
143
|
+
entry = @data.get(escape(key), options)
|
144
|
+
# NB Backwards data compatibility, to be removed at some point
|
145
|
+
entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry
|
146
|
+
rescue Dalli::DalliError => e
|
147
|
+
logger.error("DalliError: #{e.message}") if logger
|
148
|
+
nil
|
149
|
+
end
|
126
150
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
@data.send(method, escape_key(key), value, expires_in, options)
|
137
|
-
rescue Dalli::DalliError => e
|
138
|
-
logger.error("DalliError: #{e.message}") if logger
|
139
|
-
false
|
140
|
-
end
|
151
|
+
# Write an entry to the cache.
|
152
|
+
def write_entry(key, value, options) # :nodoc:
|
153
|
+
method = options[:unless_exist] ? :add : :set
|
154
|
+
expires_in = options[:expires_in]
|
155
|
+
@data.send(method, escape(key), value, expires_in, options)
|
156
|
+
rescue Dalli::DalliError => e
|
157
|
+
logger.error("DalliError: #{e.message}") if logger
|
158
|
+
false
|
159
|
+
end
|
141
160
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
161
|
+
# Delete an entry from the cache.
|
162
|
+
def delete_entry(key, options) # :nodoc:
|
163
|
+
@data.delete(escape(key))
|
164
|
+
rescue Dalli::DalliError => e
|
165
|
+
logger.error("DalliError: #{e.message}") if logger
|
166
|
+
false
|
167
|
+
end
|
149
168
|
|
150
169
|
private
|
151
|
-
def escape_key(key)
|
152
|
-
key = key.to_s.dup
|
153
|
-
key = key.force_encoding('BINARY') if key.respond_to? :force_encoding
|
154
|
-
key = key.gsub(ESCAPE_KEY_CHARS){|match| "%#{match.getbyte(0).to_s(16).upcase}"}
|
155
|
-
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
156
|
-
key
|
157
|
-
end
|
158
170
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
171
|
+
def escape(key)
|
172
|
+
key = key.to_s.dup
|
173
|
+
key = key.force_encoding("BINARY") if key.encoding_aware?
|
174
|
+
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
175
|
+
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
|
176
|
+
key
|
177
|
+
end
|
178
|
+
|
179
|
+
def instrument(operation, key, options = nil)
|
180
|
+
log(operation, key, options)
|
181
|
+
|
182
|
+
if ActiveSupport::Cache::Store.instrument
|
183
|
+
payload = { :key => key }
|
184
|
+
payload.merge!(options) if options.is_a?(Hash)
|
185
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
186
|
+
else
|
187
|
+
yield(nil)
|
168
188
|
end
|
189
|
+
end
|
169
190
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
def write_entry(key, entry, options) # :nodoc:
|
174
|
-
retval = super
|
175
|
-
if options[:raw] && local_cache && retval
|
176
|
-
raw_entry = Entry.new(entry.value.to_s)
|
177
|
-
raw_entry.expires_at = entry.expires_at
|
178
|
-
local_cache.write_entry(key, raw_entry, options)
|
179
|
-
end
|
180
|
-
retval
|
181
|
-
end
|
191
|
+
def log(operation, key, options = nil)
|
192
|
+
return unless logger && logger.debug?
|
193
|
+
logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
|
182
194
|
end
|
195
|
+
|
196
|
+
def logger
|
197
|
+
Dalli.logger
|
198
|
+
end
|
199
|
+
|
183
200
|
end
|
184
201
|
end
|
185
202
|
end
|