static void tcp_ack ( final AutoBuffer ab ) throws IOException { // Get the RPC we're waiting on int task = ab . getTask ( ) ; RPC rpc = ab . _h2o . taskGet ( task ) ; // Race with canceling a large RPC fetch: Task is already dead. Do not // bother reading from the TCP socket, just bail out & close socket. if ( rpc == null || rpc . _done ) { ab . drainClose ( ) ; } else { assert rpc . _tasknum == task ; assert ! rpc . _done ; // Here we have the result, and we're on the correct Node but wrong // Thread. If we just return, the TCP reader thread will close the // remote, the remote will UDP ACK the RPC back, and back on the current // Node but in the correct Thread, we'd wake up and realize we received a // large result. try { rpc . response ( ab ) ; } catch ( AutoBuffer . AutoBufferException e ) { // If TCP fails, we will have done a short-read crushing the original // _dt object, and be unable to resend. This is fatal right now. // Really: an unimplemented feature; fix is to notice that a partial // TCP read means that the server (1) got our remote_exec request, (2) // has computed an answer and was trying to send it to us, (3) failed // sending via TCP hence the server knows it failed and will send again // without any further work from us. We need to disable all the resend // & retry logic, and wait for the server to re-send our result. // Meanwhile the _dt object is crushed with half-read crap, and cannot // be trusted except in the base fields. throw Log . throwErr ( e . _ioe ) ; } } // ACKACK the remote, telling him "we got the answer" new AutoBuffer ( ab . _h2o , H2O . ACK_ACK_PRIORITY ) . putTask ( UDP . udp . ackack . ordinal ( ) , task ) . close ( ) ; }
reader thread .