Scott,

Your 2.2 wait(1000)change will seriously slow down applications that contend
for the same Entity.  In fact, it may even deadlock if requests for that
Entity keep on coming in.

The do..while loop does a mutex.acquire at the beginning.  It will not do a
mutex.release until after the 1 second is up.  If the transaction that
currently holds the Entity invokes on the Entity more than one time, it will
be waiting for any thread currently hold the mutex to finish.

Also, the mutex is acquired again in the finally clause of
EntityInstanceInterceptor to synchronize on ctx.unlock and such.

Bill


> -----Original Message-----
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED]]On Behalf Of Scott
> M Stark
> Sent: Monday, July 16, 2001 11:27 PM
> To: [EMAIL PROTECTED]
> Subject: [JBoss-dev] CVS update: jboss/src/main/org/jboss/ejb/plugins
> EntityInstanceInterceptor.java
>
>
>   User: starksm
>   Date: 01/07/16 20:26:51
>
>   Modified:    src/main/org/jboss/ejb/plugins Tag: Branch_2_2
>                         EntityInstanceInterceptor.java
>   Log:
>   Add a simple wait(1000) to avoid the spin wait that currently
> exists in the
>   presence of transcation contention.
>
>   Revision  Changes    Path
>   No                   revision
>
>
>   No                   revision
>
>
>   1.28.2.1  +273 -265
> jboss/src/main/org/jboss/ejb/plugins/EntityInstanceInterceptor.java
>
>   Index: EntityInstanceInterceptor.java
>   ===================================================================
>   RCS file:
> /cvsroot/jboss/jboss/src/main/org/jboss/ejb/plugins/EntityInstance
> Interceptor.java,v
>   retrieving revision 1.28
>   retrieving revision 1.28.2.1
>   diff -u -r1.28 -r1.28.2.1
>   --- EntityInstanceInterceptor.java  2001/01/12 00:05:53     1.28
>   +++ EntityInstanceInterceptor.java  2001/07/17 03:26:50     1.28.2.1
>   @@ -1,9 +1,9 @@
>    /*
>   -* JBoss, the OpenSource EJB server
>   -*
>   -* Distributable under LGPL license.
>   -* See terms of license at gnu.org.
>   -*/
>   + * JBoss, the OpenSource EJB server
>   + *
>   + * Distributable under LGPL license.
>   + * See terms of license at gnu.org.
>   + */
>    package org.jboss.ejb.plugins;
>
>    import java.lang.reflect.Method;
>   @@ -39,272 +39,280 @@
>    import org.jboss.util.Sync;
>
>    /**
>   -*   This container acquires the given instance.
>   -*
>   -*   @see <related>
>   -*   @author Rickard Öberg ([EMAIL PROTECTED])
>   -*   @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
>   -*   @author <a
> href="mailto:[EMAIL PROTECTED]";>Sebastien Alborini</a>
>   -*   @version $Revision: 1.28 $
>   -*/
>   + *   This container acquires the given instance.
>   + *
>   + *   @see <related>
>   + *   @author Rickard Öberg ([EMAIL PROTECTED])
>   + *   @author <a href="mailto:[EMAIL PROTECTED]";>Marc Fleury</a>
>   + *   @author <a
> href="mailto:[EMAIL PROTECTED]";>Sebastien Alborini</a>
>   + *   @version $Revision: 1.28.2.1 $
>   + */
>    public class EntityInstanceInterceptor
>    extends AbstractInterceptor
>    {
>   -    // Constants -----------------------------------------------------
>   -
>   -    // Attributes ----------------------------------------------------
>   -    protected EntityContainer container;
>   -
>   -    // Static --------------------------------------------------------
>   -
>   -    // Constructors --------------------------------------------------
>   -
>   -    // Public --------------------------------------------------------
>   -    public void setContainer(Container container)
>   -    {
>   -        this.container = (EntityContainer)container;
>   -    }
>   -
>   -    public  Container getContainer()
>   -    {
>   -        return container;
>   -    }
>   -
>   -    // Interceptor implementation
> --------------------------------------
>   -    public Object invokeHome(MethodInvocation mi)
>   -    throws Exception
>   -    {
>   -        // Get context
>   -        EnterpriseContext ctx =
> ((EntityContainer)getContainer()).getInstancePool().get();
>   -        mi.setEnterpriseContext(ctx);
>   -
>   -        // It is a new context for sure so we can lock it
>   -        ctx.lock();
>   -
>   -        try
>   -        {
>   -            // Invoke through interceptors
>   -            return getNext().invokeHome(mi);
>   -        } finally
>   -        {
>   -            // Always unlock, no matter what
>   -            ctx.unlock();
>   -
>   -            // Still free? Not free if create() was called successfully
>   -            if (ctx.getId() == null)
>   -            {
>   -                container.getInstancePool().free(ctx);
>   -            }
>   -        }
>   -    }
>   -
>   -    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
>   -        {
>   -            do
>   +   // Constants -----------------------------------------------------
>   +
>   +   // Attributes ----------------------------------------------------
>   +   protected EntityContainer container;
>   +
>   +   // Static --------------------------------------------------------
>   +
>   +   // Constructors --------------------------------------------------
>   +
>   +   // Public --------------------------------------------------------
>   +   public void setContainer(Container container)
>   +   {
>   +      this.container = (EntityContainer)container;
>   +   }
>   +
>   +   public  Container getContainer()
>   +   {
>   +      return container;
>   +   }
>   +
>   +   // Interceptor implementation --------------------------------------
>   +   public Object invokeHome(MethodInvocation mi)
>   +   throws Exception
>   +   {
>   +      // Get context
>   +      EnterpriseContext ctx =
> ((EntityContainer)getContainer()).getInstancePool().get();
>   +      mi.setEnterpriseContext(ctx);
>   +
>   +      // It is a new context for sure so we can lock it
>   +      ctx.lock();
>   +
>   +      try
>   +      {
>   +         // Invoke through interceptors
>   +         return getNext().invokeHome(mi);
>   +      } finally
>   +      {
>   +         // Always unlock, no matter what
>   +         ctx.unlock();
>   +
>   +         // Still free? Not free if create() was called successfully
>   +         if (ctx.getId() == null)
>   +         {
>   +            container.getInstancePool().free(ctx);
>   +         }
>   +      }
>   +   }
>   +
>   +   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
>   +      {
>   +         do
>   +         {
>   +            if (mi.getTransaction() != null &&
> mi.getTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK)
>   +               throw new RuntimeException("Transaction marked
> for rollback, possibly a timeout");
>   +
>   +            try
>                {
>   -                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
>   +
>   +               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
>   +                  Logger.debug("LOCKING-WAITING (TRANSACTION)
> for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+" tx:"+((tx ==
> null) ? "null" : tx.toString()));
>   +                  synchronized( tx )
>   +                  {
>   +                     tx.wait(1000);
>   +                  }
>   +                  // Try your luck again
>   +                  ctx = null;
>   +                  continue;
>   +               }
>   +               else
>   +               {
>   +                  // 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
>   -                        Logger.debug("LOCKING-WAITING
> (TRANSACTION) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode()+"
> tx:"+((tx == null) ? "null" : tx.toString()));
>   -
>   +                        Logger.debug("LOCKING-WAITING (CTX)
> for id "+ctx.getId()+" ctx.hash "+ctx.hashCode());
>   +
>                            // Try your luck again
>                            ctx = null;
>                            continue;
>   -                    }
>   -                    else
>   -                    {
>   -                        // 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
>   -                                Logger.debug("LOCKING-WAITING
> (CTX) for id "+ctx.getId()+" ctx.hash "+ctx.hashCode());
>   -
>   -                                // Try your luck again
>   -                                ctx = null;
>   -                                continue;
>   -                                // Not allowed reentrant call
>   -                                //throw new
> RemoteException("Reentrant call");
>   -                            }
>   -                            else
>   -                            {
>   -                                //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();
>   -                           }
>   -                   }
>   -        }
>   -    }
>   -
>   -   // Private --------------------------------------------------------
>   -
>   -   private static Method getEJBHome;
>   -   private static Method getHandle;
>   -   private static Method getPrimaryKey;
>   -   private static Method isIdentical;
>   -   private static Method remove;
>   -   static
>   -   {
>   -       try
>   -       {
>   -           Class[] noArg = new Class[0];
>   -           getEJBHome = EJBObject.class.getMethod("getEJBHome", noArg);
>   -           getHandle = EJBObject.class.getMethod("getHandle", noArg);
>   -           getPrimaryKey =
> EJBObject.class.getMethod("getPrimaryKey", noArg);
>   -           isIdentical =
> EJBObject.class.getMethod("isIdentical", new Class[] {EJBObject.class});
>   -           remove = EJBObject.class.getMethod("remove", noArg);
>   -       }
>   -       catch (Exception x) {x.printStackTrace();}
>   -   }
>   -
>   -   private boolean isCallAllowed(MethodInvocation mi)
>   -   {
>   -       boolean reentrant =
> ((EntityMetaData)container.getBeanMetaData()).isReentrant();
>   -
>   -       if (reentrant)
>   -       {
>   -           return true;
>   -       }
>   -       else
>   -       {
>   -           Method m = mi.getMethod();
>   -           if (m.equals(getEJBHome) ||
>   -               m.equals(getHandle) ||
>   -               m.equals(getPrimaryKey) ||
>   -               m.equals(isIdentical) ||
>   -               m.equals(remove))
>   -           {
>   -               return true;
>   -           }
>   -       }
>   -
>   -       return false;
>   -   }
>   +                        // Not allowed reentrant call
>   +                        //throw new RemoteException("Reentrant call");
>   +                     }
>   +                     else
>   +                     {
>   +                        //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();
>   +            }
>   +         }
>   +      }
>   +   }
>   +
>   +   // Private --------------------------------------------------------
>   +
>   +   private static Method getEJBHome;
>   +   private static Method getHandle;
>   +   private static Method getPrimaryKey;
>   +   private static Method isIdentical;
>   +   private static Method remove;
>   +   static
>   +   {
>   +      try
>   +      {
>   +         Class[] noArg = new Class[0];
>   +         getEJBHome = EJBObject.class.getMethod("getEJBHome", noArg);
>   +         getHandle = EJBObject.class.getMethod("getHandle", noArg);
>   +         getPrimaryKey =
> EJBObject.class.getMethod("getPrimaryKey", noArg);
>   +         isIdentical =
> EJBObject.class.getMethod("isIdentical", new Class[]
>   +         {EJBObject.class});
>   +         remove = EJBObject.class.getMethod("remove", noArg);
>   +      }
>   +      catch (Exception x)
>   +      {x.printStackTrace();}
>   +   }
>   +
>   +   private boolean isCallAllowed(MethodInvocation mi)
>   +   {
>   +      boolean reentrant =
> ((EntityMetaData)container.getBeanMetaData()).isReentrant();
>   +
>   +      if (reentrant)
>   +      {
>   +         return true;
>   +      }
>   +      else
>   +      {
>   +         Method m = mi.getMethod();
>   +         if (m.equals(getEJBHome) ||
>   +         m.equals(getHandle) ||
>   +         m.equals(getPrimaryKey) ||
>   +         m.equals(isIdentical) ||
>   +         m.equals(remove))
>   +         {
>   +            return true;
>   +         }
>   +      }
>   +
>   +      return false;
>   +   }
>    }
>
>
>
>
> _______________________________________________
> Jboss-development mailing list
> [EMAIL PROTECTED]
> http://lists.sourceforge.net/lists/listinfo/jboss-development
>



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

Reply via email to