Search code examples
javaapache-cayenne

Cayenne Cache - Does Query Cache Replace object Cache?


I am looking for resources on how to best configure cayenne when running in a cluster, or multiple JVMs using the same domain. I've been reading the documentation and I see this:

"there are ways to notify other stacks about the object changes. This can be set up in the Modeler. However full synchronization of every change often results in excessive network traffic and CPU consumption, and is usually avoided in favor of the query cache approach described elsewhere in this chapter."

That links to the Query-Result-Caching page. It is my understanding that object caching is used when an associated object is retrieved via a getter or when an object is retrieved by its id. Is this quote telling me that if I configure query caching, object caching won't be used? Or that I need to avoid doing that would hit the object cache in my application code? Should I disable the object cache completely (if that's even possible)? If I don't set up cayenne to notify other stacks of changes to the object cache, don't I run the risk of stale data?

I appreciate any and all tips on the best way to run cayenne across multiple nodes, or if you have some resources to point me toward, that would be very helpful as well.

Thanks in advance for your time!


Solution

  • Object cache and query cache are independent from each other, though they can affect each other's state.

    Object Cache

    Object cache is accessed when expanding object graph (as you correctly noticed). But synchronization of object cache does not just update the cache, but is also propagated to ObjectContexts, causing a refresh of the in-memory object graph. While this sounds awesome and super-automatic, from experience it is most useful in desktop apps, when you have a limited graph of objects relevant for a single user. In clustered multi-user web applications syncing object cache is more of a nuisance then help. It creates lots of network traffic, forces your instances to consume CPU to process events they don't really care about, and finally, updates your objects from underneath when you least expect it. So I usually turn off object cache syncing, and rely purely on clustered query cache to handle synchronization.

    Query Cache

    Here is an example project demonstrating query cache with clustering. It uses Cayenne 4.0, EHCache as a cache provider, and ActiveMQ/JMS for cross-instance events.

    The way query cache works, it caches lists of objects that matched a given query, including prefetched related objects if the query contained prefetches. To take full advantage of query cache, you may have to change your coding style a bit. Instead of storing long-lived references to query result lists in your instance variables (essentially doing your own caching), you create and run a query (with proper cache settings) any time you need such list, and let Cayenne decide whether the list should be returned from cache or fetched fresh from DB.

    The next step is to configure your cache in a way depending on what provider you are using to specify its default expiration policies (per cache group). E.g. a sample EHCache config.

    Finally you can add clustering and event-driven cache refreshing, which can be done either explicitly via API calls, or implicitly on commit of certain entities (only available since Cayenne 3.1).

    Query cache refreshing is very cheap. The only thing sent across the network is the name of the "cache group", and on the receiving end a bunch of lists are lazily invalidated at once. It also results in cleaner code.

    If you are to rely primarily on the query cache, you don't need to "turn off" object cache per se. Object cache is an integral part of Cayenne and is needed for a number of operations (updates, relationships handling). It will be automatically updated as you run the queries. What you'd normally need to do though, is turn off automated object refreshing. By not enabling object cache clustering, you already avoid cross-JVM sync. Additionally you may use this advice to disable cross-ObjectContext sync within the same VM.

    Version of Cayenne

    I strongly recommend upgrading to at least Cayenne 3.1 (or even to 4.0.M2). Among other nice things there, the caching mechanism is more mature than 3.0. It will make your experience configuring Cayenne and integrating external cache providers so much easier.