Return-Path: Delivered-To: apmail-tomcat-users-archive@www.apache.org Received: (qmail 86139 invoked from network); 15 Jun 2010 08:13:19 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 15 Jun 2010 08:13:19 -0000 Received: (qmail 91998 invoked by uid 500); 15 Jun 2010 08:13:16 -0000 Delivered-To: apmail-tomcat-users-archive@tomcat.apache.org Received: (qmail 91667 invoked by uid 500); 15 Jun 2010 08:13:12 -0000 Mailing-List: contact users-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Users List" Delivered-To: mailing list users@tomcat.apache.org Received: (qmail 91658 invoked by uid 99); 15 Jun 2010 08:13:10 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Jun 2010 08:13:10 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [62.180.227.30] (HELO ms03.m0019.fra.mmp.de.bt.com) (62.180.227.30) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Jun 2010 08:13:03 +0000 Received: from senmx11-mx ([62.134.46.9] [62.134.46.9]) by ms03.m0020.fra.mmp.de.bt.com with ESMTP id BT-MMP-508727 for users@tomcat.apache.org; Tue, 15 Jun 2010 10:12:43 +0200 Received: from MCHP064A.global-ad.net (unknown [172.29.37.63]) by senmx11-mx (Server) with ESMTP id 57C561EB82AE for ; Tue, 15 Jun 2010 10:12:43 +0200 (CEST) Received: from MCHP058A.global-ad.net ([172.29.37.55]) by MCHP064A.global-ad.net ([172.29.37.63]) with mapi; Tue, 15 Jun 2010 10:12:43 +0200 From: "Reich, Matthias" To: Tomcat Users List Date: Tue, 15 Jun 2010 10:12:41 +0200 Subject: RE: Connection is closed when CometEvent.close is called during an event Thread-Topic: Connection is closed when CometEvent.close is called during an event Thread-Index: AcsJEFVzXfMqrG4RRfeTWEjH6S4FjAAlK/lA Message-ID: <0983B0464228DD4E8E8F57A6055F9B1C05CF04F2A1@MCHP058A.global-ad.net> References: <0983B0464228DD4E8E8F57A6055F9B1C05CED58032@MCHP058A.global-ad.net> <0983B0464228DD4E8E8F57A6055F9B1C05CEF9A1EB@MCHP058A.global-ad.net> In-Reply-To: Accept-Language: de-DE, en-US Content-Language: de-DE X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: de-DE, en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Virus-Checked: Checked by ClamAV on apache.org Konstantin Kolinko wrote: > 2010/6/11 Reich, Matthias : > > > > The concept of long poll is e.g. described in > >=20 > http://www.javaworld.com/javaworld/jw-03-2008/jw-03-asynchhttp .html?page=3D6 > > > > The sequence of events in my situation is as follows: > > - a poll request is received by the server > > - the CoyoteAdapter.service method is called and in turn > > =A0invokes the servlet's event method with a BEGIN event > > - request.isComet() is still true when the control returns > > =A0to the CoyoteAdapter.service method > > - some other thread writes a response and closes the Writer > > =A0of the response > > - the CoyoteAdapter.event method is called and in turn > > =A0invokes the servlet's event method with an END event > > - the servlet calls event.close() > > - when the control returns to the CoyoteAdapter.event method > > =A0we have exactly this situation: > > =A0response.isClosed() && !request.isComet() &&=20 > status=3D=3DSocketStatus.OPEN > > - thus, if the error flag is set in this situation, > > =A0the connection will be closed, and a new connection must be opened > > =A0by the browser for the subsequent poll request > > > > According to the above sequence I would expect that the connection > > is always closed if request.isComet() is still true when control > > returns to the CoyoteAdapter.service method after processing > > the BEGIN event - =A0no matter how long it takes from then > > until the response is written. > > Surprisingly, I did not always observe this. > > > > Anyway, if the error flag is not set in this situation, > > the connection is kept open. > > > > > > > > ---=20 > C:\DOCUME~1\rm041693\LOCALS~1\Temp\CoyoteAdapter.java-revBASE. svn001.tmp.java =A0 =A0 =A0 Do Jun 10 22:22:20 2010 > > +++=20 > D:\tomcat\TOMCAT_6_0_26\java\org\apache\catalina\connector\Coy oteAdapter.java =A0 =A0 =A0 Mo Jun =A07 17:30:23 2010 > > @@ -215,7 +215,9 @@ > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 //CometEvent.close was = called=20 > during an event. > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=20 > request.getEvent().setEventType(CometEvent.EventType.END); > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 request.getEvent().setE= ventSubType(null); > > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0error =3D true; > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// don't set the error= flag -=20 > otherwise the socket will be closed > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// whenever CometEvent= .close is=20 > called during the event > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// error =3D true; > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=20 > connector.getContainer().getPipeline().getFirst().event(reques > t, response, request.getEvent()); > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } > > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 res.action(ActionCode.ACTION_CO= MET_END, null); > > >=20 > Now I understand. Thank you. >=20 > I would say that you are trying to combine Comet and Keep-Alive. Well, it actually was combined (maybe unintentionally) in 6.0.18. (I retested an older version of our application which uses 6.0.18 and didn't observe that connections were closed in similar situations.)=20 Since 6.0.20, the connections are closed upon event.close(), but it took me some time to get aware of this because when the subsequent request fails due to the close, the browsers silently retry that request. =20 >=20 > In comet to send a portion of data (a response), you do > writer.flush(). It sends the data over the wire. Doing event.close() > terminates comet request processing. >=20 > If it were possible not to close the connection, it were possible to > alternate comet and non-comet processing of subsequent requests over > the same connection, and to process different requests by different > servlets. >=20 > > - some other thread writes a response and closes the Writer > > of the response >=20 > Response object is not thread safe. You must write your response in > the thread that received your EventType.READ event (or any other > event) while you are processing that event. >=20 > Otherwise, any random result might happen. >=20 Doesn't the sample code on the documentation page include async=20 writes as well? When it gets a READ event from one connection it writes to all open connetions. With respect to all other connections, this is an async write. In a long poll scenario, closing the Writer seems to be=20 the only way to trigger a further event (i.e. an END event) after the BEGIN event. >=20 > BTW, for reference: > There exists the following documentation page, > http://tomcat.apache.org/tomcat-6.0-doc/aio.html#CometEvent > and sample code in > webapps/examples/WEB-INF/classes/chat/ChatServlet.java > plus some helper JSPs. >=20 > The sample is callable as > http://localost:8080/examples/jsp/chat/chat.jsp in Tomcat=20 > 6.0.26 and earlier > http://localost:8080/examples/jsp/chat/index.jsp in Tomcat 7 and in > Tomcat 6.0.27 and later >=20 >=20 > Regarding Comet + Keep-Alive, if it does not work, it is worth filing > an enhancement request against Tomcat 7. It would be easier if there > were some sample code or better a test case. This new use case has to > be tested. I'll try to find the time to prepare something. In the repository=20 (6.0.26) I have not detected any Comet related test cases. Are there any test cases you could recommend as an example of how I should organize it? What is the best way to deliver the code to you? >=20 > The patch you proposing looks promising, but as of now I am=20 > not sure that >=20 > a) both cases when that branch is called are equivalent, > I mean (response.isClosed()) vs. (!request.isComet()) whether in both > cases we can go without closing the socket > Calling CometEventImpl.close() will set both conditions to true. > I think that response.isClosed() when isComet() =3D=3D true will mean an > error and needs closing the socket. Need to think more about it. >=20 I think you are right. If the response is already closed before the container is invoked, the servlet receives an END event and must call event.close(). If it doesn't, it is an error. However, the following CAN happen: - the servlet processes a READ event and therefore does not call event.close() - then the response is closed by another thread=20 - then control returns to CoyoteAdpater.event - now we have response.isClosed() when isComet() =3D=3D true=20 This can only happen in the streaming case, as it requires a READ event, and even if it is not really an error, I think=20 it is acceptable to close the socket in this situation. The servlet programmer knows if the servlet implements long poll or streaming.=20 So, maybe the servlet should be enabled to declare that the connection shall be kept open, e.g. via an additional method CometEvent.close(boolean keepalive). Existing code that relies on the socket close would not be=20 broken if CometEvent.close() would behave like=20 CometEvent.close(false). Such an interface extension would also have the charm=20 of making explicit that closing an event does not only affect=20 the associated request but also the connection. > b) how the socket will be processed further and be returned to the > poller. There are non-comet vs. comet pollers. There are some > keepAlive settings (like "maxKeepAliveRequests") and those have to be > respected. >=20 For long poll I want to keep the polling connection open as long as possible. Therefore I am using maxKeepAliveRequests =3D -1. Best regards, Matthias Reich --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org For additional commands, e-mail: users-help@tomcat.apache.org