Skip to content

Remove ActiveSupport::Cache::MemCacheStore #6296

Closed
wants to merge 4 commits into from
View
3 Gemfile
@@ -41,9 +41,6 @@ group :doc do
gem 'w3c_validators'
end
-# AS
-gem 'memcache-client', '>= 1.8.5'
-
# Add your own local bundler stuff
local_gemfile = File.dirname(__FILE__) + "/.Gemfile"
instance_eval File.read local_gemfile if File.exists? local_gemfile
View
3 activesupport/CHANGELOG.md
@@ -1,5 +1,8 @@
## Rails 4.0.0 (unreleased) ##
+* Deletes ActiveSupport::Cache::MemCacheStore in favour of
+ ActiveSupport::Cache::DalliStore shipped with dalli gem *Guillermo Iguaran*
+
* `Object#try` can't call private methods. *Vasiliy Ermolovich*
* `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez*
View
11 activesupport/lib/active_support/cache.rb
@@ -15,7 +15,6 @@ module ActiveSupport
module Cache
autoload :FileStore, 'active_support/cache/file_store'
autoload :MemoryStore, 'active_support/cache/memory_store'
- autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
autoload :NullStore, 'active_support/cache/null_store'
# These options mean something to all cache implementations. Individual cache
@@ -39,8 +38,8 @@ class << self
# ActiveSupport::Cache.lookup_store(:memory_store)
# # => returns a new ActiveSupport::Cache::MemoryStore object
#
- # ActiveSupport::Cache.lookup_store(:mem_cache_store)
- # # => returns a new ActiveSupport::Cache::MemCacheStore object
+ # ActiveSupport::Cache.lookup_store(:dalli_store)
+ # # => returns a new ActiveSupport::Cache::DalliStore object
#
# Any additional arguments will be passed to the corresponding cache store
# class's constructor:
@@ -100,7 +99,7 @@ def retrieve_cache_key(key)
# An abstract cache store class. There are multiple cache store
# implementations, each having its own additional features. See the classes
# under the ActiveSupport::Cache module, e.g.
- # ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most
+ # ActiveSupport::Cache::DalliStore. DalliStore is currently the most
# popular cache store for large production websites.
#
# Some implementations may not support all methods beyond the basic cache
@@ -260,11 +259,11 @@ def self.instrument
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache miss.
# +options+ will be passed to the #read and #write calls.
#
- # For example, MemCacheStore's #write method supports the +:raw+
+ # For example, DalliStore's #write method supports the +:raw+
# option, which tells the memcached server to store all values as strings.
# We can use this option with #fetch too:
#
- # cache = ActiveSupport::Cache::MemCacheStore.new
+ # cache = ActiveSupport::Cache::DalliStore.new
# cache.fetch("foo", :force => true, :raw => true) do
# :bar
# end
View
205 activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -1,205 +0,0 @@
-begin
- require 'memcache'
-rescue LoadError => e
- $stderr.puts "You don't have memcache-client installed in your application. Please add it to your Gemfile and run bundle install"
- raise e
-end
-
-require 'digest/md5'
-
-module ActiveSupport
- module Cache
- # A cache store implementation which stores data in Memcached:
- # http://memcached.org/
- #
- # This is currently the most popular cache store for production websites.
- #
- # Special features:
- # - Clustering and load balancing. One can specify multiple memcached servers,
- # and MemCacheStore will load balance between all available servers. If a
- # server goes down, then MemCacheStore will ignore it until it comes back up.
- #
- # MemCacheStore implements the Strategy::LocalCache strategy which implements
- # an in-memory cache inside of a block.
- class MemCacheStore < Store
- module Response # :nodoc:
- STORED = "STORED\r\n"
- NOT_STORED = "NOT_STORED\r\n"
- EXISTS = "EXISTS\r\n"
- NOT_FOUND = "NOT_FOUND\r\n"
- DELETED = "DELETED\r\n"
- end
-
- ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
-
- def self.build_mem_cache(*addresses)
- addresses = addresses.flatten
- options = addresses.extract_options!
- addresses = ["localhost:11211"] if addresses.empty?
- MemCache.new(addresses, options)
- end
-
- # Creates a new MemCacheStore 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::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
- #
- # If no addresses are specified, then MemCacheStore will connect to
- # localhost port 11211 (the default memcached port).
- #
- # Instead of addresses one can pass in a MemCache-like object. For example:
- #
- # require 'memcached' # gem install memcached; uses C bindings to libmemcached
- # ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
- def initialize(*addresses)
- addresses = addresses.flatten
- options = addresses.extract_options!
- super(options)
-
- if addresses.first.respond_to?(:get)
- @data = addresses.first
- else
- mem_cache_options = options.dup
- UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
- @data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
- end
-
- extend Strategy::LocalCache
- extend LocalCacheWithRaw
- end
-
- # Reads multiple values from the cache using a single call to the
- # servers for all keys. Options can be passed in the last argument.
- def read_multi(*names)
- options = names.extract_options!
- options = merged_options(options)
- keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
- raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
- values = {}
- raw_values.each do |key, value|
- entry = deserialize_entry(value)
- values[keys_to_names[key]] = entry.value unless entry.expired?
- end
- values
- 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 initialize that value
- # to zero.
- def increment(name, amount = 1, options = nil) # :nodoc:
- options = merged_options(options)
- response = instrument(:increment, name, :amount => amount) do
- @data.incr(escape_key(namespaced_key(name, options)), amount)
- end
- response == Response::NOT_FOUND ? nil : response.to_i
- rescue MemCache::MemCacheError
- 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 initialize that value
- # to zero.
- def decrement(name, amount = 1, options = nil) # :nodoc:
- options = merged_options(options)
- response = instrument(:decrement, name, :amount => amount) do
- @data.decr(escape_key(namespaced_key(name, options)), amount)
- end
- response == Response::NOT_FOUND ? nil : response.to_i
- rescue MemCache::MemCacheError
- nil
- end
-
- # Clear the entire cache on all memcached servers. This method should
- # be used with care when shared cache is being used.
- def clear(options = nil)
- @data.flush_all
- end
-
- # Get the statistics from the memcached servers.
- def stats
- @data.stats
- end
-
- protected
- # Read an entry from the cache.
- def read_entry(key, options) # :nodoc:
- deserialize_entry(@data.get(escape_key(key), true))
- rescue MemCache::MemCacheError => e
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
- nil
- end
-
- # Write an entry to the cache.
- def write_entry(key, entry, options) # :nodoc:
- method = options && options[:unless_exist] ? :add : :set
- value = options[:raw] ? entry.value.to_s : entry
- expires_in = options[:expires_in].to_i
- if expires_in > 0 && !options[:raw]
- # Set the memcache expire a few minutes in the future to support race condition ttls on read
- expires_in += 5.minutes
- end
- response = @data.send(method, escape_key(key), value, expires_in, options[:raw])
- response == Response::STORED
- rescue MemCache::MemCacheError => e
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
- false
- end
-
- # Delete an entry from the cache.
- def delete_entry(key, options) # :nodoc:
- response = @data.delete(escape_key(key))
- response == Response::DELETED
- rescue MemCache::MemCacheError => e
- logger.error("MemCacheError (#{e}): #{e.message}") if logger
- false
- end
-
- private
-
- # Memcache keys are binaries. So we need to force their encoding to binary
- # before applying the regular expression to ensure we are escaping all
- # characters properly.
- def escape_key(key)
- key = key.to_s.dup
- key = key.force_encoding("BINARY")
- key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
- key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
- key
- end
-
- def deserialize_entry(raw_value)
- if raw_value
- entry = Marshal.load(raw_value) rescue raw_value
- entry.is_a?(Entry) ? entry : Entry.new(entry)
- else
- nil
- end
- end
-
- # Provide support for raw values in the local cache strategy.
- module LocalCacheWithRaw # :nodoc:
- protected
- def read_entry(key, options)
- entry = super
- if options[:raw] && local_cache && entry
- entry = deserialize_entry(entry.value)
- end
- entry
- end
-
- def write_entry(key, entry, options) # :nodoc:
- retval = super
- if options[:raw] && local_cache && retval
- raw_entry = Entry.new(entry.value.to_s)
- raw_entry.expires_at = entry.expires_at
- local_cache.write_entry(key, raw_entry, options)
- end
- retval
- end
- end
- end
- end
-end
View
10 activesupport/test/abstract_unit.rb
@@ -23,15 +23,5 @@
ENV['NO_RELOAD'] = '1'
require 'active_support'
-def uses_memcached(test_name)
- require 'memcache'
- begin
- MemCache.new('localhost:11211').stats
- yield
- rescue MemCache::MemCacheError
- $stderr.puts "Skipping #{test_name} tests. Start memcached and try again."
- end
-end
-
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
View
86 activesupport/test/caching_test.rb
@@ -69,7 +69,7 @@ def test_expand_cache_key_of_false
def test_expand_cache_key_of_true
assert_equal 'true', ActiveSupport::Cache.expand_cache_key(true)
end
-
+
def test_expand_cache_key_of_array_like_object
assert_equal 'foo/bar/baz', ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum)
end
@@ -82,40 +82,6 @@ def test_file_fragment_cache_store
assert_equal "/path/to/cache/directory", store.cache_path
end
- def test_mem_cache_fragment_cache_store
- MemCache.expects(:new).with(%w[localhost], {})
- store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost"
- assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
- end
-
- def test_mem_cache_fragment_cache_store_with_given_mem_cache
- mem_cache = MemCache.new
- MemCache.expects(:new).never
- store = ActiveSupport::Cache.lookup_store :mem_cache_store, mem_cache
- assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
- end
-
- def test_mem_cache_fragment_cache_store_with_given_mem_cache_like_object
- MemCache.expects(:new).never
- memcache = Object.new
- def memcache.get() true end
- store = ActiveSupport::Cache.lookup_store :mem_cache_store, memcache
- assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
- end
-
- def test_mem_cache_fragment_cache_store_with_multiple_servers
- MemCache.expects(:new).with(%w[localhost 192.168.1.1], {})
- store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1'
- assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
- end
-
- def test_mem_cache_fragment_cache_store_with_options
- MemCache.expects(:new).with(%w[localhost 192.168.1.1], { :timeout => 10 })
- store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1', :namespace => 'foo', :timeout => 10
- assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
- assert_equal 'foo', store.options[:namespace]
- end
-
def test_object_assigned_fragment_cache_store
store = ActiveSupport::Cache.lookup_store ActiveSupport::Cache::FileStore.new("/path/to/cache/directory")
assert_kind_of(ActiveSupport::Cache::FileStore, store)
@@ -693,56 +659,6 @@ def test_write_with_unless_exist
end
end
-uses_memcached 'memcached backed store' do
- class MemCacheStoreTest < ActiveSupport::TestCase
- def setup
- @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :expires_in => 60)
- @peek = ActiveSupport::Cache.lookup_store(:mem_cache_store)
- @data = @cache.instance_variable_get(:@data)
- @cache.clear
- @cache.silence!
- @cache.logger = ActiveSupport::Logger.new("/dev/null")
- end
-
- include CacheStoreBehavior
- include LocalCacheBehavior
- include CacheIncrementDecrementBehavior
- include EncodedKeyCacheBehavior
-
- def test_raw_values
- cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
- cache.clear
- cache.write("foo", 2)
- assert_equal "2", cache.read("foo")
- end
-
- def test_raw_values_with_marshal
- cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
- cache.clear
- cache.write("foo", Marshal.dump([]))
- assert_equal [], cache.read("foo")
- end
-
- def test_local_cache_raw_values
- cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
- cache.clear
- cache.with_local_cache do
- cache.write("foo", 2)
- assert_equal "2", cache.read("foo")
- end
- end
-
- def test_local_cache_raw_values_with_marshal
- cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
- cache.clear
- cache.with_local_cache do
- cache.write("foo", Marshal.dump([]))
- assert_equal [], cache.read("foo")
- end
- end
- end
-end
-
class NullStoreTest < ActiveSupport::TestCase
def setup
@cache = ActiveSupport::Cache.lookup_store(:null_store)
View
3 guides/code/getting_started/config/environments/production.rb
@@ -40,7 +40,8 @@
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
- # config.cache_store = :mem_cache_store
+ # Add dalli to Gemfile for :dalli_store
+ # config.cache_store = :dalli_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
View
3 railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -42,7 +42,8 @@
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
- # config.cache_store = :mem_cache_store
+ # Add dalli to Gemfile for :dalli_store
+ # config.cache_store = :dalli_store
@spastorino
Ruby on Rails member
spastorino added a note May 13, 2012

Do you need to set the cache_store to :dalli_store? Why the gem doesn't do that automatically?

@guilleiguaran
Ruby on Rails member

dalli isn't shipped with a railtie to set this config

cc @mperham

@mperham
mperham added a note May 15, 2012

Just a PR away. :-)

@steveklabnik
Ruby on Rails member
steveklabnik added a note May 17, 2012

@mperham just sent one ;) ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
Something went wrong with that request. Please try again.