sábado, 21 de julio de 2012

Implementando Caching con PostSharp mediante AOP

En computación, la cache es un conjunto de datos duplicados de los valores originales almacenados en otra parte, donde los datos originales son más difíciles de conseguir por el hecho de que lleva un mayor tiempo de procesamiento comparando al esfuerzo que se toma al leerlo solamente en la cache. Podemos indicar además, que una cache es una zona temporal de almacenamiento donde en varias ocasiones se acceden a los datos para un rápido acceso. Desde el momento en que los datos estén guardados en la cache, se pueden utilizar a partir de entonces accediendo a la misma sin la necesidad de acceder a la fuente original de los datos, de tal forma a evitar el reprocesamiento en la obtención de los mismos.

El uso de la cache ha sido comprobado y analizado, resultando ser sumamente efectivo en muchas áreas de la computación por el hecho de que el modelo de acceso en usos de computadores típicos se maneja a través de direccionamiento por referencias o posiciones de memoria. Existen varias clases de lugar o posicionamiento, pero aquí nos centramos específicamente con los datos que se sitúan cerca en el tiempo (el lugar temporal). Los datos podrían estar o no localizados físicamente cerca uno del otro (el lugar espacial).

Como ya lo explicamos la cache es un espacio de almacenamiento temporal, es decir, es un bloque de memoria que se utiliza para recuperar ciertos datos más rápidamente. El procesador y el disco duro frecuentemente utilizan la cache, además de los navegadores web y servidores web.


Una cache está compuesta de un conjunto de entradas. Cada entrada contiene un dato que es una copia del dato que está en su lugar original, a su vez, cada entrada tiene una etiqueta, que especifica la identidad del dato del lugar original del cual la entrada es una copia.


Cuando el cliente de la cache (procesador, navegador web, sistema operativo) desea utilizar un dato presumiblemente en la memoria, este primero busca en la cache. Si una entrada puede ser encontrada coincidiendo con una etiqueta, el cual es el dato buscado, el dato de la entrada se utiliza en su reemplazo. Esta situación es conocida como hit cache. Para ir a un ejemplo más simple y concreto, un programa del navegador web puede revisar la cache local en el disco para verificar si este tiene una copia local del contenido de la página web de un enlace URL en particular. En este ejemplo la URL es una etiqueta y el contenido de la página web es el dato. El porcentaje de acceso que resulta en la cache hit es conocido como hit rate de la cache.


La situación alternativa, sucede cuando la cache es consultada y no contiene el dato de la etiqueta deseada, a este fenómeno se le denomina cache miss (pérdida de la cache). El dato previo no cacheado se recupera del lugar original durante el proceso en donde ocurre el cache miss, aquí el dato es comúnmente copiado a la cache, para que en las próximas búsquedas ya se encuentre el dato en la cache.


Podemos nombrar algunos tipos de cache existentes tales como: Cache de procesador, Cache de disco, Cache de web y otros.

A continuación demostramos el código en C# .net valiéndonos de la utilidad del caching:


Ejemplo de Caching en POO
private const string KeyNumber = "RandomNumber";
private int GetNumber()
{
       int value;
       if (!CacheHelper.Get(KeyNumber, out value)
      {
              value = DataAccess.GetNumberRandom();
              CacheHelper.Add(value, KeyNumber);
       }
       return value;
}

Podemos observar que en el método GetNumber se devuelve un número entero y dentro de la lógica mediante !CacheHelper.Get se verifica si el valor que se quiere obtener ya se encuentra en la cache de ser así entonces automáticamente se retorna dicho valor, sin embargo si es que no se encuentra en la cache se obtiene el valor entero de la base de datos por medio de DataAccess.GetNumberRandom() y se agrega a la cache por única vez con el método CacheHelper.Add para que en las sucesivas peticiones del dato este se encuentre ya en la cache.

La implementación de caching con el framework PostSharp quedaría de la siguiente manera:

Ejemplo de Caching en AOP con PostSharp
private const string KeyNumber = "RandomNumber";
// Se pasa la clave asociada con el item cacheado en el constructor
[Cache(KeyNumber)]
private int GetNumber()
{
       /* Esta lógica es ejecutada solamente cuando el atributo Cache lo amerita*/
       return DataAccess.GetNumberRandom();
}


Por último se define el cuerpo del aspecto en el siguiente fragmento de código:

Definición de Aspecto de Caching en AOP con PostSharp
[Serializable]
public sealed class CacheAttribute : OnMethodInvocationAspect
{
       private readonly string key;
       public CacheAttribute(string key)
       {
              this.key = key;
       }
     
       public override void OnInvocation(MethodInvocationEventArgs context)
      {
              object value;
              if (!CacheHelper.Get(key, out value))
             {
                    /* Se hace la consulta basada en la lógica del llamador*/
                    value = context.Delegate.DynamicInvoke();
                    CacheHelper.Add(value, key);
               }
               context.ReturnValue = value;
       }
}

En esta sección de código en la definición del aspecto de caching, podemos indicar que el método OnInvocation se encarga de verificar a través de !CacheHelper.Get si el valor numérico se encuentra o no en la cache y de esta manera decide si ir a buscar o no en la base de datos.