You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by "Dalia Abo Sheasha (JIRA)" <ji...@apache.org> on 2014/02/05 22:40:10 UTC

[jira] [Updated] (OPENJPA-2472) Concurrency issue in ClassMetaData.getPkAndNonPersistentManagedFmdIndexes()

     [ https://issues.apache.org/jira/browse/OPENJPA-2472?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Dalia Abo Sheasha updated OPENJPA-2472:
---------------------------------------

    Attachment: OPENJPA-2472.txt

I have attached a patch where I solve this issue by using a temporary variable to store the field's data we're interested in and populate it. Then after the temporary variable is finished being populated, the field is assigned to the temporary variable. 
I also attached the tests I used to make sure the problem is solved using this solution. 

> 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
>         Attachments: OPENJPA-2472.txt
>
>
> 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)