Diseño de un caché de carga de guayaba con vencimiento de entrada variable


Estoy usando LoadingCache de Guayava en mi proyecto para manejar la carga de caché de thread-{safe,friendly} y funciona maravillosamente bien. Sin embargo, hay una limitación.

El código actual que define la caché se ve así:

cache = CacheBuilder.newBuilder().maximumSize(100L).build(new CacheLoader<K, V>()
{
    // load() method implemented here
}

No especifico un tiempo de caducidad.

El problema es que de acuerdo con los valores de la clave, algunos valores asociados pueden caducar y otros no. Y CacheLoader no tiene en cuenta esto, si especifica un tiempo de caducidad, es para todos y cada uno entrada.

¿Cómo abordarías este problema?

Author: fge, 2012-12-20

5 answers

Otra alternativa es ExpiringMap , que admite la caducidad de entrada variable:

Map<String, String> map = ExpiringMap.builder().variableExpiration().build();
map.put("foo", "bar", ExpirationPolicy.ACCESSED, 5, TimeUnit.MINUTES);
map.put("baz", "pez", ExpirationPolicy.CREATED, 10, TimeUnit.MINUTES);
 24
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-16 01:42:55

Le sugiero que incluya el tiempo de caducidad directamente en su clase de entrada y lo desaloje manualmente de la caché si ha expirado inmediatamente después de obtenerlo de la caché:

MyItem item = cache.getIfPresent(key);
if (item != null && item.isExpired()) {
    cache.invalidate(key);
    item = cache.get(key);
    // or use cache.put if you load it externally
}

Como alternativa, puedo sugerirle que revise la biblioteca EhCache que admite la política de caducidad por elemento.

 11
Author: hoaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-21 21:12:49

LoadingCache ofrece algunas políticas de caducidad de uso común, pero cuando estas se quedan cortas para lo que necesita, necesita rodar su propia.

Simplemente agrega un DelayQueue. Cada vez que agregue algo a la caché, agregue un Delayed a esa cola, con el tiempo de caducidad apropiado. El objeto Delayed debe tener un (débil? referencia a la clave.

El ingrediente final es que necesita sondear periódicamente esta cola, para ver si algo expiró y tiene que ser desalojado. No necesariamente añadir un hilo para hacer esto, usted podría simplemente piggyback en cualquier hilo está accediendo a la LoadingCache. Justo antes de acceder a la caché, por ejemplo:

private void drainCache() {
  MyDelayed expired;
  while ((expired = delayedQueue.poll()) != null) {
    K key = expired.getReference();
    if (key != null) { // this only in case if you hold the key in a weak reference
      loadingCache.invalidate(key);
    }
  }
}

..
V lookup(K key) {
  drainCache();
  return loadingCache.getUnchecked(key);
}
 5
Author: Dimitris Andreou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-14 01:23:12

Supongo que podría usar el invalidar explícito para definir exactamente qué entradas deben ser desalojadas, pero eso no es probablemente lo que desea.

Sin embargo, puede dar diferentes pesos para las entradas. No es perfecto, pero puede guiar la caché para desalojar las entradas que son menos importantes. Ver Weighter, las entradas con peso 0 no serán desalojadas por desalojo por tamaño.

 0
Author: blomqvie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-20 20:20:00

En caso de que las entradas sean grandes y necesites conservar memoria, no creo que haya una buena solución, pero estos hacks vienen en mente:

  • Utilice un PriorityQueue ordenado por el tiempo de caducidad para eliminar manualmente las entradas. Si desea asegurarse de que ninguna entrada caducada se utiliza, necesita combinar esto con la solución de hoaz; la cola solo evita que las entradas inútiles ocupen memoria.

  • Usted escribió " algunos valores asociados pueden expirar y others may not", lo que sugiere que el retraso de vencimiento es el mismo para todas las entradas que expiran. Esto permitiría usar un Queue más simple y rápido (por ejemplo, ArrayDeque en lugar del PriorityQueue).

  • En caso de que el retraso de vencimiento sea bastante grande, puede dejar que todas las entradas caduquen y volver a insertar aquellas que deberían vivir para siempre en un RemovalListener. Esto puede fallar de dos maneras: 1. Usted puede conseguir una señorita en el ínterin. 2. Las eliminaciones y re-inserciones pueden costar mucho tiempo de CPU.

 0
Author: maaartinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-20 21:24:26