10 Replies Latest reply on Jun 23, 2009 3:10 AM by galder.zamarreno

    Refresh cache from cache loader on demand?

    drcallaway

      I have a configuration where I'm using JBoss Cache in local mode (with sticky sessions) along with a JDBC cache loader. At startup, the JBoss Cache preloads a node in the cache with mostly static data that had previously been persisted to the database. Though mostly static, this data may occasionally change. When this happens, is there a way to force the cache to refresh this node with data from the cache loader? This process would be similar to removing the node and then running preload again.

      Thanks!

      Dustin

        • 1. Re: Refresh cache from cache loader on demand?
          drcallaway

          I was able to get this working with this code:

          CacheSPI cacheSpi = (CacheSPI) cache;
          CacheStoreInterceptor csi = null;
          int index = 0;

          for (Object o : cacheSpi.getInterceptorChain())
          {
          if (o instanceof CacheStoreInterceptor)
          {
          csi = (CacheStoreInterceptor) o;
          break;
          }
          index++;
          }

          cacheSpi.removeInterceptor(CacheStoreInterceptor.class);
          rootNode.removeChild("mostlyStaticDataNode");
          cacheSpi.addInterceptor(csi, index);
          rootNode.getChild("mostlyStaticDataNode");

          Basically, I remove the cache store interceptor before removing the child (this removes the local node but doesn't touch the database). I then add the interceptor back and retrieve the node. This will "refresh" the node from the database.

          Of course, there are a couple problems with this code. The first is that I'm casting Cache to CacheSPI which I know is not recommended. The second is that it's pretty much a hack. Is there a more elegant way to accomplish this?

          Dustin

          • 2. Re: Refresh cache from cache loader on demand?
            drcallaway

            Woops! Should have previewed that. Here it is again a bit more readable:

             CacheSPI cacheSpi = (CacheSPI) cache;
             CacheStoreInterceptor csi = null;
             int index = 0;
            
             for (Object o : cacheSpi.getInterceptorChain())
             {
             if (o instanceof CacheStoreInterceptor)
             {
             csi = (CacheStoreInterceptor) o;
             break;
             }
             index++;
             }
            
             cacheSpi.removeInterceptor(CacheStoreInterceptor.class);
             rootNode.removeChild("content");
             cacheSpi.addInterceptor(csi, index);
             rootNode.getChild("content");
            


            • 3. Re: Refresh cache from cache loader on demand?
              galder.zamarreno

               

              "drcallaway" wrote:
              .. Though mostly static, this data may occasionally change. When this happens, is there a way to force the cache to refresh this node with data from the cache loader? This process would be similar to removing the node and then running preload again.

              What do you exactly mean with data changing? Is data changing as a result of your interaction with the cache? Are you changing the data directly in the cache store? I don't understand why you'd want the data to be replaced with the one in the cache store.

              • 4. Re: Refresh cache from cache loader on demand?
                mircea.markus

                 

                Basically, I remove the cache store interceptor before removing the child (this removes the local node but doesn't touch the database). I then add the interceptor back and retrieve the node. This will "refresh" the node from the database.

                So you know that data changed in the cache store and want to 'refresh', you cannot do a cache.remove as this would also remove it from persistent store, right? If so take a look at org.jboss.cache.config.Option#suppressPersistence API. Another way would be to make your cache store read only, i.e. use
                <loade ignoreModifications="true" ../>
                , but that's a general setting and cannot be configured an a per call basis.

                • 5. Re: Refresh cache from cache loader on demand?
                  drcallaway

                   

                  "galder.zamarreno@jboss.com" wrote:

                  What do you exactly mean with data changing? Is data changing as a result of your interaction with the cache? Are you changing the data directly in the cache store? I don't understand why you'd want the data to be replaced with the one in the cache store.


                  I mean that the data is changed by another cache client. For example, say I store pricing information in my cache that changes once a month. I can refresh the cache from a single client by replacing the existing "pricing" node with new information and this will push the new information into the backing database. However, all of the other clients that share this database aren't aware that the data has changed. I'd like to be able to force a refresh periodically so that these other clients dump their current information and reload from the data store.

                  • 6. Re: Refresh cache from cache loader on demand?
                    drcallaway

                     

                    "mircea.markus" wrote:
                    So you know that data changed in the cache store and want to 'refresh', you cannot do a cache.remove as this would also remove it from persistent store, right?


                    Yes. That's exactly the problem. Removing a node from the cache also removes it from the data store. I would like to be able to remove a node from the local in-memory cache and then retrieve it from the data store when it is next requested. It would sure be nice if a node had a "refreshFromCacheLoader()" method or even a "removeFromLocalCache()" method.

                    Can you say a little more about the Option.suppressPersistence API? How would I use that? Where can I get a reference to the Option object?

                    Thanks for your suggestions!

                    • 7. Re: Refresh cache from cache loader on demand?
                      drcallaway

                       

                      "drcallaway" wrote:
                      Can you say a little more about the Option.suppressPersistence API? How would I use that? Where can I get a reference to the Option object?

                      Never mind. I figured it out and your suggestion worked great. Here's the new code:

                      Option option = cache.getInvocationContext().getOptionOverrides();
                      option.setSuppressPersistence(true);
                      rootNode.removeChild("content");
                      option.setSuppressPersistence(false);
                      rootNode.getChild("content");

                      That's much cleaner than how I was doing it before. Thanks for your help!

                      • 8. Re: Refresh cache from cache loader on demand?
                        galder.zamarreno

                         

                        "drcallaway" wrote:
                        "galder.zamarreno@jboss.com" wrote:

                        What do you exactly mean with data changing? Is data changing as a result of your interaction with the cache? Are you changing the data directly in the cache store? I don't understand why you'd want the data to be replaced with the one in the cache store.


                        I mean that the data is changed by another cache client. For example, say I store pricing information in my cache that changes once a month. I can refresh the cache from a single client by replacing the existing "pricing" node with new information and this will push the new information into the backing database. However, all of the other clients that share this database aren't aware that the data has changed. I'd like to be able to force a refresh periodically so that these other clients dump their current information and reload from the data store.


                        Looks to me the different caches accessed by your clients are not clustered which is the root of your problem. If they're clustered, modifications could be replicated to other cache instances or modifications could result in invalidation messages to other nodes. Either of these two options would allow other clients to access the most up to date data. In the case of replication because the cache contains up to date data. In the case of invalidation because after data was updated in another node, the cache would not contain the data and it will result on the cache store being queried.

                        • 9. Re: Refresh cache from cache loader on demand?
                          drcallaway

                           

                          "galder.zamarreno@jboss.com" wrote:

                          Looks to me the different caches accessed by your clients are not clustered which is the root of your problem. If they're clustered, modifications could be replicated to other cache instances or modifications could result in invalidation messages to other nodes. Either of these two options would allow other clients to access the most up to date data. In the case of replication because the cache contains up to date data. In the case of invalidation because after data was updated in another node, the cache would not contain the data and it will result on the cache store being queried.


                          Yes. That's exactly right. In the interest of keeping our solution as simple as possible, we have chosen not to use clustering right now.

                          • 10. Re: Refresh cache from cache loader on demand?
                            galder.zamarreno

                            Ah Ok. I'm glad that you're aware of this :). Your use case sounded very similar to the 2nd level cache use case and the reason explained earlier is why when using a standard 2nd level cache, caches need to be somehow clustered.

                            Hey, once you've got the solution complete, why don't you write a wiki or blog explaining what you did? Other users might be interested in doing something similar without necessarily having to set up a cluster.