-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
We just found an issue inside com.fasterxml.jackson.databind.util.LRUMap that result in a cache corruption when running on IBM J9 on high load.
The error manifests with the following stack (jackson-databind-2.4.1.1):
7799 at java.util.LinkedHashMap.get(LinkedHashMap.java:333)
7800 at com.fasterxml.jackson.databind.util.LRUMap.get(LRUMap.java:58)
7801 at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:707)
7802 at com.fasterxml.jackson.databind.type.TypeFactory._constructType(TypeFactory.java:387)
7803 at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:801)
7804 at com.fasterxml.jackson.databind.type.TypeFactory._constructType(TypeFactory.java:391)
7805 at com.fasterxml.jackson.databind.type.TypeBindings.resolveType(TypeBindings.java:102)
7806 at com.fasterxml.jackson.databind.introspect.Annotated.getType(Annotated.java:60)
7807 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._constructWriter(BeanSerializerFactory.java:703)
7808 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:559)
7809 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:344)
7810 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:263)
7811 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:222)
7812 at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:152)
7813 at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1077)
7814 at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1037)
7815 at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:445)
7816 at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:599)
7817 at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:92)
7818 at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:2866)
7819 at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2289)
After analyzing the issue, we found out that the implementation of com.fasterxml.jackson.databind.util.LRUMap.get(Object) incorrectly assumes that the superclass implementation of this method is read-only. This is not true because the constructor of LRUMap sets the accessOrder to true, thus allowing get() to promote changes in the internal structure of the map in order to optimize the access (see http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html for further details).
Given that, the implementation of com.fasterxml.jackson.databind.util.LRUMap.get(Object) must be protect the call with a write lock instead of a read lock:
@Override
public V get(Object key) {
_writeLock.lock();
try {
return super.get(key);
} finally {
_writeLock.unlock();
}
}
It is also possible to solve this issue by changing the constructor parameter accessOrder to false instead and leave the current implementation of the get() as is. This however will disable the LRU behavior of this implementation.
I know that this change will result in performance issues due to the need of synchronization. I'll test the performance of other synchronization options as well in order to determine what is the best solution for this problem.
As far as I could see, this issue is closely related to the issue #435.