HttpUriRequest.abort - race condition with ThreadSafeClientConnManager.releaseConnection

View: New views
2 Messages — Rating Filter:   Alert me  

HttpUriRequest.abort - race condition with ThreadSafeClientConnManager.releaseConnection

by Boemker, Tim :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

If HttpUriRequest.abort() is called at about the same time that the
request completes, it's possible for an aborted connection to be
returned to the pool.  The next time the connection is used,
HttpClient.execute fails without retrying, throwing this exception:

java.io.IOException: Connection already shutdown
        at
org.apache.http.impl.conn.DefaultClientConnection.opening(DefaultClientC
onnection.java:112)
        at
org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection
(DefaultClientConnectionOperator.java:120)
        at
org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:
147)
        at
org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledC
onnAdapter.java:101)
        at
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultReques
tDirector.java:381)
        at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClien
t.java:641)
        at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClien
t.java:576)

Steps to reproduce:
1) Set a breakpoint in ThreadSafeClientConnManager.releaseConnection
just after "reusable" is set (and found to be true).
2) Run to the breakpoint in releaseConnection.
3) Call HttpUriRequest.abort.
4) Let releaseConnection complete.

When the connection is next used, the exception will be thrown.

Snippet from ThreadSafeClientConnManager:
    public void releaseConnection(ManagedClientConnection conn, long
validDuration, TimeUnit timeUnit) {
                ...
            boolean reusable = hca.isMarkedReusable();
            if (log.isDebugEnabled()) {                             //
breakpoint here
                if (reusable) {
                    log.debug("Released connection is reusable.");
                } else {
                    log.debug("Released connection is not reusable.");
                }
            }
            hca.detach();
            if (entry != null) {
                connectionPool.freeEntry(entry, reusable, validDuration,
timeUnit);
            }
        }
    }

I read the contract of ConnectionReleaseTrigger to say that only the
first call of either method has effect so that, for example, a call to
abortConnection made after a call to releaseConnection would be ignored,
but I don't think that's the way AbstractClientConnAdapter is
implemented; I think that it's possible for both methods to have effect.

Am I looking at this correctly?

Thanks for your consideration.

Tim

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...


Re: HttpUriRequest.abort - race condition with ThreadSafeClientConnManager.releaseConnection

by olegk :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, 2009-10-14 at 11:42 -0400, Boemker, Tim wrote:

> If HttpUriRequest.abort() is called at about the same time that the
> request completes, it's possible for an aborted connection to be
> returned to the pool.  The next time the connection is used,
> HttpClient.execute fails without retrying, throwing this exception:
>
> java.io.IOException: Connection already shutdown
> at
> org.apache.http.impl.conn.DefaultClientConnection.opening(DefaultClientC
> onnection.java:112)
> at
> org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection
> (DefaultClientConnectionOperator.java:120)
> at
> org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:
> 147)
> at
> org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledC
> onnAdapter.java:101)
> at
> org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultReques
> tDirector.java:381)
> at
> org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClien
> t.java:641)
> at
> org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClien
> t.java:576)
>
> Steps to reproduce:
> 1) Set a breakpoint in ThreadSafeClientConnManager.releaseConnection
> just after "reusable" is set (and found to be true).
> 2) Run to the breakpoint in releaseConnection.
> 3) Call HttpUriRequest.abort.
> 4) Let releaseConnection complete.
>
> When the connection is next used, the exception will be thrown.
>
> Snippet from ThreadSafeClientConnManager:
>     public void releaseConnection(ManagedClientConnection conn, long
> validDuration, TimeUnit timeUnit) {
> ...
>             boolean reusable = hca.isMarkedReusable();
>             if (log.isDebugEnabled()) {                             //
> breakpoint here
>                 if (reusable) {
>                     log.debug("Released connection is reusable.");
>                 } else {
>                     log.debug("Released connection is not reusable.");
>                 }
>             }
>             hca.detach();
>             if (entry != null) {
>                 connectionPool.freeEntry(entry, reusable, validDuration,
> timeUnit);
>             }
>         }
>     }
>
> I read the contract of ConnectionReleaseTrigger to say that only the
> first call of either method has effect so that, for example, a call to
> abortConnection made after a call to releaseConnection would be ignored,
> but I don't think that's the way AbstractClientConnAdapter is
> implemented; I think that it's possible for both methods to have effect.
>
> Am I looking at this correctly?
>

Yes, you are. Obviously this is a bug that needs fixing. Could you
please raise a JIRA for this defect? A patch would also be quite
welcome.

https://issues.apache.org/jira/browse/HTTPCLIENT

Oleg


> Thanks for your consideration.
>
> Tim
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@...
> For additional commands, e-mail: dev-help@...
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@...
For additional commands, e-mail: dev-help@...