2014-06-14 0:21 GMT+04:00  <ma...@apache.org>:
> Author: markt
> Date: Fri Jun 13 20:21:32 2014
> New Revision: 1602510
>
> URL: http://svn.apache.org/r1602510
> Log:
> Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56518
> Do not attempt an NIO write if a thread has been interrupted as it can lead 
> to a connection limit leak
>
> Modified:
>     tomcat/tc7.0.x/trunk/   (props changed)
>     tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
>     
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
>     
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java
>     
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java
>     tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java
>     tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java
>     tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
>     tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
>     tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java
>     
> tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
>     tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
>
> Propchange: tomcat/tc7.0.x/trunk/
> ------------------------------------------------------------------------------
>   Merged /tomcat/trunk:r1602198
>
> Modified: 
> tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
> URL: 
> http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1602510&r1=1602509&r2=1602510&view=diff
> ==============================================================================
> --- 
> tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java 
> (original)
> +++ 
> tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java 
> Fri Jun 13 20:21:32 2014
> @@ -469,6 +469,34 @@ public class CoyoteAdapter implements Ad
>
>
>      @Override
> +    public void errorDispatch(org.apache.coyote.Request req,
> +            org.apache.coyote.Response res) {
> +        Request request = (Request) req.getNote(ADAPTER_NOTES);
> +        Response response = (Response) res.getNote(ADAPTER_NOTES);
> +
> +        if (request != null && request.getMappingData().context != null) {
> +            ((Context) request.getMappingData().context).logAccess(
> +                    request, response,
> +                    System.currentTimeMillis() - req.getStartTime(),
> +                    false);
> +        } else {
> +            log(req, res, System.currentTimeMillis() - req.getStartTime());
> +        }
> +
> +        if (request != null) {
> +            request.recycle();
> +        }
> +
> +        if (response != null) {
> +            response.recycle();
> +        }
> +
> +        res.recycle();
> +        res.recycle();

I fixed the typo by r1602852.

> +    }

In short, my summary on how this works (on example of NIO) on Tomcat 7
codebase is as following

In AbstractProcessor.setErrorState it now does
[[[
getEndpoint().processSocketAsync(socketWrapper, SocketStatus.CLOSE_NOW);
]]]

That goes (for example) into NioEndpoint.processSocketAsync(...) and
into NioEndpoint.processSocket(...) where it creates a new
SocketProcessor(socket, status) and submits it to an Executor.

NioEndpoint$SocketProcessor.run() obtains monitor on the socket (by
"synchronized (socket)"), calls processor (by "handler.process(ka,
status)"), receives SocketState.CLOSED from the call and counts down
the connection (done in getPoller().cancelledKey()).

The method "handler.process()" that is called there is
AbstractProtocol$AbstractConnectionHandler.process(SocketWrapper,
SocketStatus).
In Tomcat 8 it gets a processor for this socket (if there is one
associated with it), calls "processor.errorDispatch(...);" (the new
"CoyoteAdapter. errorDispatch(...)" method above) and recycles the
processor.

I have several questions.

1) The AbstractProtocol$AbstractConnectionHandler.process() mentioned
above is from Tomcat 8. The code for handling SocketStatus.CLOSE_NOW
there is missing in backport to Tomcat 7.

In Tomcat 7 the SocketStatus.CLOSE_NOW enum value is used only in 1
place, where in Tomcat 8 it is used in 2 places..


2) The submission of SocketProcessor to the Executor may end with
RejectedExecutionException.
- in NioEndpoint#processSocket(NioChannel, SocketStatus, boolean)

In that case it just logs a warning and does nothing else.

How likely is this rejected execution?

My understanding/answer is that the rejection is unlikely.
The executor here is o.a.c.core.StandardThreadExecutor. Its execute()
method is unlikely to reject tasks. There is a queue that accepts
tasks. Tasks will be rejected if either
a) Executor is not running.
b) Queue is full. The maximum queue length is Integer.MAX_VALUE by
default. Though its size is configurable via
StandardThreadExecutor.setMaxQueueSize().

Will it result in failing to decrement the connection counter?
Will it result in failing to obtain and to recycle the processor
associated with the socket?

I suspect that per this BZ 56518 it will fail to decrement the counter.

3) In case if there are several executor threads that process the
socket at the same time, what happens?

My understanding/answer is that "synchronized (socket)" in
NioEndpoint$SocketProcessor.run() handles that.

In this case I see that NioEndpoint$SocketProcessor.doRun() does
"nioChannels.offer(socket)"
That is it offers the "socket" for reuse.

Thus "synchronized (socket)" is broken, as the "socket" can be
recycled and reused by another thread while the second one waits to
obtain the monitor on the "socket".


4) There are no tests for this new feature.

Best regards,
Konstantin Kolinko

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to