diff options
8 files changed, 446 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore index c96a5f491..aa5036394 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -tmp -log -coverage -sqlitedbs -cache +/tmp +/log +/coverage +/sqlitedbs +/cache .*.swp *~ diff --git a/vendor/rails/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb b/vendor/rails/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb new file mode 100644 index 000000000..d87eb1733 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb @@ -0,0 +1,20 @@ +module ActiveSupport + module Cache + class CompressedMemCacheStore < MemCacheStore + def read(name, options = nil) + if value = super(name, (options || {}).merge(:raw => true)) + if raw?(options) + value + else + Marshal.load(ActiveSupport::Gzip.decompress(value)) + end + end + end + + def write(name, value, options = nil) + value = ActiveSupport::Gzip.compress(Marshal.dump(value)) unless raw?(options) + super(name, value, (options || {}).merge(:raw => true)) + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/drb_store.rb b/vendor/rails/activesupport/lib/active_support/cache/drb_store.rb new file mode 100644 index 000000000..b16ed25aa --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/drb_store.rb @@ -0,0 +1,14 @@ +module ActiveSupport + module Cache + class DRbStore < MemoryStore #:nodoc: + attr_reader :address + + def initialize(address = 'druby://localhost:9192') + require 'drb' unless defined?(DRbObject) + super() + @address = address + @data = DRbObject.new(nil, address) + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/file_store.rb b/vendor/rails/activesupport/lib/active_support/cache/file_store.rb new file mode 100644 index 000000000..7f34cb52a --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/file_store.rb @@ -0,0 +1,72 @@ +module ActiveSupport + module Cache + # A cache store implementation which stores everything on the filesystem. + class FileStore < Store + attr_reader :cache_path + + def initialize(cache_path) + @cache_path = cache_path + end + + def read(name, options = nil) + super + File.open(real_file_path(name), 'rb') { |f| Marshal.load(f) } rescue nil + end + + def write(name, value, options = nil) + super + ensure_cache_path(File.dirname(real_file_path(name))) + File.atomic_write(real_file_path(name), cache_path) { |f| Marshal.dump(value, f) } + value + rescue => e + logger.error "Couldn't create cache directory: #{name} (#{e.message})" if logger + end + + def delete(name, options = nil) + super + File.delete(real_file_path(name)) + rescue SystemCallError => e + # If there's no cache, then there's nothing to complain about + end + + def delete_matched(matcher, options = nil) + super + search_dir(@cache_path) do |f| + if f =~ matcher + begin + File.delete(f) + rescue SystemCallError => e + # If there's no cache, then there's nothing to complain about + end + end + end + end + + def exist?(name, options = nil) + super + File.exist?(real_file_path(name)) + end + + private + def real_file_path(name) + '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')] + end + + def ensure_cache_path(path) + FileUtils.makedirs(path) unless File.exist?(path) + end + + def search_dir(dir, &callback) + Dir.foreach(dir) do |d| + next if d == "." || d == ".." + name = File.join(dir, d) + if File.directory?(name) + search_dir(name, &callback) + else + callback.call name + end + end + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb b/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb new file mode 100644 index 000000000..4d8e1fdd6 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -0,0 +1,132 @@ +require 'memcache' + +module ActiveSupport + module Cache + # A cache store implementation which stores data in Memcached: + # http://www.danga.com/memcached/ + # + # 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 goes back + # online. + # - Time-based expiry support. See #write and the +:expires_in+ option. + # - Per-request in memory cache for all communication with the MemCache server(s). + 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 + + attr_reader :addresses + + # 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). + def initialize(*addresses) + addresses = addresses.flatten + options = addresses.extract_options! + addresses = ["localhost"] if addresses.empty? + @addresses = addresses + @data = MemCache.new(addresses, options) + + extend Strategy::LocalCache + end + + def read(key, options = nil) # :nodoc: + super + @data.get(key, raw?(options)) + rescue MemCache::MemCacheError => e + logger.error("MemCacheError (#{e}): #{e.message}") + nil + end + + # Writes a value to the cache. + # + # Possible options: + # - +:unless_exist+ - set to true if you don't want to update the cache + # if the key is already set. + # - +:expires_in+ - the number of seconds that this value may stay in + # the cache. See ActiveSupport::Cache::Store#write for an example. + def write(key, value, options = nil) + super + method = options && options[:unless_exist] ? :add : :set + # memcache-client will break the connection if you send it an integer + # in raw mode, so we convert it to a string to be sure it continues working. + value = value.to_s if raw?(options) + response = @data.send(method, key, value, expires_in(options), raw?(options)) + response == Response::STORED + rescue MemCache::MemCacheError => e + logger.error("MemCacheError (#{e}): #{e.message}") + false + end + + def delete(key, options = nil) # :nodoc: + super + response = @data.delete(key, expires_in(options)) + response == Response::DELETED + rescue MemCache::MemCacheError => e + logger.error("MemCacheError (#{e}): #{e.message}") + false + end + + def exist?(key, options = nil) # :nodoc: + # Doesn't call super, cause exist? in memcache is in fact a read + # But who cares? Reading is very fast anyway + # Local cache is checked first, if it doesn't know then memcache itself is read from + !read(key, options).nil? + end + + def increment(key, amount = 1) # :nodoc: + log("incrementing", key, amount) + + response = @data.incr(key, amount) + response == Response::NOT_FOUND ? nil : response + rescue MemCache::MemCacheError + nil + end + + def decrement(key, amount = 1) # :nodoc: + log("decrement", key, amount) + response = @data.decr(key, amount) + response == Response::NOT_FOUND ? nil : response + rescue MemCache::MemCacheError + nil + end + + def delete_matched(matcher, options = nil) # :nodoc: + # don't do any local caching at present, just pass + # through and let the error happen + super + raise "Not supported by Memcache" + end + + def clear + @data.flush_all + end + + def stats + @data.stats + end + + private + def expires_in(options) + (options && options[:expires_in]) || 0 + end + + def raw?(options) + options && options[:raw] + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/memory_store.rb b/vendor/rails/activesupport/lib/active_support/cache/memory_store.rb new file mode 100644 index 000000000..1b30d4915 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/memory_store.rb @@ -0,0 +1,52 @@ +module ActiveSupport + module Cache + # A cache store implementation which stores everything into memory in the + # same process. If you're running multiple Ruby on Rails server processes + # (which is the case if you're using mongrel_cluster or Phusion Passenger), + # then this means that your Rails server process instances won't be able + # to share cache data with each other. If your application never performs + # manual cache item expiry (e.g. when you're using generational cache keys), + # then using MemoryStore is ok. Otherwise, consider carefully whether you + # should be using this cache store. + # + # MemoryStore is not only able to store strings, but also arbitrary Ruby + # objects. + # + # MemoryStore is not thread-safe. Use SynchronizedMemoryStore instead + # if you need thread-safety. + class MemoryStore < Store + def initialize + @data = {} + end + + def read(name, options = nil) + super + @data[name] + end + + def write(name, value, options = nil) + super + @data[name] = value.freeze + end + + def delete(name, options = nil) + super + @data.delete(name) + end + + def delete_matched(matcher, options = nil) + super + @data.delete_if { |k,v| k =~ matcher } + end + + def exist?(name,options = nil) + super + @data.has_key?(name) + end + + def clear + @data.clear + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb b/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb new file mode 100644 index 000000000..d83e259a2 --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -0,0 +1,104 @@ +module ActiveSupport + module Cache + module Strategy + module LocalCache + # this allows caching of the fact that there is nothing in the remote cache + NULL = 'remote_cache_store:null' + + def with_local_cache + Thread.current[thread_local_key] = MemoryStore.new + yield + ensure + Thread.current[thread_local_key] = nil + end + + def middleware + @middleware ||= begin + klass = Class.new + klass.class_eval(<<-EOS, __FILE__, __LINE__) + def initialize(app) + @app = app + end + + def call(env) + Thread.current[:#{thread_local_key}] = MemoryStore.new + @app.call(env) + ensure + Thread.current[:#{thread_local_key}] = nil + end + EOS + klass + end + end + + def read(key, options = nil) + value = local_cache && local_cache.read(key) + if value == NULL + nil + elsif value.nil? + value = super + local_cache.write(key, value || NULL) if local_cache + value + else + # forcing the value to be immutable + value.duplicable? ? value.dup : value + end + end + + def write(key, value, options = nil) + value = value.to_s if respond_to?(:raw?) && raw?(options) + local_cache.write(key, value || NULL) if local_cache + super + end + + def delete(key, options = nil) + local_cache.write(key, NULL) if local_cache + super + end + + def exist(key, options = nil) + value = local_cache.read(key) if local_cache + if value == NULL + false + elsif value + true + else + super + end + end + + def increment(key, amount = 1) + if value = super + local_cache.write(key, value.to_s) if local_cache + value + else + nil + end + end + + def decrement(key, amount = 1) + if value = super + local_cache.write(key, value.to_s) if local_cache + value + else + nil + end + end + + def clear + local_cache.clear if local_cache + super + end + + private + def thread_local_key + @thread_local_key ||= "#{self.class.name.underscore}_local_cache".gsub("/", "_").to_sym + end + + def local_cache + Thread.current[thread_local_key] + end + end + end + end +end diff --git a/vendor/rails/activesupport/lib/active_support/cache/synchronized_memory_store.rb b/vendor/rails/activesupport/lib/active_support/cache/synchronized_memory_store.rb new file mode 100644 index 000000000..ea03a119c --- /dev/null +++ b/vendor/rails/activesupport/lib/active_support/cache/synchronized_memory_store.rb @@ -0,0 +1,47 @@ +module ActiveSupport + module Cache + # Like MemoryStore, but thread-safe. + class SynchronizedMemoryStore < MemoryStore + def initialize + super + @guard = Monitor.new + end + + def fetch(key, options = {}) + @guard.synchronize { super } + end + + def read(name, options = nil) + @guard.synchronize { super } + end + + def write(name, value, options = nil) + @guard.synchronize { super } + end + + def delete(name, options = nil) + @guard.synchronize { super } + end + + def delete_matched(matcher, options = nil) + @guard.synchronize { super } + end + + def exist?(name,options = nil) + @guard.synchronize { super } + end + + def increment(key, amount = 1) + @guard.synchronize { super } + end + + def decrement(key, amount = 1) + @guard.synchronize { super } + end + + def clear + @guard.synchronize { super } + end + end + end +end |