3

I am interested in knowing what is the effective way of loadAll method implementation introduced in google guava 11.0 library.

Here is the following code that describes load all method implementation extended
as per the example from CachesExplained

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder().maximumSize(1000)
.refreshAfterWrite(1, TimeUnit.MINUTES)
.build(
   new CacheLoader<Key, Graph>() {
     public Graph load(Key key) { // no checked exception
       return getGraphFromDatabase(key);
     }

     public Map<Key, Graph> loadAll(Iterable<? extends K> keys) {
         return getAllGraphsFromDatabase(keys);
     }
   }
);

private Map<Key, Graph> getAllGraphsFromDatabase(Iterable<? extends key> keys)
{
  lListOfGraph = //resultset got from DB Call
  for (lCount = 0; lCount < lListOfGraph.size(); lCount++)
  {
     lGraph = (Graph)lListOfGraph.get(lCount).get(0);
     graphs.asMap().put((key , lGraph);
  }
  return (Map<key, Graph>) graphs;
}

Here return type that is Map throws error java.lang.ClassCastException:com.google.common.cache.LocalCache$LocalLoadingCache cannot be cast to java.util.Map (Knowing the fact that Loading Cache object can not be of type Map)

If this is not the correct way of implementation of using LoadingCache then How is the data injected in LoadingCache's Component so that it can be used as Cache.

Patrick M
  • 10,547
  • 9
  • 68
  • 101
Anand Sanghvi
  • 99
  • 1
  • 2
  • 10

1 Answers1

5

Your getAllGraphsFromDatabase method should be fetching the values from the underlying data store. The LoadingCache implementation handles adding the returned values to the map for you.

I think your loading method should look like:

private Map<Key, Graph> getAllGraphsFromDatabase(Iterable<? extends key> keys)
{
  final List<Graph> lListOfGraph = //resultset got from DB Call

  final Map<Key, Graph> map = new HashMap<Key, Graph>(listOfGraph.size());
  for (final Graph graph : lListOfGraph)
    map.put(graph.getKey(), graph);

  return map;
}
SimonC
  • 6,590
  • 1
  • 23
  • 40
  • Currently Data is fetched from DB and stored in the LoadingCache object that is graphs but there needs to be a map to be returned for getAllGraphsFromDatabase. Do we mean that return would have null value for this kind of implementation. here graphs is LoadingCache object should i just pass null as return type after using graphs.asMap().put; – Anand Sanghvi Aug 03 '12 at 11:34
  • 2
    You shouldn't be putting anything into the map directly. The point of the `CacheLoader` is to retrieve values for the `LoadingCache` to put into the map. So if `lListOfGraph` has been retrieved from the DB, you need to just return it as a map. – SimonC Aug 03 '12 at 12:07
  • 1
    Rephrasing SimonC's answer: CacheLoader#load is for SELECT * FROM graphs WHERE id = key and CacheLoader#loadAll is for SELECT * FROM graphs (and select results are mapped to Graph objects). – Grzegorz Rożniecki Aug 03 '12 at 12:22
  • I got your comments thanks for it. But here we are creating a map using HashMap as per solution indicated. We in our solution are trying to use LoadingCache as replacement of HashMap. Since HashMap objects are static and do not hold weak keys weak refrences. If we put the data in map then that object is created in JVM,and remains throughout untill restart thus increasing the memory Load. Our main intention is to make the object of resizable size in JVM using LoadingCache so that stale data is eliminated. – Anand Sanghvi Aug 03 '12 at 12:54
  • Please let me know if there is any wrong interpretation about JVM objects. If that the case then LoadingCache would be only beneficial in the case for data retrieval purpose as it would use optimized filter using DataStructure like Bloomfilter and Funnel for fetching the data from the object nothing else. – Anand Sanghvi Aug 03 '12 at 12:57
  • Your objects will remain in JVM memory as long as there are references to them. It looks like you want to use `expireAfterAccess` which would remove the reference to your object (from the `LoadingCache`) after the specified time. As long as there are no other references to the object outside of the `LoadingCache` it will be eligible for garbage collection. – SimonC Aug 03 '12 at 13:02
  • I will use expireAfterAcess in the implementation of LoadingCache So we means here that object created eg map as per above is created using HashMap implementation that will be there during initial period or whenever the loadall call is done and then available for garbage collection . So there will be times when graphs and map are two objects that are created which have same data inside it that is too heavy for our usage as there are 100 maps in our application that contains static & dynamic data. – Anand Sanghvi Aug 03 '12 at 13:16
  • Sorry, are you asking anything there? – SimonC Aug 03 '12 at 13:42
  • Can I avoid creating two objects, lets say for this example map and graphs two objects will be created that will have same set of data occupying memory for some period of intervals until map(object) is garbage collected by JVM – Anand Sanghvi Aug 03 '12 at 13:46
  • 2
    `CacheLoader.load` and `CacheLoader.loadAll` will only be called for keys that are not in the cache (either because they haven't been loaded before, or because they've been expired). So say you call `get(1)` then before the expiry call `getAll(1,2,3)`, the `loadAll` method will be called with just `(2,3)`. As a result your cache will have single `Graph` entries for keys `1`, `2`, and `3`. Also, for reference, `LoadingCache` ensures that the `load`/`loadAll` method won't be called twice by two different threads simultaneously for the same key. – SimonC Aug 03 '12 at 14:03
  • 2
    The `Map` created temporarily in the `loadAll` implementation will get garbage-collected almost immediately. Unless you actually have benchmarks indicating otherwise, this will almost certainly not be a performance bottleneck. – Louis Wasserman Aug 03 '12 at 15:47
  • @AnandSanghvi, the JavaDoc explicitly states that a map containing `null` keys should not be passed to the `CacheLoader.loadAll` method. It's a little less clear on the `LoadingCache.getAll` method though. Even if it works now, it may not in the future. – SimonC Aug 06 '12 at 11:48
  • Basically it is Select * from graphs which will return an Id column which will represent as keys and entire graph object will represent as value. So there are no known keys when call is made to loadAll() method. – Anand Sanghvi Aug 06 '12 at 13:00
  • @AnandSanghvi, I think you're what you're doing is the only way to achieve what you need. It's unfortunate that's no officially supported method to prime the cache. – SimonC Aug 07 '12 at 11:12