Benjamin Bentmann created OPENJPA-2472:
------------------------------------------
Summary: Concurrency issue in
ClassMetaData.getPkAndNonPersistentManagedFmdIndexes()
Key: OPENJPA-2472
URL: https://issues.apache.org/jira/browse/OPENJPA-2472
Project: OpenJPA
Issue Type: Bug
Components: kernel
Affects Versions: 2.2.2, 2.3.0
Reporter: Benjamin Bentmann
In a scenario where brand new entity instances of the same class get inserted
concurrently, we noticed sporadic failures like this:
Caused by: <openjpa-2.3.0-r422266:1540826 fatal store error>
org.apache.openjpa.persistence.EntityNotFoundException: The transaction has
been rolled back. See the nested exceptions for details on the errors that
occurred.
at
org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2370)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2207)
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2105)
at
org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:2023)
at
org.apache.openjpa.kernel.LocalManagedRuntime.commit(LocalManagedRuntime.java:81)
at org.apache.openjpa.kernel.BrokerImpl.commit(BrokerImpl.java:1528)
at
org.apache.openjpa.kernel.DelegatingBroker.commit(DelegatingBroker.java:933)
at
org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.java:570)
... 2 more
Caused by: <openjpa-2.3.0-r422266:1540826 nonfatal store error>
org.apache.openjpa.persistence.EntityNotFoundException: The instance of type
"class ..." with oid "ec2cfaa9e2f04b628d7e1991e65751dc" no longer exists in the
data store. This may mean that you deleted the instance in a separate
transaction, but this context still has a cached version.
at
org.apache.openjpa.kernel.StateManagerImpl.loadFields(StateManagerImpl.java:3109)
at
org.apache.openjpa.kernel.StateManagerImpl.loadField(StateManagerImpl.java:3188)
at
org.apache.openjpa.kernel.StateManagerImpl.fetchStringField(StateManagerImpl.java:2474)
at
org.apache.openjpa.kernel.StateManagerImpl.fetchString(StateManagerImpl.java:2464)
at
org.apache.openjpa.jdbc.meta.strats.StringFieldStrategy.insert(StringFieldStrategy.java:105)
at
org.apache.openjpa.jdbc.meta.FieldMapping.insert(FieldMapping.java:623)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.insert(AbstractUpdateManager.java:238)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.populateRowManager(AbstractUpdateManager.java:165)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:96)
at
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:77)
at
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:732)
at
org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:131)
... 9 more
The primary ID of each entity is set manually by the app prior to insertion.
Debugging led me to ClassMetaData.getPkAndNonPersistentManagedFmdIndexes()
which is called from StateManagerImpl.initialize() to set up the _loaded bit
set. When the above exception occurs, all bits in that set are zero. This
ultimately caused the erroneous loadField() call that fails the insertion.
The following line in getPkAndNonPersistentManagedFmdIndexes() disturbs the
thread-safety:
_pkAndNonPersistentManagedFmdIndexes = new int[idsSize];
Once this has executed, another thread which executes the if
(_pkAndNonPersistentManagedFmdIndexes == null) in line 2778 can read the array
before the first thread has finished the loop that initializes its values.
The line following "// Default to FALSE, until proven true." in
hasPKFieldsFromAbstractClass() looks equally troublesome, setting an instance
variable to a temp value. Somebody whose more familar with the codebase might
want to check for more occurrences of this pattern.
--
This message was sent by Atlassian JIRA
(v6.1.5#6160)