0

I'm looking for an in-memory cache with the following behaviour.

  • On the first access or after initialization it read's all data to be cached at once. E.g. all rows of a table.
  • After one hour the complete cache is cleared and all data is read again at once.
  • The cache could be cleared on demand.

I know how to implement such a cache, but does anybody know an existing library, which provides a cache like this.

This is my idea about the interface. There are elements for the cache

Element element = new Element(Object key, Object objectToCache);

A loader provides all elements

Collection<Element> elements = myLoader.getElements();

In the end there is the cache

public Cache {
  public Cache(CacheLoader loader, int timeToReload) {
    ...
  }

  public Object getValueForKey(Object key {
    ...
  }

  ...
}

A solution would be to have a cache with a single entry, which is a HashMap of the real entries. With this solution I can use existing caches like Ehcache or Guava Caches.

But nevertheless I'm looking for existing code, before I start writing a own library.

jjnguy
  • 136,852
  • 53
  • 295
  • 323
Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72

5 Answers5

2

Do you look for some kind of distributed cache and want spread the initial load over many instances, right?

Hazlecast persistent datastore API is always worth a look.

Hazlecast Doc

Initialization on startup As of 1.9.3 MapLoader has the new MapLoader.loadAllKeys API. It is used for pre-populating the in-memory map when the map is first touched/used. If MapLoader.loadAllKeys returns NULL then nothing will be loaded. Your MapLoader.loadAllKeys implementation can return all or some of the keys. You may select and return only the hot keys, for instance. Also note that this is the fastest way of pre-populating the map as Hazelcast will optimize the loading process by having each node loading owned portion of the entries.

In combination with the hazelcast.initial.min.cluster.size configuration property you can distribute your initial load.

1

I'm not sure what kind of collection you need (Map, Set, List or Queue) but take a look at Google Guava Cache implemetantions

Kiril Kirilov
  • 11,167
  • 5
  • 49
  • 74
0

This functionality is probably to simple to be wrapped in a library efficiently. After all, it boils down to having a thread call the reinitalize function every hour.

Getter:

if (collection == null) reinitialize();
return collection.get(key);

Clearing thread:

while(true) {
  Thread.sleep(60*60);
  collection = null; // probably as a method.
}

Notice that I would not call this "caching".

The strategy you are calling for is a timer-triggered reinitialization. Caching usually means

  • lazy loading of needed records only
  • LRU or age based expiry of single records
Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
  • I don't want to reinvent the wheel. If there's a library it may have additional usefule features, I would not think about. And its contributors already solved bugs, which don't think about, too. – Stefan Birkner Feb 25 '12 at 11:18
  • Well, you aren't. There is nothing reinventing the wheel in reinitializing from time to time. Note that you are *not* using fine-grained caching, you are reinitializing. – Has QUIT--Anony-Mousse Feb 25 '12 at 13:41
0

Sounds like you need to override HashMap.get() and add an if that has a timer for resetting, and code that loads if necessary.

If you do not need more than that I would not look for a library for it. Most caches do not populate fully at first access anyway.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • I need something a little bit more sophisticated. – Stefan Birkner Feb 25 '12 at 11:37
  • Acutally from your spec, you seem to *not* want a sophisticated cache, but a timer-triggered reinitialization. And since that is less than 10 lines of code - and you'll need at least as much glue code anyway - there is no library. – Has QUIT--Anony-Mousse Feb 25 '12 at 13:45
0

I cannot see where this is a library, either. Simply because your requirements are very special:

  • You have such a small dataset to cache or lots of memory that you can load it all at once
  • But you want to initialize the 'Cache' (I would rather call it in-memory data structure) lazily, probably because you do not want to slow down the app startup
  • And you can afford to let the cache be filled forever

I would drop the lazy-"requirement" and simply use a ExecutorService.newSingleThreadScheduledExecutor(ThreadFactory) with a scheduled daemon thread that reloads a ConcurrentHashMap every hour, starting on application startup (asynchroneously). That is as simple as it can get.

If you want to have it more complicated make your get method synchronized and check for an isInitialized or use double-checked locking or, or, or. You see where this gets? This tiny requirement you created makes you wanna go for a library, but because of the other requirements I would just question that it makes any sense at all and go for a simpler solution.

Stefan Schubert-Peters
  • 5,419
  • 2
  • 20
  • 21
  • You only missed one point: After one hour the complete cache is cleared and all data is read again at once. I want to have all objects of a specific type in memory. But they are modified by other servers. These changes must not be visible immediately, but after a specific period of time. – Stefan Birkner Feb 29 '12 at 19:27
  • You mean read again: Read again lazily or the cache is filled instantly again? – Stefan Schubert-Peters Mar 01 '12 at 07:54