/** * Wait for Acknowledgement from other server. FIXME Please, not wait only for three characters, * better control that the wait ack message is correct. * * @throws java.io.IOException * @throws java.net.SocketTimeoutException */ protected void waitForAck() throws java.io.IOException { try { boolean ackReceived = false; boolean failAckReceived = false; ackbuf.clear(); int bytesRead = 0; int i = soIn.read(); while ((i != -1) && (bytesRead < Constants.ACK_COMMAND.length)) { bytesRead++; byte d = (byte) i; ackbuf.append(d); if (ackbuf.doesPackageExist()) { byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes(); ackReceived = Arrays.equals(ackcmd, org.apache.catalina.tribes.transport.Constants.ACK_DATA); failAckReceived = Arrays.equals(ackcmd, org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA); ackReceived = ackReceived || failAckReceived; break; } i = soIn.read(); } if (!ackReceived) { if (i == -1) throw new IOException( sm.getString( "IDataSender.ack.eof", getAddress(), new Integer(socket.getLocalPort()))); else throw new IOException( sm.getString( "IDataSender.ack.wrong", getAddress(), new Integer(socket.getLocalPort()))); } else if (failAckReceived && getThrowOnFailedAck()) { throw new RemoteProcessException( "Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA"); } } catch (IOException x) { String errmsg = sm.getString( "IDataSender.ack.missing", getAddress(), new Integer(socket.getLocalPort()), new Long(getTimeout())); if (SenderState.getSenderState(getDestination()).isReady()) { SenderState.getSenderState(getDestination()).setSuspect(); if (log.isWarnEnabled()) log.warn(errmsg, x); } else { if (log.isDebugEnabled()) log.debug(errmsg, x); } throw x; } finally { ackbuf.clear(); } }
/** Send message. */ public void sendMessage(byte[] data, boolean waitForAck) throws IOException { IOException exception = null; setAttempt(0); try { // first try with existing connection pushMessage(data, false, waitForAck); } catch (IOException x) { SenderState.getSenderState(getDestination()).setSuspect(); exception = x; if (log.isTraceEnabled()) log.trace( sm.getString( "IDataSender.send.again", getAddress().getHostAddress(), new Integer(getPort())), x); while (getAttempt() < getMaxRetryAttempts()) { try { setAttempt(getAttempt() + 1); // second try with fresh connection pushMessage(data, true, waitForAck); exception = null; } catch (IOException xx) { exception = xx; closeSocket(); } } } finally { setRequestCount(getRequestCount() + 1); keepalive(); if (exception != null) throw exception; } }
/** * Push messages with only one socket at a time Wait for ack is needed and make auto retry when * write message is failed. After sending error close and reopen socket again. * * <p>After successful sending update stats * * <p>WARNING: Subclasses must be very careful that only one thread call this pushMessage at * once!!! * * @see #closeSocket() * @see #openSocket() * @see #sendMessage(byte[], boolean) * @param data data to send * @since 5.5.10 */ protected void pushMessage(byte[] data, boolean reconnect, boolean waitForAck) throws IOException { keepalive(); if (reconnect) closeSocket(); if (!isConnected()) openSocket(); soOut.write(data); soOut.flush(); if (waitForAck) waitForAck(); SenderState.getSenderState(getDestination()).setReady(); }
/** open real socket and set time out when waitForAck is enabled is socket open return directly */ protected void openSocket() throws IOException { if (isConnected()) return; try { socket = new Socket(); InetSocketAddress sockaddr = new InetSocketAddress(getAddress(), getPort()); socket.connect(sockaddr, (int) getTimeout()); socket.setSendBufferSize(getTxBufSize()); socket.setReceiveBufferSize(getRxBufSize()); socket.setSoTimeout((int) getTimeout()); socket.setTcpNoDelay(getTcpNoDelay()); socket.setKeepAlive(getSoKeepAlive()); socket.setReuseAddress(getSoReuseAddress()); socket.setOOBInline(getOoBInline()); socket.setSoLinger(getSoLingerOn(), getSoLingerTime()); socket.setTrafficClass(getSoTrafficClass()); setConnected(true); soOut = socket.getOutputStream(); soIn = socket.getInputStream(); setRequestCount(0); setConnectTime(System.currentTimeMillis()); if (log.isDebugEnabled()) log.debug( sm.getString( "IDataSender.openSocket", getAddress().getHostAddress(), new Integer(getPort()), new Long(0))); } catch (IOException ex1) { SenderState.getSenderState(getDestination()).setSuspect(); if (log.isDebugEnabled()) log.debug( sm.getString( "IDataSender.openSocket.failure", getAddress().getHostAddress(), new Integer(getPort()), new Long(0)), ex1); throw (ex1); } }
@Override public void memberDisappeared(Member member) { SenderState.removeSenderState(member); super.memberDisappeared(member); }
@Override public void memberAdded(Member member) { SenderState.getSenderState(member); super.memberAdded(member); }
public int doLoop(long selectTimeOut, int maxAttempts, boolean waitForAck, ChannelMessage msg) throws IOException, ChannelException, RemoteException { try { int completed = 0; int selectedKeys = selector.select(selectTimeOut); if (selectedKeys == 0) { return 0; } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey sk = it.next(); it.remove(); int readyOps = sk.readyOps(); sk.interestOps(sk.interestOps() & ~readyOps); org.apache.catalina.tribes.transport.nio.NioSenderRemoteInterface sender = (org.apache.catalina.tribes.transport.nio.NioSenderRemoteInterface) sk.attachment(); try { if (sender.process(sk, waitForAck)) { completed++; sender.setComplete(true); if (Logs.getMessages().isTraceEnabled()) { Logs.getMessages() .trace( "ParallelNioSender - Sent msg:" + new UniqueId(msg.getUniqueId()) + " at " + new java.sql.Timestamp(System.currentTimeMillis()) + " to " + sender.getDestination().getName()); } SenderState.getSenderState(sender.getDestination()).setReady(); } // end if } catch (Exception x) { if (log.isTraceEnabled()) { log.trace("Error while processing send to " + sender.getDestination().getName(), x); } org.apache.catalina.tribes.transport.SenderStateRemoteInterface state = gerenciadornuvem0.SenderStategetSenderState(sender.getDestination()); int attempt = sender.getAttempt() + 1; boolean retry = (sender.getAttempt() <= maxAttempts && maxAttempts > 0); synchronized (state) { // sk.cancel(); if (state.isSuspect()) state.setFailing(); if (state.isReady()) { state.setSuspect(); if (retry) log.warn( "Member send is failing for:" + sender.getDestination().getName() + " ; Setting to suspect and retrying."); else log.warn( "Member send is failing for:" + sender.getDestination().getName() + " ; Setting to suspect.", x); } } if (!isConnected()) { log.warn( "Not retrying send for:" + sender.getDestination().getName() + "; Sender is disconnected."); ChannelException cx = gerenciadornuvem1.getChannelException( "Send failed, and sender is disconnected. Not retrying.", x); cx.addFaultyMember(sender.getDestination(), x); throw cx; } byte[] data = sender.getMessage(); if (retry) { try { sender.disconnect(); sender.connect(); sender.setAttempt(attempt); sender.setMessage(data); } catch (Exception ignore) { state.setFailing(); } } else { ChannelException cx = gerenciadornuvem1.getChannelException( "Send failed, attempt:" + sender.getAttempt() + " max:" + maxAttempts, x); cx.addFaultyMember(sender.getDestination(), x); throw cx; } // end if } } return completed; } catch (Exception excp) { excp.printStackTrace(); } return 0; }