6 Replies Latest reply on Mar 31, 2016 3:28 PM by William Burns

    Recompute expired cached value keeping old value till done

    Vincent Massol Newbie

      Hi there,

       

      I'm working on the XWiki project (http://xwiki.org) and we have a cache macro that is using Infinispan under the hood. I'm trying to implement entry recomputation when they expire (lifespan reached) but at the same time without incurring any wait for the end user hitting the cache. The reason is that we use this cache macro to speed wiki pages when the page contains scripts that take a long time to execute and I'd like to prevent users from waiting when cache entries expire.

       

      So the way I've been approaching this is:

      * Listen to @CacheEntryRemoved/@CacheEntriesEvicted events

      * Upon such event start a background thread to recompute the value that should be cached and put back the entry in the cache

       

      My current issue is that my listener's @CacheEntryRemoved and @CacheEntriesEvicted methods don't get called at all.


      FTR In my test I have the following cache set up:

      * lifespan = 10s

      * max entries = 2

      * reaper enabled and wake up interval set to 1s


      Using infinispan 7.2.5.Final


      I have 2 questions:

      1) why are my listener methods not called? I read that the infinispan can clear an expired cache entry when a get() or containsKey() is called on that cache which is why in my test I set a fast wake up interval for the reaper to make sure it's called before that.

      2) Is there a better strategy to implement my need?


      Thanks a lot

      -Vincent



        • 2. Re: Recompute expired cached value keeping old value till done
          Vincent Massol Newbie

          Note that I have now tried with 8.2.0.Final and I have the same issue.

          • 3. Re: Recompute expired cached value keeping old value till done
            Vincent Massol Newbie

            ok so I was using the wrong event. It works better with @CacheEntryExpired.

             

            Of course I'm now hitting the problem of not having the lock when I try to put back the cache entry in the cache before starting the async recomputation.

             

            Any idea for that part?

             

            Thanks

            • 4. Re: Recompute expired cached value keeping old value till done
              William Burns Expert

              Vincent Massol wrote:

               

              ok so I was using the wrong event. It works better with @CacheEntryExpired.

               

              Of course I'm now hitting the problem of not having the lock when I try to put back the cache entry in the cache before starting the async recomputation.

               

              Any idea for that part?

               

              Thanks

              So there could be a few things you might be able to do, but I think we may need to know exactly what you are trying to do. It sounds like you are using expiration to basically cache a value in memory for the lifespan and then get the updated value after the lifespan occurs, keeping a value in memory and updating every so often.

               

              If this it the use case I would recommend you add your own CacheLoader (note not CacheWriter) implementation that does this computation.  Then you can easily use expiration or even better in my opinion eviction so that you can have the most recently used values in memory all the time.

               

              But in this case if an entry expires or is evicted it won't be recomputed (doesn't take up memory even) until you have another get on this key and then the loader can do the recomputation and then ISPN takes the result of the loader writes it to the cache and returns it to the caller.

              • 5. Re: Recompute expired cached value keeping old value till done
                Vincent Massol Newbie

                Thanks William for the replly (still trying to process and understand it, I'm not familiar with CacheLoader).

                 

                Here's my use case (note that I've also created https://issues.jboss.org/browse/ISPN-6443).

                • I have some lenghty computations that gives results that I cache for some time (lifespan)
                • I don't want users to incur the wait before the computation is finished so I need to always have some value to return immediately to them, and in parallel, when the lifespan is reached, recompute the results asynchronously and overwrite the existing values in the cache

                 

                More specifically, this is for a wiki (XWiki, http://xwiki.org), we have a {{cache}} macro (http://extensions.xwiki.org/xwiki/bin/view/Extension/Cache+Macro) that ca be used in wiki pages. Inside that macro users can use scripting macros to perform various API calls and computations. The {{cache}} macro caches the result of rendering what's inside it. For example:

                 

                {{cache}}

                {{velocity}}

                  $xwiki.someLengthyCall()

                {{/velocity}}

                {{/cache}}

                 

                My goal is to never have users to wait for the rendering to be done and instead to always return a stored result from the cache and to recompute the rendering asynchronously when the lifespan is reached.

                 

                Do you still think the best solution is having a custom CacheLoader? An idea I had (hence the jira issue) would have been to be able to cancel the expiration event in my listener so that the value stays in the cache for another round and in parallel I would have started a recomputation thread to compute a new value. My issue ATM is that I can't put back the cache value since the cache has a lock on it.

                 

                Thanks a lot for your help.

                • 6. Re: Recompute expired cached value keeping old value till done
                  William Burns Expert

                  In the case of your computation taking a long time and you can't block the reader for that duration, I would say using the CacheLoader approach may not work out for you.  With the cache loader approach the user would be blocked while the value is recomputed.

                   

                  To be honest given your use case you may want to do this yourself.  Unfortunately expiration is really about removing a value and returning null to the user asap.  Cancelling an expiration imo doesn't really make as much sense.

                   

                  What you could do is store some sort of timestamp along with your value.  Then when you retrieve your value you can check this and if needed fire off an async operation to replace this value and return the current one to the caller immediately.  You can even use the new FunctionalMap [1] to help you out here by using the eval method and writing a MetaParam.Writable instance if you don't want to have a wrapper object.

                   

                  [1] Infinispan User Guide