Projektowanie Guava LoadingCache ze zmienną datą wejścia

Używam Guava ' s LoadingCache do mojego projektu do obsługi thread-{bezpieczne, przyjazne} Ładowanie pamięci podręcznej i działa cudownie dobrze. Istnieje jednak pewne ograniczenie.

Bieżący kod definiujący pamięć podręczną wygląda następująco:

cache = CacheBuilder.newBuilder().maximumSize(100L).build(new CacheLoader<K, V>()
{
    // load() method implemented here
}
Nie podaję czasu wygaśnięcia.

Problem polega na tym, że zgodnie z wartościami klucza, niektóre powiązane wartości mogą wygasnąć, a inne nie. I CacheLoader nie uwzględnia tego, jeśli podasz czas wygaśnięcia, to dla każdego wejście.

Jak poradziłbyś sobie z tym problemem?
Author: fge, 2012-12-20

5 answers

Inną alternatywą jest ExpiringMap , która obsługuje datę wygaśnięcia wpisu zmiennej:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-16 01:42:55

Sugeruję, abyś włączył czas wygaśnięcia bezpośrednio do swojej klasy wejściowej i ręcznie wyrzucił go z pamięci podręcznej, jeśli wygasł natychmiast po pobraniu go z pamięci podręcznej:

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
}

Jako alternatywę, mogę zasugerować, aby sprawdzić bibliotekę EhCache, która obsługuje politykę expire per element.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-21 21:12:49

LoadingCache oferuje kilka powszechnie używanych zasad wygaśnięcia, ale gdy nie spełniają one tego, czego potrzebujesz, musisz rzucić własne.

Wystarczy dodać DelayQueue . Za każdym razem, gdy dodajesz coś do pamięci podręcznej, dodaj Delayed do tej kolejki, z odpowiednim czasem wygaśnięcia. Delayed obiekt powinien mieć (słaby?) odniesienie do klucza.

Ostatnim składnikiem jest to, że musisz okresowo przepytywać tę kolejkę, aby sprawdzić, czy coś wygasło i musi zostać eksmitowane. Nie koniecznie dodaj aby to zrobić, możesz po prostu przejść do dowolnego wątku, który ma dostęp do LoadingCache. Tuż przed uzyskaniem dostępu do pamięci podręcznej, np.:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-14 01:23:12

Myślę, że możesz użyć jawnego invalidate, aby dokładnie określić, które wpisy powinny zostać eksmitowane, ale to nie jest prawdopodobnie to, czego chcesz.

Można jednak podać różne wagi dla wpisów. Nie jest idealny, ale możesz poprowadzić pamięć podręczną, aby eksmitować wpisy, które są mniej ważne. Zobacz Weighter , wpisy o wadze 0 nie będą eksmitowane przez eksmisję opartą na rozmiarze.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-20 20:20:00

W przypadku, gdy wpisy są duże i trzeba zachować pamięć , myślę, że nie ma dobrego rozwiązania, ale te hacki przychodzą na myśl:

  • Użyj PriorityQueue uporządkowanej według czasu wygaśnięcia do ręcznego usuwania wpisów. Jeśli chcesz mieć pewność, że żaden wygasły wpis nie zostanie użyty, musisz połączyć to z rozwiązaniem hoaza; Kolejka zapobiega tylko niepotrzebnym wpisom zajmującym pamięć.

  • Napisałeś "niektóre powiązane wartości mogą wygasnąć i inni nie mogą", co sugeruje, że opóźnienie wygaśnięcia jest takie samo dla wszystkich wygasających wpisów. Pozwala to na użycie prostszego i szybszego Queue (np. ArrayDeque zamiast PriorityQueue).

  • W przypadku, gdy opóźnienie wygaśnięcia jest dość duże, możesz pozwolić, aby wszystkie wpisy wygasły i ponownie wstawić te, które powinny żyć wiecznie w RemovalListener. Może to się nie udać na dwa sposoby: 1. W międzyczasie możesz dostać pudło. 2. Usuwanie i ponowne wstawianie może kosztować dużo czasu procesora.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-20 21:24:26