13 Replies Latest reply on Jun 3, 2016 7:16 AM by mmr11408

    Infinispan: ways to keep cache up to date with the DB

    mmr11408

      I have an app that uses JDBC to access the DB and load values into clustered, replicated named caches. In order to keep the cache up to date with the DB one idea is to set expiration for the cache and define a custom interceptor that when an entry expires it gets called to fetch the data from the DB, compare it to what is in the cache, update the cache if the value in the DB was changed, reset the expiration of the entry in the cache.

       

      For a quick prototype I defined an interceptor which has methods that override most of the "visit" calls. Using jconsole I can see that the cache starts with the entries that get loaded into it at startup and after expiration time is reached the cache is emptied. But during that process only the visitPutKeyValueCommand method is called. All others, such as visitEvictCommand, visitRemoveCommand, visitInvalidateCommand are never called.

       

      I am using Infinispan v6.x in embedded mode running in tomcat 8 using java 8. Infinispan can be upgraded to 8.x if necessary.

       

      1) Is there an inceptor that gets called when an entry expires?

       

      2) Is there a better approach to keeping the cache up to date with the DB. I am not using Hibernate but if that provides significant benefit over JDBC I can consider it.

       

      Thanks in advance!

        • 1. Re: Infinispan: ways to keep cache up to date with the DB
          pferraro

          Hibernate includes a second-level cache abstraction and an implementation based on Infinispan.  In general, object-relational mapping tools like Hibernate are less error-prone and easier to maintain than vanilla JDBC, and since JPA, have a standard API from which operate.

          I highly encourage you to look into migrating your application to JPA, and get the 2nd-level cache optimizations for free rather than reinvent the wheel.

           

          That said, to answer your specific questions:

          Mehdi Rakhshani wrote:

          1) Is there an inceptor that gets called when an entry expires?

          Intercepting internal Infinispan methods is a very hacky way to go about this.  Infinispan allows you to register any number of listeners with a cache.  Infinispan expiration notifications (for in-memory entries only) was implemented in Infinispan 8.0.

          2) Is there a better approach to keeping the cache up to date with the DB. I am not using Hibernate but if that provides significant benefit over JDBC I can consider it.

          Use JPA.

          • 2. Re: Infinispan: ways to keep cache up to date with the DB
            wdfink

            I would use a Listener for the eviction  Listener (Infinispan Distribution 7.1.0.Final API) see docs here Listener (Infinispan Distribution 7.1.0.Final API).

            The drawback is that you reload the cache every X minutes/hours if you set a general eviction to this cache.  (Expiration means to delete the entry)

             

            If you can accept to reload some data over the time during the first access you can use eviction only.

             

            Does that makes sense to you?

            • 3. Re: Infinispan: ways to keep cache up to date with the DB
              mmr11408

              Thanks for the response. Your point about data getting reloaded is very valid. It is not desirable and as such I decided to implement a different mechanism to keep the cache up to date.

               

              But in order to learn about listeners, I created a Listener to test notifications for CacheStarted, CacheEntriesEvicted, CacheEntryRemoved and CacheEntryPassivated. I only get notified when cache is started. No notification when items expire from the cache and are removed. Am I mistaken that eviction is based on number of entries in the cache and not how long an item has been in the cache? The processes that manage the cache hold all the records in the cache so I do not want entries to be evicted. I want them to expire after certain time and be notified so I can retrieve them back from the DB. If it can be done via listeners or any other mechanism I like to learn how.

               

              • 4. Re: Infinispan: ways to keep cache up to date with the DB
                wdfink

                Yeah, thats true in this case. You need to run expirations and the expiration scheduler to delete the entries.

                 

                The only way with only update what has been changed is something external to trigger a reload.

                For example you can add a DB trigger (I know Oracle can do it) "On UPDATE" and have some Java code with a HoRod client to update the cache.

                Does that makes sense?

                • 5. Re: Infinispan: ways to keep cache up to date with the DB
                  nadirx

                  Firstly, to track expirations you need to add CacheEntryExpired which was added in 8.0.

                  Expiration happens

                  • on access, i.e. if you attempt to read an expired entry it will be removed
                  • by the expiration reaper, which you need to enable and decide how often it runs
                  • 6. Re: Infinispan: ways to keep cache up to date with the DB
                    mmr11408

                    Thanks. I will upgrade to 8.0 and will try it.

                    • 7. Re: Infinispan: ways to keep cache up to date with the DB
                      mmr11408

                       

                      For an embedded application running in Tomcat, when syncing a distributed, clustered, replicated cache with the DB, for every entry retrieved from the DB, is it better to simply call put() or is it better to do a get() first, check what is returned then call put() or replace() accordingly?

                       

                      I have two processes that manage the cache and two that strictly read the cache. In the cache managers, will calling put() for an item that already exists and its value has not changed cause any activity to occur on the cache readers or will it be local only to the cache manager that calls put()?

                       

                      On a separate but related topic, I read about: cache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).put(k, v);

                       

                      But the following code gets the error: getAdvancedCache() is not defined for BasicCache<String, Object>

                        myCache = cacheContainerProvider.getCacheContainer().getCache( "MYCACHE" );
                        myCache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).put( CacheManager.encode( key ), value );

                       

                      Casting myCache does not work. What is the trick to setting IGNORE_RETURN_VALUES?

                      • 8. Re: Infinispan: ways to keep cache up to date with the DB
                        nadirx

                        BasicCache is the root interface between Cache (the embedded variant) and RemoteCache (the HotRod counterpart). The getAdvancedCache method is only available for embedded caches. Therefore use:

                         

                        Cache<String, Object> myCache = cacheContainerProvider.getCacheContainer().getCache( "MYCACHE" );
                        myCache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).put( CacheManager.encode( key ), value );

                        • 9. Re: Infinispan: ways to keep cache up to date with the DB
                          mmr11408

                          Thanks. By casting getCacheContainer() to CacheContainer it worked.

                           

                          Any thoughts on the first part of my question?

                          • 10. Re: Infinispan: ways to keep cache up to date with the DB
                            william.burns

                            Mehdi Rakhshani wrote:

                             

                             

                            For an embedded application running in Tomcat, when syncing a distributed, clustered, replicated cache with the DB, for every entry retrieved from the DB, is it better to simply call put() or is it better to do a get() first, check what is returned then call put() or replace() accordingly?

                            This depends on if you want to guarantee atomicity or not.  If you had 2 concurrent puts the last one will win.  If you have the replace methods instead only 1 would work if they both saw the same initial value.

                             

                            Mehdi Rakhshani wrote:

                             

                            I have two processes that manage the cache and two that strictly read the cache. In the cache managers, will calling put() for an item that already exists and its value has not changed cause any activity to occur on the cache readers or will it be local only to the cache manager that calls put()?

                            This will cause the puts to be replicated if needed (REPL or DIST) and invalidations to occur (INVAL) and events to fire (ANY cache mode).  This is required to update things such as expiration as well.

                            • 11. Re: Infinispan: ways to keep cache up to date with the DB
                              mmr11408

                              Great, thank you for the response. So, even though it adds a little extra processing to the cache manager to look for an item in the cache first and decide whether to call put(), replace() or nothing, in the big picture, doing that is more efficient than simply calling put() and letting Infinispan decide what to do because a put() of an existing item that its value has not changed could create extra work for cluster members. If that is not correct please let me know.

                               

                              FYI, I have implemented a mechanism that only a single manager updates the cache, therefore, two concurrent puts is not an issue.

                              • 12. Re: Infinispan: ways to keep cache up to date with the DB
                                qkhan

                                Hi Mehdi,

                                 

                                On searching I found your post. I am having a very similar task at hand and would request if you can share your approach.

                                We have a cluster of three JDG servers in Client Server mode (not embedded mode) and we need to bring huge amount of data from a SQL Server DB into JDG cache(s). It would be read only data i.e. database does not need to be updated.

                                 

                                I would appreciate if you can throw some light as how did you bring data from database into cache? also if you can share any configuration settings.

                                 

                                Regards

                                • 13. Re: Infinispan: ways to keep cache up to date with the DB
                                  mmr11408

                                   

                                  We have an AppServer that uses the cache to respond to client requests and a CacheManager that manages the cache. The first CacheManager that comes up takes responsibility for managing the cache, others stay around and wait for the responsible CacheManager to leave the cluster before taking over. CacheManagers do other work, such as reporting statistics.

                                   

                                  Currently, a scheduled thread in CacheManager runs every n seconds, reads the DB, compares it to the cache and updates it when needed. This creates a gap between when the DB is updated and when the update gets reflected in the cache.

                                   

                                  Our plan for future is to implement a notifier that uses DB triggers to notify the CacheManagers when the data that it is interested in changes. 

                                   

                                  Hope this helps.