cache-as-sor

The cache-as-sor pattern implies using the cache as though it were the primary system-of-record (SOR). The pattern delegates SOR reading and writing activities to the cache, so that application code is absolved of this responsibility.

To implement the cache-as-sor pattern, use a combination of the following read and write patterns:

  • read-through
  • write-through or write-behind

Advantages of using the cache-as-sor pattern are:

  • Less cluttered application code (improved maintainability)
  • Choice of write-through or write-behind strategies on a per-cache basis (use only configuration)
  • Allows the cache to solve the "thundering-herd" problem

A disadvantage of using the cache-as-sor pattern is:

  • Less directly visible code-path

cache-as-sor example

public class MyDataAccessClass 
{ 
private final Ehcache cache; 
public MyDataAccessClass(Ehcache cache) 
{ 
   cache.registerCacheWriter(new MyCacheWriter()); 
   this.cache = new SelfPopulatingCache(cache); 
} 
/* read some data - notice the cache is treated as an SOR. 
* the application code simply assumes the key will always be available 
*/ 
public V readSomeData(K key) 
{ 
   return cache.get(key); 
} 
/* write some data - notice the cache is treated as an SOR, it is 
* the cache's responsibility to write the data to the SOR. 
*/ 
public void writeSomeData(K key, V value) 
{ 
   cache.put(new Element(key, value); 
} 
/** 
* Implement the CacheEntryFactory that allows the cache to provide 
* the read-through strategy 
*/ 
private class MyCacheEntryFactory implements CacheEntryFactory 
{ 
   public Object createEntry(Object key) throws Exception 
   { 
       return readDataFromDataStore(key); 
   } 
} 
/** 
* Implement the CacheWriter interface which allows the cache to provide 
* the write-through or write-behind strategy. 
*/ 
private class MyCacheWriter implements CacheWriter 
   public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException; 
   { 
       throw new CloneNotSupportedException(); 
   } 
    public void init() { } 
   void dispose() throws CacheException { } 
    void write(Element element) throws CacheException; 
   { 
       writeDataToDataStore(element.getKey(), element.getValue()); 
   } 
    void writeAll(Collection<Element> elements) throws CacheException 
   { 
       for (Element element : elements) { 
           write(element); 
       } 
   } 
    void delete(CacheEntry entry) throws CacheException 
   { 
       deleteDataFromDataStore(element.getKey()); 
   } 
    void deleteAll(Collection<CacheEntry> entries) throws CacheException 
   { 
       for (Element element : elements) { 
           delete(element); 
       } 
   } 
} 
}