You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by to...@the-ecorp.com on 2001/08/09 11:23:31 UTC

[Excalibur] DefaultPool: Could not create enough components to se rvice your request

Hi,

The error mentioned in the subject line has been reported several times on
this list.

Now, when putting load on Cocoon 2, I got the same error. And I found the
cause.

The problem is in this piece of code:

public Poolable get() throws Exception
<snip/>
  try
     {
      m_mutex.lock();
      if( m_ready.size() == 0 )
        {
         if( this instanceof Resizable )
           {
            m_mutex.unlock();
            ((Resizable)this).grow( m_controller.grow() );  //**
            m_mutex.lock();
            if ( m_ready.size() > 0 )
		   {
		    obj = (Poolable) m_ready.remove( 0 );
		   }
		else
		   {<etc/>

If this code is entered by thread1, and m_ready.size()==0, it tries to
increase the pool and go on. No problem. But if thread1 is preempted at the
position marked by //** by thread2, thread2 will find a m_ready.size() of
1, takes that instance out of the pool and sets m_ready.size() back to 0.
When thread1 starts executing again, it will find no more instances in the
pool and exit with an exception.

(I hope I make myself a bit clear)

Now, if I'm trying to get something out of an SoftLimitingResourcePool, I
would expect to always get an object. With the code provided here, this
does not happen. The solution would be to put the grow() statement in a
while loop:

while (m_ready.size() == 0) {
   m_mutex.unlock();
   ((Resizable)this).grow( m_controller.grow() );
   m_mutex.lock();
}

This will guarantee you that you have an instance available when you get
out of the loop.

I tried this solution. And I got a deadlock. The problem was that for
HardLimitingResourcePools, it might not be possible to acquire something
out of the pool. And if some threads that have one instance out of the
pool, are requiring another one, they will all be waiting on each other
(thus a deadlock). So for HardResourceLimitingPools, we should throw an
exception, and let the calling method decide what to do. In that way, the
calling method should try to acquire all necessary resources before trying
to use them (in a loop, each time releasing all resource that it has and
waiting for some time.)

So I came up with attached patch. I don't particularly like the 
	if (this instanceof HardResourceLimitingPool) {
statement, but then again, neither do I like the 
	if( this instanceof Resizable )
statement.

I hope this makes it to excalibur (maybe in a slightly modified version),
it would take out the racing condition that causes so much headaches.

I'd be happy to discuss this further.

Cheers,
tomK



Re: [Excalibur] DefaultPool: Could not create enough components to service your request

Posted by Berin Loritsch <bl...@apache.org>.
Berin Loritsch wrote:
> 
> I will commit it in a few minutes, I would like you to crosscheck it on your
> machine.

I forgot to mention: it is committed.

---------------------------------------------------------------------
To unsubscribe, e-mail: avalon-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: avalon-dev-help@jakarta.apache.org


Re: [Excalibur] DefaultPool: Could not create enough components to service your request

Posted by Berin Loritsch <bl...@apache.org>.
Berin Loritsch wrote:
> 
> tom.klaasen@the-ecorp.com wrote:
> >
> > Hi,
> >
> > The error mentioned in the subject line has been reported several times on
> > this list.
> 
> I will commit it in a few minutes, I would like you to crosscheck it on your
> machine.

Using the internal tests in Avalon, we added at least another 100% to the pool
efficiencies (in some cases doubling the efficiency of the ThreadSafe pools).

When the profiling tests are refactored, I will set the load much higher for the
pools so we can thrash them before official release.

---------------------------------------------------------------------
To unsubscribe, e-mail: avalon-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: avalon-dev-help@jakarta.apache.org


Re: [Excalibur] DefaultPool: Could not create enough components to service your request

Posted by Berin Loritsch <bl...@apache.org>.
tom.klaasen@the-ecorp.com wrote:
> 
> Hi,
> 
> The error mentioned in the subject line has been reported several times on
> this list.
> 
> Now, when putting load on Cocoon 2, I got the same error. And I found the
> cause.
> 
> The problem is in this piece of code:
> 
> public Poolable get() throws Exception
> <snip/>
>   try
>      {
>       m_mutex.lock();
>       if( m_ready.size() == 0 )
>         {
>          if( this instanceof Resizable )
>            {
>             m_mutex.unlock();
>             ((Resizable)this).grow( m_controller.grow() );  //**
>             m_mutex.lock();
>             if ( m_ready.size() > 0 )
>                    {
>                     obj = (Poolable) m_ready.remove( 0 );
>                    }
>                 else
>                    {<etc/>


I wanted to attempt a different approach first, so I had AbstractPool
implement two protected methods: internalGrow() and internalShrink().
They both assume that the lock has already been aquired and are used
inside the get() and put() methods respectively.  The public Resizeable
grow() and shrink() methods aquire the lock and call the internalGrow()
and internalShrink() methods.

This makes the code snippet look like this:

<snip/>
  try
     {
      m_mutex.lock();
      if( m_ready.size() == 0 )
        {
         if( this instanceof Resizable )
           {
            this.internalGrow( m_controller.grow() ); //**
            if ( m_ready.size() > 0 )
                   {
                    obj = (Poolable) m_ready.remove( 0 );
                   }
                else
                   {<etc/>

Notice the absence of the m_mutex releasing of the lock.  This should kill
two birds with one stone:  killing the race condition, and increased performance
through decreased iterations.

I will commit it in a few minutes, I would like you to crosscheck it on your
machine.

---------------------------------------------------------------------
To unsubscribe, e-mail: avalon-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: avalon-dev-help@jakarta.apache.org


Re: [Excalibur] DefaultPool: Could not create enough components to service your request

Posted by Berin Loritsch <bl...@apache.org>.
tom.klaasen@the-ecorp.com wrote:
> 
> Hi,
> 
> The error mentioned in the subject line has been reported several times on
> this list.
> 
> Now, when putting load on Cocoon 2, I got the same error. And I found the
> cause.

Excellent!  I have been looking for this for a while.  I don't really have the
tools available to find these things (nor the time to do an exhaustive test).

> The problem is in this piece of code:
> 
> public Poolable get() throws Exception
> <snip/>
>   try
>      {
>       m_mutex.lock();
>       if( m_ready.size() == 0 )
>         {
>          if( this instanceof Resizable )
>            {
>             m_mutex.unlock();
>             ((Resizable)this).grow( m_controller.grow() );  //**
>             m_mutex.lock();
>             if ( m_ready.size() > 0 )
>                    {
>                     obj = (Poolable) m_ready.remove( 0 );
>                    }
>                 else
>                    {<etc/>
> 
> If this code is entered by thread1, and m_ready.size()==0, it tries to
> increase the pool and go on. No problem. But if thread1 is preempted at the
> position marked by //** by thread2, thread2 will find a m_ready.size() of
> 1, takes that instance out of the pool and sets m_ready.size() back to 0.
> When thread1 starts executing again, it will find no more instances in the
> pool and exit with an exception.

I understand completely.  I will apply your patch as soon as possible.

> (I hope I make myself a bit clear)
> 
> Now, if I'm trying to get something out of an SoftLimitingResourcePool, I
> would expect to always get an object. With the code provided here, this
> does not happen. The solution would be to put the grow() statement in a
> while loop:
> 
> while (m_ready.size() == 0) {
>    m_mutex.unlock();
>    ((Resizable)this).grow( m_controller.grow() );
>    m_mutex.lock();
> }
> 
> This will guarantee you that you have an instance available when you get
> out of the loop.
> 
> I tried this solution. And I got a deadlock. The problem was that for
> HardLimitingResourcePools, it might not be possible to acquire something
> out of the pool. And if some threads that have one instance out of the
> pool, are requiring another one, they will all be waiting on each other
> (thus a deadlock). So for HardResourceLimitingPools, we should throw an
> exception, and let the calling method decide what to do. In that way, the
> calling method should try to acquire all necessary resources before trying
> to use them (in a loop, each time releasing all resource that it has and
> waiting for some time.)

That is an issue with the HardLimitingResourcePool.  I tried using it with
the ComponentManager--but with improperly sized pools it makes Cocoon break
with deadlocks.  This puts more of an emphasis on configuring than I like
for a system that is supposed to just "work".

> So I came up with attached patch. I don't particularly like the
>         if (this instanceof HardResourceLimitingPool) {
> statement, but then again, neither do I like the
>         if( this instanceof Resizable )
> statement.

Instead of the grow() method, we can use the newPoolable() method (which
does not require giving up the lock).  I want to make the pools actively
managed--but I haven't figured out a clean way of doing it yet.

> I hope this makes it to excalibur (maybe in a slightly modified version),
> it would take out the racing condition that causes so much headaches.

I appreciate this very much.  If you have any more contributions you
want to submit, let me know.

---------------------------------------------------------------------
To unsubscribe, e-mail: avalon-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: avalon-dev-help@jakarta.apache.org