2012-10-05 18 views
5

Moim zastosowaniem jest utrzymywanie pamięci podręcznej w pamięci ponad danymi przechowywanymi w trwałym DB.Wdrażanie okresowo odświeżającej pamięci podręcznej w języku Java

Używam danych do wypełnienia listy/mapy wpisów w interfejsie użytkownika. W danym momencie dane wyświetlane w interfejsie powinny być jak najbardziej zaktualizowane (cóż, można to zrobić za pomocą częstotliwości odświeżania pamięci podręcznej).

Główna różnica między zwykłą implementacją pamięci podręcznej a tą konkretną pamięcią podręczną polega na tym, że wymaga ona odświeżania wszystkich elementów w regularnych odstępach czasu, a co za tym idzie, różni się od pamięci podręcznej LRU.

Potrzebuję wykonać tę implementację w Javie i będzie świetnie, jeśli istnieją jakiekolwiek ramy, które można wykorzystać do zbudowania tego wokół nich.

Przeszukałem bibliotekę pamięci podręcznej Google Guava, ale jest ona bardziej dostosowana do odświeżania wpisu niż odświeżania zbiorczego. Nie ma prostych interfejsów API, które odświeżają całą pamięć podręczną.

Każda pomoc będzie bardzo ceniona.

Ponadto, jeśli możliwe jest przyrostowe odświeżanie, będzie wspaniale, ponieważ jedynym ograniczeniem, które powstaje podczas odświeżania całej pamięci podręcznej, jest to, że jeśli pamięć podręczna ma bardzo duży rozmiar, to stos pamięci powinien być przynajmniej dwa razy wielkość pamięci podręcznej w celu załadowania nowych wpisów i zastąpienia starej mapy nową. Jeśli pamięć podręczna jest przyrostowa lub istnieje odświeżenie klockowe (odświeżanie w równych rozmiarach), będzie świetnie.

Odpowiedz

3

EHCache jest dość pełni funkcjonalny buforowanie biblioteki Java. wyobrażam sobie, że mają coś, co będzie dla ciebie skuteczne.

Aby wykonać przyrostowe przeładowanie pamięci podręcznej (która działałaby na większości pamięci podręcznych), wystarczy przejrzeć aktualnie załadowane wpisy i wymusić ich odświeżenie. (możesz uruchomić to zadanie w programie planującym w tle).

Zamiast wymuszać przeładowanie całej pamięci podręcznej, EHCache ma możliwość określenia "czasu przeżycia" dla pozycji, więc wpisy zostaną automatycznie przeładowane, jeśli są zbyt nieaktualne.

+1

@ jtahlborn- Interfejs API BulkLoader (http://ehcache.org/documentation/apis/bulk-loading) EhCache'a jest pomocny, ale byłoby wspaniale, gdyby udostępnił opcję refreshTime lub periodic interval, w której samodzielnie zarządzałaby harmonogram odświeżania pamięci podręcznej. W każdym razie zawsze można to osiągnąć za pomocą zewnętrznego programu planującego i okresowo wywołując interfejs API ładowania zbiorczego. Dziękuję za odpowiedź. –

+0

Dla EHCache zajrzyj na: http://www.ehcache.org/documentation/3.3/thread-pools.html i http://terracotta.org/documentation/4.1/bigmemorymax/api/bulk-loading – Aliuk

+0

Ale. . nie czas na życie po prostu usuwa element z pamięci podręcznej? To NIE jest to samo, co tutaj napisałeś - "automatyczne ponowne ładowanie" – javagirl

0

Wystarczy dziedziczyć tej klasy, i wdrożyć loadDataFromDB i updateData jak chcesz uzyskać incremential aktualizacje

import org.apache.log4j.Logger; 
import java.util.List; 
import java.util.concurrent.Semaphore; 


public abstract class Updatable<T> 
{ 
    protected volatile long lastRefreshed = 0; 
    private final int REFRESH_FREQUENCY_MILLISECONDS = 300000; // 5 minutes 
    private Thread updateThread; 
    private final Semaphore updateInProgress = new Semaphore(1); 

    protected static final Logger log = Logger.getLogger(Updatable.class); 

    public void forceRefresh() 
    { 
     try 
     { 
      updateInProgress.acquire(); 
     } 
     catch (InterruptedException e) 
     { 
      log.warn("forceRefresh Interrupted"); 
     } 

     try 
     { 
      loadAllData(); 
     } 
     catch (Exception e) 
     { 
      log.error("Exception while updating data from DB", e); 
     } 
     finally 
      { 
      updateInProgress.release(); 
     } 

    } 

    protected void checkRefresh() 
    { 
     if (lastRefreshed + REFRESH_FREQUENCY_MILLISECONDS <  System.currentTimeMillis()) 
      startUpdateThread(); 
    } 

    private void startUpdateThread() 
    { 
     if (updateInProgress.tryAcquire()) 
     { 
      updateThread = new Thread(new Runnable() 
      { 
       public void run() 
       { 
        try 
        { 
         loadAllData(); 
        } 
        catch (Exception e) 
        { 
         log.error("Exception while updating data from DB", e); 
        } 
        finally 
        { 
         updateInProgress.release(); 
        } 
       } 
      }); 

      updateThread.start(); 
     } 
    } 

    /** 
    * implement this function to load the data from DB 
    * 
    * @return 
    */ 
    protected abstract List<T> loadFromDB(); 

    /** 
    * Implement this function to hotswap the data in memory after it was loaded from DB 
    * 
    * @param data 
    */ 
    protected abstract void updateData(List<T> data); 

    private void loadAllData() 
    { 
     List<T> l = loadFromDB(); 
     updateData(l); 
     lastRefreshed = System.currentTimeMillis(); 
    } 

    public void invalidateCache() 
    { 
     lastRefreshed = 0; 
    } 

} 
+0

Dzięki za odpowiedź RA. Kiedy zostanie wywołana funkcja checkRefresh()? Jeśli zrozumiem to poprawnie, będzie to wymagało ciągłego procesu, aby sondować przy użyciu checkRefresh w regularnych odstępach czasu. Z niecierpliwością oczekiwałem na czystszą implementację, w której mogłem po prostu wstawić nową pamięć podręczną za pomocą modułu ładującego pamięć podręczną. –

+0

CheckRefresh powinien być wywoływany w każdej operacji pobierania, którą implementujesz w swojej klasie. JA.E: public Data get() {checkRefresh(); // zwraca dane; } –

+0

Ale to będzie miało wpływ na opóźnienie pobierania danych w przypadkach, gdy wątek aktualizacji jest uruchamiany w taki sposób, jakby był kontynuowany jak cron i już wstępnie wczytał dane, taki przypadek nie powstałby. –

0

Jedna rzecz, którą należy sprawdzić, to czy wymagane jest okresowe odświeżanie? Możesz zastosować swoją logikę odświeżania po pobraniu danych z pamięci podręcznej, co usunie potrzebę asynchronicznego odświeżania i usunie potrzebę utrzymywania starych kopii pamięci podręcznej. Ta IMO jest najłatwiejszym i najlepszym sposobem odświeżania danych z pamięci podręcznej, ponieważ nie wiąże się z żadnymi dodatkowymi kosztami.

T getData(){ 
     // check if the last access time + refresh interval >= currenttime if so then refresh cache 
    // return data 
    } 

Zapewni to, że dane zostaną odświeżone na podstawie interwału odświeżania i nie będzie wymagać asynchronicznego odświeżania.