I found a documented bug on dirty reads on mutable objects :
and I have couple of questions regarding it.
1. Do you know if it happen in older versions than 5.0
2. According to this bug, it seems that the most common use with transactional cache is immutable objects, am I right?
cause otherwise a lot of people would have complained about this bug.
3. is there a work around to this issue?
correct, Infinispan on a single node acts as a ConcurrentHashMap, so if multiple threads get the same object (as identified by same key) they are likely to receive the same instance.
For obvious reasons different nodes will have different instances, and because of the serialization layer even on the same node it might happen to receive different instances of the same value; but these are details one should not rely on, so storing immutable objects is recommended.
You can still store mutable objects, just make sure your application makes defensive copies before making changes on them.
3. No there is no other workaround (other than making defensive copies). Feel free to ask for it as a feature request on JIRA, it should be easy to implement but beware Infinispan will need to reuse the serialization strategies, your application can possibly be smarter in terms of performance.
If I understnad you correctly, it's happen also in previous versions.
Yes, this is always been the case.
so although it's transactional and suppose to be ACID it doesn't - cause it cause dirty reads on mutable objects, right?
Yes this applies to transactional caches as well. You should not use mutable objects if you need this guarantees; if you don't like this, as mentioned it's easy to add an option to make copy-on-reads, just open a feature request on JIRA. But that would apply to all reads of such an option was enabled, so I'd be interested to know if you would really like such an option as personally as a user I wouldn't like to sacrifice that performance.
Sanne Grinovero wrote:
@Sanne, doesn't Infinispan already create new instances when reading data with storeAsBinary enabled?
@Dan, look into org.infinispan.marshall.MarshalledValue.get() : yes it is *likely* going to create a new instance on read, but race conditions on get might return the same instance. A get() operation is non-blocking if it finds another value in instance-form; if not it deserializes it and a lock is acquired only to prevent two threads from doing the same deserialize work at the same time to avoid duplicate deserialization work and return the same instance.
So it's designed for speed, and the option should not be used to get independent instances as that's a non-guaranteed side-effect - even though, you're right in that it's very likely a different instance! But this would be more likely with expensive deserialization operations and certain usage patterns.
This doesn't seem too hard to change; we could support a stronger guarantee for certain configurations (as an alternative option, I wouldn't apply it for all cases). I would also like to see an option for the opposite: keep the value in instance-form for longer, to benefit more from reuse in those cases for which the cost of deserialization is worth the extra memory.