If only a few threads are waiting on a lock for an entity bean to free 
up, the file size of server.log explodes with LOCKING-WAITING messages.  
(server.log got up to 250 meg in only a 10 minute period with only a few 
concurrent threads hitting JBoss). I fixed this so that only one 
LOCKING-WAITING message is outputed per locking thread.  When the thread 
finally aquires the lock, it outputs a FINISHED-LOCKING-WAITING 
message.  Attached is the changes I made.

BTW, this message is EXTREMLY useful in finding deadlock I read on the 
archive that you guys were thinking of removing the message.


in org.jboss.ejb.plugins.EntityInstanceInterceptor I changed the invoke 
method.

   public Object invoke(MethodInvocation mi)
   throws Exception
   {
       // The id store is a CacheKey in the case of Entity
       CacheKey key = (CacheKey)mi.getId();

       // Get cache
       AbstractInstanceCache cache = 
(AbstractInstanceCache)container.getInstanceCache();
       Sync mutex = (Sync)cache.getLock(key);

       EnterpriseContext ctx = null;

       try
       {
           boolean waitingOnTransaction = false; // So we don't output 
LOCKING-WAITING all the time
           boolean waitingOnContext = false; // So we don't output 
LOCKING-WAITING all the time

           do
           {
               if (mi.getTransaction() != null && 
mi.getTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK)
                   throw new RuntimeException("Transaction marked for 
rollback, possibly a timeout");

               try
               {

                   mutex.acquire();

                   // Get context
                   ctx = cache.get(key);

                   // Do we have a running transaction with the context
                   Transaction tx = ctx.getTransaction();
                   if (tx != null &&
                       // And are we trying to enter with another 
transaction
                       !tx.equals(mi.getTransaction()))
                   {
                       // Let's put the thread to sleep a lock release 
will wake the thread
                       // Possible deadlock
                       if (!waitingOnTransaction)
                       {
                           Logger.debug("LOCKING-WAITING (TRANSACTION) 
for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+" tx:"+((tx == null) ? 
"null" : tx.toString()));
                           waitingOnTransaction = true;
                       }

                       // Try your luck again
                       ctx = null;
                       continue;
                   }
                   else
                   {
                       if (waitingOnTransaction)
                       {
                           Logger.debug("FINISHED-LOCKING-WAITING 
(TRANSACTION) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+" 
tx:"+((tx == null) ? "null" : tx.toString()));
                           waitingOnTransaction = false;
                       }
                       // If we get here it's the right tx, or no tx
                       if (!ctx.isLocked())
                       {
                           //take it!
                           ctx.lock();
                       }
                       else
                       {
                           if (!isCallAllowed(mi)) {

                               // Go to sleep and wait for the lock to 
be released
                               // This is not one of the "home calls" so 
we need to wait for the lock

                               // Possible deadlock
                               if (!waitingOnContext) {
                                   Logger.debug("LOCKING-WAITING (CTX) 
for id "+ctx.getId()+" ctx.hash "+ctx.hashCode());
                                   waitingOnContext = true;
                               }

                               // Try your luck again
                               ctx = null;
                               continue;
                               // Not allowed reentrant call
                               //throw new RemoteException("Reentrant 
call");
                           }
                           else
                           {
                               if (waitingOnContext) {
                                   
Logger.debug("FINISHED-LOCKING-WAITING (CTX) for id "+ctx.getId()+" 
ctx.hash "+ctx.hashCode());
                                   waitingOnContext = false;
                               }
                               //We are in a home call so take the lock, 
take it!
                               ctx.lock();
                           }
                       }
                   }
               }
               catch (InterruptedException ignored) {}
               finally
               {
                   mutex.release();
               }

           } while (ctx == null);

           // Set context on the method invocation
           mi.setEnterpriseContext(ctx);

           // Go on, you won
           return getNext().invoke(mi);

       }
       catch (RemoteException e)
       {
           // Discard instance
           // EJB 1.1 spec 12.3.1
           cache.remove(key);

           throw e;
       } catch (RuntimeException e)
       {
           // Discard instance
           // EJB 1.1 spec 12.3.1
           cache.remove(key);

           throw e;
       } catch (Error e)
       {
           // Discard instance
           // EJB 1.1 spec 12.3.1
           cache.remove(key);

           throw e;
       } finally
       {
           // Logger.debug("Release instance for "+id);

           // ctx can be null if cache.get throws an Exception, for
           // example when activating a bean.
           if (ctx != null)
           {
               try
               {
                   mutex.acquire();

                   // unlock the context
                   ctx.unlock();

                   if (ctx.getId() == null)
                   {

                       // Work only if no transaction was encapsulating 
this remove()
                       if (ctx.getTransaction() == null)
                       {
                           // Here we arrive if the bean has been 
removed and no
                           // transaction was associated with the 
remove, or if
                           // the bean has been passivated

                           // Remove from cache
                           cache.remove(key);

                           // It has been removed -> send to the pool
                           container.getInstancePool().free(ctx);
                       }
                       else
                       {
                           // We want to remove the bean, but it has a 
Tx associated with
                           // the remove() method. We remove it from the 
cache, to avoid
                           // that a successive insertion with same pk 
will break the
                           // cache. Anyway we don't free the context, 
since the tx must
                           // finish. The EnterpriseContext instance 
will be GC and not
                           // recycled.
                           cache.remove(key);
                       }
                   }
                   else
                   {
                       // Yeah, do nothing
                   }
               }
               catch (InterruptedException ignored) {}
               finally
               {
                   mutex.release();
               }
           }
       }
   }



_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to