-->
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: "disappearing" update in multi-threaded app
PostPosted: Thu May 29, 2008 11:27 am 
Newbie

Joined: Wed Dec 06, 2006 11:36 am
Posts: 8
Hibernate version: 3.2.6
Spring version: 2.5.4


Code

Code:
public  void  updateFile(FileBean file){
          
          try {
          
          getHibernateTemplate().update(file);
          
          log.info(file.getFileID() + " updated. Status is " + file.getStatusID());
      } catch (Exception e) {
         
         log.error("Error updating file " + file.getFileID(),e);
      }
      
    }
   



Name and version of the database you are using: MS SQL Server 2000

I'm using the latest hibernate on the latest Spring, with c3p0 as the pool. I have a multi-threaded app that performs a lot of updates using the method above (updateFile).

99.9% of the time, this works flawlessly. You can see that I'm not doing any transaction handling at all...

In a nutshell, what happens intermittently is that update() gets called but the DB doesnt' actually get updated. for example, let's say the FileBean object has a StatusID of 4. it gets passed into update, update() runs, log.info says that the status is 4 (I can see this in the logs), but the DB doesn't reflect that new statusid.

I've been staring at this for two days, trying everything I know how to do in terms of debugging, but I can't figure it out. The darn thing just disappears into space and I don't see any errors anywhere.

As I said, it's intermittent. And it seems to manifest more on a faster machine than a slower machine, for what it's worth.

it feels like a deadlock problem on the update, but I'd expect to get some errors if that were the case, but I don't. I do have deadlock problems in general that I'm still trying to figure out, but even the other methods that exhibit the deadlock problems do in fact throw the appropriate errors.

So basically I'm appealing for any advice on figuring out why the updates are going into the ether without a word.

Quite possibly it's a problem with using a singleton DAO in a multi-threaded app without any transaction handling. But even when I put the dao to be a non-singleton the behavior persists.

possibly it's some setting I need to set that I'm not setting. Possibly it's something else. I'm really quite perplexed at this point.

I'll post the config stuff at the bottom.

Thank you thank you thank you for any advice!

Best,

marc


Hibernate config inside of spring:

Code:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
      <property name="driverClass" value="net.sourceforge.jtds.jdbc.Driver"/>
      <property name="jdbcUrl" value="${jdbc.connectstring}"/>
      <property name="user" value="${jdbc.user}"/>
      <property name="password" value="${jdbc.password}"/>
      <property name="acquireRetryDelay" value="2000"/>
      <property name="maxPoolSize" value="200"/>
      <property name="maxIdleTime" value="60"/>
      <property name="maxStatements" value="0"/>
      <property name="maxStatementsPerConnection" value="100"/>
      <property name="testConnectionOnCheckin" value="true"/>
      <property name="acquireRetryAttempts" value="5"/>
      <property name="preferredTestQuery">
         <value>Select 'This is the connection tester DOH applicationContext.xml Connection Pool'</value>
      </property>
   </bean>

   
   <!--  HIBERNATE CONFIGURATION -->
   <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      
      <!-- PUT ALL HIBERNATE MAPPING FILES HERE!!! -->
      <property name="mappingResources">         
         <list>
            <value>com/argus/doh/db/RequestStatusBean.hbm.xml</value>
            <value>com/argus/doh/db/FileBean.hbm.xml</value>
            <value>com/argus/doh/db/ManagerStatusBean.hbm.xml</value>
            <value>com/argus/doh/db/ServerBean.hbm.xml</value>
            <value>com/argus/doh/db/EnvironmentBean.hbm.xml</value>
            <value>com/argus/doh/db/AppLocationBean.hbm.xml</value>
         </list>         
      </property>
      
      <property name="hibernateProperties">
         <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <!-- Session context management -->
                <prop key="current_session_context_class">thread</prop>

                <!-- Disable 2nd level cache -->
                <prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>

                <!-- Echo all sql to stdout; useful for debugging -->
                <prop key="show_sql">true</prop>
               
                <prop key="hibernate.c3p0.max_statements">0</prop>
         </props>
      </property>
   </bean>

<bean id="fileDAO" class="com.argus.doh.db.FileDAO" singleton="false">
       <property name="sessionFactory" ref="sessionFactory"/>
    </bean>



Top
 Profile  
 
 Post subject:
PostPosted: Thu May 29, 2008 2:49 pm 
Newbie

Joined: Wed Dec 06, 2006 11:36 am
Posts: 8
Maybe it would be helpful to diagram the program flow. See, I think the problem has to do with my poor understanding of how sessions operate, and so possibly i'm doing something that I just shouldn't be doing with hibernate.

Again, this is a multi-threaded console app... no app server or anything. here goes:


Class1 --> Queries for serversbeans, for each server bean, queries for files not sent to servers. all of these queries are through hibernate. for each found file, fetches a new Class2 bean from the applicationcontext and spawns that object as a thread


Class2 --> The object that I'm spawning in a new thread. The new thread acts on the filebean and then updates it using the injected fileDAO

Class3 --> The fileDAO


Class 1 -- fetches from the dao and spawns threads, passing in those fetched objects

Code:
public class Class1 {

   public void sendRequestsToServers() {
      try {
         List<ServerBean> sbs = serverDAO.getAllServersForEnvironment();

         for (ServerBean sb : sbs) {

            //this function here deadlocks all the time
            List<FileBean> fbs = fileDAO.getUnsentFilesOnServer(Status.RUNNING.value(), sb.getServerID());

            for (FileBean fb : fbs) {
               if (currentRequests.get(fb.getRequestID()) == null) {
                  thisRequest = requestDAO.getRequest(fb.getRequestID(),false);
                  currentRequests.put(fb.getRequestID(), thisRequest);
               }

               rsb = currentRequests.get(fb.getRequestID());
               OptimizationDispatcher od = (OptimizationDispatcher) AppManager.getContext().getBean("optimizationDispatcher");
               od.init(fb, sb, rsb);
               // now send the file               
               Thread t = new Thread(od);
               t.setName("OptDispatcher:FileID=" + fb.getFileID());
               t.start();
               // this ensures that the file is ONLY updated if the
               // dispatcher is successfully spawned.

               // if i keep these here, i get many more errors than if i put them inside the spawned thread
               // fb.setSentToOptimizer(true);
               // fileDAO.updateFileRaw(fb);
            }
         }
      } catch (Exception ex) {
         optLog.error("Error in sendRequestsToServers(): "+ ex.getMessage(), ex);
      }
   }

}


Class2 --> this is the spawned thread:

Code:
public void run(){
       
       fb.setSentToOptimizer(true);      
        fb.addMessage("Inside OptimizationDispatcher.run()");
        //update the fileBean that Class1 passed into this object
        fileDAO.updateFile(fb);
        RequestStatusBean updatedRequest = requestDAO.getRequest(rsb.getRequestID(),false);       
                             
        if(performOptimization){
           //other calls to fileDAO.updateFile(fb) happen inside the sendToOptimizer method
            sendToOptimizer();
        }

    }


FileDAO

Code:
public class FileDAO extends HibernateDaoSupport  {
 
    /**
     * returns a list of files on the given server for the given file status. These files have
     * NOT been sent to the optimizer yet
     * This query in particular seems to deadlock more frequently than other queries under heavy load,
     * which is why i have the try/catch around it
     */
    public List<FileBean> getUnsentFilesOnServer(int statusID,int serverID) {
        List<FileBean> files = new ArrayList<FileBean>();
       
        try {
            //sadly, i find that this string concat is faster than using prepared statements
           files = getHibernateTemplate().find("from FileBean  where statusID="+statusID
                   +" and serverID="+serverID
                   +" and sentToOptimizer=0");
        } catch (Exception e) {
            log.error("Error in getUnsentFilesOnServer()",e);
        }
        return files;

   
     
    public  void  updateFile(FileBean file){
      getHibernateTemplate().update(file);
      log.info(file.getFileID() + " updated. Status is " + file.getStatusID());
    }
}



Again, thanks a million for anyone who can offer advice on how to best handle this multi-threaded scenario.

I'm starting to wonder if the problem is somehow related to the fact that the call to getUnsentfilesOnServers() throws a deadlock exception sometimes, and if that is causing the file beans fetched from the fileDAO to get into some state where the call to updateFile() just doesn't happen, i.e. hibernate doesnt' see the object as dirty or soemthing and so does nothing.

Thanks!


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.