4 Replies Latest reply on Jun 17, 2004 10:26 PM by dasfrosty

    How to support lazy loading using TreeCache?

    dasfrosty

      Currently we are using a home grown caching solution to avoid multiple lookups of the same object from the database. However our own caching logic is not transaction aware, so we are looking to replace it with a third party caching solution that is, potentially TreeCache.

      Our home grown solution takes a lazy loading type approach which does not seem to be completely compatible with how TreeCache is implemented:

      - When an object is requested try to get it from the local cache.
      - If the object's not in the local cache load it from the database and put it in the local cache.
      - Return a clone of the object to the requestor.

      - When an object is modified save it to the database and send a message to all cache instances in the cluster that the old version of the object is now invalid and should be removed. (I purposefully am avoiding the word "eviction" here since this is not triggered by the cache being too full or the object being left idle too long.)
      - The next time the object is requested the modified version will be retrieved from the database and stored in the cache.

      In trying to use TreeCache to support this same approach I have encountered differences in the design of TreeCache that appear to open the door to potential inconsistencies in the cache contents.

      Because TreeCache treats puts as write operations in all cases, lazy loading of an object is replicated across all instances of the cache (assuming replication is enabled). In our current implementation an object is loaded into only the cache instance that is local to the client requesting the object. Propagating the lazy load to other cache instances seems to me undesirable for a couple reasons:

      1. Adds unecessary overhead (although this could potentially reduce database calls in some situations)
      2. Can lead to stale data being propagated to other cache instances.

      To illustrate #2 consider the following scenario:

      - thread1 in tx1 puts object in cache1
      - thread1 modifies object -> object'
      - thread2 in tx2 puts object in cache2
      - thread1 removes object from cache1
      - thread1 commits tx1 (object' stored in repository)
      - thread2 commits tx2 (w/o modifying object)
      - cache1 sends update to cache2
      - cache2 sends update to cache1
      - cache1 adds ref to object
      - cache2 removes ref to object
      - cache1 has ref to object while db contains object'

      Am I misunderstanding something about the way TreeCache functions or is there another way to do lazy loading with TreeCache that doesn't allow this kind of inconsistency to occur?

      Thanks,
      Niels

        • 1. Re: How to support lazy loading using TreeCache?
          belaban

          Hi Niels,

          what you want is the CacheLoader interface, that I'm currently working on. Wait until J1 for an announcement. .. :-)

          But here's in a nutshell what it does:
          - get() fetches the data from cache. If not found, ask the cache loader to load it.
          - put() puts the data into the cache. if replicated: replicate across the cluster. If CacheLoader is present: store in CacheLoader (e.g. DB)
          - evict(): evict just from cache, not from CacheLoader
          - remove(): remove from cache and cache loader

          Have a look at the CacheLoader interface. I have also written a simple FileCacheLoader impl, you can see how it work by looking at the FileCacheLoaderTest unit test.

          This is exactly what you want, except that you want a DB-based implementation of CacheLoader, which is on the roadmap (possibly using Hibernate), but not yet done.

          If you want to implement a CacheLoader for a specific DB, I'd say it should take you not more than 2 days.

          If you happen to be at J1, be sure to stop by at the JBoss booth: we'll have a live demo of the JBossCache and CacheLoader.

          Bela

          • 2. Re: How to support lazy loading using TreeCache?
            dasfrosty

            Thanks for the quick response. That sounds exactly like what we want!

            If I'm understanding correctly we could implement a CacheLoader that would delegate the call to one of our existing EJBs, depending upon which FQN is passed in the get/put/remove. Sound reasonable?

            Is CacheLoader supported in the current version, i.e. if we implement our own cache loader now we could use it in TreeCache as is?

            Thanks,
            Niels

            • 3. Re: How to support lazy loading using TreeCache?
              belaban

               

              "dasfrosty" wrote:

              If I'm understanding correctly we could implement a CacheLoader that would delegate the call to one of our existing EJBs, depending upon which FQN is passed in the get/put/remove. Sound reasonable?


              Yes. Have a look at the FileCacheLoader. There's probably going to be a Hibernate or JDBC CacheLoader that's just delegating to Hibernate and/or plain JDBC.


              Is CacheLoader supported in the current version, i.e. if we implement our own cache loader now we could use it in TreeCache as is?


              The hooks that call out into the CacheLoader are mostly in place in CVS *head*. I think the CacheLoader API will not change much, so if you implement against it, we will have our side ready by J1, and you can use your CacheLoader impl.

              Bela

              • 4. Re: How to support lazy loading using TreeCache?
                dasfrosty

                Great, thanks for the info!

                See you at J1 :)