Hi again Tomasz,
Based on the discussion so far (the fact that you only do one fetch, one
thread, only once), I now doubt that this is your problem. The bug my patch
is for is purely a concurrency problem as far as I can tell.
I guess it is at least worth a try, so I have attached the patch for you.
I had to rip it out of a larger patch, but it is pretty simple and is only one
file so I think I got it correctly. If you do have any problems, let me know.
Good luck,
Sam
On July 8, 2004 07:00 am, Tomasz Piontek wrote:
> Hi,
>
> I don't know whether it's exactly the same problem, but is very similar
> to yours.
> In my case there is no necessity to start many threads. Even in
> one-threaded application I get following exception:
>
> org.exolab.castor.jdo.PersistenceException: Lock conflict: attempt to
> load object of type dbItem with identity 1 in two different locks modes
> (exclusive and non exclusive) in the same transaction
> at
> org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:6
>27) at
> org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:5
>55) at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:764) at
> org.exolab.castor.persist.LockEngine.load(LockEngine.java:356) at
> org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:6
>49) at
> org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:5
>55) at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:793) at
> org.exolab.castor.persist.LockEngine.load(LockEngine.java:356) at
> org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:6
>49) at org.exolab.castor.persist.QueryResults.fetch(QueryResults.java:229)
> at
> org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryIm
>pl.java:627) at
> org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryIm
>pl.java:610) at LockTest.getItem(LockTest.java:176)
> at LockTest.runWriter(LockTest.java:118)
> at LockTest.run(LockTest.java:105)
>
> Maybe I do something wrong or a stupid error, but it doesn't work in one
> thread :-(
> It is somehow connected with 1-N relatationships, because my simple test
> program stopped working when I added 1-N relationship.
>
> I tested the problem with castor-0.9.5.3.
> BTW does anyone know when the next castor version will be released?
> According to the web-page it should be done on "June, 7 2004".
>
> If it is possible please send your patch to me. I will recheck the
> problem with patched 0.9.5.1.
> All the best,
> Tomasz
>
> Sam Maloney wrote:
> >Hi Tomasz,
> >
> >I found and fixed recently a bug that caused that exact error.
> >
> >The bug would happen in this situation:
> >
> >Any tree of mapped objects where there is at least one 1:N relationships
> > to a dependant object. ie:
> >
> >Store <-->> Register (depends=Store)
> >
> >These can even be empty (minus the Pk). All that is needed to cause this
> > is a 1:N relationship where the Ns are dependant on the 1 AND the
> > parent/reverse relationship (in the map) from the N to the 1 MUST be
> > there for the bug to happen.
> >
> >In any case with such a setup (which is most likely very common, and
> > appears to be your case), the bug would happen simply by spawning two or
> > more threads concurrently that fetch the same object at the same time,
> > even both in the same access mode (exclusive or dblocked).
> >
> >ie:
> >-----
> >public static void testLockProblem() {
> > Runnable runner = new Runnable() {
> > public void run() {
> > _testLockProblem();
> > }
> > };
> >
> > new Thread(runner, "test runner 1").start();
> > new Thread(runner, "test runner 2").start();
> >}
> >
> >public static void _testLockProblem() {
> > try {
> > db.begin();
> > db.load(Store.class, new Long(0), Database.DbLocked);
> >
> > // Wait to simulate processing, thus holding the lock, thus enabling
> > // concurrency to happen for sure.
> > Object obj = new Object();
> > synchronized(obj){
> > try {
> > obj.wait(1000);
> > } catch (InterruptedException e) {
> > }
> > }
> >
> > db.commit();
> > } catch (Exception e) {
> > throw new RuntimeException(e);
> > }
> >}
> >-----
> >
> >If you run the above test on a simple tree as described above and this
> > problem happens every single time you run the test, then most likely it
> > is the exact same problem.
> >
> >If you confirm this is the case, then msg the list again and we can
> > discuss the patch. It is tested and works perfect, however it is an
> > unofficial patch against version 0.9.5.1. So mention which version you
> > are using in your reply.
> >
> >Later,
> >Sam
> >
> >On July 7, 2004 06:14 am, Tomasz Piontek wrote:
> >>Hello,
> >>
> >>I would be very grateful if anyone could explain to me why the following
> >>code complains about the "LockConflict"?
> >>I make only one query in Exclusive mode, so why the QueryResults tries
> >>to lock the object again and causes LockConflict?
> >>
> >>I read the documentation and in my opinion the conflict is caused
> >>because the query was made (as it was specified in Exclusive mode) and
> >>when the object is loaded by QueryResults it is done in default mode (I
> >>didn't specified "access" attribute in mapping file) which is Shared one.
> >>
> >>Could anyone tell me what did I wrong. I want to query from my code
> >>objects as well in ReadOnly as in Exclusive mode. I don't want to use
> >>Shared mode.
> >>
> >>It's not a productive code, I simplified my code as it was possible.
> >>
> >> public void manual()
> >> {
> >> JDO jdo = null;
> >> Database db = null;
> >> QueryResults result = null;
> >> try {
> >> jdo = new JDO();
> >> jdo.setDatabaseName( "grms-devel_jobreg" );
> >> jdo.setConfiguration( "./etc/jobreg_database.xml" );
> >> db = jdo.getDatabase();
> >> db.begin();
> >> OQLQuery query = db.getOQLQuery("select job from
> >>grms.jobreg.JobInfo job where job.id=$1");
> >> query.bind("JOB_ID0");
> >> result = query.execute( Database.Exclusive);
> >> JobInfo job = null;
> >> if( result.hasMore())
> >> job = (JobInfo)result.next();
> >>
> >> //some updates
> >> System.out.println( "JOB_NAME = " + job.jobId);
> >> db.commit();
> >> db.close();
> >> } catch ( Exception e) {
> >> e.printStackTrace();
> >> }
> >> }
> >>
> >>The executions finishes with following exception:
> >>
> >>org.exolab.castor.jdo.PersistenceException: Lock conflict: attempt to
> >>load object of type grms.jobreg.JobInfo with identity 1 in two different
> >>locks modes (exclusive and non exclusive) in the same transaction
> >> at
> >>org.exolab.castor.persist.TransactionContext.load(TransactionContext.java
> >>:6 27) at
> >>org.exolab.castor.persist.TransactionContext.load(TransactionContext.java
> >>:5 55) at
> >> org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:764) at
> >> org.exolab.castor.persist.LockEngine.load(LockEngine.java:356) at
> >> org.exolab.castor.persist.TransactionContext.load(TransactionContext.jav
> >>a:6 49) at
> >>org.exolab.castor.persist.TransactionContext.load(TransactionContext.java
> >>:5 55) at
> >> org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:793) at
> >> org.exolab.castor.persist.LockEngine.load(LockEngine.java:356) at
> >> org.exolab.castor.persist.TransactionContext.load(TransactionContext.jav
> >>a:6 49) at
> >>org.exolab.castor.persist.QueryResults.fetch(QueryResults.java:229)
> >> at
> >>org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQuery
> >>Im pl.java:627) at
> >>org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQuery
> >>Im pl.java:610) at
> >>grms.tests.jobreg.RepositoryThreads.manual(RepositoryThreads.java:198)
> >> at
> >>grms.tests.jobreg.RepositoryThreads.main(RepositoryThreads.java:212)
> >>
> >>and the mapping file more less is:
> >>
> >><?xml version="1.0" encoding="UTF-8"?>
> >>
> >><mapping>
> >> <description>Castor generated mapping file</description>
> >>
> >> <class name="grms.jobreg.JobInfo" identity="dbId" key-generator="MAX">
> >> <description>Default mapping for class
> >> grms.jobreg.JobInfo</description> <map-to xml="job-info"
> >> table="grms_repository_job"/>
> >> <field name="dbId" type="int">
> >> <bind-xml name="db-id" node="attribute"/>
> >> <sql name="job_rep_job_id" type="integer"/>
> >> </field>
> >>
> >>
> >> <field name="id" type="java.lang.String">
> >> <bind-xml name="id" node="element"/>
> >> <sql name="job_id" type="char"/>
> >> </field>
> >>
> >> <field name="fileDirs" type="grms.jobreg.InOutFileDir"
> >>collection="array">
> >> <bind-xml name="out-files" node="element"/>
> >> <sql many-key="job_rep_job_id"/>
> >> </field>
> >>
> >> <field name="jobHistory" type="grms.jobreg.JobHistory"
> >>collection="array">
> >> <bind-xml name="job-history" node="element"/>
> >> <sql many-key="job_rep_job_id"/>
> >> </field>
> >>
> >> <field name="jobNotifications" type="grms.jobreg.JobNotification"
> >>collection="array">
> >> <bind-xml name="job-notifications" node="element"/>
> >> <sql many-key="job_rep_job_id"/>
> >> </field>
> >> </class>
> >>
> >> <class name="grms.jobreg.JobHistory" identity="dbId"
> >>key-generator="MAX" depends="grms.jobreg.JobInfo">
> >> <description>Default mapping for class
> >>grms.jobreg.JobHistory</description>
> >> <map-to xml="job-history" table="grms_repository_history"/>
> >> <field name="dbId" type="integer">
> >> <bind-xml name="db-id" node="attribute"/>
> >> <sql name="job_rep_history_id" type="integer"/>
> >> </field>
> >>
> >> <field name="homeDirectory" type="java.lang.String">
> >> <bind-xml name="home-directory" node="element"/>
> >> <sql name="home_directory" type="char"/>
> >> </field>
> >>
> >> <field name="jobInfo" type="grms.jobreg.JobInfo">
> >> <bind-xml name="job-info" node="attribute"/>
> >> <sql name="job_rep_job_id"/>
> >> </field>
> >>
> >> </class>
> >>
> >>
> >> <class name="grms.jobreg.InOutFileDir" identity="dbId"
> >>key-generator="MAX" depends="grms.jobreg.JobInfo">
> >> <description>Default mapping for class InOutFile</description>
> >> <map-to table="grms_repository_filedir"/>
> >>
> >> <field name="dbId" type="integer" direct="true">
> >> <bind-xml name="db-id" node="attribute"/>
> >> <sql name="job_rep_filedir_id" type="integer"/>
> >> </field>
> >>
> >> <field name="jobInfo" type="grms.jobreg.JobInfo"
> >> direct="true"> <bind-xml reference="true" node="attribute"/>
> >> <sql name="job_rep_job_id"/>
> >> </field>
> >> </class>
> >>
> >>
> >> <class name="grms.jobreg.JobNotification" identity="dbId"
> >>key-generator="MAX" depends="grms.jobreg.JobInfo">
> >> <description>Default mapping for class
> >>grms.jobreg.JobNotification</description>
> >> <map-to table="grms_repository_notif"/>
> >> <field name="dbId" type="integer">
> >> <bind-xml name="db-id" node="attribute"/>
> >> <sql name="job_rep_notif_id" type="integer"/>
> >> </field>
> >>
> >> <field name="jobNotificationUsers"
> >>type="grms.jobreg.JobNotificationUser" collection="array">
> >> <bind-xml name="job-notification-users" node="element"/>
> >> <sql many-key="job_rep_notif_id"/>
> >> </field>
> >>
> >> <field name="JobInfo" type="grms.jobreg.JobInfo">
> >> <bind-xml reference="true" node="attribute"/>
> >> <sql name="job_rep_job_id"/>
> >> </field>
> >> </class>
> >>
> >> <class name="grms.jobreg.JobNotificationUser" identity="dbId"
> >>key-generator="MAX" depends="grms.jobreg.JobNotification">
> >> <description>Default mapping for class
> >>grms.jobreg.JobNotificationUser</description>
> >> <map-to table="grms_repository_notif_dn"/>
> >> <field name="dbId" type="int">
> >> <bind-xml name="db-id" node="attribute"/>
> >> <sql name="job_rep_notif_dn_id" type="integer"/>
> >> </field>
> >>
> >> <field name="JobNotification" type="grms.jobreg.JobNotification">
> >> <bind-xml reference="true" node="attribute"/>
> >> <sql name="job_rep_notif_id"/>
> >> </field>
> >>
> >> </class>
> >></mapping>
> >>
> >>I will be very grateful for any hints how to solve the problem and for
> >>information what is the casue of it.
> >>
> >>All the best,
> >>Tomasz
> >
> >-----------------------------------------------------------
> >If you wish to unsubscribe from this mailing, send mail to
> >[EMAIL PROTECTED] with a subject of:
> > unsubscribe castor-dev
Index: LockEngine.java
===================================================================
RCS file: /cvsroot/castor/src/org/exolab/castor/persist/LockEngine.java,v
retrieving revision 1.2
retrieving revision 1.4
diff -u -3 -p -u -r1.2 -r1.4
--- LockEngine.java 30 Jun 2004 18:39:22 -0000 1.2
+++ LockEngine.java 9 Jul 2004 15:12:03 -0000 1.4
@@ -40,7 +40,7 @@
*
* Copyright 1999 (C) Intalio, Inc. All Rights Reserved.
*
- * $Id: LockEngine.java,v 1.2 2004/06/30 18:39:22 samm Exp $
+ * $Id: LockEngine.java,v 1.4 2004/07/09 15:12:03 samm Exp $
*/
@@ -99,7 +99,7 @@ import org.exolab.castor.util.Messages;
*
* @author <a href="[EMAIL PROTECTED]">Assaf Arkin</a>
* @author <a href="[EMAIL PROTECTED]">Thomas Yip</a>
- * @version $Revision: 1.2 $ $Date: 2004/06/30 18:39:22 $
+ * @version $Revision: 1.4 $ $Date: 2004/07/09 15:12:03 $
*/
public final class LockEngine {
@@ -905,8 +905,12 @@ public final class LockEngine {
ObjectLock lock;
TypeInfo typeInfo;
typeInfo = (TypeInfo) _typeInfo.get( oid.getName() );
- lock = typeInfo.release( oid, tx );
+
+ lock = (ObjectLock)typeInfo.locks.get(oid);
+
+ //FIXME: Perhaps this should be synchronized on 'locks'.
lock.getOID().setDbLock( false );
+ lock = typeInfo.release( oid, tx );
}
@@ -1165,6 +1169,7 @@ public final class LockEngine {
ObjectLock entry = null;
boolean newentry = false;
boolean failed = true;
+ boolean update_entry_oid = false;
// sync on "locks" is, unfortunately, necessary if we employ
// some LRU mechanism, especially if we allow NoCache, to avoid
// duplicated LockEntry exist at the same time.
@@ -1188,7 +1193,8 @@ public final class LockEngine {
entry = new ObjectLock( oid );
locks.put( oid, entry );
} else {
- oid = entry.getOID();
+// oid = entry.getOID();
+ update_entry_oid = true;
}
entry.enter();
}
@@ -1217,6 +1223,11 @@ public final class LockEngine {
throw new IllegalArgumentException( "lockType "+lockAction+" is undefined!");
}
failed = false;
+
+ if (update_entry_oid) {
+ entry.setOID(oid);
+ }
+
return entry;
} finally {
synchronized( locks ) {
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-dev