<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: cache code</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Thu, 24 Jul 2008 06:33:39 GMT</pubDate>
    <description>DZone Snippets: cache code</description>
    <item>
      <title>Automatic Expiration of Rails Action Caching</title>
      <link>http://snippets.dzone.com/posts/show/5776</link>
      <description>Would love to get some feedback on this...&lt;br /&gt;&lt;br /&gt;No doubt, 5 minutes after posting this, someone will tell me of the built-in Rails way of doing this, but alas I could not find it.&lt;br /&gt;&lt;br /&gt;Usage looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class PeopleController &lt; ApplicationController&lt;br /&gt;  caches_action :show, :for =&gt; 1.hour, :cache_path =&gt; Proc.new { |c| "people/#{c.params[:id]}_for_#{Person.logged_in.id}" }&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The ":for =&gt; 1.hour" part is where the magic happens.&lt;br /&gt;&lt;br /&gt;Basically, this bit of code adds a before_filter that checks the last modified time of the cache entry, and expires it if it is older than the specified time period.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;module ActionController&lt;br /&gt;  module Caching&lt;br /&gt;    module Fragments&lt;br /&gt;      # expire a cache key only if the block returns true or&lt;br /&gt;      # if the age of the fragment is more than the specified age argument.&lt;br /&gt;      def expire_fragment_by_mtime(key, age=nil, &amp;block)&lt;br /&gt;        block = Proc.new { |m| m &lt; age.ago } unless block_given?&lt;br /&gt;        if (m = cache_store.mtime(fragment_cache_key(key))) and block.call(m)&lt;br /&gt;          expire_fragment(key)&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    module Actions&lt;br /&gt;      module ClassMethods&lt;br /&gt;        # adds an option :for&lt;br /&gt;        # caches_action :show, :for =&gt; 2.hours, :cache_path =&gt; ...&lt;br /&gt;        # :cache_path is required, unfortunately&lt;br /&gt;        def caches_action_with_for(*actions)&lt;br /&gt;          original_actions = actions.clone&lt;br /&gt;          options = actions.extract_options!&lt;br /&gt;          if for_time = options.delete(:for)&lt;br /&gt;            cache_path = options[:cache_path]&lt;br /&gt;            before_filter do |controller|&lt;br /&gt;              cache_path = cache_path.call(controller) if cache_path.respond_to?(:call)&lt;br /&gt;              controller.expire_fragment_by_mtime(cache_path, for_time)&lt;br /&gt;            end&lt;br /&gt;          end&lt;br /&gt;          caches_action_without_for(*original_actions)&lt;br /&gt;        end&lt;br /&gt;        alias_method_chain :caches_action, :for&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Add a method to grab the last modified time of the cache key.&lt;br /&gt;# If you use a store other than the FileStore, you'll need to add&lt;br /&gt;# a method like this to your store.&lt;br /&gt;module ActiveSupport&lt;br /&gt;  module Cache&lt;br /&gt;    class FileStore&lt;br /&gt;      def mtime(name)&lt;br /&gt;        File.mtime(real_file_path(name)) rescue nil&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 16 Jul 2008 03:21:22 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5776</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Marshalize (Cache) ActiveRecord Query Results</title>
      <link>http://snippets.dzone.com/posts/show/5058</link>
      <description>A quick way to cache results in a file and read from the file on subsequent requests instead of the database. Makes the initial query a bit slower, but later queries *much* faster.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class MyCachedModel &lt; ActiveRecord::Base&lt;br /&gt;  class &lt;&lt; self&lt;br /&gt;    alias_method :rails_original_find_by_sql, :find_by_sql&lt;br /&gt;    def find_by_sql(sql)&lt;br /&gt;      cache_filename = Base64.encode64(sql)&lt;br /&gt;      if File.exists? cache_filename&lt;br /&gt;        Marshal.load(File.open(cache_filename))&lt;br /&gt;      else&lt;br /&gt;        Marshal.dump(records = rails_original_find_by_sql(sql), File.open(cache_filename, 'w'))&lt;br /&gt;        return records&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 31 Jan 2008 01:37:39 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5058</guid>
      <author>timmorgan (Tim Morgan)</author>
    </item>
    <item>
      <title>Attribute Cache</title>
      <link>http://snippets.dzone.com/posts/show/4002</link>
      <description>Sometimes, you don't want to calculate the value of an attribute every time--like the sum of an array.  However, you don't want it cached on the outside of the object since that makes for messy code.  But you seem to cache things over and over again inside objects.  Here's a module AttributeCache that does a little meta programming to make attribute caching a little bit easier.  more details at &lt;a href="http://webjazz.blogspot.com/2007/05/ruby-snippet-caching-object-attributes.html"&gt;http://webjazz.blogspot.com/2007/05/ruby-snippet-caching-object-attributes.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;module AttributeCache&lt;br /&gt;&lt;br /&gt;  def metaclass; class &lt;&lt; self; self; end; end&lt;br /&gt;  &lt;br /&gt;  def cache(attr_name, options)&lt;br /&gt;    instance_variable_set "@#{attr_name}", options[:initial]&lt;br /&gt;    instance_variable_set "@#{:sum}_outdated", true&lt;br /&gt;&lt;br /&gt;    metaclass.instance_eval do &lt;br /&gt;      define_method("outdate_#{attr_name}") do&lt;br /&gt;        puts "in outdated"&lt;br /&gt;        instance_variable_set "@#{attr_name}_outdated", true&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    metaclass.class_eval %Q{&lt;br /&gt;      def cached_#{attr_name}(&amp;block)&lt;br /&gt;        if @#{attr_name}_outdated&lt;br /&gt;          puts "in cached to update!"&lt;br /&gt;          @#{attr_name}_outdated = false&lt;br /&gt;          @#{attr_name} = block.call&lt;br /&gt;        else&lt;br /&gt;          puts "in cached to give cache!"&lt;br /&gt;        end&lt;br /&gt;        return @#{attr_name}&lt;br /&gt;      end&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Collection&lt;br /&gt;  include AttributeCache&lt;br /&gt;&lt;br /&gt;  def initialize&lt;br /&gt;    @array = []&lt;br /&gt;    cache :sum, :initial =&gt; 0&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def add(x)&lt;br /&gt;    outdate_sum&lt;br /&gt;    @array &lt;&lt; x&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def sum&lt;br /&gt;    cached_sum { @array.inject {|t, e| t += e} }&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;c = Collection.new&lt;br /&gt;puts c.public_methods(false).inspect&lt;br /&gt;c.add(2)&lt;br /&gt;c.add(3)&lt;br /&gt;puts c.sum&lt;br /&gt;puts c.sum&lt;br /&gt;c.add(4)&lt;br /&gt;puts c.sum&lt;br /&gt;puts c.sum&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Sun, 13 May 2007 13:45:43 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4002</guid>
      <author>iamwil (wilhelm)</author>
    </item>
    <item>
      <title>JS cache control</title>
      <link>http://snippets.dzone.com/posts/show/3507</link>
      <description>The following JSP snippet shows a simple caching policy for JS files, i.e.&lt;br /&gt;the browser fetches js files when a new build is available.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;qBuildNum&lt;/em&gt; is a build number or a repository revision suffix, e.g.?102 etc.&lt;br /&gt;&lt;em&gt;ServerInfoService.getBuildNumber()&lt;/em&gt; is a function which returns current build number. This function has to be coded manually, alternatively a servlet context attribute can be used...&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;%&lt;br /&gt;    String qBuildNum = '?' + ServerInfoService.getBuildNumber(); //Suffix for JS to avoid caching&lt;br /&gt;%&gt;&lt;br /&gt;&lt;script type="text/javascript" src="dwr/engine.js?113"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="dwr/util.js?113"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="rico/prototype.js?14"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="rico/rico.js?112"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="script/controller.js&lt;%=qBuildNum%&gt;"&gt;&lt;/script&gt;&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Tue, 13 Feb 2007 08:21:16 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3507</guid>
      <author>ejboy (Fyodor Kupolov)</author>
    </item>
    <item>
      <title>Rails - &#8216;poor mans&#8217; SQL cache.</title>
      <link>http://snippets.dzone.com/posts/show/3286</link>
      <description>Rails memcached is not very easy to introduce to a large rails installation. Memcached also chews up a lot of memory on the box and overall cached model does not work the way I needed it to. Basically, I have just a &#226;&#8364;&#339;few&#226;&#8364;? queries that I needed to cache because pagination sucks just that bad in rails.&lt;br /&gt;So, I built my own cache, similar to how I build them in PHP except I am not using disk cache, I am using MySQL itself to cache it&#226;&#8364;&#8482;s own results&lt;br /&gt;&lt;br /&gt;First, we need a table to hold all this info (note the &#226;&#8364;&#732;blob&#226;&#8364;&#8482; field)&lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE TABLE `cacheditems` (&lt;br /&gt;`id` int(11) NOT NULL auto_increment,&lt;br /&gt;`cachekey` varchar(255) default NULL,&lt;br /&gt;`created` datetime default NULL,&lt;br /&gt;`expires` datetime default NULL,&lt;br /&gt;`content` longblob,&lt;br /&gt;`cachehit` int(11) NOT NULL,&lt;br /&gt;PRIMARY KEY  (`id`),&lt;br /&gt;KEY `cacheditems_cachekey_index` (`cachekey`),&lt;br /&gt;KEY `cacheditems_created_index` (`created`),&lt;br /&gt;KEY `cacheditems_expires_index` (`expires`)&lt;br /&gt;)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then we create a model called &#226;&#8364;&#339;cacheditem&#226;&#8364;? which has the following functions&lt;br /&gt;&lt;code&gt;&lt;br /&gt;require 'digest/sha1'&lt;br /&gt;class Cacheditem &lt; ActiveRecord::Base&lt;br /&gt;&lt;br /&gt;def self.checkfor(sql)&lt;br /&gt;key = Digest::MD5.hexdigest(Marshal.dump(sql))&lt;br /&gt;logger.info "%%% checking for key #{key}"&lt;br /&gt;#logger.info "%%% checking by sql #{sql[0]}"&lt;br /&gt;Cacheditem.find( :first, :conditions =&gt; [ &#226;&#8364;&#339;cachekey = ? AND expires &gt; NOW()&#226;&#8364;?, key] )&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def self.getcached(sql)&lt;br /&gt;key = Digest::MD5.hexdigest(Marshal.dump(sql))&lt;br /&gt;logger.info &#226;&#8364;&#339;%%% getting by key #{key}&#226;&#8364;?&lt;br /&gt;#logger.info &#226;&#8364;&#339;%%% getting by sql #{sql[0]}&#226;&#8364;?&lt;br /&gt;getc = Cacheditem.find( :first, :conditions =&gt; [ &#226;&#8364;&#339;cachekey = ?&#226;&#8364;?, key] )&lt;br /&gt;hitcount = getc.cachehit + 1&lt;br /&gt;Cacheditem.update(getc.id, {:cachehit =&gt; hitcount})&lt;br /&gt;Cacheditem.delete_all &#226;&#8364;&#339;expires &lt; NOW()"  # cleaner&lt;br /&gt;return Marshal.load( getc.content )&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def self.storeresult(sql, result)&lt;br /&gt;key = Digest::MD5.hexdigest(Marshal.dump(sql))&lt;br /&gt;logger.info "%%% storing by key #{key}"&lt;br /&gt;content = Marshal.dump(result)&lt;br /&gt;logger.level = (4) # this stops display in logs of the marshal data&lt;br /&gt;ci = new()&lt;br /&gt;ci.cachekey    = key&lt;br /&gt;ci.created       = Time.now()&lt;br /&gt;ci.expires        = 30.minutes.from_now() # change as needed&lt;br /&gt;ci.content        = content&lt;br /&gt;ci.cachehit       = 0&lt;br /&gt;ci.save&lt;br /&gt;return  result&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then, in application.rb I added the following function&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def find_by_sql_cache(sql)&lt;br /&gt;iscached = Cacheditem.checkfor(sql)&lt;br /&gt;if iscached&lt;br /&gt;Cacheditem.getcached(sql)&lt;br /&gt;else&lt;br /&gt;result = connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }&lt;br /&gt;Cacheditem.storeresult(sql, result)&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;just throw &#226;&#8364;&#339;_cache&#226;&#8364;? after any &#226;&#8364;&#339;find_by_sql&#226;&#8364;? statement you have a need to cache and there you are.&lt;br /&gt;&lt;br /&gt;This works very fast, very well, and doesn&#226;&#8364;&#8482;t hog your memory. It cleans up after itself in the database, and perhaps it does that too much.. It would be easy to add in a standard garbage collection function which runs on a random but I felt this gave me much better stats of the actual thirty-minute cache&#226;&#8364;&#166;&lt;br /&gt;If you use zabbix for monitoring your network, you can have fun graphs of cache statistics by adding the following to your zabbix_agentd.conf&lt;br /&gt;&lt;code&gt;&lt;br /&gt;UserParameter=mysql.totalcache,mysql &#226;&#8364;&#8220;batch &#226;&#8364;&#8220;skip-column-names -D {YOUR_DATABASE} -u{YOUR_USERNAME} -p{YOUR_PASSWORD} -e &#226;&#8364;&#339;SELECT count( * ) AS total, SUM( cachehit ) AS amount from cacheditems;&#226;&#8364;? | cut -f1&lt;br /&gt;UserParameter=mysql.cachehits,mysql &#226;&#8364;&#8220;batch &#226;&#8364;&#8220;skip-column-names -D {YOUR_DATABASE} -u{YOUR_USERNAME} -p{YOUR_PASSWORD} -e &#226;&#8364;&#339;SELECT count( * ) AS total, SUM( cachehit ) AS amount from cacheditems;&#226;&#8364;? | cut -f2&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Mon, 15 Jan 2007 22:55:31 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3286</guid>
      <author>joeldg (joeldg)</author>
    </item>
    <item>
      <title>Time based expiration of cache fragments in Ruby on Rails (MemCacheStore and FileStore)</title>
      <link>http://snippets.dzone.com/posts/show/2975</link>
      <description>This allows to expire cached fragments by ttl. Example usage (in views):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;% cache("name", :ttl =&gt; 7.days) do %&gt;&lt;br /&gt;  ... some database-heavy stuff ...&lt;br /&gt;&lt;% end %&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Put the following in environment.rb or in lib/.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class ActionController::Caching::Fragments::MemCacheStore&lt;br /&gt;  def write(name, value, options=nil)&lt;br /&gt;    if options.is_a?(Hash) &amp;&amp; options.has_key?(:ttl)&lt;br /&gt;      ttl = options[:ttl]&lt;br /&gt;    else&lt;br /&gt;      ttl = 0&lt;br /&gt;    end&lt;br /&gt;    @data.set(name, value, ttl)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module ActionView::Helpers::CacheHelper&lt;br /&gt;  def cache(name = {}, options = nil, &amp;block)&lt;br /&gt;    @controller.cache_erb_fragment(block, name, options)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class ActionController::Caching::Fragments::UnthreadedFileStore&lt;br /&gt;  def read(name, options = nil) &lt;br /&gt;    if options.is_a?(Hash) &amp;&amp; options.has_key?(:ttl)&lt;br /&gt;      ttl = options[:ttl]&lt;br /&gt;    else&lt;br /&gt;      ttl = 0&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    fn = real_file_path(name)&lt;br /&gt;&lt;br /&gt;    # if cache expired act as if file doesn't exist&lt;br /&gt;    return if ttl &gt; 0 &amp;&amp; File.exists?(fn) &amp;&amp; (File.mtime(fn) &lt; (Time.now - ttl))&lt;br /&gt;&lt;br /&gt;    File.open(fn, 'rb') { |f| f.read } rescue nil&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Mon, 06 Nov 2006 13:00:58 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2975</guid>
      <author>jacek.becela (Jacek Becela)</author>
    </item>
    <item>
      <title>Clear DNS lookup / IP address cache on OS X Tiger</title>
      <link>http://snippets.dzone.com/posts/show/598</link>
      <description>&lt;code&gt;lookupd -flushcache&lt;/code&gt;</description>
      <pubDate>Thu, 25 Aug 2005 06:37:15 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/598</guid>
      <author>peter (Peter Cooperx)</author>
    </item>
  </channel>
</rss>
