2012-09-05 15 views
7

Simplemente, tengo que anular la forma en que la memoria caché elige la clave correcta porque algunos campos (p. Ej., Marca de tiempo, id de mensaje, etc.) no deben considerarse cuando recuperar una clave. No puedo modificar la función hash real del objeto clave porque ya se usa para reconocer en mi código.
¿Es posible con Cachés de guayaba? Y con una solución?

Esta es mi configuración:Equal/hash personalizado al insertar la clave (Guava Cache)

CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).recordStats(). 
    expireAfterWrite(DEFAULT_AGE, TimeUnit.DAYS).build(
    new CacheLoader<Request, Response>() { 
     @Override 
     public Response load(Request request) { 
      return request.getResponse(); 
     } 
    }); 

y este es mi función hash (utilizado en otra parte de mi código):

public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + code; 
    result = prime * result + messageID; // <= **this one shouldn't evaluated** 
    result = prime * result + Arrays.hashCode(payload); 
    result = prime * result + (int) (timestamp^timestamp >>> 32); // <= **this one shouldn't evaluated** 
    result = prime * result + (type == null ? 0 : type.hashCode()); 
    result = prime * result + version; 
    return result; 
} 

Por cierto, es este tipo de caché utilizando su propia implementación de función hash (p. ej., a través de la introspección) o está utilizando la predeterminada?

** EDIT: **
Como se señaló en las respuestas, la mejor manera de lograr este resultado es una clase contenedora.
Mi solución:

/** 
* Nested class to store a request as a key in the cache. It is needed to 
* normalize the variable fields of the normal requests. 
*/ 
private static final class CachedRequest extends Request { 

    private static CachedRequest fromRequest(Request request) { 
     // set only the fields that cannot change between two same requests 
     // ... 
    } 

    @Override 
    public int hashCode() { 
     HashFunction hashFunction = Hashing.md5(); 
     HashCode hashCode; 
     // ... 
     return hashCode.asInt(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
      // coherent with hashCode() 
      // ... 
    } 
} 
+0

No me puedo imaginar que sería una utilidad muy útil si utilizara su propia implementación hash. – jtahlborn

+0

también, ¿puede explicar mejor a qué se refiere con "No puedo modificar mi función hash() porque ya se usa para reconocer que" real "equivale a objetos."? – jtahlborn

+0

De hecho, no estoy pidiendo agregar esta característica, pero si alguien sabe cómo manejar esta situación. – Hamal000

Respuesta

13

simplemente podría envolver los objetos en RequestCachedRequest objetos, donde CachedRequest implementaría hashCode() y equals() basan en los campos deseados, y proporcionar acceso a la Request envueltos.

1

Si no puede modificar la función de hash (i todavía no entiendo por qué), entonces es necesario utilizar una clave de "contenedor" para guardar en caché, por ejemplo:

public class RequestKey { 
    private final Request _req; 

    public int hashCode() { 
    // use appropriate Request fields here 
    } 

    public boolean equals(Object o) { 
    return ((this == o) || ((o != null) && (getClass() == o.getClass()) && _req.equals(((RequestKey)o)._req))); 
    } 
} 
+0

No puedo modificar el hash porque es código heredado y el hash ya se usa en otro lugar. – Hamal000

+0

@ Hamal000 - entiendo eso. sin embargo, eliminar campos del código hash no debe reducir su utilidad en otro lugar (a menos que almacene estos códigos hash en, por ejemplo, una base de datos) – jtahlborn

+0

Bueno, eliminar un campo significa reducir el espacio donde la función hash mapea los objetos, pero este no es el problema ... desafortunadamente el hash, en mi caso, se usa como id en algún lugar del lado del cliente (con esta función). – Hamal000

1

estoy bastante Seguro, no es posible con Guava. Existen casos legítimos para usar una Equivalencia personalizada, pero dicen que son demasiado raros para ser manejados por CacheBuilder y MapMaker. Incluso hay com.google.common.base.Equivalence, pero solo se usa internamente (consulte también here y here).

Se necesitan hacer es el propietario llave de los campos que desea utilizar para la consulta, o envolver su Request en otro objeto definir equals y hashCode la manera deseada.

El único caso en que se acostumbra algo diferente de la predeterminada equals/hashCode es con weakKeys (softKeys ya no existe), y entonces es el combo ==/System.identityHashCode. En ningún caso puede elegir la equivalencia libremente.

+0

+1 para weakKeys – Hamal000

+1

'Equivalence' es público: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Equivalence.html – fry

+0

@fry: De hecho lo es, pero solo hay un uso público (en 'Maps.difference'). – maaartinus

Cuestiones relacionadas