|
Hi,
We have a Doctor class whch is having N-1 relation
with a Department class. In our test code when multiple threads tried to load
and update different Doctor objects simultaneously, all but one are getting
LockNotGranted(persis t.deadlock) exceptions. The objects are loaded in
Shared mode and cache-type is set to unlimited. Going through the castor code
our finding is that:
Suppose there are two Doctors Doc1 & Doc2 both
belonging to the same Department Dept1.
When a transaction T1 loads Doc1, Doc2 is also
loaded because of its relation with the same Department and thus the T1 gets a
read lock on Doc2 also.
When another concurrent Transaction T2 loads Doc2,
Doc1 is also loaded because of its relation with the same Department and thus
the T2 gets a read lock on Doc1 also.
When T1 requests for a write lock (upgrade using
db.lock()) on Doc1, the request cannot be satisfied immediately as T2 is having
read lock on Doc1
When T2 requests for a write lock (upgrade using
db.lock()) on Doc2, the request is not satisfied as T1 is having read lock on
Doc2, and here a dead lock is detected (in detectDeadLock() method of
ObjectLock.java)
MAPPING.XML
<mapping>
<!-- Mapping for
Department-->
<class name="Department" identity="id" key-generator="MAX" access="shared" > <cache-type type="unlimited"
/>
<description>User</description> <map-to table="Department" /> <field name="id" type
="long">
<sql name="pk_department_id" type="bigint"/> </field> <field name="deptName" type="string"> <sql name="deptName" type="varchar" dirty="check"/> </field> <field name="doctors" type="Doctor"
required="false" collection="arraylist">
<sql many-key="dept_id"/> </field> </class> <!-- Mapping for Doctor--> <class name="Doctor" identity="id" key-generator="MAX" access="shared" > <cache-type type="unlimited"
/>
<description>Doctor</description> <map-to table="doctor" /> <field name="id" type
="long">
<sql name="pk_doctor_id" type="bigint"/> </field> <field name="userName" type="string"> <sql name="UserName" type="varchar" dirty="check"/> </field> <field name="dept" type="Department"> <sql name="dept_id" /> </field> </class> </mapping>
TEST.JAVA
public class Test
{ public static final String DatabaseFile = "/config/database.xml"; public static final String MappingFile = "/config/mapping.xml"; public static final String Usage = "Usage: example jdo"; private static Mapping _mapping; private static JDO _jdo; static boolean bStart=false;
static long id=1;
public static void main( String[] args ) throws
Exception
{ new Test(); // new Test(); // new Test(); } public Test() throws Exception { try { // Load the mapping file _mapping = new Mapping( getClass().getClassLoader() ); _mapping.loadMapping( getClass().getResource( MappingFile ) ); _jdo = new
JDO();
_jdo.setConfiguration( getClass().getResource( DatabaseFile ).toString() ); _jdo.setDatabaseName( "mqtest" ); OurThread th1 = new
OurThread();
OurThread th2 = new OurThread(); OurThread th3 = new OurThread(); OurThread th4 = new OurThread(); OurThread th5 = new OurThread(); do{ bStart=false; Thread.yield(); }while(th1.bReached==false || th2.bReached==false || th3.bReached==false || th4.bReached==false || th5.bReached==false ); bStart=true;
th1.join();
th2.join(); th3.join(); th4.join(); th5.join(); } catch (Exception e) { System.out.println("Exception Main"+e.getMessage()); } } public Random rand=new Random();
class OurThread extends
Thread
{ public boolean bReached=false; public OurThread() { bReached=false; start(); } public void run() { Database db1=null; try { db1 = _jdo.getDatabase(); db1.begin(); long did=++id; Doctor doc=(Doctor)db1.load(Doctor.class,new Long(did),Database.Shared); System.out.println("Loaded "+doc.getUserName()); //db1.lock(doc); rand.setSeed(System.currentTimeMillis()); doc.setUserName("Doc"+did+" ("+(Math.abs(rand.nextInt())%1000)+")"); String sName=doc.getUserName(); bReached=true; while (!bStart) Thread.yield(); System.out.println("Committing
"+Thread.currentThread());
db1.commit(); db1.close(); System.out.println("Successfully updated "+sName); } catch (Exception e) { System.out.println("Exception Thread "+e.getMessage()); //e.printStackTrace(); } finally { try{db1.close();}catch(Exception e){} } } }
}
DOCTOR.JAVA
import java.util.*;
public class Doctor extends User{ private Department dept =
null;
private String userName = null;
public String getUserName()
{
return userName; } public void setUserName(String
aUserName) {
userName = aUserName; } public Department getDept()
{
return dept; } public void setDept(Department aDept)
{
if (dept!=aDept) dept = aDept; } }
DEPARTMENT.JAVA
import java.util.*;
public class Department extends BaseJDO{ private String deptName =
null;
private ArrayList doctors = new ArrayList(); public String getDeptName()
{
return deptName; } public void setDeptName(String
aDeptName) {
deptName = aDeptName; } public ArrayList getDoctors() { return doctors; } public void addDoctor(Doctor aDoctor) { if (aDoctor!=null && !doctors.contains(aDoctor)) { doctors.add(aDoctor); aDoctor.setDept(this); } } } THIS IS THE OUTPUT
Loaded Doc5
(916)
�
Loaded Doc4 (393) Loaded Doc6 (601) Loaded Doc 3 Loaded Doc 2 Committing Thread[Thread-2,5,main] Committing Thread[Thread-1,5,main] Committing Thread[Thread-4,5,main] Committing Thread[Thread-5,5,main] Committing Thread[Thread-3,5,main] Exception Thread Nested error: org.exolab.castor.jdo.LockNotGrantedException: persist.deadlock :(org.exolab.castor.jdo.engine.TransactionContextImpl@9ce060) is having readlock on (Doctor/2/0 R/-) and is currently waiting for (Doctor/5/4 R/-) whose readlock is owned by (org.exolab.castor.jdo.engine.TransactionContextImpl@4ecfdd) Exception Thread Nested error: org.exolab.castor.jdo.LockNotGrantedException: persist.deadlock :(org.exolab.castor.jdo.engine.TransactionContextImpl@9ce060) is having readlock on (Doctor/6/1 R/-) and is currently waiting for (Doctor/5/4 R/-) whose readlock is owned by (org.exolab.castor.jdo.engine.TransactionContextImpl@476128) Exception Thread Nested error: org.exolab.castor.jdo.LockNotGrantedException: persist.deadlock :org.exolab.castor.jdo.engine.TransactionContextImpl@9ce060) is having readlock on (Doctor/3/3 R/-) and is currently waiting for (Doctor/5/4 R/-) whose readlock is owned by (org.exolab.castor.jdo.engine.TransactionContextImpl@8bf072) Exception Thread Nested error: org.exolab.castor.jdo.LockNotGrantedException: persist.deadlock :(org.exolab.castor.jdo.engine.TransactionContextImpl@9ce060) is having readlock on (Doctor/4/2 R/-) and is currently waiting for (Doctor/5/4 R/-) whose readlock is owned by (org.exolab.castor.jdo.engine.TransactionContextImpl@3b8b49) Successfully updated Doc5 (539) We are in urgent requirement of a solution and
the we are not in a position to set cache-type to none due to performance
issues.
|
- [castor-dev] Fw: Concurrency Problem -- Bug in castor??? Arun Sudhakaran
- [castor-dev] Fw: Concurrency Problem -- Bug in casto... Arun Sudhakaran
- Re: [castor-dev] Fw: Concurrency Problem -- Bug in c... Martin, Margaret
