<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/interlock/pass_through_store.rb</filename>
    </added>
    <added>
      <filename>test/unit/finder_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,5 @@
 
-v1.3. Add basic model caching.
+v1.3. Add basic finder memoization.
 
 v1.2. Add compatibility with Memcached client.
 </diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -6,8 +6,10 @@ lib/interlock/action_view.rb
 lib/interlock/active_record.rb
 lib/interlock/config.rb
 lib/interlock/core_extensions.rb
+lib/interlock/finders.rb
 lib/interlock/interlock.rb
 lib/interlock/lock.rb
+lib/interlock/pass_through_store.rb
 lib/interlock.rb
 LICENSE
 Manifest
@@ -77,6 +79,7 @@ test/integration/server_test.rb
 test/setup.rb
 test/teardown.rb
 test/test_helper.rb
+test/unit/finder_test.rb
 test/unit/interlock_test.rb
 test/unit/lock_test.rb
 TODO</diff>
      <filename>Manifest</filename>
    </modified>
    <modified>
      <diff>@@ -19,11 +19,15 @@ If you use this software, please {make a donation}[http://blog.evanweaver.com/do
 
 Note that Rails 2.0.2 is required for caching &lt;tt&gt;content_for&lt;/tt&gt; or nesting &lt;tt&gt;view_cache&lt;/tt&gt; blocks.
 
-== What it does
+== Features
 
-Interlock makes your view fragments and associated controller blocks march along together. If a fragment is fresh, the controller behavior won't run. This eliminates duplicate effort from your request cycle. Your controller blocks run so infrequently that you can use regular ActiveRecord finders and not worry about object caching at all.
+Interlock is an intelligent fragment cache for Rails. 
 
-Interlock automatically tracks invalidation dependencies based on the model lifecyle, and supports arbitrary levels of scoping per-block. It also caches &lt;tt&gt;content_for&lt;/tt&gt; calls, unlike regular Rails.
+It works by making your view fragments and associated controller blocks march along together. If a fragment is fresh, the controller behavior won't run. This eliminates duplicate effort from your request cycle. Your controller blocks run so infrequently that you can use regular ActiveRecord finders and not worry about object caching at all.
+
+Invalidations are automatically tracked based on the model lifecyle, and you can scope any block to an arbitrary level. Interlock also caches &lt;tt&gt;content_for&lt;/tt&gt; calls, unlike regular Rails, and can optionally cache simple finders.
+
+Interlock uses a tiered caching layer so that multiple lookups of a key only hit memcached once per request.
 
 == Installation
   
@@ -87,6 +91,18 @@ You can use multiple instance variables in one block, of course. Just make sure
 
 See ActionController::Base and ActionView::Helpers::CacheHelper for more details.
 
+== Caching finders
+
+Interlock 1.3 adds the ability to cache simple finder lookups. Add this line in &lt;tt&gt;config/memcached.yml&lt;/tt&gt;:
+
+  with_finders: true
+  
+Now, whenever you call &lt;b&gt;find&lt;/b&gt;, &lt;b&gt;find_by_id&lt;/b&gt;, or &lt;b&gt;find_all_by_id&lt;/b&gt; with a single id or an array of ids, the cache will be used. The cache key for each record invalidates when the record is saved or destroyed. Memcached's multiget mode is used for maximum performance.
+
+If you pass any parameters other than ids, or use dynamic finders, the cache will not be used. This means that &lt;tt&gt;:include&lt;/tt&gt; works as expected and does not require complicated invalidation. 
+
+See Interlock::Finders for more.
+
 == Notes
 
 You will not see any actual cache reuse in development mode unless you set &lt;tt&gt;config.action_controller.perform_caching = true&lt;/tt&gt; in &lt;tt&gt;config/environments/development.rb&lt;/tt&gt;.</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -7,7 +7,7 @@ Echoe.new(&quot;interlock&quot;) do |p|
   p.url = &quot;http://blog.evanweaver.com/files/doc/fauna/interlock/&quot;  
   p.docs_host = &quot;blog.evanweaver.com:~/www/bax/public/files/doc/&quot;  
   p.test_pattern = [&quot;test/integration/*.rb&quot;, &quot;test/unit/*.rb&quot;]
-  p.rdoc_pattern = [&quot;README&quot;, &quot;CHANGELOG&quot;, &quot;TODO&quot;, &quot;LICENSE&quot;, &quot;lib/interlock/memcached.rb&quot;, &quot;lib/interlock/interlock.rb&quot;, &quot;lib/interlock/action_controller.rb&quot;, &quot;lib/interlock/active_record.rb&quot;, &quot;lib/interlock/action_view.rb&quot;, &quot;lib/interlock/config.rb&quot;]
+  p.rdoc_pattern = [&quot;README&quot;, &quot;CHANGELOG&quot;, &quot;TODO&quot;, &quot;LICENSE&quot;, &quot;lib/interlock/lock.rb&quot;, &quot;lib/interlock/interlock.rb&quot;, &quot;lib/interlock/action_controller.rb&quot;, &quot;lib/interlock/active_record.rb&quot;, &quot;lib/interlock/finders.rb&quot;, &quot;lib/interlock/action_view.rb&quot;, &quot;lib/interlock/config.rb&quot;]
   p.clean_pattern += ['test/integration/app/coverage', 'test/integration/app/db/schema.rb',
                       'test/integration/app/vendor/plugins/interlock']
 end</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,7 @@ require 'interlock/core_extensions'
 require 'interlock/config'
 require 'interlock/interlock'
 require 'interlock/lock'
+require 'interlock/pass_through_store'
 require 'interlock/action_controller'
 require 'interlock/action_view'
 require 'interlock/finders'</diff>
      <filename>lib/interlock.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,7 @@ module Interlock
     :with_finders =&gt; false
   }    
   
-  CLIENT_KEYS = [ #:nodoc:
+  CLIENT_KEYS = [ 
     :hash,
     :no_block,
     :buffer_requests,
@@ -17,7 +17,7 @@ module Interlock
     :tcp_nodelay,
     :distribution,
     :namespace
-  ]
+  ] 
 
   mattr_accessor :config 
   @@config = DEFAULTS</diff>
      <filename>lib/interlock/config.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,7 @@ module Interlock
     #    
     def find(*args)
       return find_via_db(*args) if args.last.is_a? Hash or args.first.is_a? Symbol
-      records = find_via_cache(args, true)
+      records = find_via_cache(args.flatten, true)
 
       if args.length &gt; 1 or args.first.is_a? Array
         records
@@ -32,7 +32,7 @@ module Interlock
     #    
     def find_all_by_id(*args)
       return method_missing(:find_all_by_id, *args) if args.last.is_a? Hash 
-      find_via_cache(ids, false)
+      find_via_cache(args, false)
     end
     
     #
@@ -49,7 +49,7 @@ module Interlock
         
     private
     
-    def find_via_cache(ids, should_raise)
+    def find_via_cache(ids, should_raise) #:doc:
       results = []
 
       ordered_keys_to_ids = ids.map { |id| [caching_key(id), id.to_i] }
@@ -75,10 +75,7 @@ module Interlock
       results      
     end
     
-    def load_from_local_cache(current, keys_to_ids)
-      # Console and tests do not install the local cache
-      return unless Interlock.local_cache
-            
+    def load_from_local_cache(current, keys_to_ids) #:doc:            
       # Load from the local cache      
       records = {}
       keys_to_ids.each do |key, |
@@ -88,7 +85,7 @@ module Interlock
       current.merge!(records)        
     end
 
-    def load_from_memcached(current, keys_to_ids)
+    def load_from_memcached(current, keys_to_ids) #:doc:
       # Drop to memcached if necessary
       if current.size &lt; keys_to_ids.size
         records = {}
@@ -106,7 +103,7 @@ module Interlock
       end    
     end
 
-    def load_from_db(current, keys_to_ids)
+    def load_from_db(current, keys_to_ids) #:doc:
       # Drop to db if necessary
       if current.size &lt; keys_to_ids.size
         missed = keys_to_ids.reject { |key, | current[key] }</diff>
      <filename>lib/interlock/finders.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,6 +26,11 @@ module Interlock
   ILLEGAL_KEY_CHARACTERS_PATTERN = /\s/
   
   mattr_accessor :local_cache
+  
+  # Install the pass-through store. This is used in the console and test 
+  # environment. In a server environment, the controller callbacks install
+  # the memory store before each request.  
+  @@local_cache = Interlock::PassThroughStore.new
     
   class &lt;&lt; self
     #</diff>
      <filename>lib/interlock/interlock.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ class ServerTest &lt; Test::Unit::TestCase
   end
   
   
-  ### Tests
+  ### Fragment caching tests
   
   def test_render
     assert_match(/Welcome/, browse)</diff>
      <filename>test/integration/server_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,9 +6,11 @@ Dir.chdir &quot;#{File.dirname(__FILE__)}/integration/app/&quot; do
   `ps awx`.split(&quot;\n&quot;).grep(/4304[1-3]/).map do |process| 
     system(&quot;kill -9 #{process.to_i}&quot;)
   end
+  
+  LOG = &quot;/tmp/memcached.log&quot;
 
-  system &quot;memcached -p 43042 &amp;&quot;
-  system &quot;memcached -p 43043 &amp;&quot;
+  system &quot;memcached -vv -p 43042 &gt;&gt; #{LOG} 2&gt;&amp;1 &amp;&quot;
+  system &quot;memcached -vv -p 43043 &gt;&gt; #{LOG} 2&gt;&amp;1 &amp;&quot;
   
   Dir.chdir &quot;vendor/plugins&quot; do
     system &quot;rm interlock; ln -s ../../../../../ interlock&quot;</diff>
      <filename>test/setup.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>d0e717df97621f6cef8a3048e4b3589c47423483</id>
    </parent>
  </parents>
  <author>
    <name>Evan Weaver</name>
    <email>evan@cloudbur.st</email>
  </author>
  <url>http://github.com/lackac/interlock/commit/182a40060cc10abf248a7b97a276b391cccda647</url>
  <id>182a40060cc10abf248a7b97a276b391cccda647</id>
  <committed-date>2008-02-14T15:17:42-08:00</committed-date>
  <authored-date>2008-02-14T15:17:42-08:00</authored-date>
  <message>Backport tests and fixes for finder caching.</message>
  <tree>5c0a79d226a8d78301fc7110d40f8cb7cc65f73c</tree>
  <committer>
    <name>Evan Weaver</name>
    <email>evan@cloudbur.st</email>
  </committer>
</commit>
