The AJP protocol on the client side is often implemented in the way, that an empty body packet is interpreted as a signal to flush data to the client. This is true in mod_proxy_ajp and mod_jk. This is not part of

http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html

but the two most common implementations conform to it.

On the server side a flush to org.apache.catalina.connector.OutputBuffer always calls doFlush(true), which will write out outstanding data and then in addition send an explicit flush package via ActionCode.CLIENT_FLUSH.

For applications for which timely streaming is important, that's a good default behavior. The flush goes through until the client. But for traditional applications it might be better to let the web server buffer and decide when to flush. E.g. mod_proxy_ajp has an implementation to wait a short time for more data and then auto-flush.

What do people think about an AJP connector option to suppress the flush message sending? Default value would be no suppression, ie. unchanged behavior. It reduces the number of AJP packets to handle and allows better buffering behavior.

Example: I currently observe the pattern

- body chunk packets
- flush packet
- end request packet

where the flush doesn't serve any purpose, because the end request message already triggers flushing outstanding data in the web server.

Such a flush at the end e.g. happens, if you use servlet filters which replace the OutputStream by one which is derived on java.io.FilterOutputStream (not uncommon). FilterOutputStream on close() first calls flush(), then close().

I played a bit with the following patch. Apart from introducing the new property, the only difference is in suppressing the flush package at the end of the patch.

Index: java/org/apache/coyote/ajp/AbstractAjpProtocol.java
===================================================================
--- java/org/apache/coyote/ajp/AbstractAjpProtocol.java (revision 1726669)
+++ java/org/apache/coyote/ajp/AbstractAjpProtocol.java (working copy)
@@ -86,6 +86,20 @@
// ------------------------------------------ managed in the ProtocolHandler

     /**
+     * Ignore explicit flush?
+     * An explicit flush will send a zero byte AJP13 SEND_BODY_CHUNK
+     * package. AJP does flush at the and of the response, so if
+     * it is not important, that the packets get streamed up to
+     * the client, do not use explicit flush.
+     */
+    protected boolean ignoreExplicitFlush = false;
+    public boolean getIgnoreExplicitFlush() { return ignoreExplicitFlush; }
+    public void setIgnoreExplicitFlush(boolean ignoreExplicitFlush) {
+        this.ignoreExplicitFlush = ignoreExplicitFlush;
+    }
+
+
+    /**
      * Should authentication be done in the native web server layer,
      * or in the Servlet container ?
      */
@@ -160,6 +174,7 @@
     protected Processor createProcessor() {
AjpProcessor processor = new AjpProcessor(getPacketSize(), getEndpoint());
         processor.setAdapter(getAdapter());
+        processor.setIgnoreExplicitFlush(getIgnoreExplicitFlush());
         processor.setTomcatAuthentication(getTomcatAuthentication());
         processor.setTomcatAuthorization(getTomcatAuthorization());
         processor.setRequiredSecret(requiredSecret);
Index: java/org/apache/coyote/ajp/AjpProcessor.java
===================================================================
--- java/org/apache/coyote/ajp/AjpProcessor.java        (revision 1726669)
+++ java/org/apache/coyote/ajp/AjpProcessor.java        (working copy)
@@ -282,6 +282,20 @@


     /**
+     * Ignore explicit flush?
+     * An explicit flush will send a zero byte AJP13 SEND_BODY_CHUNK
+     * package. AJP does flush at the and of the response, so if
+     * it is not important, that the packets get streamed up to
+     * the client, do not use explicit flush.
+     */
+    protected boolean ignoreExplicitFlush = false;
+    public boolean getIgnoreExplicitFlush() { return ignoreExplicitFlush; }
+    public void setIgnoreExplicitFlush(boolean ignoreExplicitFlush) {
+        this.ignoreExplicitFlush = ignoreExplicitFlush;
+    }
+
+
+    /**
* The number of milliseconds Tomcat will wait for a subsequent request * before closing the connection. The default is -1 which is an infinite
      * timeout.
@@ -1379,7 +1393,7 @@
// Calling code should ensure that there is no data in the buffers for
         // non-blocking writes.
         // TODO Validate the assertion above
-        if (!finished) {
+        if (!ignoreExplicitFlush && !finished) {
             // Send the flush message
socketWrapper.write(true, flushMessageArray, 0, flushMessageArray.length);
             socketWrapper.flush(true);


Regards,

Rainer

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

Reply via email to