[
https://issues.apache.org/jira/browse/SHIRO-452?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13943087#comment-13943087
]
Mark Hale commented on SHIRO-452:
---------------------------------
I think I'm encountering a similar but slightly different problem. I have a
single EhCache shared between two security manager webapp instances. When I
login in one webapp, I sometimes receive:
{code}
net.sf.ehcache.CacheException: Failed to serialize element due to
ConcurrentModificationException. This is frequently the result of
inappropriately sharing thread unsafe object (eg. ArrayList, HashMap, etc)
between threads
at
net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:401)
~[ehcache-2.8.1.jar:2.8.1]
at
net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:381)
~[ehcache-2.8.1.jar:2.8.1]
at
net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:473)
~[ehcache-2.8.1.jar:2.8.1]
at
net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1067)
~[ehcache-2.8.1.jar:2.8.1]
at
net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1051)
~[ehcache-2.8.1.jar:2.8.1]
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
~[na:1.7.0_25]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
~[na:1.7.0_25]
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
~[na:1.7.0_25]
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
~[na:1.7.0_25]
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
~[na:1.7.0_25]
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
~[na:1.7.0_25]
at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]
Caused by: java.util.ConcurrentModificationException: null
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:894)
~[na:1.7.0_25]
at java.util.HashMap$EntryIterator.next(HashMap.java:934) ~[na:1.7.0_25]
at java.util.HashMap$EntryIterator.next(HashMap.java:932) ~[na:1.7.0_25]
at java.util.HashMap.writeObject(HashMap.java:1098) ~[na:1.7.0_25]
at sun.reflect.GeneratedMethodAccessor76.invoke(Unknown Source) ~[na:na]
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25]
at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
~[na:1.7.0_25]
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
~[na:1.7.0_25]
at
org.apache.shiro.session.mgt.SimpleSession.writeObject(SimpleSession.java:461)
~[shiro-core-1.2.3.jar:1.2.3]
at sun.reflect.GeneratedMethodAccessor79.invoke(Unknown Source) ~[na:na]
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25]
at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:439)
~[na:1.7.0_25]
at net.sf.ehcache.Element.writeObject(Element.java:867)
~[ehcache-2.8.1.jar:2.8.1]
at sun.reflect.GeneratedMethodAccessor78.invoke(Unknown Source) ~[na:na]
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:1.7.0_25]
at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25]
at
java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
~[na:1.7.0_25]
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
~[na:1.7.0_25]
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
~[na:1.7.0_25]
at
net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97)
~[ehcache-2.8.1.jar:2.8.1]
at
net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:399)
~[ehcache-2.8.1.jar:2.8.1]
... 11 common frames omitted
{code}
I'm posting here because I think the solution to this jira will also solve my
problem, which is also due to the disk writing thread being different to the
servlet request thread. I believe to solve both problems, you need to modify
SimpleSession.writeObject() so that it takes a copy of the attributes map
before writing it (+ make fields volatile). Or alternatively, I guess the shiro
Cache.put() implementation for EhCache could be modified to take a copy via
clone() or something and pass that to EhCache instead of the original object.
> SimpleSession serialization failing
> -----------------------------------
>
> Key: SHIRO-452
> URL: https://issues.apache.org/jira/browse/SHIRO-452
> Project: Shiro
> Issue Type: Bug
> Components: Caching , Session Management
> Affects Versions: 1.2.1
> Environment: Java 6 - EhCache 2.6.2
> Reporter: Bruno GRIEDER
>
> We cache SimpleSession in EhCache which is configured with Overflow to Disk
> and an LRU eviction policy.
> When the cache is full, EhCache will attempt to evict a session from the Disk
> Storage to reclaim space.
> To evict the `SimpleSession`, EhCache will attempt to deserialize the
> eveicted session first. From time to time, the deserialization of the
> `SimpleSession` fails. When that happens the system is locked, since no
> additional session can be created.
> `SimpleSession` has a custom serialization mechanism that calculates a bit
> mask which indicates which fields of the `SimpleSession` contain values. This
> bitMask is serialized first (as a Short) then the fields containing values.
> When deserialization is failing, the bitMask indicates that the `attributes`
> Map contains data, however no `attributes` have actually been serialized and
> the deserialization fails with a `java.io.OptionalDataException`.
> The discrepancy is very likely due to `attributes` being a non synchronized
> Map: the SimpleSession is created on a Servlet thread, however the
> serialization to Disk is performed by EhCache on one of its cache management
> threads.
> SimpleSession fields should likely be marked as volatile and the Map should
> be a Synchronized Map or SimpleSession should be made immutable.
--
This message was sent by Atlassian JIRA
(v6.2#6252)