costin 2002/06/10 17:11:03 Modified: jk/java/org/apache/jk/common ChannelJni.java Log: Fix for POST in in-process. This is a very tricky code - we must 'simulate' a 2-thread model ( i.e. one tomcat thread sending/receiving messages with apache, and one apache thread ) in a 1-thread model, with no context switch. We do this by requiring a certain behavior from the invoked method - the send() will marshal the response back into the same buffer, and next receive() will just read it. While a cleaner solution may be possible, this has the main benefit of minimizing the most expensive operation in jni - moving data between java heap and C ( we have a single java buffer that is pinned ). Of course, the rest of the code must deal with that - and make sure the buffer is not used for something else. Since we simulate the send/response in 2-thread model, the receive() will be called imediately after send(), so things are not too bad. The problem with POST was the 'special' chunk sent imediately after the request data. In tcp mode, that optimize the case of small requests ( since it eliminates one round trip - well, it's not too much and it may be worth removing it for cleaner code ). In JNI mode, there is no such thing. The fix is to check if the receive() is the result of a sent(), and return an empty message otherwise. Revision Changes Path 1.13 +35 -3 jakarta-tomcat-connectors/jk/java/org/apache/jk/common/ChannelJni.java Index: ChannelJni.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/java/org/apache/jk/common/ChannelJni.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- ChannelJni.java 1 Jun 2002 08:29:34 -0000 1.12 +++ ChannelJni.java 11 Jun 2002 00:11:03 -0000 1.13 @@ -111,6 +111,25 @@ throws IOException { Msg sentResponse=(Msg)ep.getNote( receivedNote ); + ep.setNote( receivedNote, null ); + + if( sentResponse == null ) { + if( log.isDebugEnabled() ) + log.debug("No send() prior to receive(), no data buffer"); + // No sent() was done prior to receive. + msg.reset(); + return 0; + } + + sentResponse.processHeader(); + + if( log.isTraceEnabled() ) + sentResponse.dump("received response "); + + if( msg != sentResponse ) { + log.error( "Error, in JNI mode the msg used for receive() must be identical with the one used for send()"); + } + return 0; } @@ -121,8 +140,15 @@ public int send( Msg msg, MsgContext ep ) throws IOException { + if( log.isDebugEnabled() ) log.debug("ChannelJni.send: " + msg ); + int rc=super.nativeDispatch( msg, ep, JK_HANDLE_JNI_DISPATCH, 0); + + // nativeDispatch will put the response in the same buffer. + // Next receive() will just get it from there. Very tricky to do + // things in one thread instead of 2. ep.setNote( receivedNote, msg ); + return rc; } @@ -146,23 +172,28 @@ * if anyone asks for it - same lazy behavior as in 3.3 ). */ public int invoke(Msg msg, MsgContext ep ) throws IOException { - if( log.isDebugEnabled() ) log.debug("ChannelJni.invoke: " + ep ); - if( apr==null ) return -1; long xEnv=ep.getJniEnv(); long cEndpointP=ep.getJniContext(); int type=ep.getType(); + if( log.isDebugEnabled() ) log.debug("ChannelJni.invoke: " + ep + " " + type); switch( type ) { case JkHandler.HANDLE_RECEIVE_PACKET: return receive( msg, ep ); case JkHandler.HANDLE_SEND_PACKET: + ep.setNote( receivedNote, null ); return send( msg, ep ); case JkHandler.HANDLE_FLUSH: + ep.setNote( receivedNote, null ); return 0; } + + // Reset receivedNote. It'll be visible only after a SEND and before a receive. + ep.setNote( receivedNote, null ); + // Default is FORWARD - called from C try { // first, we need to get an endpoint. It should be @@ -171,7 +202,8 @@ // The endpoint will store the message pt. msg.processHeader(); - // if( log.isInfoEnabled() ) msg.dump("Incoming msg "); + + if( log.isTraceEnabled() ) msg.dump("Incoming msg "); int status= next.invoke( msg, ep );
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>