/** * Sends an RPC request to the given {@link InetSocketAddress}. * * @param remoteSocketAddress the remote address to send the request to * @param request the RPC request to send * @return the return value of the RPC call, possibly <code>null</code> * @throws Throwable any exception that is thrown by the remote receiver of the RPC call */ Object sendRPCRequest(final InetSocketAddress remoteSocketAddress, final RPCRequest request) throws Throwable { if (this.shutdownRequested.get()) throw new IOException("Shutdown of RPC service has already been requested"); final long start = System.currentTimeMillis(); final DatagramPacket[] packets = this.messageToPackets(remoteSocketAddress, request); final Integer messageID = Integer.valueOf(request.getMessageID()); final RPCRequestMonitor requestMonitor = new RPCRequestMonitor(); this.pendingRequests.put(messageID, requestMonitor); RPCResponse rpcResponse = null; int numberOfRetries; try { numberOfRetries = this.networkThread.send(packets); // Wait for the response synchronized (requestMonitor) { while (true) { if (requestMonitor.rpcResponse != null) { rpcResponse = requestMonitor.rpcResponse; break; } final long sleepTime = RPC_TIMEOUT - (System.currentTimeMillis() - start); if (sleepTime > 0L) requestMonitor.wait(sleepTime); else break; } } } finally { // Request is no longer pending this.pendingRequests.remove(messageID); } if (rpcResponse == null) throw new IOException( "Unable to complete RPC of method " + request.getMethodName() + " on " + remoteSocketAddress); // Report the successful call to the statistics module final String methodName = request.getMethodName(); this.statistics.reportSuccessfulTransmission(methodName, packets.length, numberOfRetries); this.statistics.reportRTT(methodName, (int) (System.currentTimeMillis() - start)); // TODO: Send clean up message if (rpcResponse instanceof RPCReturnValue) return ((RPCReturnValue) rpcResponse).getRetVal(); throw ((RPCThrowable) rpcResponse).getThrowable(); }
/** * Processes an incoming RPC response. * * @param rpcResponse the RPC response to be processed */ void processIncomingRPCResponse(final RPCResponse rpcResponse) { final Integer messageID = Integer.valueOf(rpcResponse.getMessageID()); final RPCRequestMonitor requestMonitor = this.pendingRequests.get(messageID); // The caller has already timed out or received an earlier response if (requestMonitor == null) return; synchronized (requestMonitor) { requestMonitor.rpcResponse = rpcResponse; requestMonitor.notify(); } }