Rails MemcachedStore for the Memcached Gem

Posted by acts_as_flinn Sun, 26 Oct 2008 01:55:00 GMT

11

I’ve been experimenting with the memcached gem (the c gem that runs up to 150x faster than memcache-client). Merb already has pretty good support for the Memcached gem and in typical merb style does it better with fewer lines of code but I digress. Here’s my test implementation, so far so good nothing really heavy on it yet. YMMV so be warned this is not tested in a production environment don’t say I didn’t warn you so and such.


# in your environment file
config.cache_store = :memcached_store, 'localhost:11211'

# lib/memcached_store.rb
require 'memcached'

module ActiveSupport
  module Cache
    class MemcachedStore < Store
      attr_reader :addresses

      def initialize(*addresses)
        addresses = addresses.flatten
        options = addresses.extract_options!
        addresses = ["localhost"] if addresses.empty?
        @addresses = addresses
        @data = Memcached::Rails.new(addresses, options)
      end

      def read(key, options = nil)
        super
        @data.get(key, raw?(options))
      rescue Memcached::Error => e
        logger.error("Memcached::Error (#{e}): #{e.message}")
        nil
      end

      # Set key = value. Pass :unless_exist => true if you don't 
      # want to update the cache if the key is already set. 
      def write(key, value, options = nil)
        super
        method = options && options[:unless_exist] ? :add : :set
        response = @data.send(method, key, value, expires_in(options), raw?(options))
        response == nil
      rescue Memcached::Error => e
        logger.error("Memcached::Error (#{e}): #{e.message}")
        false
      end

      def delete(key, options = nil)
        super
        response = @data.delete(key, expires_in(options))
        response == nil
      rescue Memcached::Error => e
        logger.error("Memcached::Error (#{e}): #{e.message}")
        false
      end

      def exist?(key, options = nil)
        # Doesn't call super, cause exist? in memcache is in fact a read
        # But who cares? Reading is very fast anyway
        !read(key, options).nil?
      end

      def increment(key, amount = 1)       
        log("incrementing", key, amount)

        @data.incr(key, amount)  
      rescue Memcached::Error
        nil
      end

      def decrement(key, amount = 1)
        log("decrement", key, amount)

        @data.decr(key, amount) 
      rescue Memcached::Error
        nil
      end        

      def delete_matched(matcher, options = nil)
        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
Snippet

Thoughts on User.current and Thread Safety

Posted by acts_as_flinn Sun, 26 Oct 2008 01:38:00 GMT

A thimble

Pratik Naik has an interesting post Thread safety for your Rails about what thread safety in Rails means (and what it doesn’t). One of the interesting points is that a common pattern of using class attributes is not thread safe and can lead to race conditions. I found it interesting because I’m a big proponent of User.current. I’ve always gotten great millage out of it and I’ve always felt like it’s a necessary evil for protecting user_id attributes from mass assignment and not totally driving yourself nuts with @foo.user_id = session[:user_id] all over your controller actions.

So the problem now is that if you ever intend to use User.current with a thread safe Rails app you’ve got to adjust fire. My thoughts are now turned toward investigating the following.


class ApplicationController < ActionController::Base
 before_filter :current_user_id

 # Set the value
 def current_user_id
   Thread.current[:current_user_id] = session[:user_id]
 end
end

class User < ActiveRecord::Base
 def self.current
   Thread.current[:current_user] ||= self.fetch_by_id(Thread.current[:current_user_id])
 end
end
Snippet

This seems like a thread safe method of accessing the current User without trading off the real functionality we want.

Slicehost Acquired by Rackspace

Posted by acts_as_flinn Sat, 25 Oct 2008 19:38:00 GMT

Slicehost

In case you’ve had your head in the sand the technology world is abuzz with hype about “the cloud”. Last week Rackspace had there own little cloud announcement and I was grimacing with the thought of yet another large host entering the fray. In case you don’t know I’m not a huge fan of “the cloud,” so I was imagining Rackspace might introduce yet another subpar on demand computing service. I couldn’t have been more wrong as it turns out. Rackspace wasn’t introducing a new unprove service, they were acquiring a proven leader already well respected in the industry, Slicehost.

Slicehost has been around for a few years now and has had such demand in the beginning I was on a waiting list. It was worth it because the service has been great. I’ve been hosting Snippy for a little while now on it and a few other things and I’m very happy. I’ve also had really great luck with Rackspace in the past so to hear that they were going to be adding their financial support and letting Slicehost run as a subsidiary is a awesome.

Slicehost will be able to keep it’s great level of support and is already lowering the pricing on some of their existing slices. Check them out if you’re looking for rails hosting, they’‘re well worth it.

Older posts: 1 2 3 ... 13