protected void cleanupCalls(long rpcTimeout) { Iterator<Entry<Integer, Call>> itor = calls.entrySet().iterator(); while (itor.hasNext()) { Call c = itor.next().getValue(); long waitTime = System.currentTimeMillis() - c.getStartTime(); if (waitTime >= rpcTimeout) { if (this.closeException == null) { // There may be no exception in the case that there are many calls // being multiplexed over this connection and these are succeeding // fine while this Call object is taking a long time to finish // over on the server; e.g. I just asked the regionserver to bulk // open 3k regions or its a big fat multiput into a heavily-loaded // server (Perhaps this only happens at the extremes?) this.closeException = new CallTimeoutException( "Call id=" + c.id + ", waitTime=" + waitTime + ", rpcTimetout=" + rpcTimeout); } c.setException(this.closeException); synchronized (c) { c.notifyAll(); } itor.remove(); } else { break; } } try { if (!calls.isEmpty()) { Call firstCall = calls.get(calls.firstKey()); long maxWaitTime = System.currentTimeMillis() - firstCall.getStartTime(); if (maxWaitTime < rpcTimeout) { rpcTimeout -= maxWaitTime; } } if (!shouldCloseConnection.get()) { closeException = null; if (socket != null) { socket.setSoTimeout((int) rpcTimeout); } } } catch (SocketException e) { LOG.debug("Couldn't lower timeout, which may result in longer than expected calls"); } }
/** * Add a call to this connection's call queue and notify a listener; synchronized. If the * connection is dead, the call is not added, and the caller is notified. This function can * return a connection that is already marked as 'shouldCloseConnection' It is up to the user * code to check this status. * * @param call to add */ protected synchronized void addCall(Call call) { // If the connection is about to close, we manage this as if the call was already added // to the connection calls list. If not, the connection creations are serialized, as // mentioned in HBASE-6364 if (this.shouldCloseConnection.get()) { if (this.closeException == null) { call.setException( new IOException( "Call " + call.id + " not added as the connection " + remoteId + " is closing")); } else { call.setException(this.closeException); } synchronized (call) { call.notifyAll(); } } else { calls.put(call.id, call); notify(); } }