Thursday, January 17, 2013

Cache storage explained

Introduction 

Caching is about improve applications performance. The most expensive performance costs of the applications are related with the data retrieving, typically when this data requires to be moved across the network or loaded from disk. But some data have an slow changing behavior (a.k.a nonvolatile) and doesn't requires to be re-read with the same frequency of the volatile data.

So, to improve your application performance and handling this "nonvolatile" data from a pretty clean approach, Catel comes with a CacheStorage<TKey, TValue> class. Notice that the first generic parameter is the type of the key and the second the type of the value that will be stored, just like a Dictionary<TKey, TValue> but CacheStorage isn't it just a Dictionary. 

This class allows you to retrieve data and storing it into the cache with single statement and also helps you to handle expiration policy if you need it.

Let’s take a look into these features:

Initializing a cache storage

To initialize a cache storage field into your class use the follow code:

/*...*/
private readonly CacheStorage<string, Person> _personCache = new CacheStorageCacheStorage<string, Person>(allowNullValues: true);

Retrieve data and storing into cache with single statement

To retrieve data and storing into a cache with a single statement use the follow code:

/*...*/
var person = _personCache.GetFromCacheOrFetch(Id, () => service.FindPersonById(Id));

When this statement is executed more than once with the with the same key, the value will be retrieved from the cache storage instead from the service call (notice the usage of a lambda expression). The service call will be executed just the first time or if the item is removed from the cache manually or automatically due by the expiration policy.

Using cache expiration policies

The cache expiration policies adds a removal behavior to the cache storage items. A policy signals that an item is expired to makes that cache storage removes the item automatically.

A default cache expiration policy initialization code can be specified during cache storage initialization constructor:

/*...*/
private readonly CacheStorage<string, Person> _personCache = new CacheStorageCacheStorage<string, Person>(() => ExpirationPolicy.Duration(TimeSpan.FromMinutes(5)), true);

You can specify an specific expiration policy for an item when it's storing:

/*...*/
var person = _personCache.GetFromCacheOrFetch(id, () => service.GetPersonById(id), ExpirationPolicy.Duration(TimeSpan.FromMinutes(10)));

The default cache policy specified at cache storage initialization will be used if during item storing the expiration policy is not specified.

Build-in expiration policies

Catel comes with build-in expiration policies. They are listed in the follow table:

Expiration policy Type Description Initialization code sample
AbsoluteExpirationPolicy Time-base The cache item will expire on the absolute expiration DateTime
ExpirationPolicy.
Absolute(new DateTime(21, 12, 2012))
DurationExpirationPolicy Time-base The cache item will expire using the duration TimeSpan to calculate the absolute expiration from DateTime.Now
ExpirationPolicy.
Duration(TimeSpan.FromMinutes(5))
SlidingExpirationPolicy Time-base The cache item will expire using the duration TimeSpan to calculate the absolute expiration from DateTime.Now, but everytime the item is requested, it is expanded again with the specified TimeSpan
ExpirationPolicy.
Sliding(TimeSpan.FromMinutes(5))
CustomExpirationPolicy Custom The cache item will expire using the expire function and execute the reset action if is specified. The example shows how create an sliding expiration policy with a custom expiration policy.
var startDateTime = DateTime.Now;
var duration = TimeSpan.FromMinutes(5);
ExpirationPolicy.
Custom(() => DateTime.Now >
startDateTime.Add(duration), 
() => startDateTime = DateTime.Now); 
CompositeExpirationPolicy Custom Combines several expiration policy into a single one. It can be configured to expires when any or all policies expires.
new CompositeExpirationPolicy().
Add(ExpirationPolicy.
Sliding(TimeSpan.FromMinutes(5))).
Add(ExpirationPolicy.
Custom(()=>...))

Implementing your own expiration cache policy

If the CustomExpirationPolicy is not enough, you can implement your own expiration policy to makes that cache item expires triggered from a custom event. You are also able to add some code to reset the expiration policy if the item is read from the cache before it expires (just like SlidingExpirationPolicy does).

To implement an expiration cache policy use the follow code template:

public class MyExpirationPolicy : ExpirationCachePolicy
{
   public MyExpirationPolicy():base(true)
   {
   }

   public override bool IsExpired
   {
      get
      {
         // Add your custom expiration code to detect if the item expires
      }
   }

   public override void OnReset()
   {
      // Add your custom code to reset the policy if the item is read.
   }
}

Notice that the base constructor have a parameter to indicates if the policy can be reset. Therefore, if you call the base constructor with false then the OnReset method will never called.

Conclusion

If you are using caching in your current projects, you are probably using a different caching strategy. Now you have learned about the caching possibilities in Catel, you should definitely try it out and be amazed of the possibilities :)