Yesterday, one of our consultants (Chris Harris) brought up a very interesting point regarding local changes on direct custom object or collections references that are cached:
I have a customer who is trying to use TreeCache 1.4 directly and our doing something like : (Note I am writing this code directly in this case so it may not compile ;-) ):
//within the transaction
List aList = new ArrayList();
tree.put("/a/b/c", "name", aList);
//outside the transaction
They are experiencing that if they add something to the List within the cache after the put then the new element within the list is also cached. I would have not expected this as I always thought you need to explicitly call put to add the object back into the cache.
They are also experiencing that "Test3" is also added the the cache but is not replicated until the next transaction is commits. Again I don't think this is right.
The design of their application involves putting a layer in front of TreeCache that exposes simple put and get methods to the users of their API. They are considered that users may now be adding data to the cache that they did not intend to add.
Can someone validate if this is the expected behavior of TreeCache.
The workaround I have is to clone the object before giving it back to the client but they is not a very nice solution.
Here's the response that I gave to him:
When it comes to standard JBoss Cache usage, transactional work is primarily used to limit replication which is costly. Local changes on direct custom object or collections references will be visible locally.
When it comes to pessimistic locking, JBossCache maintains a direct reference to the object stored in memory, so adding an element to a list after a put will be visible in the cached element, but the thing to bear in mind is that if transaction commits, it'll get replicated and if it rollbacks, it won't get replicated and the local modifications via put will be rollbacked, in this case, the put will be reverted and won't be visible.
Even though the changes the cached changes will be visible after "aList.add("Test2");", this will only be visible within that transaction. Locking will prevent that other transactions act on the cached object.
Same happens with OL even though changes within a transaction are maintained in a workspace. If you're within a transaction and you call get(), the value returned will be looked up in the workspace for the transaction, so in your case, a get call after "aList.add("Test2");" will return a list with Test2 too. We also store direct references to objects in OL's workspaces.
Outside of a transaction, unless you do a put call, there won't be a replication, which is why adding to a List does not produce a replication. You'd need to use PojoCache to get this type of behavior.
Chris is pretty much now forced to clone inputs or returns to the cache to avoid this type of issue. Thoughts?
Is this maybe an option we wanna be providing in the future? or is this is an edge case that the user must deal with?
In core JBossCache, we have no control over the references to these objects.