Skip to content
Snippets Groups Projects
Commit 8f75d11a authored by Apertis package maintainers's avatar Apertis package maintainers
Browse files

Import Upstream version 2.7.11

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #498517 skipped
Showing with 1660 additions and 0 deletions
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/test/tmp/
/test/version_tmp/
/tmp/
## Specific to RubyMotion:
.dat*
.repl_history
build/
## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/html/
/rdoc/
## Environment normalisation:
/.bundle/
/lib/bundler/man/
# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
Gemfile.lock
gemfiles/*.lock
.ruby-version
.ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
language: ruby
cache: bundler
rvm:
- 2.7
- 2.6
- 2.5
- jruby
gemfile:
- gemfiles/rails5.0.gemfile
- gemfiles/rails5.1.gemfile
- gemfiles/rails5.2.gemfile
- gemfiles/rails6.0.gemfile
matrix:
fast_finish: true
env:
global:
- JRUBY_OPTS='--debug'
script:
- bundle exec rake
before_install:
- gem install bundler
- sudo apt-get -y remove memcached
- sudo apt-get install libevent-dev
- wget https://memcached.org/files/memcached-1.5.20.tar.gz
- tar -zxvf memcached-1.5.20.tar.gz
- cd memcached-1.5.20
- ./configure --enable-sasl
- make
- sudo make install
appraise 'rails5.0' do
gem 'rails', '~> 5.0.0'
end
appraise 'rails5.1' do
gem 'rails', '~> 5.1.0'
end
appraise 'rails5.2' do
gem 'rails', '~> 5.2.0'
end
appraise 'rails6.0' do
gem 'rails', '~> 6.0.0'
end
Gemfile 0 → 100644
source 'https://rubygems.org'
gemspec
gem 'appraisal'
gem 'kgio', :platform => :mri
gem 'rails'
group :test do
gem 'minitest'
gem 'mocha'
gem 'rake'
gem 'connection_pool'
gem 'simplecov'
end
Dalli Changelog
=====================
2.7.11
==========
- DEPRECATION: :dalli_store will be removed in Dalli 3.0.
Use Rails' official :mem_cache_store instead.
https://guides.rubyonrails.org/caching_with_rails.html
- Add new `digest_class` option to Dalli::Client [#724]
- Don't treat NameError as a network error [#728]
- Handle nested comma separated server strings (sambostock)
2.7.10
==========
- Revert frozen string change (schneems)
- Advertise supports_cached_versioning? in DalliStore (schneems)
- Better detection of fork support, to allow specs to run under Truffle Ruby (deepj)
- Update logging for over max size to log as error (aeroastro)
2.7.9
==========
- Fix behavior for Rails 5.2+ cache_versioning (GriwMF)
- Ensure fetch provides the key to the fallback block as an argument (0exp)
- Assorted performance improvements (schneems)
2.7.8
==========
- Rails 5.2 compatibility (pbougie)
- Fix Session Cache compatibility (pixeltrix)
2.7.7
==========
- Support large cache keys on fetch multi (sobrinho)
- Not found checks no longer trigger the result's equality method (dannyfallon)
- Use SVG build badges (olleolleolle)
- Travis updates (junaruga, tiarly, petergoldstein)
- Update default down_retry_delay (jaredhales)
- Close kgio socket after IO.select timeouts
- Documentation updates (tipair)
- Instrument DalliStore errors with instrument_errors configuration option. (btatnall)
2.7.6
==========
- Rails 5.0.0.beta2 compatibility (yui-knk, petergoldstein)
- Add cas!, a variant of the #cas method that yields to the block whether or not the key already exist (mwpastore)
- Performance improvements (nateberkopec)
- Add Ruby 2.3.0 to support matrix (tricknotes)
2.7.5
==========
- Support rcvbuff and sndbuff byte configuration. (btatnall)
- Add `:cache_nils` option to support nil values in `DalliStore#fetch` and `Dalli::Client#fetch` (wjordan, #559)
- Log retryable server errors with 'warn' instead of 'info' (phrinx)
- Fix timeout issue with Dalli::Client#get_multi_yielder (dspeterson)
- Escape namespaces with special regexp characters (Steven Peckins)
- Ensure LocalCache supports the `:raw` option and Entry unwrapping (sj26)
- Ensure bad ttl values don't cause Dalli::RingError (eagletmt, petergoldstein)
- Always pass namespaced key to instrumentation API (kaorimatz)
- Replace use of deprecated TimeoutError with Timeout::Error (eagletmt)
- Clean up gemspec, and use Bundler for loading (grosser)
- Dry up local cache testing (grosser)
2.7.4
==========
- Restore Windows compatibility (dfens, #524)
2.7.3
==========
- Assorted spec improvements
- README changes to specify defaults for failover and compress options (keen99, #470)
- SASL authentication changes to deal with Unicode characters (flypiggy, #477)
- Call to_i on ttl to accomodate ActiveSupport::Duration (#494)
- Change to implicit blocks for performance (glaucocustodio, #495)
- Change to each_key for performance (jastix, #496)
- Support stats settings - (dterei, #500)
- Raise DallError if hostname canno be parsed (dannyfallon, #501)
- Fix instrumentation for falsey values (AlexRiedler, #514)
- Support UNIX socket configurations (r-stu31, #515)
2.7.2
==========
- The fix for #423 didn't make it into the released 2.7.1 gem somehow.
2.7.1
==========
- Rack session will check if servers are up on initialization (arthurnn, #423)
- Add support for IPv6 addresses in hex form, ie: "[::1]:11211" (dplummer, #428)
- Add symbol support for namespace (jingkai #431)
- Support expiration intervals longer than 30 days (leonid-shevtsov #436)
2.7.0
==========
- BREAKING CHANGE:
Dalli::Client#add and #replace now return a truthy value, not boolean true or false.
- Multithreading support with dalli\_store:
Use :pool\_size to create a pool of shared, threadsafe Dalli clients in Rails:
```ruby
config.cache_store = :dalli_store, "cache-1.example.com", "cache-2.example.com", :compress => true, :pool_size => 5, :expires_in => 300
```
This will ensure the Rails.cache singleton does not become a source of contention.
**PLEASE NOTE** Rails's :mem\_cache\_store does not support pooling as of
Rails 4.0. You must use :dalli\_store.
- Implement `version` for retrieving version of connected servers [dterei, #384]
- Implement `fetch_multi` for batched read/write [sorentwo, #380]
- Add more support for safe updates with multiple writers: [philipmw, #395]
`require 'dalli/cas/client'` augments Dalli::Client with the following methods:
* Get value with CAS: `[value, cas] = get_cas(key)`
`get_cas(key) {|value, cas| ...}`
* Get multiple values with CAS: `get_multi_cas(k1, k2, ...) {|value, metadata| cas = metadata[:cas]}`
* Set value with CAS: `new_cas = set_cas(key, value, cas, ttl, options)`
* Replace value with CAS: `replace_cas(key, new_value, cas, ttl, options)`
* Delete value with CAS: `delete_cas(key, cas)`
- Fix bug with get key with "Not found" value [uzzz, #375]
2.6.4
=======
- Fix ADD command, aka `write(unless_exist: true)` (pitr, #365)
- Upgrade test suite from mini\_shoulda to minitest.
- Even more performance improvements for get\_multi (xaop, #331)
2.6.3
=======
- Support specific stats by passing `:items` or `:slabs` to `stats` method [bukhamseen]
- Fix 'can't modify frozen String' errors in `ActiveSupport::Cache::DalliStore` [dblock]
- Protect against objects with custom equality checking [theron17]
- Warn if value for key is too large to store [locriani]
2.6.2
=======
- Properly handle missing RubyInline
2.6.1
=======
- Add optional native C binary search for ring, add:
gem 'RubyInline'
to your Gemfile to get a 10% speedup when using many servers.
You will see no improvement if you are only using one server.
- More get_multi performance optimization [xaop, #315]
- Add lambda support for cache namespaces [joshwlewis, #311]
2.6.0
=======
- read_multi optimization, now checks local_cache [chendo, #306]
- Re-implement get_multi to be non-blocking [tmm1, #295]
- Add `dalli` accessor to dalli_store to access the underlying
Dalli::Client, for things like `get_multi`.
- Add `Dalli::GzipCompressor`, primarily for compatibility with nginx's HttpMemcachedModule using `memcached_gzip_flag`
2.5.0
=======
- Don't escape non-ASCII keys, memcached binary protocol doesn't care. [#257]
- :dalli_store now implements LocalCache [#236]
- Removed lots of old session_store test code, tests now all run without a default memcached server [#275]
- Changed Dalli ActiveSupport adapter to always attempt instrumentation [brianmario, #284]
- Change write operations (add/set/replace) to return false when value is too large to store [brianmario, #283]
- Allowing different compressors per client [naseem]
2.4.0
=======
- Added the ability to swap out the compressed used to [de]compress cache data [brianmario, #276]
- Fix get\_multi performance issues with lots of memcached servers [tmm1]
- Throw more specific exceptions [tmm1]
- Allowing different types of serialization per client [naseem]
2.3.0
=======
- Added the ability to swap out the serializer used to [de]serialize cache data [brianmario, #274]
2.2.1
=======
- Fix issues with ENV-based connections. [#266]
- Fix problem with SessionStore in Rails 4.0 [#265]
2.2.0
=======
- Add Rack session with\_lock helper, for Rails 4.0 support [#264]
- Accept connection string in the form of a URL (e.g., memcached://user:pass@hostname:port) [glenngillen]
- Add touch operation [#228, uzzz]
2.1.0
=======
- Add Railtie to auto-configure Dalli when included in Gemfile [#217, steveklabnik]
2.0.5
=======
- Create proper keys for arrays of objects passed as keys [twinturbo, #211]
- Handle long key with namespace [#212]
- Add NODELAY to TCP socket options [#206]
2.0.4
=======
- Dalli no longer needs to be reset after Unicorn/Passenger fork [#208]
- Add option to re-raise errors rescued in the session and cache stores. [pitr, #200]
- DalliStore#fetch called the block if the cached value == false [#205]
- DalliStore should have accessible options [#195]
- Add silence and mute support for DalliStore [#207]
- Tracked down and fixed socket corruption due to Timeout [#146]
2.0.3
=======
- Allow proper retrieval of stored `false` values [laserlemon, #197]
- Allow non-ascii and whitespace keys, only the text protocol has those restrictions [#145]
- Fix DalliStore#delete error-handling [#196]
2.0.2
=======
- Fix all dalli\_store operations to handle nil options [#190]
- Increment and decrement with :initial => nil now return nil (lawrencepit, #112)
2.0.1
=======
- Fix nil option handling in dalli\_store#write [#188]
2.0.0
=======
- Reimplemented the Rails' dalli\_store to remove use of
ActiveSupport::Cache::Entry which added 109 bytes overhead to every
value stored, was a performance bottleneck and duplicated a lot of
functionality already in Dalli. One benchmark went from 4.0 sec to 3.0
sec with the new dalli\_store. [#173]
- Added reset\_stats operation [#155]
- Added support for configuring keepalive on TCP connections to memcached servers (@bianster, #180)
Notes:
* data stored with dalli\_store 2.x is NOT backwards compatible with 1.x.
Upgraders are advised to namespace their keys and roll out the 2.x
upgrade slowly so keys do not clash and caches are warmed.
`config.cache_store = :dalli_store, :expires_in => 24.hours.to_i, :namespace => 'myapp2'`
* data stored with plain Dalli::Client API is unchanged.
* removed support for dalli\_store's race\_condition\_ttl option.
* removed support for em-synchrony and unix socket connection options.
* removed support for Ruby 1.8.6
* removed memcache-client compability layer and upgrade documentation.
1.1.5
=======
- Coerce input to incr/decr to integer via #to\_i [#165]
- Convert test suite to minitest/spec (crigor, #166)
- Fix encoding issue with keys [#162]
- Fix double namespacing with Rails and dalli\_store. [#160]
1.1.4
=======
- Use 127.0.0.1 instead of localhost as default to avoid IPv6 issues
- Extend DalliStore's :expires\_in when :race\_condition\_ttl is also used.
- Fix :expires\_in option not propogating from DalliStore to Client, GH-136
- Added support for native Rack session store. Until now, Dalli's
session store has required Rails. Now you can use Dalli to store
sessions for any Rack application.
require 'rack/session/dalli'
use Rack::Session::Dalli, :memcache_server => 'localhost:11211', :compression => true
1.1.3
=======
- Support Rails's autoloading hack for loading sessions with objects
whose classes have not be required yet, GH-129
- Support Unix sockets for connectivity. Shows a 2x performance
increase but keep in mind they only work on localhost. (dfens)
1.1.2
=======
- Fix incompatibility with latest Rack session API when destroying
sessions, thanks @twinge!
1.1.1
=======
v1.1.0 was a bad release. Yanked.
1.1.0
=======
- Remove support for Rails 2.3, add support for Rails 3.1
- Fix socket failure retry logic, now you can restart memcached and Dalli won't complain!
- Add support for fibered operation via em-synchrony (eliaslevy)
- Gracefully handle write timeouts, GH-99
- Only issue bug warning for unexpected StandardErrors, GH-102
- Add travis-ci build support (ryanlecompte)
- Gracefully handle errors in get_multi (michaelfairley)
- Misc fixes from crash2burn, fphilipe, igreg, raggi
1.0.5
=======
- Fix socket failure retry logic, now you can restart memcached and Dalli won't complain!
1.0.4
=======
- Handle non-ASCII key content in dalli_store
- Accept key array for read_multi in dalli_store
- Fix multithreaded race condition in creation of mutex
1.0.3
=======
- Better handling of application marshalling errors
- Work around jruby IO#sysread compatibility issue
1.0.2
=======
- Allow browser session cookies (blindsey)
- Compatibility fixes (mwynholds)
- Add backwards compatibility module for memcache-client, require 'dalli/memcache-client'. It makes
Dalli more compatible with memcache-client and prints out a warning any time you do something that
is no longer supported so you can fix your code.
1.0.1
=======
- Explicitly handle application marshalling bugs, GH-56
- Add support for username/password as options, to allow multiple bucket access
from the same Ruby process, GH-52
- Add support for >1MB values with :value_max_bytes option, GH-54 (r-stu31)
- Add support for default TTL, :expires_in, in Rails 2.3. (Steven Novotny)
config.cache_store = :dalli_store, 'localhost:11211', {:expires_in => 4.hours}
1.0.0
=======
Welcome gucki as a Dalli committer!
- Fix network and namespace issues in get_multi (gucki)
- Better handling of unmarshalling errors (mperham)
0.11.2
=======
- Major reworking of socket error and failover handling (gucki)
- Add basic JRuby support (mperham)
0.11.1
======
- Minor fixes, doc updates.
- Add optional support for kgio sockets, gives a 10-15% performance boost.
0.11.0
======
Warning: this release changes how Dalli marshals data. I do not guarantee compatibility until 1.0 but I will increment the minor version every time a release breaks compatibility until 1.0.
IT IS HIGHLY RECOMMENDED YOU FLUSH YOUR CACHE BEFORE UPGRADING.
- multi() now works reentrantly.
- Added new Dalli::Client option for default TTLs, :expires_in, defaults to 0 (aka forever).
- Added new Dalli::Client option, :compression, to enable auto-compression of values.
- Refactor how Dalli stores data on the server. Values are now tagged
as "marshalled" or "compressed" so they can be automatically deserialized
without the client having to know how they were stored.
0.10.1
======
- Prefer server config from environment, fixes Heroku session store issues (thanks JoshMcKin)
- Better handling of non-ASCII values (size -> bytesize)
- Assert that keys are ASCII only
0.10.0
======
Warning: this release changed how Rails marshals data with Dalli. Unfortunately previous versions double marshalled values. It is possible that data stored with previous versions of Dalli will not work with this version.
IT IS HIGHLY RECOMMENDED YOU FLUSH YOUR CACHE BEFORE UPGRADING.
- Rework how the Rails cache store does value marshalling.
- Rework old server version detection to avoid a socket read hang.
- Refactor the Rails 2.3 :dalli\_store to be closer to :mem\_cache\_store.
- Better documentation for session store config (plukevdh)
0.9.10
----
- Better server retry logic (next2you)
- Rails 3.1 compatibility (gucki)
0.9.9
----
- Add support for *_multi operations for add, set, replace and delete. This implements
pipelined network operations; Dalli disables network replies so we're not limited by
latency, allowing for much higher throughput.
dc = Dalli::Client.new
dc.multi do
dc.set 'a', 1
dc.set 'b', 2
dc.set 'c', 3
dc.delete 'd'
end
- Minor fix to set the continuum sorted by value (kangster)
- Implement session store with Rails 2.3. Update docs.
0.9.8
-----
- Implement namespace support
- Misc fixes
0.9.7
-----
- Small fix for NewRelic integration.
- Detect and fail on older memcached servers (pre-1.4).
0.9.6
-----
- Patches for Rails 3.0.1 integration.
0.9.5
-----
- Major design change - raw support is back to maximize compatibility with Rails
and the increment/decrement operations. You can now pass :raw => true to most methods
to bypass (un)marshalling.
- Support symbols as keys (ddollar)
- Rails 2.3 bug fixes
0.9.4
-----
- Dalli support now in rack-bug (http://github.com/brynary/rack-bug), give it a try!
- Namespace support for Rails 2.3 (bpardee)
- Bug fixes
0.9.3
-----
- Rails 2.3 support (beanieboi)
- Rails SessionStore support
- Passenger integration
- memcache-client upgrade docs, see Upgrade.md
0.9.2
----
- Verify proper operation in Heroku.
0.9.1
----
- Add fetch and cas operations (mperham)
- Add incr and decr operations (mperham)
- Initial support for SASL authentication via the MEMCACHE_{USERNAME,PASSWORD} environment variables, needed for Heroku (mperham)
0.9.0
-----
- Initial gem release.
LICENSE 0 → 100644
Copyright (c) Peter M. Goldstein, Mike Perham
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Performance
====================
Caching is all about performance, so I carefully track Dalli performance to ensure no regressions.
You can optionally use kgio to give Dalli a 10-20% performance boost: `gem install kgio`.
Note I've added some benchmarks over time to Dalli that the other libraries don't necessarily have.
memcache-client
---------------
Testing 1.8.5 with ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]
user system total real
set:plain:memcache-client 1.860000 0.310000 2.170000 ( 2.188030)
set:ruby:memcache-client 1.830000 0.290000 2.120000 ( 2.130212)
get:plain:memcache-client 1.830000 0.340000 2.170000 ( 2.176156)
get:ruby:memcache-client 1.900000 0.330000 2.230000 ( 2.235045)
multiget:ruby:memcache-client 0.860000 0.120000 0.980000 ( 0.987348)
missing:ruby:memcache-client 1.630000 0.320000 1.950000 ( 1.954867)
mixed:ruby:memcache-client 3.690000 0.670000 4.360000 ( 4.364469)
dalli
-----
Testing with Rails 3.2.1
Using kgio socket IO
Testing 2.0.0 with ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.3.0]
user system total real
mixed:rails:dalli 1.580000 0.570000 2.150000 ( 3.008839)
set:plain:dalli 0.730000 0.300000 1.030000 ( 1.567098)
setq:plain:dalli 0.520000 0.120000 0.640000 ( 0.634402)
set:ruby:dalli 0.800000 0.300000 1.100000 ( 1.640348)
get:plain:dalli 0.840000 0.330000 1.170000 ( 1.668425)
get:ruby:dalli 0.850000 0.330000 1.180000 ( 1.665716)
multiget:ruby:dalli 0.700000 0.260000 0.960000 ( 0.965423)
missing:ruby:dalli 0.720000 0.320000 1.040000 ( 1.511720)
mixed:ruby:dalli 1.660000 0.640000 2.300000 ( 3.320743)
mixedq:ruby:dalli 1.630000 0.510000 2.140000 ( 2.629734)
incr:ruby:dalli 0.270000 0.100000 0.370000 ( 0.547618)
README.md 0 → 100644
Dalli [![Build Status](https://secure.travis-ci.org/petergoldstein/dalli.svg)](http://travis-ci.org/petergoldstein/dalli)
=====
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.
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).
![Persistence of Memory](http://www.virtualdali.com/assets/paintings/31PersistenceOfMemory.jpg)
Dalli's initial development was sponsored by [CouchBase](http://www.couchbase.com/). Many thanks to them!
Supported Ruby versions and implementations
------------------------------------------------
Dalli should work identically on:
* JRuby 1.6+
* Ruby 1.9.3+
* Rubinius 2.0
If you have problems, please enter an issue.
Installation and Usage
------------------------
Remember, Dalli **requires** memcached 1.4+. You can check the version with `memcached -h`. Please note that the memcached version that *Mac OS X Snow Leopard* ships with is 1.2.8 and it won't work. Install memcached 1.4.x using Homebrew with
brew install memcached
On Ubuntu you can install it by running:
apt-get install memcached
You can verify your installation using this piece of code:
```bash
gem install dalli
```
```ruby
require 'dalli'
options = { :namespace => "app_v1", :compress => true }
dc = Dalli::Client.new('localhost:11211', options)
dc.set('abc', 123)
value = dc.get('abc')
```
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.
Dalli has no runtime dependencies.
Usage with Rails 3.x and 4.x
---------------------------
In your Gemfile:
```ruby
gem 'dalli'
```
In `config/environments/production.rb`:
```ruby
config.cache_store = :dalli_store
```
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.
```ruby
config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com:11211:2',
{ :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
```
You can specify a port and a weight by appending to the server name. You may wish to increase the weight of a server with more memory configured. (e.g. to specify port 11211 and a weight of 2, append `:11211:2` )
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:
```ruby
config.cache_store = :dalli_store, nil, { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }
```
To use Dalli for Rails session storage that times out after 20 minutes, in `config/initializers/session_store.rb`:
For Rails >= 3.2.4:
```ruby
Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes
```
For Rails 3.x:
```ruby
require 'action_dispatch/middleware/session/dalli_store'
Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 20.minutes
```
Dalli does not support Rails 2.x.
Multithreading and Rails
--------------------------
If you use Puma or another threaded app server, as of Dalli 2.7, you can use a pool
of Dalli clients with Rails to ensure the `Rails.cache` singleton does not become a
source of thread contention. You must add `gem 'connection_pool'` to your Gemfile and
add :pool\_size to your `dalli_store` config:
```ruby
config.cache_store = :dalli_store, 'cache-1.example.com', { :pool_size => 5 }
```
You can then use the Rails cache as normal and Rails.cache will use the pool transparently under the covers, or you can check out a Dalli client directly from the pool:
```ruby
Rails.cache.fetch('foo', :expires_in => 300) do
'bar'
end
Rails.cache.dalli.with do |client|
# client is a Dalli::Client instance which you can
# use ONLY within this block
end
```
Configuration
------------------------
**servers**: An Array of "host:port:weight" where weight allows you to distribute cache unevenly.
Dalli::Client accepts the following options. All times are in seconds.
**expires_in**: Global default for key TTL. Default is 0, which means no expiry.
**namespace**: If specified, prepends each key with this value to provide simple namespacing. Default is nil.
**failover**: Boolean, if true Dalli will failover to another server if the main server for a key is down. Default is true.
**threadsafe**: Boolean. If true Dalli ensures that only one thread is using a socket at a given time. Default is true. You can set to false if you are using the Client within a thread-safe connection pool.
**serializer**: The serializer to use for objects being stored (ex. JSON).
Default is Marshal.
**compress**: Boolean, if true Dalli will gzip-compress values larger than 1K. Default is false.
**compression_min_size**: Minimum value byte size for which to attempt compression. Default is 1K.
**compression_max_size**: Maximum value byte size for which to attempt compression. Default is unlimited.
**compressor**: The compressor to use for objects being stored.
Default is zlib, implemented under `Dalli::Compressor`.
If serving compressed data using nginx's HttpMemcachedModule, set `memcached_gzip_flag 2` and use `Dalli::GzipCompressor`
**keepalive**: Boolean. If true, Dalli will enable keep-alive for socket connections. Default is true.
**socket_timeout**: Timeout for all socket operations (connect, read, write). Default is 0.5.
**socket_max_failures**: When a socket operation fails after socket_timeout, the same operation is retried. This is to not immediately mark a server down when there's a very slight network problem. Default is 2.
**socket_failure_delay**: Before retrying a socket operation, the process sleeps for this amount of time. Default is 0.01. Set to nil for no delay.
**down_retry_delay**: When a server has been marked down due to many failures, the server will be checked again for being alive only after this amount of time. Don't set this value too low, otherwise each request which tries the failed server might hang for the maximum **socket_timeout**. Default is 60 seconds.
**value_max_bytes**: The maximum size of a value in memcached. Defaults to 1MB, this can be increased with memcached's -I parameter. You must also configure Dalli to allow the larger size here.
**error_when_over_max_size**: Boolean. If true, Dalli will throw a Dalli::ValueOverMaxSize exception when trying to store data larger than **value_max_bytes**. Defaults to false, meaning only a warning is logged.
**username**: The username to use for authenticating this client instance against a SASL-enabled memcached server. Heroku users should not need to use this normally.
**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.
**sndbuf**: In bytes, set the socket SO_SNDBUF. Defaults to operating system default.
**rcvbuf**: In bytes, set the socket SO_RCVBUF. Defaults to operating system default.
**cache_nils**: Boolean. If true Dalli will not treat cached `nil` values as 'not found' for `#fetch` operations. Default is false.
**raise_errors**: Boolean. When true DalliStore will reraise Dalli:DalliError instead swallowing the error. Default is false.
**instrument_errors**: Boolean. When true DalliStore will send notification of Dalli::DalliError via a 'cache_error.active_support' event. Default is false.
Features and Changes
------------------------
By default, Dalli is thread-safe. Disable thread-safety at your own peril.
Dalli does not need anything special in Unicorn/Passenger since 2.0.4.
It will detect sockets shared with child processes and gracefully reopen the
socket.
Note that Dalli does not require ActiveSupport or Rails. You can safely use it in your own Ruby projects.
[View the Client API](http://www.rubydoc.info/github/mperham/dalli/Dalli/Client)
Helping Out
-------------
If you have a fix you wish to provide, please fork the code, fix in your local project and then send a pull request on github. Please ensure that you include a test which verifies your fix and update `History.md` with a one sentence description of your fix so you get credit as a contributor.
We're not accepting new compressors. They are trivial to add in an initializer. See #385 (LZ4), #406 (Snappy)
Thanks
------------
Mike Perham - for originally authoring the Dalli project and serving as maintainer and primary contributor
Eric Wong - for help using his [kgio](http://bogomips.org/kgio/) library.
Brian Mitchell - for his remix-stash project which was helpful when implementing and testing the binary protocol support.
[CouchBase](http://couchbase.com) - for their project sponsorship
Authors
----------
* [Peter M. Goldstein](https://github.com/petergoldstein) - current maintainer
* [Mike Perham](https://github.com/mperham) and contributors
Copyright
-----------
Copyright (c) Mike Perham, Peter M. Goldstein. See LICENSE for details.
Rakefile 0 → 100644
require 'bundler/gem_tasks'
require 'appraisal'
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.pattern = 'test/**/test_*.rb'
test.warning = true
test.verbose = true
end
task :default => :test
Rake::TestTask.new(:bench) do |test|
test.pattern = 'test/benchmark_test.rb'
end
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project maintainer at peter.m.goldstein AT gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
require './lib/dalli/version'
Gem::Specification.new do |s|
s.name = "dalli"
s.version = Dalli::VERSION
s.license = "MIT"
s.authors = ['Peter M. Goldstein', 'Mike Perham']
s.description = s.summary = 'High performance memcached client for Ruby'
s.email = ['peter.m.goldstein@gmail.com', 'mperham@gmail.com']
s.files = Dir.glob('lib/**/*') + [
'LICENSE',
'README.md',
'History.md',
'Gemfile'
]
s.homepage = 'https://github.com/petergoldstein/dalli'
end
# This file was generated by Appraisal
source "https://rubygems.org"
gem "appraisal"
gem "kgio", platform: :mri
gem "rails", "~> 5.0.0"
group :test do
gem "minitest"
gem "mocha"
gem "rake"
gem "connection_pool"
gem "simplecov"
end
gemspec path: "../"
# This file was generated by Appraisal
source "https://rubygems.org"
gem "appraisal"
gem "kgio", platform: :mri
gem "rails", "~> 5.1.0"
group :test do
gem "minitest"
gem "mocha"
gem "rake"
gem "connection_pool"
gem "simplecov"
end
gemspec path: "../"
# This file was generated by Appraisal
source "https://rubygems.org"
gem "appraisal"
gem "kgio", platform: :mri
gem "rails", "~> 5.2.0"
group :test do
gem "minitest"
gem "mocha"
gem "rake"
gem "connection_pool"
gem "simplecov"
end
gemspec path: "../"
# This file was generated by Appraisal
source 'https://rubygems.org'
gem 'kgio', platform: :mri
gem 'rails', '~> 5.0.0'
gem 'minitest', '< 5.10'
gemspec path: '../'
# This file was generated by Appraisal
source "https://rubygems.org"
gem "appraisal"
gem "kgio", platform: :mri
gem "rails", "~> 6.0.0"
group :test do
gem "minitest"
gem "mocha"
gem "rake"
gem "connection_pool"
gem "simplecov"
end
gemspec path: "../"
# frozen_string_literal: true
require 'active_support/cache'
require 'action_dispatch/middleware/session/abstract_store'
require 'dalli'
# Dalli-based session store for Rails 3.0.
module ActionDispatch
module Session
class DalliStore < AbstractStore
def initialize(app, options = {})
# Support old :expires option
options[:expire_after] ||= options[:expires]
super
@default_options = { :namespace => 'rack:session' }.merge(@default_options)
@pool = options[:cache] || begin
Dalli::Client.new(
@default_options[:memcache_server], @default_options)
end
@namespace = @default_options[:namespace]
@raise_errors = !!@default_options[:raise_errors]
super
end
def reset
@pool.reset
end
private
def get_session(env, sid)
sid = generate_sid unless sid and !sid.empty?
begin
session = @pool.get(sid) || {}
rescue Dalli::DalliError => ex
# re-raise ArgumentError so Rails' session abstract_store.rb can autoload any missing models
raise ArgumentError, ex.message if ex.message =~ /unmarshal/
Rails.logger.warn("Session::DalliStore#get: #{ex.message}")
session = {}
end
[sid, session]
end
def set_session(env, sid, session_data, options = nil)
options ||= env[ENV_SESSION_OPTIONS_KEY]
expiry = options[:expire_after]
@pool.set(sid, session_data, expiry)
sid
rescue Dalli::DalliError
Rails.logger.warn("Session::DalliStore#set: #{$!.message}")
raise if @raise_errors
false
end
def destroy_session(env, session_id, options)
begin
@pool.delete(session_id)
rescue Dalli::DalliError
Rails.logger.warn("Session::DalliStore#destroy_session: #{$!.message}")
raise if @raise_errors
end
return nil if options[:drop]
generate_sid
end
def destroy(env)
if sid = current_session_id(env)
@pool.delete(sid)
end
rescue Dalli::DalliError
Rails.logger.warn("Session::DalliStore#destroy: #{$!.message}")
raise if @raise_errors
false
end
end
end
end
# encoding: ascii
# frozen_string_literal: true
require 'dalli'
module ActiveSupport
module Cache
class DalliStore
attr_reader :silence, :options
alias_method :silence?, :silence
def self.supports_cache_versioning?
true
end
# Silence the logger.
def silence!
@silence = true
self
end
# Silence the logger within a block.
def mute
previous_silence, @silence = defined?(@silence) && @silence, true
yield
ensure
@silence = previous_silence
end
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/
# Creates a new DalliStore object, with the given memcached server
# addresses. Each address is either a host name, or a host-with-port string
# in the form of "host_name:port". For example:
#
# ActiveSupport::Cache::DalliStore.new("localhost", "server-downstairs.localnetwork:8229")
#
# If no addresses are specified, then DalliStore will connect to
# localhost port 11211 (the default memcached port).
#
# Connection Pool support
#
# If you are using multithreaded Rails, the Rails.cache singleton can become a source
# of contention. You can use a connection pool of Dalli clients with Rails.cache by
# passing :pool_size and/or :pool_timeout:
#
# config.cache_store = :dalli_store, 'localhost:11211', :pool_size => 10
#
# Both pool options default to 5. You must include the `connection_pool` gem if you
# wish to use pool support.
#
def initialize(*addresses)
puts <<-EOS
DEPRECATION: :dalli_store will be removed in Dalli 3.0.
Please use Rails' official :mem_cache_store instead.
https://guides.rubyonrails.org/caching_with_rails.html
EOS
addresses = addresses.flatten
options = addresses.extract_options!
@options = options.dup
pool_options = {}
pool_options[:size] = options[:pool_size] if options[:pool_size]
pool_options[:timeout] = options[:pool_timeout] if options[:pool_timeout]
@options[:compress] ||= @options[:compression]
addresses.compact!
servers = if addresses.empty?
nil # use the default from Dalli::Client
else
addresses
end
if pool_options.empty?
@data = Dalli::Client.new(servers, @options)
else
@data = ::ConnectionPool.new(pool_options) { Dalli::Client.new(servers, @options.merge(:threadsafe => false)) }
end
extend Strategy::LocalCache
extend LocalCacheEntryUnwrapAndRaw
end
##
# Access the underlying Dalli::Client or ConnectionPool instance for
# access to get_multi, etc.
def dalli
@data
end
def with(&block)
@data.with(&block)
end
# Fetch the value associated with the key.
# If a value is found, then it is returned.
#
# If a value is not found and no block is given, then nil is returned.
#
# If a value is not found (or if the found value is nil and :cache_nils is false)
# and a block is given, the block will be invoked and its return value
# written to the cache and returned.
def fetch(name, options=nil)
options ||= {}
options[:cache_nils] = true if @options[:cache_nils]
namespaced_name = namespaced_key(name, options)
not_found = options[:cache_nils] ? Dalli::Server::NOT_FOUND : nil
if block_given?
entry = not_found
unless options[:force]
entry = instrument_with_log(:read, namespaced_name, options) do |payload|
read_entry(namespaced_name, options).tap do |result|
if payload
payload[:super_operation] = :fetch
payload[:hit] = not_found != result
end
end
end
end
if not_found == entry
result = instrument_with_log(:generate, namespaced_name, options) do |payload|
yield(name)
end
write(name, result, options)
result
else
instrument_with_log(:fetch_hit, namespaced_name, options) { |payload| }
entry
end
else
read(name, options)
end
end
def read(name, options=nil)
options ||= {}
name = namespaced_key(name, options)
instrument_with_log(:read, name, options) do |payload|
entry = read_entry(name, options)
payload[:hit] = !entry.nil? if payload
entry
end
end
def write(name, value, options=nil)
options ||= {}
name = namespaced_key(name, options)
instrument_with_log(:write, name, options) do |payload|
with do |connection|
options = options.merge(:connection => connection)
write_entry(name, value, options)
end
end
end
def exist?(name, options=nil)
options ||= {}
name = namespaced_key(name, options)
log(:exist, name, options)
!read_entry(name, options).nil?
end
def delete(name, options=nil)
options ||= {}
name = namespaced_key(name, options)
instrument_with_log(:delete, name, options) do |payload|
delete_entry(name, options)
end
end
# Reads multiple keys from the cache using a single call to the
# servers for all keys. Keys must be Strings.
def read_multi(*names)
options = names.extract_options!
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
instrument_with_log(:read_multi, mapping.keys) do
results = {}
if local_cache
mapping.each_key do |key|
if value = local_cache.read_entry(key, options)
results[key] = value
end
end
end
data = with { |c| c.get_multi(mapping.keys - results.keys) }
results.merge!(data)
results.inject({}) do |memo, (inner, _)|
entry = results[inner]
# NB Backwards data compatibility, to be removed at some point
value = (entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry)
memo[mapping[inner]] = value
local_cache.write_entry(inner, value, options) if local_cache
memo
end
end
end
# Fetches data from the cache, using the given keys. If there is data in
# the cache with the given keys, then that data is returned. Otherwise,
# the supplied block is called for each key for which there was no data,
# and the result will be written to the cache and returned.
def fetch_multi(*names)
options = names.extract_options!
mapping = names.inject({}) { |memo, name| memo[namespaced_key(name, options)] = name; memo }
instrument_with_log(:fetch_multi, mapping.keys) do
with do |connection|
results = connection.get_multi(mapping.keys)
connection.multi do
mapping.inject({}) do |memo, (expanded, name)|
memo[name] = results[expanded]
if memo[name].nil?
value = yield(name)
memo[name] = value
options = options.merge(:connection => connection)
write_entry(expanded, value, options)
end
memo
end
end
end
end
end
# Increment a cached value. This method uses the memcached incr atomic
# operator and can only be used on values written with the :raw option.
# Calling it on a value not stored with :raw will fail.
# :initial defaults to the amount passed in, as if the counter was initially zero.
# memcached counters cannot hold negative values.
def increment(name, amount = 1, options=nil)
options ||= {}
name = namespaced_key(name, options)
initial = options.has_key?(:initial) ? options[:initial] : amount
expires_in = options[:expires_in]
instrument_with_log(:increment, name, :amount => amount) do
with { |c| c.incr(name, amount, expires_in, initial) }
end
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
nil
end
# Decrement a cached value. This method uses the memcached decr atomic
# operator and can only be used on values written with the :raw option.
# Calling it on a value not stored with :raw will fail.
# :initial defaults to zero, as if the counter was initially zero.
# memcached counters cannot hold negative values.
def decrement(name, amount = 1, options=nil)
options ||= {}
name = namespaced_key(name, options)
initial = options.has_key?(:initial) ? options[:initial] : 0
expires_in = options[:expires_in]
instrument_with_log(:decrement, name, :amount => amount) do
with { |c| c.decr(name, amount, expires_in, initial) }
end
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
nil
end
# Clear the entire cache on all memcached servers. This method should
# be used with care when using a shared cache.
def clear(options=nil)
instrument_with_log(:clear, 'flushing all keys') do
with { |c| c.flush_all }
end
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
nil
end
# Clear any local cache
def cleanup(options=nil)
end
# Get the statistics from the memcached servers.
def stats
with { |c| c.stats }
end
def reset
with { |c| c.reset }
end
def logger
Dalli.logger
end
def logger=(new_logger)
Dalli.logger = new_logger
end
protected
# Read an entry from the cache.
def read_entry(key, options) # :nodoc:
entry = with { |c| c.get(key, options) }
# NB Backwards data compatibility, to be removed at some point
entry.is_a?(ActiveSupport::Cache::Entry) ? entry.value : entry
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
nil
end
# Write an entry to the cache.
def write_entry(key, value, options) # :nodoc:
# cleanup LocalCache
cleanup if options[:unless_exist]
method = options[:unless_exist] ? :add : :set
expires_in = options[:expires_in]
connection = options.delete(:connection)
connection.send(method, key, value, expires_in, options)
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
false
end
# Delete an entry from the cache.
def delete_entry(key, options) # :nodoc:
with { |c| c.delete(key) }
rescue Dalli::DalliError => e
log_dalli_error(e)
instrument_error(e) if instrument_errors?
raise if raise_errors?
false
end
private
def namespaced_key(key, options)
digest_class = @options[:digest_class] || ::Digest::MD5
key = expanded_key(key)
namespace = options[:namespace] if options
prefix = namespace.is_a?(Proc) ? namespace.call : namespace
key = "#{prefix}:#{key}" if prefix
key = "#{key[0, 213]}:md5:#{digest_class.hexdigest(key)}" if key && key.size > 250
key
end
alias :normalize_key :namespaced_key
# Expand key to be a consistent string value. Invokes +cache_key_with_version+
# first to support Rails 5.2 cache versioning.
# Invoke +cache_key+ if object responds to +cache_key+. Otherwise, to_param method
# will be called. If the key is a Hash, then keys will be sorted alphabetically.
def expanded_key(key) # :nodoc:
return key.cache_key_with_version.to_s if key.respond_to?(:cache_key_with_version)
return key.cache_key.to_s if key.respond_to?(:cache_key)
case key
when Array
if key.size > 1
key = key.collect{|element| expanded_key(element)}
else
key = key.first
end
when Hash
key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
end
key = key.to_param
if key.respond_to? :force_encoding
key = key.dup
key.force_encoding('binary')
end
key
end
def log_dalli_error(error)
logger.error("DalliError: #{error.message}") if logger
end
def instrument_with_log(operation, key, options=nil)
log(operation, key, options)
payload = { :key => key }
payload.merge!(options) if options.is_a?(Hash)
instrument(operation, payload) { |p| yield(p) }
end
def instrument_error(error)
instrument(:error, { :key => 'DalliError', :message => error.message })
end
def instrument(operation, payload)
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) do
yield(payload) if block_given?
end
end
def log(operation, key, options=nil)
return unless logger && logger.debug? && !silence?
logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
end
def raise_errors?
!!@options[:raise_errors]
end
def instrument_errors?
!!@options[:instrument_errors]
end
# Make sure LocalCache is giving raw values, not `Entry`s, and
# respect `raw` option.
module LocalCacheEntryUnwrapAndRaw # :nodoc:
protected
def read_entry(key, options)
retval = super(key, **options)
if retval.is_a? ActiveSupport::Cache::Entry
# Must have come from LocalStore, unwrap it
if options[:raw]
retval.value.to_s
else
retval.value
end
else
retval
end
end
end
end
end
end
# frozen_string_literal: true
require 'dalli/compressor'
require 'dalli/client'
require 'dalli/ring'
require 'dalli/server'
require 'dalli/socket'
require 'dalli/version'
require 'dalli/options'
require 'dalli/railtie' if defined?(::Rails::Railtie)
module Dalli
# generic error
class DalliError < RuntimeError; end
# socket/server communication error
class NetworkError < DalliError; end
# no server available/alive error
class RingError < DalliError; end
# application error in marshalling serialization
class MarshalError < DalliError; end
# application error in marshalling deserialization or decompression
class UnmarshalError < DalliError; end
# payload too big for memcached
class ValueOverMaxSize < DalliError; end
def self.logger
@logger ||= (rails_logger || default_logger)
end
def self.rails_logger
(defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger) ||
(defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:debug) && RAILS_DEFAULT_LOGGER)
end
def self.default_logger
require 'logger'
l = Logger.new(STDOUT)
l.level = Logger::INFO
l
end
def self.logger=(logger)
@logger = logger
end
end
if defined?(RAILS_VERSION) && RAILS_VERSION < '3'
raise Dalli::DalliError, "Dalli #{Dalli::VERSION} does not support Rails version < 3.0"
end
# frozen_string_literal: true
require 'dalli/client'
module Dalli
class Client
##
# Get the value and CAS ID associated with the key. If a block is provided,
# value and CAS will be passed to the block.
def get_cas(key)
(value, cas) = perform(:cas, key)
value = (!value || value == 'Not found') ? nil : value
if block_given?
yield value, cas
else
[value, cas]
end
end
##
# Fetch multiple keys efficiently, including available metadata such as CAS.
# If a block is given, yields key/data pairs one a time. Data is an array:
# [value, cas_id]
# If no block is given, returns a hash of
# { 'key' => [value, cas_id] }
def get_multi_cas(*keys)
if block_given?
get_multi_yielder(keys) {|*args| yield(*args)}
else
Hash.new.tap do |hash|
get_multi_yielder(keys) {|k, data| hash[k] = data}
end
end
end
##
# Set the key-value pair, verifying existing CAS.
# Returns the resulting CAS value if succeeded, and falsy otherwise.
def set_cas(key, value, cas, ttl=nil, options=nil)
ttl ||= @options[:expires_in].to_i
perform(:set, key, value, ttl, cas, options)
end
##
# Conditionally add a key/value pair, verifying existing CAS, only if the
# key already exists on the server. Returns the new CAS value if the
# operation succeeded, or falsy otherwise.
def replace_cas(key, value, cas, ttl=nil, options=nil)
ttl ||= @options[:expires_in].to_i
perform(:replace, key, value, ttl, cas, options)
end
# Delete a key/value pair, verifying existing CAS.
# Returns true if succeeded, and falsy otherwise.
def delete_cas(key, cas=0)
perform(:delete, key, cas)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment