Hi All,
I'd like to propose the challenge of how we think vendors should deal with transactions in the context of Caches with CacheLoaders/Writers configured, especially in the context of a distributed Cache. While this is an "implementation concern", it's very important to see how this may be implemented as it very much effects the API design.
As part of reviewing the specification with the Java EE team, and in particular how multiple-servers will interact, we've found a few challenges. In the spirit of openness, I've added some commentary to the following issue:
https://github.com/jsr107/jsr107spec/issues/153
Currently I feel that the way the API is defined, all CacheLoader and CacheWriter operations will need to be performed "locally" which fundamentally prevents efficient (or any) implementation in a highly concurrent and distributed manner. Furthermore, interaction across multiple application processes, Java SE or otherwise may be a problem, simply because the API doesn't provide enough fidelity for CacheLoader and CacheWriter operations to be part of a larger transaction. eg: there's no "prepare" and "commit" for CacheWriters! Just "store".
Even with a few changes, as I've suggested in the issue above, I honestly feel we're essentially forcing vendors to implement fully recoverable XA Transaction Managers as part of their Caching infrastructure, simply to coordinate transactions across the underlying Cache Writers in a distributed setting. Why? because the API basically implies this coordination would need to be performed by the Cache implementation itself - even in "local" mode!
eg: Say a developer starts a transaction that updated n entries, those of which are partitioned across n servers. As part of the "commit", all n servers will need to take care of committing, say to memory. Behind this are the Cache Writers, which also need to be coordinated. The entries need to be stored as part of the Caching contract.
Unfortunately our current API provides no mechanism to coordinately this, eg: share a global transaction to a single database across said the n Cache Writers. Without this what essentially happens at the moment is that each CacheWriter starts their own individual transaction, not attached to or part of the application transaction. That may seem reasonable to some, but consider the case where there is a parent-child or some other relationship between the cache entries that are being updated (which is why your using a transaction in the first place). If individual transactions are used by the Cache Writers and are committed in some non-deterministic order (as there is no ordering constraints or ways to control this in the API) database integrity constraints are likely to be violated. So while the "commit" to the Cache may seem to be atomic, the "stores" to the underlying Cache Writers aren't.
Essentially there are a few options (as I've covered in the issue).
1. Allow a global transaction to be provided to all of the Cache Writers. Wow... that would be pretty crazy and horribly slow. Every server would need to contact the transaction manager, do a bunch of work, etc, just to set things up.
This sort of contradicts the entire reason people would be using a cache in the first place. To even achieve this I think we'd need to change the CacheLoader/Writer API. Specifically we'd need to add "prepare", "commit" and "rollback".
2. Don't allow CacheLoaders/Writers to be configured with Caches. I think this is pretty easy to do, but again, wow... that would force developers to change their application code significantly to use Transactional Caches with external stores.
3. Only allow "local" transactions to be performed. This would ultimately mean that Caches would be the last-local-resource in XA transactions (not too bad, though it's a challenge if there are others as well). Additionally in the distributed case, while entries may be distributed, the loading / writing would always occur locally. This works, but significantly reduces scalability as all "versioning" of data being touched may need to be held locally. It's highly likely a huge amount of distributed locks would be required (if the Cache isn't using MVVC), which we know is horribly slow. eg: imagine a transaction with a "putAll" containing a few million entries. In pessimistic mode, an implementation may need to do a lot of work locally to ensure versioning is held and updated correctly. It may also need to perform a few million locks! Saying that a developer shouldn't use "putAll" with transactions probably isn't a solution either.
Personally I'm not sure if any of this is desirable? I haven't really seen much of this discussed or addressed. Perhaps I'm missing something? I'd certainly be happy to do some further research!
The bottom line is that while we're trying to define an API that provides developers with a means to improve the performance, through-put and scalability of an application through the temporary storage of data, the requirements to implement transactions, even optionally, may throw much of the benefit away.
It would be great to get your thoughts on this. I don't think we can get away with the statement "transactions are implementation specific" in the specification, especially if the API doesn't provide enough fidelity to cover these simple use-cases.
-- Brian
--
You received this message because you are subscribed to the Google Groups "jsr107" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jsr107+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.