In my cache I store Lists indexed by Integers (Cache<Integer, LinkedList<MyClass>>) and I am using an optimistic locking. When a transaction is invalidated by another concurrent transaction, and its commit fails with rollback, I replay the transaction until it succeeds (this is the whole idea of optimistic locking, I believe). For this approach to work properly, my transactional code must have no side effects when commit fails, and this is giving me trouble. Consider the following transaction (without the boilerplate code):
tm.begin(); List<MyClass> list = cache.get(10); list.add(new MyClass()); cache.put(10, list); tm.commit();
Now suppose the transaction was rolled back for some external reason. In cache's view, this transaction has done nothing, and its state altered. The problem is that in local cache copy, there may be a leftover garbage of the previous failed transaction. If I call:
List<MyClass> list = cache.get(10);
There is a chance that the list I get is the list modified by the failed transaction. So, even if commit failed, the cache may return a value affected by it. This seems be an issue with every cache with mutable objects as value; and the only solution I see is to always copy the object before modifying it. This is certainly a thing that I don't want to do, because, as I stated previously, I am being optimistic about my transactions. So I came here to aks: is this a common issue faced by infinispan users? How do you solve it? Is there a better solution?
I found this very related bug reported:
The symptoms are the same, but the steps to get it were different. They are all caused by reusing internal mutable object reference between separated uncommited transactions.
It seems I'll have to clone the mutable objects myself just after get().