-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Relatively simple test case to force deadlock?
PostPosted: Fri Apr 09, 2004 1:48 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
So our object model is getting moderately complex and yesterday I saw our first (non-easily-reproducible, timing-dependent) database deadlock.

I'm a relative database newbie, so while I understand (I believe) the basic concepts behind row-level locking and Hibernate's use of locking, I would like to get more clarity on exactly when deadlock scenarios happen and what kinds of lock reordering will likely fix them.

So I am wanting to write a simple test case or two to create a database-level deadlock, and then start experimenting with different lock orderings in order to eliminate the deadlocks.

My questions are:

1) has anyone else done this?
2) if yes, what's your code look like?
3) if no, but you know more about deadlocks than I do, then what's a common pattern of interleaved reads/updates among different sessions that you would expect to produce a deadlock?

I am aware this is a pretty open-ended question and probably too lame to get good responses, but I've been pleasantly surprised by peoples' generosity here before, so... :-)

Cheers!
Rob


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 09, 2004 2:33 pm 
Expert
Expert

Joined: Thu Jan 08, 2004 6:17 pm
Posts: 278
Never mind :-)

I have a simple parent-child relationship, Client (parent) and Campaign (child). The following code deadlocks against MySQL:

Code:
        Persistence.beginTransaction();
        Client client = new Client("deadlock test", new HashSet());
        Campaign campaign = new Campaign("deadlock test", client);
        Persistence.save(client);
        Persistence.commitTransaction();
        Persistence.closeSession();

        // Normally there is only ever one session per thread.  But in this test case
        // we require two sessions.  So we use the testing-only method to get them.
        Session session1 = Persistence.testingOnlyGetJdbcSessionFactory().openSession();
        Session session2 = Persistence.testingOnlyGetJdbcSessionFactory().openSession();
        Transaction tx1 = session1.beginTransaction();
        Transaction tx2 = session2.beginTransaction();

        Client client1 = (Client)session1.createQuery("from Client client where client.name = ?")
                .setParameter(0, "deadlock test", Hibernate.STRING)
                .uniqueResult();
        Campaign campaign1 = (Campaign)client1.getCampaigns().iterator().next();

        Client client2 = (Client)session2.createQuery("from Client client where client.name = ?")
                .setParameter(0, "deadlock test", Hibernate.STRING)
                .uniqueResult();
        Campaign campaign2 = (Campaign)client2.getCampaigns().iterator().next();

        // now try modifying the clients and campaigns in an interleaved order
        campaign2.setName("deadlock test 2");
        client1.setName("deadlock test 1");

        session1.flush();
        session2.flush();

        client2.setName("deadlock test 2");
        campaign1.setName("deadlock test 1");

        session1.flush();
        session2.flush();

        tx1.commit();
        tx2.commit();
        session1.close();
        session2.close();

Fails with:
Code:
    [junit] Testcase: testDeadlock(com.nimblefish.core.test.persist.PersistenceManagerTest):    Caused an ERROR
    [junit] Could not execute JDBC batch update
    [junit] net.sf.hibernate.JDBCException: Could not execute JDBC batch update
    [junit]     at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:125)
    [junit]     at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2311)
    [junit]     at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2262)
    [junit]     at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2187)
    [junit]     at com.nimblefish.core.test.persist.PersistenceManagerTest.testDeadlock(PersistenceManagerTest.java:672)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    [junit]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [junit]     at junit.extensions.TestDecorator.basicRun(TestDecorator.java:22)
    [junit]     at junit.extensions.TestSetup$1.protect(TestSetup.java:19)
    [junit]     at junit.extensions.TestSetup.run(TestSetup.java:23)
    [junit] Caused by: java.sql.BatchUpdateException: General error,  message from server: "Lock wait timeout exceeded; Try restarting transaction"
    [junit]     at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1469)
    [junit]     at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
    [junit]     at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:118)
    [junit]     ... 24 more

So looks like I can make the database wedge on demand :-)

Now obviously the thing to do is to make a multithreaded test with well-controlled synchronization, to verify that different lock orderings either do or don't address this kind of a deadlock. (This single-threaded test can't demonstrate lock ordering making any difference since there's no way for one session to make progress while another is waiting.) I'll post the test case code I come up with.

Sorry for the simpleminded first post -- an earlier version of this test case had a simple thinko that I caught immediately after posting.
Cheers!
Rob


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.