Carmelo Foti
Carmelo Foti

Reputation: 93

Guava cache return an empty result on the second hit

I have a strange (at least for me) behaviour with guava cache. After the first hit, the following accesses will return an empty object. I did not use strange evinction, so I can't figure out where I'm doing wrong. I declared the following LoadingCache:

LoadingCache<String, Vector<Location>> locations = CacheBuilder.newBuilder()
            .maximumSize(100000)
            .build(
                    new CacheLoader<String,Vector<Location>>() {
                        @Override
                        public Vector<Location> load(String key)  {
                            return _getLocationListByTranscriptId(key);
                        }
                    });

and I used it only in this method:

public Vector<Location> getLocationListByTranscriptId (String transcriptid) {
    if (transcriptid.equals("TCONS_00000046"))  System.out.println("tcons found, will this work?");
    Vector<Location> result;
    try {
        result = locations.get(transcriptid);
    } catch (ExecutionException e) {
        System.err.println("Error accessing cache, doing the hard way");
        result = _getLocationListByTranscriptId(transcriptid);
    }
    if (transcriptid.equals("TCONS_00000046")){
        if (result.size()==0){
            System.out.println("this is a problem");
            return null;
        }
        System.out.println("this is good!");
    }
    return result;
}

Iterating a Collection of input string, i get the following output:

tcons found, will this work?
this is good!
tcons found, will this work?
this is a problem

So, the first time i use the cache, it works, but A) the value is not correctly stored for future accesses; B) the value is resetted for some strange behaviour. What can i do? Thanks all for reading this!

EDIT: Thanks to axtavt answer I could immediately figure out where I was editing the resulting list. Don't know why, i was sure about guava cache returning a copy of the values. Thank you for the answer, and for the suggestions about defensive programming. (Sorry if i can't rate your answer yet).

Upvotes: 4

Views: 1746

Answers (1)

axtavt
axtavt

Reputation: 242786

I believe you accidentially clear the Vector somewhere in your code. There are two possibilities:

  • Vector is modified by the code that obtains it from the cache.

    This kind of mistakes can be prevented by making defensive copy (though it ruins the idea of caching), or returning immutable view of collection:

    LoadingCache<String, List<Location>> locations = CacheBuilder.newBuilder()
         .maximumSize(100000)
         .build(
                 new CacheLoader<String, List<Location>>() {
                     @Override
                     public List<Location> load(String key)  {
                         return Collections.unmodifiableList(
                             _getLocationListByTranscriptId(key));
                     }
                 }); 
    

    After changing the code this way it will be easy to spot the place where illegal modification of collection takes place.

    Note that there is no unmodifiable view of Vector, therefore List should be used instead.

  • _getLocationListByTranscriptId() stores its result in a field where it can be accessed by other methods (or other invocation of the same method). So, you should check that _getLocationListByTranscriptId() doesn't leave any references to its result in fields.

Upvotes: 7

Related Questions