init
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import org.apache.catalina.tribes.io.ListenCallback;
|
||||
|
||||
public abstract class AbstractRxTask implements Runnable
|
||||
{
|
||||
|
||||
public static final int OPTION_DIRECT_BUFFER = ReceiverBase.OPTION_DIRECT_BUFFER;
|
||||
|
||||
private ListenCallback callback;
|
||||
private RxTaskPool pool;
|
||||
private boolean doRun = true;
|
||||
private int options;
|
||||
protected boolean useBufferPool = true;
|
||||
|
||||
public AbstractRxTask(ListenCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setTaskPool(RxTaskPool pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public void setOptions(int options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public void setCallback(ListenCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setDoRun(boolean doRun) {
|
||||
this.doRun = doRun;
|
||||
}
|
||||
|
||||
public RxTaskPool getTaskPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
public int getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public ListenCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public boolean isDoRun() {
|
||||
return doRun;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
doRun = false;
|
||||
}
|
||||
|
||||
public void setUseBufferPool(boolean usebufpool) {
|
||||
useBufferPool = usebufpool;
|
||||
}
|
||||
|
||||
public boolean getUseBufferPool() {
|
||||
return useBufferPool;
|
||||
}
|
||||
}
|
||||
349
java/org/apache/catalina/tribes/transport/AbstractSender.java
Normal file
349
java/org/apache/catalina/tribes/transport/AbstractSender.java
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public abstract class AbstractSender implements DataSender {
|
||||
|
||||
private volatile boolean connected = false;
|
||||
private int rxBufSize = 25188;
|
||||
private int txBufSize = 43800;
|
||||
private int udpRxBufSize = 25188;
|
||||
private int udpTxBufSize = 43800;
|
||||
private boolean directBuffer = false;
|
||||
private int keepAliveCount = -1;
|
||||
private int requestCount = 0;
|
||||
private long connectTime;
|
||||
private long keepAliveTime = -1;
|
||||
private long timeout = 3000;
|
||||
private Member destination;
|
||||
private InetAddress address;
|
||||
private int port;
|
||||
private int maxRetryAttempts = 1;//1 resends
|
||||
private int attempt;
|
||||
private boolean tcpNoDelay = true;
|
||||
private boolean soKeepAlive = false;
|
||||
private boolean ooBInline = true;
|
||||
private boolean soReuseAddress = true;
|
||||
private boolean soLingerOn = false;
|
||||
private int soLingerTime = 3;
|
||||
private int soTrafficClass = 0x04 | 0x08 | 0x010;
|
||||
private boolean throwOnFailedAck = true;
|
||||
private boolean udpBased = false;
|
||||
private int udpPort = -1;
|
||||
|
||||
/**
|
||||
* transfers sender properties from one sender to another
|
||||
* @param from AbstractSender
|
||||
* @param to AbstractSender
|
||||
*/
|
||||
public static void transferProperties(AbstractSender from, AbstractSender to) {
|
||||
to.rxBufSize = from.rxBufSize;
|
||||
to.txBufSize = from.txBufSize;
|
||||
to.directBuffer = from.directBuffer;
|
||||
to.keepAliveCount = from.keepAliveCount;
|
||||
to.keepAliveTime = from.keepAliveTime;
|
||||
to.timeout = from.timeout;
|
||||
to.destination = from.destination;
|
||||
to.address = from.address;
|
||||
to.port = from.port;
|
||||
to.maxRetryAttempts = from.maxRetryAttempts;
|
||||
to.tcpNoDelay = from.tcpNoDelay;
|
||||
to.soKeepAlive = from.soKeepAlive;
|
||||
to.ooBInline = from.ooBInline;
|
||||
to.soReuseAddress = from.soReuseAddress;
|
||||
to.soLingerOn = from.soLingerOn;
|
||||
to.soLingerTime = from.soLingerTime;
|
||||
to.soTrafficClass = from.soTrafficClass;
|
||||
to.throwOnFailedAck = from.throwOnFailedAck;
|
||||
to.udpBased = from.udpBased;
|
||||
to.udpPort = from.udpPort;
|
||||
}
|
||||
|
||||
|
||||
public AbstractSender() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* connect
|
||||
*
|
||||
* @throws IOException
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.DataSender method
|
||||
*/
|
||||
@Override
|
||||
public abstract void connect() throws IOException;
|
||||
|
||||
/**
|
||||
* disconnect
|
||||
*
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.DataSender method
|
||||
*/
|
||||
@Override
|
||||
public abstract void disconnect();
|
||||
|
||||
/**
|
||||
* keepalive
|
||||
*
|
||||
* @return boolean
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.DataSender method
|
||||
*/
|
||||
@Override
|
||||
public boolean keepalive() {
|
||||
boolean disconnect = false;
|
||||
if (isUdpBased()) disconnect = true; //always disconnect UDP, TODO optimize the keepalive handling
|
||||
else if ( keepAliveCount >= 0 && requestCount>keepAliveCount ) disconnect = true;
|
||||
else if ( keepAliveTime >= 0 && (System.currentTimeMillis()-connectTime)>keepAliveTime ) disconnect = true;
|
||||
if ( disconnect ) disconnect();
|
||||
return disconnect;
|
||||
}
|
||||
|
||||
protected void setConnected(boolean connected){
|
||||
this.connected = connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getConnectTime() {
|
||||
return connectTime;
|
||||
}
|
||||
|
||||
public Member getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
|
||||
public int getKeepAliveCount() {
|
||||
return keepAliveCount;
|
||||
}
|
||||
|
||||
public long getKeepAliveTime() {
|
||||
return keepAliveTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequestCount() {
|
||||
return requestCount;
|
||||
}
|
||||
|
||||
public int getRxBufSize() {
|
||||
return rxBufSize;
|
||||
}
|
||||
|
||||
public long getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public int getTxBufSize() {
|
||||
return txBufSize;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getMaxRetryAttempts() {
|
||||
return maxRetryAttempts;
|
||||
}
|
||||
|
||||
public void setDirectBuffer(boolean directBuffer) {
|
||||
this.directBuffer = directBuffer;
|
||||
}
|
||||
|
||||
public boolean getDirectBuffer() {
|
||||
return this.directBuffer;
|
||||
}
|
||||
|
||||
public int getAttempt() {
|
||||
return attempt;
|
||||
}
|
||||
|
||||
public boolean getTcpNoDelay() {
|
||||
return tcpNoDelay;
|
||||
}
|
||||
|
||||
public boolean getSoKeepAlive() {
|
||||
return soKeepAlive;
|
||||
}
|
||||
|
||||
public boolean getOoBInline() {
|
||||
return ooBInline;
|
||||
}
|
||||
|
||||
public boolean getSoReuseAddress() {
|
||||
return soReuseAddress;
|
||||
}
|
||||
|
||||
public boolean getSoLingerOn() {
|
||||
return soLingerOn;
|
||||
}
|
||||
|
||||
public int getSoLingerTime() {
|
||||
return soLingerTime;
|
||||
}
|
||||
|
||||
public int getSoTrafficClass() {
|
||||
return soTrafficClass;
|
||||
}
|
||||
|
||||
public boolean getThrowOnFailedAck() {
|
||||
return throwOnFailedAck;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeepAliveCount(int keepAliveCount) {
|
||||
this.keepAliveCount = keepAliveCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKeepAliveTime(long keepAliveTime) {
|
||||
this.keepAliveTime = keepAliveTime;
|
||||
}
|
||||
|
||||
public void setRequestCount(int requestCount) {
|
||||
this.requestCount = requestCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRxBufSize(int rxBufSize) {
|
||||
this.rxBufSize = rxBufSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTxBufSize(int txBufSize) {
|
||||
this.txBufSize = txBufSize;
|
||||
}
|
||||
|
||||
public void setConnectTime(long connectTime) {
|
||||
this.connectTime = connectTime;
|
||||
}
|
||||
|
||||
public void setMaxRetryAttempts(int maxRetryAttempts) {
|
||||
this.maxRetryAttempts = maxRetryAttempts;
|
||||
}
|
||||
|
||||
public void setAttempt(int attempt) {
|
||||
this.attempt = attempt;
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = tcpNoDelay;
|
||||
}
|
||||
|
||||
public void setSoKeepAlive(boolean soKeepAlive) {
|
||||
this.soKeepAlive = soKeepAlive;
|
||||
}
|
||||
|
||||
public void setOoBInline(boolean ooBInline) {
|
||||
this.ooBInline = ooBInline;
|
||||
}
|
||||
|
||||
public void setSoReuseAddress(boolean soReuseAddress) {
|
||||
this.soReuseAddress = soReuseAddress;
|
||||
}
|
||||
|
||||
public void setSoLingerOn(boolean soLingerOn) {
|
||||
this.soLingerOn = soLingerOn;
|
||||
}
|
||||
|
||||
public void setSoLingerTime(int soLingerTime) {
|
||||
this.soLingerTime = soLingerTime;
|
||||
}
|
||||
|
||||
public void setSoTrafficClass(int soTrafficClass) {
|
||||
this.soTrafficClass = soTrafficClass;
|
||||
}
|
||||
|
||||
public void setThrowOnFailedAck(boolean throwOnFailedAck) {
|
||||
this.throwOnFailedAck = throwOnFailedAck;
|
||||
}
|
||||
|
||||
public void setDestination(Member destination) throws UnknownHostException {
|
||||
this.destination = destination;
|
||||
this.address = InetAddress.getByAddress(destination.getHost());
|
||||
this.port = destination.getPort();
|
||||
this.udpPort = destination.getUdpPort();
|
||||
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setAddress(InetAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
|
||||
public boolean isUdpBased() {
|
||||
return udpBased;
|
||||
}
|
||||
|
||||
|
||||
public void setUdpBased(boolean udpBased) {
|
||||
this.udpBased = udpBased;
|
||||
}
|
||||
|
||||
|
||||
public int getUdpPort() {
|
||||
return udpPort;
|
||||
}
|
||||
|
||||
|
||||
public void setUdpPort(int udpPort) {
|
||||
this.udpPort = udpPort;
|
||||
}
|
||||
|
||||
|
||||
public int getUdpRxBufSize() {
|
||||
return udpRxBufSize;
|
||||
}
|
||||
|
||||
|
||||
public void setUdpRxBufSize(int udpRxBufSize) {
|
||||
this.udpRxBufSize = udpRxBufSize;
|
||||
}
|
||||
|
||||
|
||||
public int getUdpTxBufSize() {
|
||||
return udpTxBufSize;
|
||||
}
|
||||
|
||||
|
||||
public void setUdpTxBufSize(int udpTxBufSize) {
|
||||
this.udpTxBufSize = udpTxBufSize;
|
||||
}
|
||||
|
||||
}
|
||||
40
java/org/apache/catalina/tribes/transport/Constants.java
Normal file
40
java/org/apache/catalina/tribes/transport/Constants.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
|
||||
/**
|
||||
* Manifest constants for the <code>org.apache.catalina.tribes.transport</code>
|
||||
* package.
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final String Package = "org.apache.catalina.tribes.transport";
|
||||
|
||||
/*
|
||||
* Do not change any of these values!
|
||||
*/
|
||||
public static final byte[] ACK_DATA = new byte[] {6, 2, 3};
|
||||
public static final byte[] FAIL_ACK_DATA = new byte[] {11, 0, 5};
|
||||
public static final byte[] ACK_COMMAND = XByteBuffer.createDataPackage(ACK_DATA);
|
||||
public static final byte[] FAIL_ACK_COMMAND = XByteBuffer.createDataPackage(FAIL_ACK_DATA);
|
||||
|
||||
}
|
||||
33
java/org/apache/catalina/tribes/transport/DataSender.java
Normal file
33
java/org/apache/catalina/tribes/transport/DataSender.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface DataSender {
|
||||
public void connect() throws IOException;
|
||||
public void disconnect();
|
||||
public boolean isConnected();
|
||||
public void setRxBufSize(int size);
|
||||
public void setTxBufSize(int size);
|
||||
public boolean keepalive();
|
||||
public void setTimeout(long timeout);
|
||||
public void setKeepAliveCount(int maxRequests);
|
||||
public void setKeepAliveTime(long keepAliveTimeInMs);
|
||||
public int getRequestCount();
|
||||
public long getConnectTime();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=Failed to disconnect sender
|
||||
|
||||
pooledSender.closed.queue=Queue is closed
|
||||
|
||||
receiverBase.bind.failed=Failed bind replication listener on address:[{0}]
|
||||
receiverBase.socket.bind=Receiver Server Socket bound to:[{0}]
|
||||
receiverBase.udp.bind=UDP Receiver Server Socket bound to:[{0}]
|
||||
receiverBase.unable.bind=Unable to bind server socket to:[{0}] throwing error.
|
||||
receiverBase.unable.bind.udp=Unable to bind UDP socket to:[{0}] throwing error.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
receiverBase.unable.bind=Kann Server Socket nicht an [{0}] binden. Werfe einen Fehler.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=No pude desconectar al remitente
|
||||
|
||||
receiverBase.bind.failed=Fallo al atachar el escuchador de replicación en la dirección: [{0}]\n
|
||||
receiverBase.unable.bind=Imposible vincular el socket del servidor a:[{0}] lanzando error.
|
||||
receiverBase.unable.bind.udp=Imposible atar el socket UDP a:[{0}] lanzando error.\n
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=Impossible de se déconnecter de l'envoyeur
|
||||
|
||||
pooledSender.closed.queue=La queue est fermée
|
||||
|
||||
receiverBase.bind.failed=Échec d''attachement en écoute de la réplication à l''adresse [{0}]
|
||||
receiverBase.socket.bind=Socket de réception du serveur attaché à : [{0}]
|
||||
receiverBase.udp.bind=Le socket serveur receveur est associé avec [{0}]
|
||||
receiverBase.unable.bind=Impossible d''attacher la socket serveur à [{0}], cela provoque une erreur.
|
||||
receiverBase.unable.bind.udp=Impossible d''associer le socket UDP à [{0}], propagation de l''erreur
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=Senderの切断に失敗しました。
|
||||
|
||||
pooledSender.closed.queue=キューは閉じられています。
|
||||
|
||||
receiverBase.bind.failed=アドレス [{0}] にレプリケーションリスナーを束縛できません。
|
||||
receiverBase.socket.bind=Receiver Serverソケットがバインドされました:[{0}]
|
||||
receiverBase.udp.bind=UDP 受信用のサーバーソケットを [{0}] にバインドしました。
|
||||
receiverBase.unable.bind=[{0}] へサーバーソケットをバインドできなかったためエラーを送出しました。
|
||||
receiverBase.unable.bind.udp=UDP ソケットを [{0}] へ束縛できません。エラーを送出します。
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=Sender의 연결을 끊지 못했습니다.
|
||||
|
||||
pooledSender.closed.queue=큐가 닫힌 상태입니다.
|
||||
|
||||
receiverBase.bind.failed=복제 리스너를 어드레스 [{0}]에 바인딩하지 못했습니다.
|
||||
receiverBase.socket.bind=Receiver 서버 소켓이 [{0}]에 바인딩 되었습니다.
|
||||
receiverBase.udp.bind=UDP 수신 서버 소켓이 [{0}]에 바인딩 됨.
|
||||
receiverBase.unable.bind=서버 소켓을 바인드 할 수 없습니다: [{0}]에서 오류 발생.
|
||||
receiverBase.unable.bind.udp=오류 발생으로 인해 UDP 소켓을 [{0}]에 바인딩할 수 없습니다.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
PooledSender.senderDisconnectFail=与 sender 断开连接失败
|
||||
|
||||
receiverBase.bind.failed=对内容类型[{2}]返回[{3}]使用[{0}]匹配[{1}]
|
||||
receiverBase.socket.bind=服务器套接字接收器绑定到:[{0}]
|
||||
receiverBase.unable.bind=无法绑定套接字端口:{{0}},出现异常
|
||||
receiverBase.unable.bind.udp=无法将UDP套接字绑定到:[{0}]抛出错误。
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport;
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
/**
|
||||
* @since 5.5.16
|
||||
*/
|
||||
public interface MultiPointSender extends DataSender
|
||||
{
|
||||
public void sendMessage(Member[] destination, ChannelMessage data) throws ChannelException;
|
||||
public void setMaxRetryAttempts(int attempts);
|
||||
public void setDirectBuffer(boolean directBuf);
|
||||
public void add(Member member);
|
||||
public void remove(Member member);
|
||||
}
|
||||
229
java/org/apache/catalina/tribes/transport/PooledSender.java
Normal file
229
java/org/apache/catalina/tribes/transport/PooledSender.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public abstract class PooledSender extends AbstractSender implements MultiPointSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PooledSender.class);
|
||||
protected static final StringManager sm =
|
||||
StringManager.getManager(Constants.Package);
|
||||
|
||||
private final SenderQueue queue;
|
||||
private int poolSize = 25;
|
||||
private long maxWait = 3000;
|
||||
public PooledSender() {
|
||||
queue = new SenderQueue(this,poolSize);
|
||||
}
|
||||
|
||||
public abstract DataSender getNewDataSender();
|
||||
|
||||
public DataSender getSender() {
|
||||
return queue.getSender(getMaxWait());
|
||||
}
|
||||
|
||||
public void returnSender(DataSender sender) {
|
||||
sender.keepalive();
|
||||
queue.returnSender(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void connect() throws IOException {
|
||||
//do nothing, happens in the socket sender itself
|
||||
queue.open();
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect() {
|
||||
queue.close();
|
||||
setConnected(false);
|
||||
}
|
||||
|
||||
|
||||
public int getInPoolSize() {
|
||||
return queue.getInPoolSize();
|
||||
}
|
||||
|
||||
public int getInUsePoolSize() {
|
||||
return queue.getInUsePoolSize();
|
||||
}
|
||||
|
||||
|
||||
public void setPoolSize(int poolSize) {
|
||||
this.poolSize = poolSize;
|
||||
queue.setLimit(poolSize);
|
||||
}
|
||||
|
||||
public int getPoolSize() {
|
||||
return poolSize;
|
||||
}
|
||||
|
||||
public long getMaxWait() {
|
||||
return maxWait;
|
||||
}
|
||||
|
||||
public void setMaxWait(long maxWait) {
|
||||
this.maxWait = maxWait;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keepalive() {
|
||||
//do nothing, the pool checks on every return
|
||||
return (queue==null)?false:queue.checkIdleKeepAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Member member) {
|
||||
// no op, senders created upon demands
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Member member) {
|
||||
//no op for now, should not cancel out any keys
|
||||
//can create serious sync issues
|
||||
//all TCP connections are cleared out through keepalive
|
||||
//and if remote node disappears
|
||||
}
|
||||
// ----------------------------------------------------- Inner Class
|
||||
|
||||
private static class SenderQueue {
|
||||
private int limit = 25;
|
||||
|
||||
PooledSender parent = null;
|
||||
|
||||
private List<DataSender> notinuse = null;
|
||||
|
||||
private List<DataSender> inuse = null;
|
||||
|
||||
private boolean isOpen = true;
|
||||
|
||||
public SenderQueue(PooledSender parent, int limit) {
|
||||
this.limit = limit;
|
||||
this.parent = parent;
|
||||
notinuse = new java.util.LinkedList<>();
|
||||
inuse = new java.util.LinkedList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the limit.
|
||||
*/
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
/**
|
||||
* @param limit The limit to set.
|
||||
*/
|
||||
public void setLimit(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public int getInUsePoolSize() {
|
||||
return inuse.size();
|
||||
}
|
||||
|
||||
public int getInPoolSize() {
|
||||
return notinuse.size();
|
||||
}
|
||||
|
||||
public synchronized boolean checkIdleKeepAlive() {
|
||||
DataSender[] list = new DataSender[notinuse.size()];
|
||||
notinuse.toArray(list);
|
||||
boolean result = false;
|
||||
for (int i=0; i<list.length; i++) {
|
||||
result = result | list[i].keepalive();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized DataSender getSender(long timeout) {
|
||||
long start = System.currentTimeMillis();
|
||||
while ( true ) {
|
||||
if (!isOpen)throw new IllegalStateException(sm.getString("pooledSender.closed.queue"));
|
||||
DataSender sender = null;
|
||||
if (notinuse.size() == 0 && inuse.size() < limit) {
|
||||
sender = parent.getNewDataSender();
|
||||
} else if (notinuse.size() > 0) {
|
||||
sender = notinuse.remove(0);
|
||||
}
|
||||
if (sender != null) {
|
||||
inuse.add(sender);
|
||||
return sender;
|
||||
}//end if
|
||||
long delta = System.currentTimeMillis() - start;
|
||||
if ( delta > timeout && timeout>0) return null;
|
||||
else {
|
||||
try {
|
||||
wait(Math.max(timeout - delta,1));
|
||||
}catch (InterruptedException x){}
|
||||
}//end if
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void returnSender(DataSender sender) {
|
||||
if ( !isOpen) {
|
||||
sender.disconnect();
|
||||
return;
|
||||
}
|
||||
//to do
|
||||
inuse.remove(sender);
|
||||
//just in case the limit has changed
|
||||
if ( notinuse.size() < this.getLimit() ) notinuse.add(sender);
|
||||
else
|
||||
try {
|
||||
sender.disconnect();
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString(
|
||||
"PooledSender.senderDisconnectFail"), e);
|
||||
}
|
||||
}
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
isOpen = false;
|
||||
Object[] unused = notinuse.toArray();
|
||||
Object[] used = inuse.toArray();
|
||||
for (int i = 0; i < unused.length; i++) {
|
||||
DataSender sender = (DataSender) unused[i];
|
||||
sender.disconnect();
|
||||
}//for
|
||||
for (int i = 0; i < used.length; i++) {
|
||||
DataSender sender = (DataSender) used[i];
|
||||
sender.disconnect();
|
||||
}//for
|
||||
notinuse.clear();
|
||||
inuse.clear();
|
||||
notifyAll();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public synchronized void open() {
|
||||
isOpen = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
606
java/org/apache/catalina/tribes/transport/ReceiverBase.java
Normal file
606
java/org/apache/catalina/tribes/transport/ReceiverBase.java
Normal file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.ChannelReceiver;
|
||||
import org.apache.catalina.tribes.MessageListener;
|
||||
import org.apache.catalina.tribes.io.ListenCallback;
|
||||
import org.apache.catalina.tribes.jmx.JmxRegistry;
|
||||
import org.apache.catalina.tribes.util.ExecutorFactory;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public abstract class ReceiverBase implements ChannelReceiver, ListenCallback, RxTaskPool.TaskCreator {
|
||||
|
||||
public static final int OPTION_DIRECT_BUFFER = 0x0004;
|
||||
|
||||
private static final Log log = LogFactory.getLog(ReceiverBase.class);
|
||||
|
||||
private static final Object bindLock = new Object();
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(Constants.Package);
|
||||
|
||||
private MessageListener listener;
|
||||
private String host = "auto";
|
||||
private InetAddress bind;
|
||||
private int port = 4000;
|
||||
private int udpPort = -1;
|
||||
private int securePort = -1;
|
||||
private int rxBufSize = 43800;
|
||||
private int txBufSize = 25188;
|
||||
private int udpRxBufSize = 43800;
|
||||
private int udpTxBufSize = 25188;
|
||||
|
||||
private volatile boolean listen = false;
|
||||
private RxTaskPool pool;
|
||||
private boolean direct = true;
|
||||
private long tcpSelectorTimeout = 5000;
|
||||
//how many times to search for an available socket
|
||||
private int autoBind = 100;
|
||||
private int maxThreads = 15;
|
||||
private int minThreads = 6;
|
||||
private int maxTasks = 100;
|
||||
private int minTasks = 10;
|
||||
private boolean tcpNoDelay = true;
|
||||
private boolean soKeepAlive = false;
|
||||
private boolean ooBInline = true;
|
||||
private boolean soReuseAddress = true;
|
||||
private boolean soLingerOn = true;
|
||||
private int soLingerTime = 3;
|
||||
private int soTrafficClass = 0x04 | 0x08 | 0x010;
|
||||
private int timeout = 3000; //3 seconds
|
||||
private boolean useBufferPool = true;
|
||||
private boolean daemon = true;
|
||||
private long maxIdleTime = 60000;
|
||||
|
||||
private ExecutorService executor;
|
||||
private Channel channel;
|
||||
|
||||
/**
|
||||
* the ObjectName of this Receiver.
|
||||
*/
|
||||
private ObjectName oname = null;
|
||||
|
||||
public ReceiverBase() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
if ( executor == null ) {
|
||||
//executor = new ThreadPoolExecutor(minThreads,maxThreads,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
|
||||
String channelName = "";
|
||||
if (channel.getName() != null) channelName = "[" + channel.getName() + "]";
|
||||
TaskThreadFactory tf = new TaskThreadFactory("Tribes-Task-Receiver" + channelName + "-");
|
||||
executor = ExecutorFactory.newThreadPool(minThreads, maxThreads, maxIdleTime, TimeUnit.MILLISECONDS, tf);
|
||||
}
|
||||
// register jmx
|
||||
JmxRegistry jmxRegistry = JmxRegistry.getRegistry(channel);
|
||||
if (jmxRegistry != null) this.oname = jmxRegistry.registerJmx(",component=Receiver", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if ( executor != null ) executor.shutdownNow();//ignore left overs
|
||||
executor = null;
|
||||
if (oname != null) {
|
||||
JmxRegistry jmxRegistry = JmxRegistry.getRegistry(channel);
|
||||
if (jmxRegistry != null) jmxRegistry.unregisterJmx(oname);
|
||||
oname = null;
|
||||
}
|
||||
channel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* getMessageListener
|
||||
*
|
||||
* @return MessageListener
|
||||
*/
|
||||
@Override
|
||||
public MessageListener getMessageListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The port
|
||||
*/
|
||||
@Override
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getRxBufSize() {
|
||||
return rxBufSize;
|
||||
}
|
||||
|
||||
public int getTxBufSize() {
|
||||
return txBufSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* setMessageListener
|
||||
*
|
||||
* @param listener MessageListener
|
||||
*/
|
||||
@Override
|
||||
public void setMessageListener(MessageListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setRxBufSize(int rxBufSize) {
|
||||
this.rxBufSize = rxBufSize;
|
||||
}
|
||||
|
||||
public void setTxBufSize(int txBufSize) {
|
||||
this.txBufSize = txBufSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the bind.
|
||||
*/
|
||||
public InetAddress getBind() {
|
||||
if (bind == null) {
|
||||
try {
|
||||
if ("auto".equals(host)) {
|
||||
host = java.net.InetAddress.getLocalHost().getHostAddress();
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Starting replication listener on address:"+ host);
|
||||
bind = java.net.InetAddress.getByName(host);
|
||||
} catch (IOException ioe) {
|
||||
log.error(sm.getString("receiverBase.bind.failed", host), ioe);
|
||||
}
|
||||
}
|
||||
return bind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to bind using the provided port and if that fails attempts to
|
||||
* bind to each of the ports from portstart to (portstart + retries -1)
|
||||
* until either there are no more ports or the bind is successful. The
|
||||
* address to bind to is obtained via a call to {link {@link #getBind()}.
|
||||
* @param socket The socket to bind
|
||||
* @param portstart Starting port for bind attempts
|
||||
* @param retries Number of times to attempt to bind (port incremented
|
||||
* between attempts)
|
||||
* @throws IOException Socket bind error
|
||||
*/
|
||||
protected void bind(ServerSocket socket, int portstart, int retries) throws IOException {
|
||||
synchronized (bindLock) {
|
||||
InetSocketAddress addr = null;
|
||||
int port = portstart;
|
||||
while (retries > 0) {
|
||||
try {
|
||||
addr = new InetSocketAddress(getBind(), port);
|
||||
socket.bind(addr);
|
||||
setPort(port);
|
||||
log.info(sm.getString("receiverBase.socket.bind", addr));
|
||||
retries = 0;
|
||||
} catch ( IOException x) {
|
||||
retries--;
|
||||
if ( retries <= 0 ) {
|
||||
log.info(sm.getString("receiverBase.unable.bind", addr));
|
||||
throw x;
|
||||
}
|
||||
port++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as bind() except it does it for the UDP port
|
||||
* @param socket The socket to bind
|
||||
* @param portstart Starting port for bind attempts
|
||||
* @param retries Number of times to attempt to bind (port incremented
|
||||
* between attempts)
|
||||
* @return int The retry count
|
||||
* @throws IOException Socket bind error
|
||||
*/
|
||||
protected int bindUdp(DatagramSocket socket, int portstart, int retries) throws IOException {
|
||||
InetSocketAddress addr = null;
|
||||
while ( retries > 0 ) {
|
||||
try {
|
||||
addr = new InetSocketAddress(getBind(), portstart);
|
||||
socket.bind(addr);
|
||||
setUdpPort(portstart);
|
||||
log.info(sm.getString("receiverBase.udp.bind", addr));
|
||||
return 0;
|
||||
}catch ( IOException x) {
|
||||
retries--;
|
||||
if ( retries <= 0 ) {
|
||||
log.info(sm.getString("receiverBase.unable.bind.udp", addr));
|
||||
throw x;
|
||||
}
|
||||
portstart++;
|
||||
try {
|
||||
Thread.sleep(25);
|
||||
} catch (InterruptedException ti) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
retries = bindUdp(socket,portstart,retries);
|
||||
}
|
||||
}
|
||||
return retries;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void messageDataReceived(ChannelMessage data) {
|
||||
if ( this.listener != null ) {
|
||||
if ( listener.accept(data) ) listener.messageReceived(data);
|
||||
}
|
||||
}
|
||||
|
||||
public int getWorkerThreadOptions() {
|
||||
int options = 0;
|
||||
if ( getDirect() ) options = options | OPTION_DIRECT_BUFFER;
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bind The bind to set.
|
||||
*/
|
||||
public void setBind(java.net.InetAddress bind) {
|
||||
this.bind = bind;
|
||||
}
|
||||
|
||||
public boolean getDirect() {
|
||||
return direct;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setDirect(boolean direct) {
|
||||
this.direct = direct;
|
||||
}
|
||||
|
||||
|
||||
public String getAddress() {
|
||||
getBind();
|
||||
return this.host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return getAddress();
|
||||
}
|
||||
|
||||
public long getSelectorTimeout() {
|
||||
return tcpSelectorTimeout;
|
||||
}
|
||||
|
||||
public boolean doListen() {
|
||||
return listen;
|
||||
}
|
||||
|
||||
public MessageListener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public RxTaskPool getTaskPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
public int getAutoBind() {
|
||||
return autoBind;
|
||||
}
|
||||
|
||||
public int getMaxThreads() {
|
||||
return maxThreads;
|
||||
}
|
||||
|
||||
public int getMinThreads() {
|
||||
return minThreads;
|
||||
}
|
||||
|
||||
public boolean getTcpNoDelay() {
|
||||
return tcpNoDelay;
|
||||
}
|
||||
|
||||
public boolean getSoKeepAlive() {
|
||||
return soKeepAlive;
|
||||
}
|
||||
|
||||
public boolean getOoBInline() {
|
||||
return ooBInline;
|
||||
}
|
||||
|
||||
|
||||
public boolean getSoLingerOn() {
|
||||
return soLingerOn;
|
||||
}
|
||||
|
||||
public int getSoLingerTime() {
|
||||
return soLingerTime;
|
||||
}
|
||||
|
||||
public boolean getSoReuseAddress() {
|
||||
return soReuseAddress;
|
||||
}
|
||||
|
||||
public int getSoTrafficClass() {
|
||||
return soTrafficClass;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public boolean getUseBufferPool() {
|
||||
return useBufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecurePort() {
|
||||
return securePort;
|
||||
}
|
||||
|
||||
public int getMinTasks() {
|
||||
return minTasks;
|
||||
}
|
||||
|
||||
public int getMaxTasks() {
|
||||
return maxTasks;
|
||||
}
|
||||
|
||||
public ExecutorService getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public boolean isListening() {
|
||||
return listen;
|
||||
}
|
||||
|
||||
public void setSelectorTimeout(long selTimeout) {
|
||||
tcpSelectorTimeout = selTimeout;
|
||||
}
|
||||
|
||||
public void setListen(boolean doListen) {
|
||||
this.listen = doListen;
|
||||
}
|
||||
|
||||
|
||||
public void setAddress(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
public void setHost(String host) {
|
||||
setAddress(host);
|
||||
}
|
||||
|
||||
public void setListener(MessageListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setPool(RxTaskPool pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setAutoBind(int autoBind) {
|
||||
this.autoBind = autoBind;
|
||||
if ( this.autoBind <= 0 ) this.autoBind = 1;
|
||||
}
|
||||
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
public void setMinThreads(int minThreads) {
|
||||
this.minThreads = minThreads;
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = tcpNoDelay;
|
||||
}
|
||||
|
||||
public void setSoKeepAlive(boolean soKeepAlive) {
|
||||
this.soKeepAlive = soKeepAlive;
|
||||
}
|
||||
|
||||
public void setOoBInline(boolean ooBInline) {
|
||||
this.ooBInline = ooBInline;
|
||||
}
|
||||
|
||||
|
||||
public void setSoLingerOn(boolean soLingerOn) {
|
||||
this.soLingerOn = soLingerOn;
|
||||
}
|
||||
|
||||
public void setSoLingerTime(int soLingerTime) {
|
||||
this.soLingerTime = soLingerTime;
|
||||
}
|
||||
|
||||
public void setSoReuseAddress(boolean soReuseAddress) {
|
||||
this.soReuseAddress = soReuseAddress;
|
||||
}
|
||||
|
||||
public void setSoTrafficClass(int soTrafficClass) {
|
||||
this.soTrafficClass = soTrafficClass;
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public void setUseBufferPool(boolean useBufferPool) {
|
||||
this.useBufferPool = useBufferPool;
|
||||
}
|
||||
|
||||
public void setSecurePort(int securePort) {
|
||||
this.securePort = securePort;
|
||||
}
|
||||
|
||||
public void setMinTasks(int minTasks) {
|
||||
this.minTasks = minTasks;
|
||||
}
|
||||
|
||||
public void setMaxTasks(int maxTasks) {
|
||||
this.maxTasks = maxTasks;
|
||||
}
|
||||
|
||||
public void setExecutor(ExecutorService executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void heartbeat() {
|
||||
//empty operation
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUdpPort() {
|
||||
return udpPort;
|
||||
}
|
||||
|
||||
public void setUdpPort(int udpPort) {
|
||||
this.udpPort = udpPort;
|
||||
}
|
||||
|
||||
public int getUdpRxBufSize() {
|
||||
return udpRxBufSize;
|
||||
}
|
||||
|
||||
public void setUdpRxBufSize(int udpRxBufSize) {
|
||||
this.udpRxBufSize = udpRxBufSize;
|
||||
}
|
||||
|
||||
public int getUdpTxBufSize() {
|
||||
return udpTxBufSize;
|
||||
}
|
||||
|
||||
public void setUdpTxBufSize(int udpTxBufSize) {
|
||||
this.udpTxBufSize = udpTxBufSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChannel(Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
// ---------------------------------------------- stats of the thread pool
|
||||
/**
|
||||
* Return the current number of threads that are managed by the pool.
|
||||
* @return the current number of threads that are managed by the pool
|
||||
*/
|
||||
public int getPoolSize() {
|
||||
if (executor instanceof ThreadPoolExecutor) {
|
||||
return ((ThreadPoolExecutor) executor).getPoolSize();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current number of threads that are in use.
|
||||
* @return the current number of threads that are in use
|
||||
*/
|
||||
public int getActiveCount() {
|
||||
if (executor instanceof ThreadPoolExecutor) {
|
||||
return ((ThreadPoolExecutor) executor).getActiveCount();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of tasks that have ever been scheduled for execution by the pool.
|
||||
* @return the total number of tasks that have ever been scheduled for execution by the pool
|
||||
*/
|
||||
public long getTaskCount() {
|
||||
if (executor instanceof ThreadPoolExecutor) {
|
||||
return ((ThreadPoolExecutor) executor).getTaskCount();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of tasks that have completed execution by the pool.
|
||||
* @return the total number of tasks that have completed execution by the pool
|
||||
*/
|
||||
public long getCompletedTaskCount() {
|
||||
if (executor instanceof ThreadPoolExecutor) {
|
||||
return ((ThreadPoolExecutor) executor).getCompletedTaskCount();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------- ThreadFactory Inner Class
|
||||
class TaskThreadFactory implements ThreadFactory {
|
||||
final ThreadGroup group;
|
||||
final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
final String namePrefix;
|
||||
|
||||
TaskThreadFactory(String namePrefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
|
||||
t.setDaemon(daemon);
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDaemon() {
|
||||
return daemon;
|
||||
}
|
||||
|
||||
public long getMaxIdleTime() {
|
||||
return maxIdleTime;
|
||||
}
|
||||
|
||||
public void setDaemon(boolean daemon) {
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(long maxIdleTime) {
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.ChannelSender;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.jmx.JmxRegistry;
|
||||
import org.apache.catalina.tribes.transport.nio.PooledParallelSender;
|
||||
|
||||
/**
|
||||
* Transmit message to other cluster members
|
||||
* Actual senders are created based on the replicationMode
|
||||
* type
|
||||
*/
|
||||
public class ReplicationTransmitter implements ChannelSender {
|
||||
|
||||
private Channel channel;
|
||||
|
||||
/**
|
||||
* the ObjectName of this Sender.
|
||||
*/
|
||||
private ObjectName oname = null;
|
||||
|
||||
public ReplicationTransmitter() {
|
||||
}
|
||||
|
||||
private MultiPointSender transport = new PooledParallelSender();
|
||||
|
||||
public MultiPointSender getTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
||||
public void setTransport(MultiPointSender transport) {
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- public
|
||||
|
||||
/**
|
||||
* Send data to one member
|
||||
* @see org.apache.catalina.tribes.ChannelSender#sendMessage(org.apache.catalina.tribes.ChannelMessage, org.apache.catalina.tribes.Member[])
|
||||
*/
|
||||
@Override
|
||||
public void sendMessage(ChannelMessage message, Member[] destination) throws ChannelException {
|
||||
MultiPointSender sender = getTransport();
|
||||
sender.sendMessage(destination,message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* start the sender and register transmitter mbean
|
||||
*
|
||||
* @see org.apache.catalina.tribes.ChannelSender#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() throws java.io.IOException {
|
||||
getTransport().connect();
|
||||
// register jmx
|
||||
JmxRegistry jmxRegistry = JmxRegistry.getRegistry(channel);
|
||||
if (jmxRegistry != null) this.oname = jmxRegistry.registerJmx(",component=Sender", transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* stop the sender and deregister mbeans (transmitter, senders)
|
||||
*
|
||||
* @see org.apache.catalina.tribes.ChannelSender#stop()
|
||||
*/
|
||||
@Override
|
||||
public synchronized void stop() {
|
||||
getTransport().disconnect();
|
||||
if (oname != null) {
|
||||
JmxRegistry.getRegistry(channel).unregisterJmx(oname);
|
||||
oname = null;
|
||||
}
|
||||
channel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call transmitter to check for sender socket status
|
||||
*
|
||||
* @see org.apache.catalina.ha.tcp.SimpleTcpCluster#backgroundProcess()
|
||||
*/
|
||||
@Override
|
||||
public void heartbeat() {
|
||||
if (getTransport()!=null) getTransport().keepalive();
|
||||
}
|
||||
|
||||
/**
|
||||
* add new cluster member and create sender ( s. replicationMode) transfer
|
||||
* current properties to sender
|
||||
*
|
||||
* @see org.apache.catalina.tribes.ChannelSender#add(org.apache.catalina.tribes.Member)
|
||||
*/
|
||||
@Override
|
||||
public synchronized void add(Member member) {
|
||||
getTransport().add(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove sender from transmitter. ( deregister mbean and disconnect sender )
|
||||
*
|
||||
* @see org.apache.catalina.tribes.ChannelSender#remove(org.apache.catalina.tribes.Member)
|
||||
*/
|
||||
@Override
|
||||
public synchronized void remove(Member member) {
|
||||
getTransport().remove(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChannel(Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
}
|
||||
154
java/org/apache/catalina/tribes/transport/RxTaskPool.java
Normal file
154
java/org/apache/catalina/tribes/transport/RxTaskPool.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A very simple thread pool class. The pool size is set at
|
||||
* construction time and remains fixed. Threads are cycled
|
||||
* through a FIFO idle queue.
|
||||
* @version 1.0
|
||||
*/
|
||||
public class RxTaskPool {
|
||||
|
||||
final List<AbstractRxTask> idle = new LinkedList<>();
|
||||
final List<AbstractRxTask> used = new LinkedList<>();
|
||||
|
||||
final Object mutex = new Object();
|
||||
boolean running = true;
|
||||
|
||||
private int maxTasks;
|
||||
private int minTasks;
|
||||
|
||||
private final TaskCreator creator;
|
||||
|
||||
|
||||
public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception {
|
||||
// fill up the pool with worker threads
|
||||
this.maxTasks = maxTasks;
|
||||
this.minTasks = minTasks;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
protected void configureTask(AbstractRxTask task) {
|
||||
synchronized (task) {
|
||||
task.setTaskPool(this);
|
||||
// task.setName(task.getClass().getName() + "[" + inc() + "]");
|
||||
// task.setDaemon(true);
|
||||
// task.setPriority(Thread.MAX_PRIORITY);
|
||||
// task.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an idle worker thread, if any. Could return null.
|
||||
* @return a worker
|
||||
*/
|
||||
public AbstractRxTask getRxTask()
|
||||
{
|
||||
AbstractRxTask worker = null;
|
||||
synchronized (mutex) {
|
||||
while ( worker == null && running ) {
|
||||
if (idle.size() > 0) {
|
||||
try {
|
||||
worker = idle.remove(0);
|
||||
} catch (java.util.NoSuchElementException x) {
|
||||
//this means that there are no available workers
|
||||
worker = null;
|
||||
}
|
||||
} else if ( used.size() < this.maxTasks && creator != null) {
|
||||
worker = creator.createRxTask();
|
||||
configureTask(worker);
|
||||
} else {
|
||||
try {
|
||||
mutex.wait();
|
||||
} catch (java.lang.InterruptedException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}//while
|
||||
if ( worker != null ) used.add(worker);
|
||||
}
|
||||
return worker;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return idle.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the worker thread to return itself to the
|
||||
* idle pool.
|
||||
* @param worker The worker
|
||||
*/
|
||||
public void returnWorker (AbstractRxTask worker) {
|
||||
if ( running ) {
|
||||
synchronized (mutex) {
|
||||
used.remove(worker);
|
||||
//if ( idle.size() < minThreads && !idle.contains(worker)) idle.add(worker);
|
||||
if ( idle.size() < maxTasks && !idle.contains(worker)) idle.add(worker); //let max be the upper limit
|
||||
else {
|
||||
worker.setDoRun(false);
|
||||
synchronized (worker){worker.notifyAll();}
|
||||
}
|
||||
mutex.notifyAll();
|
||||
}
|
||||
} else {
|
||||
worker.setDoRun(false);
|
||||
synchronized (worker){worker.notifyAll();}
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxThreads() {
|
||||
return maxTasks;
|
||||
}
|
||||
|
||||
public int getMinThreads() {
|
||||
return minTasks;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
running = false;
|
||||
synchronized (mutex) {
|
||||
Iterator<AbstractRxTask> i = idle.iterator();
|
||||
while ( i.hasNext() ) {
|
||||
AbstractRxTask worker = i.next();
|
||||
returnWorker(worker);
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxTasks(int maxThreads) {
|
||||
this.maxTasks = maxThreads;
|
||||
}
|
||||
|
||||
public void setMinTasks(int minThreads) {
|
||||
this.minTasks = minThreads;
|
||||
}
|
||||
|
||||
public TaskCreator getTaskCreator() {
|
||||
return this.creator;
|
||||
}
|
||||
|
||||
public static interface TaskCreator {
|
||||
public AbstractRxTask createRxTask();
|
||||
}
|
||||
}
|
||||
99
java/org/apache/catalina/tribes/transport/SenderState.java
Normal file
99
java/org/apache/catalina/tribes/transport/SenderState.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public class SenderState {
|
||||
|
||||
public static final int READY = 0;
|
||||
public static final int SUSPECT = 1;
|
||||
public static final int FAILING = 2;
|
||||
|
||||
protected static final ConcurrentMap<Member, SenderState> memberStates = new ConcurrentHashMap<>();
|
||||
|
||||
public static SenderState getSenderState(Member member) {
|
||||
return getSenderState(member, true);
|
||||
}
|
||||
|
||||
public static SenderState getSenderState(Member member, boolean create) {
|
||||
SenderState state = memberStates.get(member);
|
||||
if (state == null && create) {
|
||||
state = new SenderState();
|
||||
SenderState current = memberStates.putIfAbsent(member, state);
|
||||
if (current != null) {
|
||||
state = current;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public static void removeSenderState(Member member) {
|
||||
memberStates.remove(member);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
private volatile int state = READY;
|
||||
|
||||
// ----------------------------------------------------- Constructor
|
||||
|
||||
|
||||
private SenderState() {
|
||||
this(READY);
|
||||
}
|
||||
|
||||
private SenderState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isSuspect() {
|
||||
return (state == SUSPECT) || (state == FAILING);
|
||||
}
|
||||
|
||||
public void setSuspect() {
|
||||
state = SUSPECT;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return state == READY;
|
||||
}
|
||||
|
||||
public void setReady() {
|
||||
state = READY;
|
||||
}
|
||||
|
||||
public boolean isFailing() {
|
||||
return state == FAILING;
|
||||
}
|
||||
|
||||
public void setFailing() {
|
||||
state = FAILING;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Public Properties
|
||||
|
||||
}
|
||||
154
java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
Normal file
154
java/org/apache/catalina/tribes/transport/bio/BioReceiver.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.ReceiverBase;
|
||||
import org.apache.catalina.tribes.transport.RxTaskPool;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public class BioReceiver extends ReceiverBase implements Runnable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioReceiver.class);
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(BioReceiver.class);
|
||||
|
||||
protected ServerSocket serverSocket;
|
||||
|
||||
public BioReceiver() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
super.start();
|
||||
try {
|
||||
setPool(new RxTaskPool(getMaxThreads(),getMinThreads(),this));
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("bioReceiver.threadpool.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
try {
|
||||
getBind();
|
||||
bind();
|
||||
String channelName = "";
|
||||
if (getChannel().getName() != null) channelName = "[" + getChannel().getName() + "]";
|
||||
Thread t = new Thread(this, "BioReceiver" + channelName);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("bioReceiver.start.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractRxTask createRxTask() {
|
||||
return getReplicationThread();
|
||||
}
|
||||
|
||||
protected BioReplicationTask getReplicationThread() {
|
||||
BioReplicationTask result = new BioReplicationTask(this);
|
||||
result.setOptions(getWorkerThreadOptions());
|
||||
result.setUseBufferPool(this.getUseBufferPool());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
setListen(false);
|
||||
try {
|
||||
this.serverSocket.close();
|
||||
} catch (Exception x) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReceiver.socket.closeFailed"), x);
|
||||
}
|
||||
}
|
||||
super.stop();
|
||||
}
|
||||
|
||||
|
||||
protected void bind() throws IOException {
|
||||
// allocate an unbound server socket channel
|
||||
serverSocket = new ServerSocket();
|
||||
// set the port the server channel will listen to
|
||||
//serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
|
||||
bind(serverSocket,getPort(),getAutoBind());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
listen();
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("bioReceiver.run.fail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
public void listen() throws Exception {
|
||||
if (doListen()) {
|
||||
log.warn(sm.getString("bioReceiver.already.started"));
|
||||
return;
|
||||
}
|
||||
setListen(true);
|
||||
|
||||
while ( doListen() ) {
|
||||
Socket socket = null;
|
||||
if ( getTaskPool().available() < 1 ) {
|
||||
if ( log.isWarnEnabled() )
|
||||
log.warn(sm.getString("bioReceiver.threads.busy"));
|
||||
}
|
||||
BioReplicationTask task = (BioReplicationTask)getTaskPool().getRxTask();
|
||||
if ( task == null ) continue; //should never happen
|
||||
try {
|
||||
socket = serverSocket.accept();
|
||||
}catch ( Exception x ) {
|
||||
if ( doListen() ) throw x;
|
||||
}
|
||||
if ( !doListen() ) {
|
||||
task.setDoRun(false);
|
||||
task.serviceSocket(null,null);
|
||||
getExecutor().execute(task);
|
||||
break; //regular shutdown
|
||||
}
|
||||
if ( socket == null ) continue;
|
||||
socket.setReceiveBufferSize(getRxBufSize());
|
||||
socket.setSendBufferSize(getTxBufSize());
|
||||
socket.setTcpNoDelay(getTcpNoDelay());
|
||||
socket.setKeepAlive(getSoKeepAlive());
|
||||
socket.setOOBInline(getOoBInline());
|
||||
socket.setReuseAddress(getSoReuseAddress());
|
||||
socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
|
||||
socket.setSoTimeout(getTimeout());
|
||||
ObjectReader reader = new ObjectReader(socket);
|
||||
task.serviceSocket(socket,reader);
|
||||
getExecutor().execute(task);
|
||||
}//while
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.bio;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.io.BufferPool;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.ListenCallback;
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.Constants;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A worker thread class which can drain channels and echo-back the input. Each
|
||||
* instance is constructed with a reference to the owning thread pool object.
|
||||
* When started, the thread loops forever waiting to be awakened to service the
|
||||
* channel associated with a SelectionKey object. The worker is tasked by
|
||||
* calling its serviceChannel() method with a SelectionKey object. The
|
||||
* serviceChannel() method stores the key reference in the thread object then
|
||||
* calls notify() to wake it up. When the channel has been drained, the worker
|
||||
* thread returns itself to its parent pool.
|
||||
*/
|
||||
public class BioReplicationTask extends AbstractRxTask {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioReplicationTask.class);
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(BioReplicationTask.class);
|
||||
|
||||
protected Socket socket;
|
||||
protected ObjectReader reader;
|
||||
|
||||
public BioReplicationTask (ListenCallback callback) {
|
||||
super(callback);
|
||||
}
|
||||
|
||||
// loop forever waiting for work to do
|
||||
@Override
|
||||
public synchronized void run()
|
||||
{
|
||||
if ( socket == null ) return;
|
||||
try {
|
||||
drainSocket();
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("bioReplicationTask.unable.service"), x);
|
||||
}finally {
|
||||
try {
|
||||
socket.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.socket.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.reader.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
reader = null;
|
||||
socket = null;
|
||||
}
|
||||
// done, ready for more, return to pool
|
||||
if ( getTaskPool() != null ) getTaskPool().returnWorker (this);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void serviceSocket(Socket socket, ObjectReader reader) {
|
||||
this.socket = socket;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
protected void execute(ObjectReader reader) throws Exception{
|
||||
int pkgcnt = reader.count();
|
||||
|
||||
if ( pkgcnt > 0 ) {
|
||||
ChannelMessage[] msgs = reader.execute();
|
||||
for ( int i=0; i<msgs.length; i++ ) {
|
||||
/**
|
||||
* Use send ack here if you want to ack the request to the remote
|
||||
* server before completing the request
|
||||
* This is considered an asynchronous request
|
||||
*/
|
||||
if (ChannelData.sendAckAsync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
|
||||
try {
|
||||
//process the message
|
||||
getCallback().messageDataReceived(msgs[i]);
|
||||
/**
|
||||
* Use send ack here if you want the request to complete on this
|
||||
* server before sending the ack to the remote server
|
||||
* This is considered a synchronized request
|
||||
*/
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
|
||||
}catch ( Exception x ) {
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.FAIL_ACK_COMMAND);
|
||||
log.error(sm.getString("bioReplicationTask.messageDataReceived.error"),x);
|
||||
}
|
||||
if ( getUseBufferPool() ) {
|
||||
BufferPool.getBufferPool().returnBuffer(msgs[i].getMessage());
|
||||
msgs[i].setMessage(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual code which drains the channel associated with
|
||||
* the given key. This method assumes the key has been
|
||||
* modified prior to invocation to turn off selection
|
||||
* interest in OP_READ. When this method completes it
|
||||
* re-enables OP_READ and calls wakeup() on the selector
|
||||
* so the selector will resume watching this channel.
|
||||
* @throws Exception IO exception or execute exception
|
||||
*/
|
||||
protected void drainSocket() throws Exception {
|
||||
InputStream in = socket.getInputStream();
|
||||
// loop while data available, channel is non-blocking
|
||||
byte[] buf = new byte[1024];
|
||||
int length = in.read(buf);
|
||||
while ( length >= 0 ) {
|
||||
int count = reader.append(buf,0,length,true);
|
||||
if ( count > 0 ) execute(reader);
|
||||
length = in.read(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a reply-acknowledgment (6,2,3)
|
||||
* @param command The command to write
|
||||
*/
|
||||
protected void sendAck(byte[] command) {
|
||||
try {
|
||||
OutputStream out = socket.getOutputStream();
|
||||
out.write(command);
|
||||
out.flush();
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("ACK sent to " + socket.getPort());
|
||||
}
|
||||
} catch ( java.io.IOException x ) {
|
||||
log.warn(sm.getString("bioReplicationTask.unable.sendAck", x.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
setDoRun(false);
|
||||
try {
|
||||
socket.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.socket.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("bioReplicationTask.reader.closeFailed"), e);
|
||||
}
|
||||
}
|
||||
reader = null;
|
||||
socket = null;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
281
java/org/apache/catalina/tribes/transport/bio/BioSender.java
Normal file
281
java/org/apache/catalina/tribes/transport/bio/BioSender.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.catalina.tribes.RemoteProcessException;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.Constants;
|
||||
import org.apache.catalina.tribes.transport.SenderState;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Send cluster messages with only one socket. Ack and keep Alive Handling is
|
||||
* supported
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
* @since 5.5.16
|
||||
*/
|
||||
public class BioSender extends AbstractSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BioSender.class);
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(BioSender.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* current sender socket
|
||||
*/
|
||||
private Socket socket = null;
|
||||
private OutputStream soOut = null;
|
||||
private InputStream soIn = null;
|
||||
|
||||
protected final XByteBuffer ackbuf =
|
||||
new XByteBuffer(Constants.ACK_COMMAND.length, true);
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Constructor
|
||||
|
||||
public BioSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Connect other cluster member receiver
|
||||
* @see org.apache.catalina.tribes.transport.DataSender#connect()
|
||||
*/
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
openSocket();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* disconnect and close socket
|
||||
*
|
||||
* @see org.apache.catalina.tribes.transport.DataSender#disconnect()
|
||||
*/
|
||||
@Override
|
||||
public void disconnect() {
|
||||
boolean connect = isConnected();
|
||||
closeSocket();
|
||||
if (connect) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.disconnect", getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message.
|
||||
* @param data The data to send
|
||||
* @param waitForAck Wait for an ack
|
||||
* @throws IOException An IO error occurred sending the 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("bioSender.send.again", getAddress().getHostAddress(),Integer.valueOf(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder("DataSender[(");
|
||||
buf.append(super.toString()).append(")");
|
||||
buf.append(getAddress()).append(":").append(getPort()).append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Protected Methods
|
||||
|
||||
/**
|
||||
* Open real socket and set time out when waitForAck is enabled
|
||||
* is socket open return directly.
|
||||
* @throws IOException Error opening socket
|
||||
*/
|
||||
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("bioSender.openSocket", getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
} catch (IOException ex1) {
|
||||
SenderState.getSenderState(getDestination()).setSuspect();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.openSocket.failure",getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)), ex1);
|
||||
throw ex1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Close socket.
|
||||
*
|
||||
* @see #disconnect()
|
||||
*/
|
||||
protected void closeSocket() {
|
||||
if(isConnected()) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException x) {
|
||||
// Ignore
|
||||
} finally {
|
||||
socket = null;
|
||||
soOut = null;
|
||||
soIn = null;
|
||||
}
|
||||
}
|
||||
setRequestCount(0);
|
||||
setConnected(false);
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("bioSender.closeSocket",getAddress().getHostAddress(), Integer.valueOf(getPort()), Long.valueOf(0)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* After successful sending update stats
|
||||
*
|
||||
* 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
|
||||
* @param reconnect Do a reconnect (close socket then reopen)
|
||||
* @param waitForAck Wait for an acknowledgement
|
||||
* @throws IOException IO error writing data
|
||||
* @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();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Acknowledgement from other server.
|
||||
* FIXME Please, not wait only for three characters, better control that the wait ack message is correct.
|
||||
* @throws IOException An IO error occurred
|
||||
*/
|
||||
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("bioSender.ack.eof",getAddress(), Integer.valueOf(socket.getLocalPort())));
|
||||
else throw new IOException(sm.getString("bioSender.ack.wrong",getAddress(), Integer.valueOf(socket.getLocalPort())));
|
||||
} else if ( failAckReceived && getThrowOnFailedAck()) {
|
||||
throw new RemoteProcessException(sm.getString("bioSender.fail.AckReceived"));
|
||||
}
|
||||
} catch (IOException x) {
|
||||
String errmsg = sm.getString("bioSender.ack.missing", getAddress(), Integer.valueOf(socket.getLocalPort()), Long.valueOf(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.already.started=ServerSocket already started
|
||||
bioReceiver.run.fail=Unable to run replication listener.
|
||||
bioReceiver.socket.closeFailed=Failed to close socket
|
||||
bioReceiver.start.fail=Unable to start cluster receiver
|
||||
bioReceiver.threadpool.fail=ThreadPool cannot be initialized. Listener not started
|
||||
bioReceiver.threads.busy=All BIO server replication threads are busy, unable to handle more requests until a thread is freed up.
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=Error thrown from messageDataReceived.
|
||||
bioReplicationTask.reader.closeFailed=Failed to close reader
|
||||
bioReplicationTask.socket.closeFailed=Failed to close socket
|
||||
bioReplicationTask.unable.sendAck=Unable to send ACK back through channel, channel disconnected?: [{0}]
|
||||
bioReplicationTask.unable.service=Unable to service bio socket
|
||||
|
||||
bioSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again.
|
||||
bioSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}]
|
||||
bioSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer})
|
||||
bioSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer})
|
||||
bioSender.fail.AckReceived=Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer})
|
||||
bioSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer})
|
||||
bioSender.send.again=Send data again to [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.retrieve.fail=Unable to retrieve a sender from the sender pool
|
||||
pooledMultiSender.unable.retrieve.sender=Unable to retrieve a data sender, time out([{0}] ms) error.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.socket.closeFailed=Socket konnte nicht geschlossen werden
|
||||
|
||||
bioSender.send.again=Sende Daten erneut an [{0}:{1,number,integer}]
|
||||
@@ -0,0 +1,27 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.socket.closeFailed=Fallo al cerrar el socket
|
||||
|
||||
bioReplicationTask.reader.closeFailed=Fallo al cerrar el lector
|
||||
|
||||
bioSender.ack.eof=EOF alcanzado en puerto local [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=No puedo leer reconocimiento desde [{0}:{1,number,integer}] en {2,number,integer} ms. Desconectando conector e intentando otra vez.
|
||||
bioSender.ack.wrong=Falta ACK correcto tras 10 bytes leídos en puerto local [{0}:{1,number,integer}]
|
||||
bioSender.closeSocket=El remitente cerró el conector con [{0}:{1,number,integer}] (contador de cierre {2,number,integer})
|
||||
bioSender.disconnect=Remitente desconectado de [{0}:{1,number,integer}] (contador de desconexión {2,number,integer})
|
||||
bioSender.openSocket=Remitente abrió conector con [{0}:{1,number,integer}] (contador de apertura {2,number,integer})
|
||||
bioSender.openSocket.failure=¡No pude abrir conector de remitente [{0}:{1,number,integer}]! (contador de fallo de apertura {2,number,integer})
|
||||
bioSender.send.again=Enviar datos de nuevo a [{0}:{1,number,integer}]
|
||||
@@ -0,0 +1,40 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.already.started=Le ServerSocket a déjà démarré
|
||||
bioReceiver.run.fail=Impossible d'exécuter l’écouteur de réplication
|
||||
bioReceiver.socket.closeFailed=Echec de fermeture de la connection
|
||||
bioReceiver.start.fail=Impossible de démarrer le receveur du cluster
|
||||
bioReceiver.threadpool.fail=Le ThreadPool n'a pas pu être initialisé, l'écouteur n'a pas démarré
|
||||
bioReceiver.threads.busy=Tous les fils d'exécution du serveur de réplication sont occupés, impossible de traiter plus de requêtes avant qu'un ne se libère
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=Erreur lors de messageDataReceived
|
||||
bioReplicationTask.reader.closeFailed=Echec de fermeture du lecteur
|
||||
bioReplicationTask.socket.closeFailed=Ecech de la fermeture du socket
|
||||
bioReplicationTask.unable.sendAck=Impossible de renvoyer une confirmation par le canal, il peut être déconnecté: [{0}]
|
||||
bioReplicationTask.unable.service=Incapable de traiter un socket BIO
|
||||
|
||||
bioSender.ack.eof=EOF recontré sur le port local [{0}:{1,number,integer}]
|
||||
bioSender.ack.missing=Incapable de lire l'accusé de réception de [{0}:{1,number,integer}] en {2,number,integer] ms. Déconnexion de la socket et nouvel tentative.
|
||||
bioSender.ack.wrong=Il manque un ACK correct après la lecture de 10 octets sur le port local [{0}]: {1,number,integer}
|
||||
bioSender.closeSocket=Sender fermeture du socket vers [{0}:{1,number,integer}] (nombre de fermetures {2,number,integer})
|
||||
bioSender.disconnect=L'envoyeur s'est déconnecté de [{0}:{1,number,integer}] (nombre de déconnections {2,number,integer})
|
||||
bioSender.fail.AckReceived=Reçu une confirmation en échec: org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=L''expéditeur ouvre une socket vers [{0}:{1,number,integer}] ({2,number,integer} sockets ouvertes})
|
||||
bioSender.openSocket.failure=Echec d'ouverture du socket d'envoi [{0}:{1,number,integer} (nombre d'écecs d'ouverture {2,number,integer})
|
||||
bioSender.send.again=Envoyer les données à nouveau à [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.retrieve.fail=Impossible d'obtenir un envoyeur à partir du pool
|
||||
pooledMultiSender.unable.retrieve.sender=Impossible de récupéré un expéditeur de données. délai d''attente ([{0}] ms) dépassé
|
||||
@@ -0,0 +1,40 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.already.started=サーバーソケットはすでに開始しています。
|
||||
bioReceiver.run.fail=レプリケーションリスナーを実行できません。
|
||||
bioReceiver.socket.closeFailed=ソケットを切断できませんでした。
|
||||
bioReceiver.start.fail=クラスタレシーバを起動できません
|
||||
bioReceiver.threadpool.fail=スレッドプールを初期化できません。リスナーを開始しませんでした。
|
||||
bioReceiver.threads.busy=全ての BIO サーバーレプリケーションスレッドがビジー状態です。スレッドが解放されるまで新しいリクエストは処理できません。
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=messageDataReceivedから送出されたエラー
|
||||
bioReplicationTask.reader.closeFailed=Readerを閉じることに失敗しました。
|
||||
bioReplicationTask.socket.closeFailed=ソケットクロースに失敗
|
||||
bioReplicationTask.unable.sendAck=チャンネルへACKを送信できません。チャンネルが切断されているかもしれません: [{0}]
|
||||
bioReplicationTask.unable.service=bio ソケットを開始できません。
|
||||
|
||||
bioSender.ack.eof=ローカルポート[{0}:{1、number、integer}]でEOF
|
||||
bioSender.ack.missing=[{0}:{1,number,integer}] から [{2,number,integer}] ms 以内に確認応答(ACK)を読み取ることができませんでした。ソケットを切断して再試行してください。
|
||||
bioSender.ack.wrong=ローカルポート [{0}:{1,number,integer}] から 10 バイト読み込んだ後に正しい ACK が見つかりません。
|
||||
bioSender.closeSocket=[{0}:{1、number、integer}](close count {2、number、integer})に送信側のクローズソケット
|
||||
bioSender.disconnect=[{0}:{1,number,integer}](切断カウント{2,number,integer})からのSender切断
|
||||
bioSender.fail.AckReceived=失敗したACK:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATAの受信
|
||||
bioSender.openSocket=Sender オブジェクトが [{0}:{1,number,integer}] (接続数 {2,number,integer}) へソケット接続を開始しました。
|
||||
bioSender.openSocket.failure=開いているSender側ソケット[{0}:{1,number,integer}]失敗! (オープン失敗カウント{2,number,integer}))
|
||||
bioSender.send.again=[{0}:{1,number,integer}] へデータを再送します。
|
||||
|
||||
pooledMultiSender.retrieve.fail=SenderプールからSenderを取得できません。
|
||||
pooledMultiSender.unable.retrieve.sender=データSenderを取得できません。タイムアウト([{0}] ms)エラー。
|
||||
@@ -0,0 +1,40 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.already.started=ServerSocket이 이미 시작되었습니다.
|
||||
bioReceiver.run.fail=복제 리스너를 실행할 수 없습니다.
|
||||
bioReceiver.socket.closeFailed=소켓을 닫지 못했습니다.
|
||||
bioReceiver.start.fail=클러스터 Receiver를 시작할 수 없습니다.
|
||||
bioReceiver.threadpool.fail=쓰레드풀이 초기화될 수 없습니다. 리스너가 시작되지 않았습니다.
|
||||
bioReceiver.threads.busy=모든 BIO 서버 복제 쓰레드들이 작업 중입니다. 유휴 쓰레드가 하나라도 생기기 전에는, 더 이상 요청을 처리할 수 없습니다.
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=messageDataReceived로부터 오류 발생
|
||||
bioReplicationTask.reader.closeFailed=Reader를 닫지 못했습니다.
|
||||
bioReplicationTask.socket.closeFailed=소켓을 닫지 못했습니다.
|
||||
bioReplicationTask.unable.sendAck=채널을 통해 ACK을 되돌려 보낼 수 없습니다. 채널의 연결이 끊겼나요?: [{0}]
|
||||
bioReplicationTask.unable.service=BIO 소켓을 서비스할 수 없습니다.
|
||||
|
||||
bioSender.ack.eof=로컬 포트 [{0}:{1,number,integer}]에서 EOF에 도달했습니다.
|
||||
bioSender.ack.missing=[{0}:{1,number,integer}](으)로부터 ACK을 {2,number,integer} 밀리초 내에 읽을 수 없습니다. 소켓 연결을 끊고, 다시 시도합니다.
|
||||
bioSender.ack.wrong=10 바이트들을 로컬 포트 [{0}]에서 읽고 난 후 올바른 ACK를 받지 못했습니다: {1,number,integer}]
|
||||
bioSender.closeSocket=Sender가 소켓 닫기 메시지를 [{0}:{1,number,integer}]에 전송합니다. (전송 회수: {2,number,integer})
|
||||
bioSender.disconnect=Sender가 [{0}:{1,number,integer}](으)로부터 연결을 끊습니다. (연결 끊기 회수: {2,number,integer})
|
||||
bioSender.fail.AckReceived=실패한 ACK을 받았습니다: org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=Sender가 [{0}:{1,number,integer}]을(를) 향해 소켓을 엽니다. (연 소켓 개수: {2,number,integer})
|
||||
bioSender.openSocket.failure=Sender 소켓 [{0}:{1,number,integer}]을(를) 열지 못했습니다! (열기 실패 회수: {2,number,integer})
|
||||
bioSender.send.again=데이터를 [{0}:{1,number,integer}](으)로 다시 전송합니다.
|
||||
|
||||
pooledMultiSender.retrieve.fail=Sender 풀로부터 sender를 검색할 수 없습니다.
|
||||
pooledMultiSender.unable.retrieve.sender=데이터 sender를 조회할 수 없습니다. 제한 시간 초과 ([{0}] 밀리초) 오류 발생.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioSender.send.again=Послать данные ещё раз в [{0}:{1,number,integer}]
|
||||
@@ -0,0 +1,32 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bioReceiver.socket.closeFailed=socket.关闭失败
|
||||
bioReceiver.threadpool.fail=线程池可以初始化。侦听器未启动
|
||||
|
||||
bioReplicationTask.messageDataReceived.error=错误抛出,来自于消息数据收到
|
||||
bioReplicationTask.reader.closeFailed=无法关闭reader
|
||||
bioReplicationTask.socket.closeFailed=无法关闭套接字
|
||||
bioReplicationTask.unable.service=不能服务bio套接字
|
||||
|
||||
bioSender.ack.eof=在本地端口[{0}:{1,number,integer}]达到EOF
|
||||
bioSender.ack.missing=不能读确认表格:[{0}] {1,number,integer}] in {2,number,integer} 毫秒, 失去socket连接, 重试连接.
|
||||
bioSender.ack.wrong=在本地端口[{0}:{1,number,integer}]读取10个字节后丢失正确的ACK
|
||||
bioSender.closeSocket=发件人关闭套接字到[{0}:{1,number,integer}](关闭计数{2,数字,整数})
|
||||
bioSender.fail.AckReceived=收到一个失败的 ack ):org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
bioSender.openSocket=发件人打开套接字到[{0}:{1,number,integer}](打开计数{2,数字,整数})
|
||||
bioSender.send.again=再次发送数据到 [{0}:{1,number,integer}]
|
||||
|
||||
pooledMultiSender.unable.retrieve.sender=无法获取数据发送器,超时([{0}] ms)错误
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.MultiPointSender;
|
||||
|
||||
public class MultipointBioSender extends AbstractSender implements MultiPointSender {
|
||||
public MultipointBioSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
protected final HashMap<Member, BioSender> bioSenders = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
|
||||
byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
|
||||
BioSender[] senders = setupForSend(destination);
|
||||
ChannelException cx = null;
|
||||
for ( int i=0; i<senders.length; i++ ) {
|
||||
try {
|
||||
senders[i].sendMessage(data,(msg.getOptions()&Channel.SEND_OPTIONS_USE_ACK)==Channel.SEND_OPTIONS_USE_ACK);
|
||||
} catch (Exception x) {
|
||||
if (cx == null) cx = new ChannelException(x);
|
||||
cx.addFaultyMember(destination[i],x);
|
||||
}
|
||||
}
|
||||
if (cx!=null ) throw cx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected BioSender[] setupForSend(Member[] destination) throws ChannelException {
|
||||
ChannelException cx = null;
|
||||
BioSender[] result = new BioSender[destination.length];
|
||||
for ( int i=0; i<destination.length; i++ ) {
|
||||
try {
|
||||
BioSender sender = bioSenders.get(destination[i]);
|
||||
if (sender == null) {
|
||||
sender = new BioSender();
|
||||
AbstractSender.transferProperties(this,sender);
|
||||
sender.setDestination(destination[i]);
|
||||
bioSenders.put(destination[i], sender);
|
||||
}
|
||||
result[i] = sender;
|
||||
if (!result[i].isConnected() ) result[i].connect();
|
||||
result[i].keepalive();
|
||||
}catch (Exception x ) {
|
||||
if ( cx== null ) cx = new ChannelException(x);
|
||||
cx.addFaultyMember(destination[i],x);
|
||||
}
|
||||
}
|
||||
if ( cx!=null ) throw cx;
|
||||
else return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
//do nothing, we connect on demand
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
|
||||
private synchronized void close() throws ChannelException {
|
||||
ChannelException x = null;
|
||||
Object[] members = bioSenders.keySet().toArray();
|
||||
for (int i=0; i<members.length; i++ ) {
|
||||
Member mbr = (Member)members[i];
|
||||
try {
|
||||
BioSender sender = bioSenders.get(mbr);
|
||||
sender.disconnect();
|
||||
}catch ( Exception e ) {
|
||||
if ( x == null ) x = new ChannelException(e);
|
||||
x.addFaultyMember(mbr,e);
|
||||
}
|
||||
bioSenders.remove(mbr);
|
||||
}
|
||||
if ( x != null ) throw x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Member member) {
|
||||
// NO-OP
|
||||
// Members are defined by the array of members specified in the call to
|
||||
// sendMessage()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Member member) {
|
||||
//disconnect senders
|
||||
BioSender sender = bioSenders.remove(member);
|
||||
if ( sender != null ) sender.disconnect();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect() {
|
||||
try {
|
||||
close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
setConnected(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
disconnect();
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean keepalive() {
|
||||
boolean result = false;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<Member,BioSender>[] entries = bioSenders.entrySet().toArray(new Map.Entry[bioSenders.size()]);
|
||||
for ( int i=0; i<entries.length; i++ ) {
|
||||
BioSender sender = entries[i].getValue();
|
||||
if ( sender.keepalive() ) {
|
||||
bioSenders.remove(entries[i].getKey());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport.bio;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.DataSender;
|
||||
import org.apache.catalina.tribes.transport.MultiPointSender;
|
||||
import org.apache.catalina.tribes.transport.PooledSender;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
|
||||
public class PooledMultiSender extends PooledSender {
|
||||
|
||||
protected static final StringManager sm = StringManager.getManager(PooledMultiSender.class);
|
||||
|
||||
public PooledMultiSender() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
|
||||
MultiPointSender sender = null;
|
||||
try {
|
||||
sender = (MultiPointSender)getSender();
|
||||
if (sender == null) {
|
||||
ChannelException cx = new ChannelException(sm.getString(
|
||||
"pooledMultiSender.unable.retrieve.sender", Long.toString(getMaxWait())));
|
||||
for (int i = 0; i < destination.length; i++)
|
||||
cx.addFaultyMember(destination[i], new NullPointerException(sm.getString("pooledMultiSender.retrieve.fail")));
|
||||
throw cx;
|
||||
} else {
|
||||
sender.sendMessage(destination, msg);
|
||||
}
|
||||
sender.keepalive();
|
||||
}finally {
|
||||
if ( sender != null ) returnSender(sender);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSender getNewDataSender() {
|
||||
MultipointBioSender sender = new MultipointBioSender();
|
||||
AbstractSender.transferProperties(this,sender);
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.alreadyStarted=ServerSocketChannel already started
|
||||
nioReceiver.cleanup.fail=Unable to cleanup on selector close
|
||||
nioReceiver.clientDisconnect=Replication client disconnected, error when polling key. Ignoring client.
|
||||
nioReceiver.requestError=Unable to process request in NioReceiver
|
||||
nioReceiver.run.fail=Unable to run replication listener
|
||||
nioReceiver.start.fail=Unable to start cluster receiver
|
||||
nioReceiver.stop.fail=Unable to close cluster receiver selector
|
||||
nioReceiver.stop.threadRunning=The NioReceiver thread did not stop in a timely manner. Errors may be observed when the selector is closed.
|
||||
nioReceiver.threadpool.fail=ThreadPool cannot be initialized. Listener not started.
|
||||
nioReceiver.threadsExhausted=Channel key is registered, but has had no interest ops for the last [{0}] ms. (cancelled: [{1}]):[{2}] last access:[{3}] Possible cause: all threads used, perform thread dump
|
||||
|
||||
nioReplicationTask.error.register.key=Error registering key for read:[{0}]
|
||||
nioReplicationTask.exception.drainChannel=Exception caught in TcpReplicationThread.drainChannel.
|
||||
nioReplicationTask.process.clusterMsg.failed=Processing of cluster message failed.
|
||||
nioReplicationTask.unable.ack=Unable to send ACK back through channel, channel disconnected?: [{0}]
|
||||
nioReplicationTask.unable.drainChannel.ioe=IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed[{0}].
|
||||
|
||||
nioSender.already.connected=NioSender is already in connected state.
|
||||
nioSender.datagram.already.established=Datagram channel has already been established. Connection might be in progress.
|
||||
nioSender.key.inValid=Key is not valid, it must have been cancelled.
|
||||
nioSender.not.connected=NioSender is not connected, this should not occur.
|
||||
nioSender.receive.failedAck=Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
nioSender.sender.disconnected=Sender has been disconnected, can't process selection key.
|
||||
nioSender.socketChannel.already.established=Socket channel has already been established. Connection might be in progress.
|
||||
nioSender.unable.disconnect=Unable to disconnect NioSender. msg=[{0}]
|
||||
nioSender.unable.receive.ack=Unable to receive an ack message. EOF on socket channel has been reached.
|
||||
nioSender.unknown.state=Data is in unknown state. readyOps=[{0}]
|
||||
|
||||
parallelNioSender.error.keepalive=Error during keepalive test for sender:[{0}]
|
||||
parallelNioSender.operation.timedout=Operation has timed out([{0}] ms.).
|
||||
parallelNioSender.send.fail=Member send is failing for:[{0}] ; Setting to suspect.
|
||||
parallelNioSender.send.fail.retrying=Member send is failing for:[{0}] ; Setting to suspect and retrying.
|
||||
parallelNioSender.send.failed=Parallel NIO send failed.
|
||||
parallelNioSender.sendFailed.attempt=Send failed, attempt:[{0}] max:[{1}]
|
||||
parallelNioSender.sender.disconnected.notRetry=Not retrying send for:[{0}]; Sender is disconnected.
|
||||
parallelNioSender.sender.disconnected.sendFailed=Send failed, and sender is disconnected. Not retrying.
|
||||
parallelNioSender.unable.setup.NioSender=Unable to setup NioSender.
|
||||
|
||||
pooledParallelSender.sender.disconnected=Sender not connected.
|
||||
pooledParallelSender.unable.open=Unable to open NIO selector.
|
||||
pooledParallelSender.unable.retrieveSender=Unable to retrieve a sender from the sender pool
|
||||
pooledParallelSender.unable.retrieveSender.timeout=Unable to retrieve a data sender, time out([{0}] ms) error.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.start.fail=Cluster-Empfänger konnte nicht gestartet werden
|
||||
nioReceiver.stop.fail=Kann den Cluster Receiver Selektor nicht schliessen
|
||||
nioReceiver.threadpool.fail=ThreadPool kann nicht initialisiert werden. Der Listener wird nicht gestartet.
|
||||
|
||||
nioReplicationTask.process.clusterMsg.failed=Verarbeitung der Cluster Nachricht fehlgeschlagen.
|
||||
|
||||
nioSender.unknown.state=Daten sind in unbekanntem Zustand. readyOps=[{0}]
|
||||
|
||||
pooledParallelSender.sender.disconnected=Sender nicht verbunden
|
||||
@@ -0,0 +1,34 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.cleanup.fail=Imposible hacer limpieza en el cierre del selector
|
||||
nioReceiver.start.fail=Incapaz de iniciar el recividor del cluster
|
||||
nioReceiver.stop.fail=No fue posible cerrar el selector de recepción del cluster
|
||||
nioReceiver.threadpool.fail=ThreadPool no pudo ser inicializado. Escuchador no iniciado.\n
|
||||
|
||||
nioReplicationTask.error.register.key=Error al registrar la llave para lectura:[{0}]
|
||||
nioReplicationTask.process.clusterMsg.failed=Fallo al procesar el mensaje del cluster
|
||||
nioReplicationTask.unable.ack=No se pudo devolver el ACK a travez del canal. Esta el canal desconectado?: [{0}]\n
|
||||
|
||||
nioSender.not.connected=El NioSender no esta conectado, esto no deberia ocurrir.\n
|
||||
nioSender.unknown.state=Los Datos estan en un estado desconocido. readyOps=[{0}]
|
||||
|
||||
parallelNioSender.send.fail.retrying=El envió de miembro esta fallando por:[{0}] ; Fijándolo como sospechoso y reintentando.
|
||||
parallelNioSender.send.failed=Fallo al enviar NIO paralelo.
|
||||
parallelNioSender.sendFailed.attempt=Fallo de envío, intento:[{0}] máximo:[{1}]\n
|
||||
parallelNioSender.sender.disconnected.sendFailed=Envio fallido, y el remitente esta desconctado. No intentando nuevamente.\n
|
||||
|
||||
pooledParallelSender.sender.disconnected=El remitente no esta conectado
|
||||
pooledParallelSender.unable.retrieveSender=Incapaz de recuperar el enviador desde el pool de enviadores
|
||||
@@ -0,0 +1,57 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.alreadyStarted=ServerSocketChannel est déjà démarré
|
||||
nioReceiver.cleanup.fail=Impossible de nettoyer lors de la fermeture du sélecteur
|
||||
nioReceiver.clientDisconnect=Le client de réplication est déconnecté, erreur lors du "polling" de clé. Le client est ignoré.
|
||||
nioReceiver.requestError=Impossible de traiter la requête dans NioReceiver
|
||||
nioReceiver.run.fail=Impossible d'exécuter l'écouteur de réplication
|
||||
nioReceiver.start.fail=Incapable de démarrer le récepteur de cluster
|
||||
nioReceiver.stop.fail=Incapable de femer le sélecteur de récepteur de cluster ("cluster receiver selector")
|
||||
nioReceiver.stop.threadRunning=Le thread NioReceiver ne s'est pas arrêté suffisamment rapidement, des erreurs peuvent se produire lorsque le sélecteur sera fermé
|
||||
nioReceiver.threadpool.fail=Le ThreadPool n'a pas pu être initialisé. Le Listener n'a pas démarré.
|
||||
nioReceiver.threadsExhausted=La clé du canal est enregistrée mais n''a pas reçue d''opérations qui l''intéressaient depuis [{0}] ms (annulé: [{1}]):[{2}] dernier accès: [{3}] cause possible: tous les threads sont utilisés, effectuez un dump des threads
|
||||
|
||||
nioReplicationTask.error.register.key=Erreur lors de l''enregistrement de la clé en lecture: [{0}]
|
||||
nioReplicationTask.exception.drainChannel=Erreur rencontrée dans TcpReplicationThread.drainChannel
|
||||
nioReplicationTask.process.clusterMsg.failed=Le traitement du message du cluster a échoué
|
||||
nioReplicationTask.unable.ack=Impossible d''envoyer un ACK réponse par le canal, le canal peut avoir été déconnecté: [{0}]
|
||||
nioReplicationTask.unable.drainChannel.ioe=IOException pendant le traitement de la réplication, impossible de drainer le canal, cause probable: le socket gardé actif a été fermé [{0}]
|
||||
|
||||
nioSender.already.connected=NioSender est déjà dans l'état connecté
|
||||
nioSender.datagram.already.established=Le canal de datagramme a déjà été établi, une connection peut être déjà en cours
|
||||
nioSender.key.inValid=La clé est invalide, elle doit avoir été annulée
|
||||
nioSender.not.connected=NioSender n'est pas connecté, cela ne devrait jamais arriver
|
||||
nioSender.receive.failedAck=Réception d'un échec de confirmation:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
nioSender.sender.disconnected=L'envoyeur s'est déconnecté, impossible d'envoyer la clé de sélection
|
||||
nioSender.socketChannel.already.established=Le canal du socket a déjà été établi, la connection est peut-être déjà en cours
|
||||
nioSender.unable.disconnect=Impossible de déconnecter le NioSender, msg=[{0}]
|
||||
nioSender.unable.receive.ack=Impossible de recevoir un message de confirmation, le canal a rencontré l'EOF
|
||||
nioSender.unknown.state=Les données sont dans un état inconnu. readyOps=[{0}]
|
||||
|
||||
parallelNioSender.error.keepalive=Erreur lors du test de temps d''attente pour l''expéditeur [{0}]
|
||||
parallelNioSender.operation.timedout=L''opération a dépassé le temps imparti ([{0}] ms)
|
||||
parallelNioSender.send.fail=L''envoi d''un membre a échoué pour [{0}], le membre est considéré suspect
|
||||
parallelNioSender.send.fail.retrying=L''envoi au membre[{0}] ne fonctionne pas ; Marqué comme suspect et nouvel essai.
|
||||
parallelNioSender.send.failed=L'envoi NIO en parallèle a échoué
|
||||
parallelNioSender.sendFailed.attempt=Echec de l''envoi, tentative: [{0}] maximum:[{1}]
|
||||
parallelNioSender.sender.disconnected.notRetry=Pas de réessai d''envoi de [{0}], l''expéditeur s''est déconnecté
|
||||
parallelNioSender.sender.disconnected.sendFailed=L'envoi a échoué et l'envoyeur est déconnecté, pas de nouvel essai
|
||||
parallelNioSender.unable.setup.NioSender=Impossible d'installer un NioSender
|
||||
|
||||
pooledParallelSender.sender.disconnected=Emetteur non connecté
|
||||
pooledParallelSender.unable.open=Impossible d'ouvrir le sélecteur NIO
|
||||
pooledParallelSender.unable.retrieveSender=Impossible d'obtenir un envoyeur depuis le pool
|
||||
pooledParallelSender.unable.retrieveSender.timeout=Impossible d''obtenir un expéditeur de données, temps d''attente dépassé ([{0}] ms)
|
||||
@@ -0,0 +1,57 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.alreadyStarted=ServerSocketChannel は既に開始しています。
|
||||
nioReceiver.cleanup.fail=セレクターの切断と後始末が失敗しました。
|
||||
nioReceiver.clientDisconnect=レプリケーションクライアントが切断されました。ポーリングキーでエラーが発生しました。 クライアントを無視します。
|
||||
nioReceiver.requestError=NioReceiverでリクエストを処理できません
|
||||
nioReceiver.run.fail=レプリケーションリスナーを実行できません。
|
||||
nioReceiver.start.fail=クラスタレシーバを起動出来ません
|
||||
nioReceiver.stop.fail=クラスターレシーバーのセレクタを切断できませんでした。
|
||||
nioReceiver.stop.threadRunning=NioReceiver スレッドは時間内に停止できませんでした。Selectorを切断するときに異常を検出した可能性があります。
|
||||
nioReceiver.threadpool.fail=ThreadPool を初期化できません。リスナーを開始しませんでした。
|
||||
nioReceiver.threadsExhausted=チャネルキーは登録されていますが、最後の[{0}]ミリ秒間はinterest ops がありませんでした。 (キャンセル {1}]):[{2}]最終アクセス:[{3}]考えられる原因:すべてのスレッドが使用され、スレッドダンプを実行します。
|
||||
|
||||
nioReplicationTask.error.register.key=読み取り用のキーを登録するときに異常が発生しました: [{0}]
|
||||
nioReplicationTask.exception.drainChannel=TcpReplicationThread.drainChannelで例外をキャッチしました。
|
||||
nioReplicationTask.process.clusterMsg.failed=クラスターメッセージを処理できませんでした。
|
||||
nioReplicationTask.unable.ack=チャンネルから ACK を送信できません。切断されている可能性があります。: [{0}]
|
||||
nioReplicationTask.unable.drainChannel.ioe=レプリケーションワーカーのIOException、チャネルを排除できません。 考えられる原因:キープアライブソケットが切断[{0}]。
|
||||
|
||||
nioSender.already.connected=NioSenderはすでに接続された状態です。
|
||||
nioSender.datagram.already.established=データグラムチャネルはすでに確立されています。 コネクションが進行中である可能性があります。
|
||||
nioSender.key.inValid=キーは無効です。キャンセルされている必要があります。
|
||||
nioSender.not.connected=NioSender は接続していません。これは発生するべきではない事象です。
|
||||
nioSender.receive.failedAck=失敗したackを受け取りました:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA
|
||||
nioSender.sender.disconnected=Sender が切断されました。Selectキーを処理できません。
|
||||
nioSender.socketChannel.already.established=ソケットチャネルはすでに確立されています。 接続が進行中である可能性があります。
|
||||
nioSender.unable.disconnect=NioSenderを切断できません。 msg = [{0}]
|
||||
nioSender.unable.receive.ack=レスポンスメッセージを受信できません。ソケットチャンネルは終端に達しています。
|
||||
nioSender.unknown.state=不明な状態です。実行可能操作セット=[{0}]
|
||||
|
||||
parallelNioSender.error.keepalive=Sender:[{0}]のキープアライブテスト中にエラーが発生しました。
|
||||
parallelNioSender.operation.timedout=操作がタイムアウトしました([{0}]ミリ秒)。
|
||||
parallelNioSender.send.fail=メンバーの送信に失敗しました:[{0}]; Settingに設定します。
|
||||
parallelNioSender.send.fail.retrying=[{0}] へのメッセージ送信が失敗しました。状態を SUSPECT へ変更して再送します。
|
||||
parallelNioSender.send.failed=パラレル NIO 送信の失敗
|
||||
parallelNioSender.sendFailed.attempt=送信に失敗しました:試行[{0}] 最大:[{1}]
|
||||
parallelNioSender.sender.disconnected.notRetry=再試行していません:[{0}]; Sender が切断されました。
|
||||
parallelNioSender.sender.disconnected.sendFailed=送信が失敗しました。送信先との接続も失われています。再送信を行いません。
|
||||
parallelNioSender.unable.setup.NioSender=NioSenderのセットアップが出来ません。
|
||||
|
||||
pooledParallelSender.sender.disconnected=Sender 接続されていません。
|
||||
pooledParallelSender.unable.open=NIO selectorをオープン出来ません。
|
||||
pooledParallelSender.unable.retrieveSender=SenderプールからSenderを取得できません
|
||||
pooledParallelSender.unable.retrieveSender.timeout=データSenderを取得できません。タイムアウト([{0}] ms)エラー。
|
||||
@@ -0,0 +1,57 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.alreadyStarted=ServerSocketChannel이 이미 시작되었습니다.
|
||||
nioReceiver.cleanup.fail=selector close 시에 cleanup을 할 수 없습니다.
|
||||
nioReceiver.clientDisconnect=복제 클라이언트가 연결이 끊겼습니다. 키를 poll할 때, 오류가 발생했습니다. 해당 클라이언트는 무시됩니다.
|
||||
nioReceiver.requestError=NioReceiver에서 요청을 처리할 수 없습니다.
|
||||
nioReceiver.run.fail=복제 리스너를 실행할 수 없습니다.
|
||||
nioReceiver.start.fail=클러스터 receiver를 시작 할 수 없습니다.
|
||||
nioReceiver.stop.fail=클러스터 receiver selector를 닫을 수 없습니다.
|
||||
nioReceiver.stop.threadRunning=NioReceiver 쓰레드가 적절한 시간 내에 중지되지 않았습니다. Selector가 닫힐 때에 오류들이 발견될 수 있습니다.
|
||||
nioReceiver.threadpool.fail=쓰레드풀을 초기화할 수 없습니다. 리스너가 시작되지 못했습니다.
|
||||
nioReceiver.threadsExhausted=채널 키가 등록되지만, 마지막 [{0}] 밀리초 동안에 어떠한 interest 오퍼레이션도 없었습니다 (취소 여부: [{1}]). 키:[{2}], 최종 접근 시간:[{3}], 있을 법한 사유: 모든 쓰레드들이 사용 중이고, 쓰레드 덤프 수행.
|
||||
|
||||
nioReplicationTask.error.register.key=읽기를 위한 키 등록 중 오류 발생: [{0}]
|
||||
nioReplicationTask.exception.drainChannel=TcpReplicationThread.drainChannel에서 예외 발생
|
||||
nioReplicationTask.process.clusterMsg.failed=클러스터 메시지 처리가 실패했습니다.
|
||||
nioReplicationTask.unable.ack=채널을 통해 ACK을 되돌려 전송할 수 없습니다. 채널이 단절되었나요?: [{0}]
|
||||
nioReplicationTask.unable.drainChannel.ioe=복제 worker에서 IOException이 발생했으며, 채널을 깨끗이 비울 수 없습니다. 있음직한 사유: Keep alive 소켓이 닫히는 경우. [{0}]
|
||||
|
||||
nioSender.already.connected=NioSender가 이미 연결된 상태에 있습니다.
|
||||
nioSender.datagram.already.established=데이터그램 채널이 이미 확립되어 있습니다. 연결이 진행 중인 상태일 수 있습니다.
|
||||
nioSender.key.inValid=키가 유효하지 않습니다. 이는 필시 이미 취소되었던 키일 것입니다.
|
||||
nioSender.not.connected=NioSender가 연결되어 있지 않습니다. 이는 일어나서는 안될 일입니다.
|
||||
nioSender.receive.failedAck=실패한 ACK: org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA를 받았습니다.
|
||||
nioSender.sender.disconnected=Sender가 연결이 끊어진 상태입니다. SelectionKey를 처리할 수 없습니다.
|
||||
nioSender.socketChannel.already.established=소켓 채널이 이미 확립되어 있습니다. 혹시 연결이 진행 중일 수 있습니다.
|
||||
nioSender.unable.disconnect=NioSender의 연결을 끊을 수 없습니다. 메시지=[{0}]
|
||||
nioSender.unable.receive.ack=Ack 메시지를 받을 수 없습니다. 소켓 채널에서 EOF에 도달했습니다.
|
||||
nioSender.unknown.state=데이터가 알 수 없는 상태에 있습니다. readyOps=[{0}]
|
||||
|
||||
parallelNioSender.error.keepalive=Sender [{0}]을(를) 위해 keepalive 검사 중 오류 발생
|
||||
parallelNioSender.operation.timedout=오퍼레이션이 제한 시간 초과되었습니다 (제한 시간: [{0}] 밀리초).
|
||||
parallelNioSender.send.fail=멤버에 대한 전송이 실패하고 있습니다: [{0}]; 의심 멤버로 설정합니다.
|
||||
parallelNioSender.send.fail.retrying=멤버로 전송이 실패했습니다: [{0}]. 의심 멤버로 설정하고 다시 시도합니다.
|
||||
parallelNioSender.send.failed=병렬 NIO 전송 실패.
|
||||
parallelNioSender.sendFailed.attempt=전송 실패, 총시도회수:[{0}] 최대시도회수:[{1}]
|
||||
parallelNioSender.sender.disconnected.notRetry=[{0}]을(를) 위해 다시 전송 시도를 하지 않습니다. Sender가 연결이 끊겼습니다.
|
||||
parallelNioSender.sender.disconnected.sendFailed=전송이 실패했으며 sender가 연결이 끊겼습니다. 재시도는 하지 않습니다.
|
||||
parallelNioSender.unable.setup.NioSender=NioSender를 셋업할 수 없습니다.
|
||||
|
||||
pooledParallelSender.sender.disconnected=Sender가 연결되어 있지 않습니다.
|
||||
pooledParallelSender.unable.open=NIO selector를 열 수 없습니다.
|
||||
pooledParallelSender.unable.retrieveSender=Sender를 해당 sender 풀로부터 얻을 수 없습니다.
|
||||
pooledParallelSender.unable.retrieveSender.timeout=데이터 sender를 조회할 수 없습니다. 제한 시간 초과 ([{0}] 밀리초) 오류.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
nioReceiver.alreadyStarted=ServerSocketChannel已经被启动
|
||||
nioReceiver.cleanup.fail=无法清除关闭的选择器
|
||||
nioReceiver.clientDisconnect=复制客户端已断开连接,轮询密钥时出错。忽略客户端。
|
||||
nioReceiver.requestError=NioReceiver无法处理请求
|
||||
nioReceiver.run.fail=不能允许复制监听器
|
||||
nioReceiver.start.fail=无法启动集群接收器
|
||||
nioReceiver.stop.fail=无法关闭集群接收的选择器
|
||||
nioReceiver.stop.threadRunning=NioReceiver线程没有及时停止。关闭选择器时可能会观察到错误。
|
||||
nioReceiver.threadpool.fail=ThreadPool 无法初始化。 监听器未启动。
|
||||
|
||||
nioReplicationTask.error.register.key=错误的注册key被读取:[{0}]
|
||||
nioReplicationTask.process.clusterMsg.failed=处理集群消息失败
|
||||
nioReplicationTask.unable.ack=不能通过channel发送ack,channel已经断开?[{0}]
|
||||
|
||||
nioSender.datagram.already.established=数据报通道已经建立。连接可能正在进行中。
|
||||
nioSender.not.connected=NioSender未连接,这是不应该发生的。
|
||||
nioSender.sender.disconnected=发件人已断开连接,无法处理选择密钥。
|
||||
nioSender.unable.receive.ack=无法接收确认消息。已到达套接字通道上的EOF。
|
||||
nioSender.unknown.state=数据处于未知状态。readyOps = [{0}]
|
||||
|
||||
parallelNioSender.send.fail.retrying=成员发送失败:[{0}]; 设置为怀疑并重试。
|
||||
parallelNioSender.send.failed=并行的NIO.发送失败。
|
||||
parallelNioSender.sendFailed.attempt=发送失败,尝试: [{0}] 最大: [{1}]
|
||||
parallelNioSender.sender.disconnected.sendFailed=发送失败且sender已断开连接,不再重试。
|
||||
|
||||
pooledParallelSender.sender.disconnected=sender 未连接。
|
||||
pooledParallelSender.unable.open=无法打开nio选择器。
|
||||
pooledParallelSender.unable.retrieveSender=无法从sender池中获取一个sender
|
||||
459
java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
Normal file
459
java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.ReceiverBase;
|
||||
import org.apache.catalina.tribes.transport.RxTaskPool;
|
||||
import org.apache.catalina.tribes.util.ExceptionUtils;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public class NioReceiver extends ReceiverBase implements Runnable, NioReceiverMBean {
|
||||
|
||||
private static final Log log = LogFactory.getLog(NioReceiver.class);
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(NioReceiver.class);
|
||||
|
||||
private volatile boolean running = false;
|
||||
|
||||
private AtomicReference<Selector> selector = new AtomicReference<>();
|
||||
private ServerSocketChannel serverChannel = null;
|
||||
private DatagramChannel datagramChannel = null;
|
||||
|
||||
protected final Deque<Runnable> events = new ConcurrentLinkedDeque<>();
|
||||
|
||||
public NioReceiver() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
this.stopListening();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start cluster receiver.
|
||||
*
|
||||
* @throws IOException If the receiver fails to start
|
||||
*
|
||||
* @see org.apache.catalina.tribes.ChannelReceiver#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
super.start();
|
||||
try {
|
||||
setPool(new RxTaskPool(getMaxThreads(),getMinThreads(),this));
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("nioReceiver.threadpool.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
try {
|
||||
getBind();
|
||||
bind();
|
||||
String channelName = "";
|
||||
if (getChannel().getName() != null) channelName = "[" + getChannel().getName() + "]";
|
||||
Thread t = new Thread(this, "NioReceiver" + channelName);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
} catch (Exception x) {
|
||||
log.fatal(sm.getString("nioReceiver.start.fail"), x);
|
||||
if ( x instanceof IOException ) throw (IOException)x;
|
||||
else throw new IOException(x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractRxTask createRxTask() {
|
||||
NioReplicationTask thread = new NioReplicationTask(this,this);
|
||||
thread.setUseBufferPool(this.getUseBufferPool());
|
||||
thread.setRxBufSize(getRxBufSize());
|
||||
thread.setOptions(getWorkerThreadOptions());
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void bind() throws IOException {
|
||||
// allocate an unbound server socket channel
|
||||
serverChannel = ServerSocketChannel.open();
|
||||
// Get the associated ServerSocket to bind it with
|
||||
ServerSocket serverSocket = serverChannel.socket();
|
||||
// create a new Selector for use below
|
||||
this.selector.set(Selector.open());
|
||||
// set the port the server channel will listen to
|
||||
//serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
|
||||
bind(serverSocket,getPort(),getAutoBind());
|
||||
// set non-blocking mode for the listening socket
|
||||
serverChannel.configureBlocking(false);
|
||||
// register the ServerSocketChannel with the Selector
|
||||
serverChannel.register(this.selector.get(), SelectionKey.OP_ACCEPT);
|
||||
|
||||
//set up the datagram channel
|
||||
if (this.getUdpPort()>0) {
|
||||
datagramChannel = DatagramChannel.open();
|
||||
configureDatagraChannel();
|
||||
//bind to the address to avoid security checks
|
||||
bindUdp(datagramChannel.socket(),getUdpPort(),getAutoBind());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureDatagraChannel() throws IOException {
|
||||
datagramChannel.configureBlocking(false);
|
||||
datagramChannel.socket().setSendBufferSize(getUdpTxBufSize());
|
||||
datagramChannel.socket().setReceiveBufferSize(getUdpRxBufSize());
|
||||
datagramChannel.socket().setReuseAddress(getSoReuseAddress());
|
||||
datagramChannel.socket().setSoTimeout(getTimeout());
|
||||
datagramChannel.socket().setTrafficClass(getSoTrafficClass());
|
||||
}
|
||||
|
||||
public void addEvent(Runnable event) {
|
||||
Selector selector = this.selector.get();
|
||||
if (selector != null) {
|
||||
events.add(event);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Adding event to selector:" + event);
|
||||
}
|
||||
if (isListening()) {
|
||||
selector.wakeup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void events() {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Runnable r = null;
|
||||
while ((r = events.pollFirst()) != null ) {
|
||||
try {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Processing event in selector:" + r);
|
||||
}
|
||||
r.run();
|
||||
} catch (Exception x) {
|
||||
log.error("", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void cancelledKey(SelectionKey key) {
|
||||
ObjectReader reader = (ObjectReader)key.attachment();
|
||||
if ( reader != null ) {
|
||||
reader.setCancelled(true);
|
||||
reader.finish();
|
||||
}
|
||||
key.cancel();
|
||||
key.attach(null);
|
||||
if (key.channel() instanceof SocketChannel)
|
||||
try { ((SocketChannel)key.channel()).socket().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); }
|
||||
if (key.channel() instanceof DatagramChannel)
|
||||
try { ((DatagramChannel)key.channel()).socket().close(); } catch (Exception e) { if (log.isDebugEnabled()) log.debug("", e); }
|
||||
try { key.channel().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); }
|
||||
|
||||
}
|
||||
protected long lastCheck = System.currentTimeMillis();
|
||||
protected void socketTimeouts() {
|
||||
long now = System.currentTimeMillis();
|
||||
if ( (now-lastCheck) < getSelectorTimeout() ) return;
|
||||
//timeout
|
||||
Selector tmpsel = this.selector.get();
|
||||
Set<SelectionKey> keys = (isListening()&&tmpsel!=null)?tmpsel.keys():null;
|
||||
if ( keys == null ) return;
|
||||
for (Iterator<SelectionKey> iter = keys.iterator(); iter.hasNext();) {
|
||||
SelectionKey key = iter.next();
|
||||
try {
|
||||
// if (key.interestOps() == SelectionKey.OP_READ) {
|
||||
// //only timeout sockets that we are waiting for a read from
|
||||
// ObjectReader ka = (ObjectReader) key.attachment();
|
||||
// long delta = now - ka.getLastAccess();
|
||||
// if (delta > (long) getTimeout()) {
|
||||
// cancelledKey(key);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
if ( key.interestOps() == 0 ) {
|
||||
//check for keys that didn't make it in.
|
||||
ObjectReader ka = (ObjectReader) key.attachment();
|
||||
if ( ka != null ) {
|
||||
long delta = now - ka.getLastAccess();
|
||||
if (delta > getTimeout() && (!ka.isAccessed())) {
|
||||
if (log.isWarnEnabled())
|
||||
log.warn(sm.getString(
|
||||
"nioReceiver.threadsExhausted",
|
||||
Integer.valueOf(getTimeout()),
|
||||
Boolean.valueOf(ka.isCancelled()),
|
||||
key,
|
||||
new java.sql.Timestamp(ka.getLastAccess())));
|
||||
ka.setLastAccess(now);
|
||||
//key.interestOps(SelectionKey.OP_READ);
|
||||
}//end if
|
||||
} else {
|
||||
cancelledKey(key);
|
||||
}//end if
|
||||
}//end if
|
||||
}catch ( CancelledKeyException ckx ) {
|
||||
cancelledKey(key);
|
||||
}
|
||||
}
|
||||
lastCheck = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get data from channel and store in byte array
|
||||
* send it to cluster
|
||||
* @throws IOException IO error
|
||||
*/
|
||||
protected void listen() throws Exception {
|
||||
if (doListen()) {
|
||||
log.warn(sm.getString("nioReceiver.alreadyStarted"));
|
||||
return;
|
||||
}
|
||||
|
||||
setListen(true);
|
||||
|
||||
// Avoid NPEs if selector is set to null on stop.
|
||||
Selector selector = this.selector.get();
|
||||
|
||||
if (selector!=null && datagramChannel!=null) {
|
||||
ObjectReader oreader = new ObjectReader(MAX_UDP_SIZE); //max size for a datagram packet
|
||||
registerChannel(selector,datagramChannel,SelectionKey.OP_READ,oreader);
|
||||
}
|
||||
|
||||
while (doListen() && selector != null) {
|
||||
// this may block for a long time, upon return the
|
||||
// selected set contains keys of the ready channels
|
||||
try {
|
||||
events();
|
||||
socketTimeouts();
|
||||
int n = selector.select(getSelectorTimeout());
|
||||
if (n == 0) {
|
||||
//there is a good chance that we got here
|
||||
//because the TcpReplicationThread called
|
||||
//selector wakeup().
|
||||
//if that happens, we must ensure that that
|
||||
//thread has enough time to call interestOps
|
||||
// synchronized (interestOpsMutex) {
|
||||
//if we got the lock, means there are no
|
||||
//keys trying to register for the
|
||||
//interestOps method
|
||||
// }
|
||||
continue; // nothing to do
|
||||
}
|
||||
// get an iterator over the set of selected keys
|
||||
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
|
||||
// look at each key in the selected set
|
||||
while (it!=null && it.hasNext()) {
|
||||
SelectionKey key = it.next();
|
||||
// Is a new connection coming in?
|
||||
if (key.isAcceptable()) {
|
||||
ServerSocketChannel server = (ServerSocketChannel) key.channel();
|
||||
SocketChannel channel = server.accept();
|
||||
channel.socket().setReceiveBufferSize(getRxBufSize());
|
||||
channel.socket().setSendBufferSize(getTxBufSize());
|
||||
channel.socket().setTcpNoDelay(getTcpNoDelay());
|
||||
channel.socket().setKeepAlive(getSoKeepAlive());
|
||||
channel.socket().setOOBInline(getOoBInline());
|
||||
channel.socket().setReuseAddress(getSoReuseAddress());
|
||||
channel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime());
|
||||
channel.socket().setSoTimeout(getTimeout());
|
||||
Object attach = new ObjectReader(channel);
|
||||
registerChannel(selector,
|
||||
channel,
|
||||
SelectionKey.OP_READ,
|
||||
attach);
|
||||
}
|
||||
// is there data to read on this channel?
|
||||
if (key.isReadable()) {
|
||||
readDataFromSocket(key);
|
||||
} else {
|
||||
key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
|
||||
}
|
||||
|
||||
// remove key from selected set, it's been handled
|
||||
it.remove();
|
||||
}
|
||||
} catch (java.nio.channels.ClosedSelectorException cse) {
|
||||
// ignore is normal at shutdown or stop listen socket
|
||||
} catch (java.nio.channels.CancelledKeyException nx) {
|
||||
log.warn(sm.getString("nioReceiver.clientDisconnect"));
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
log.error(sm.getString("nioReceiver.requestError"), t);
|
||||
}
|
||||
|
||||
}
|
||||
serverChannel.close();
|
||||
if (datagramChannel!=null) {
|
||||
try {
|
||||
datagramChannel.close();
|
||||
}catch (Exception iox) {
|
||||
if (log.isDebugEnabled()) log.debug("Unable to close datagram channel.",iox);
|
||||
}
|
||||
datagramChannel=null;
|
||||
}
|
||||
closeSelector();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Close Selector.
|
||||
*
|
||||
* @see org.apache.catalina.tribes.transport.ReceiverBase#stop()
|
||||
*/
|
||||
protected void stopListening() {
|
||||
setListen(false);
|
||||
Selector selector = this.selector.get();
|
||||
if (selector != null) {
|
||||
try {
|
||||
// Unlock the thread if is is blocked waiting for input
|
||||
selector.wakeup();
|
||||
// Wait for the receiver thread to finish
|
||||
int count = 0;
|
||||
while (running && count < 50) {
|
||||
Thread.sleep(100);
|
||||
count ++;
|
||||
}
|
||||
if (running) {
|
||||
log.warn(sm.getString("nioReceiver.stop.threadRunning"));
|
||||
}
|
||||
closeSelector();
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("nioReceiver.stop.fail"), x);
|
||||
} finally {
|
||||
this.selector.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeSelector() throws IOException {
|
||||
Selector selector = this.selector.getAndSet(null);
|
||||
if (selector == null) return;
|
||||
try {
|
||||
// look at each key in the selected set
|
||||
for (SelectionKey key : selector.keys()) {
|
||||
key.channel().close();
|
||||
key.attach(null);
|
||||
key.cancel();
|
||||
}
|
||||
} catch (IOException ignore){
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn(sm.getString("nioReceiver.cleanup.fail"), ignore);
|
||||
}
|
||||
} catch (ClosedSelectorException ignore){
|
||||
// Ignore
|
||||
}
|
||||
try {
|
||||
selector.selectNow();
|
||||
} catch (Throwable t){
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
// Ignore everything else
|
||||
}
|
||||
selector.close();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Register the given channel with the given selector for
|
||||
* the given operations of interest
|
||||
* @param selector The selector to use
|
||||
* @param channel The channel
|
||||
* @param ops The operations to register
|
||||
* @param attach Attachment object
|
||||
* @throws Exception IO error with channel
|
||||
*/
|
||||
protected void registerChannel(Selector selector,
|
||||
SelectableChannel channel,
|
||||
int ops,
|
||||
Object attach) throws Exception {
|
||||
if (channel == null)return; // could happen
|
||||
// set the new channel non-blocking
|
||||
channel.configureBlocking(false);
|
||||
// register it with the selector
|
||||
channel.register(selector, ops, attach);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start thread and listen
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
try {
|
||||
listen();
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("nioReceiver.run.fail"), x);
|
||||
} finally {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sample data handler method for a channel with data ready to read.
|
||||
* @param key A SelectionKey object associated with a channel
|
||||
* determined by the selector to be ready for reading. If the
|
||||
* channel returns an EOF condition, it is closed here, which
|
||||
* automatically invalidates the associated key. The selector
|
||||
* will then de-register the channel on the next select call.
|
||||
* @throws Exception IO error with channel
|
||||
*/
|
||||
protected void readDataFromSocket(SelectionKey key) throws Exception {
|
||||
NioReplicationTask task = (NioReplicationTask) getTaskPool().getRxTask();
|
||||
if (task == null) {
|
||||
// No threads/tasks available, do nothing, the selection
|
||||
// loop will keep calling this method until a
|
||||
// thread becomes available, the thread pool itself has a waiting mechanism
|
||||
// so we will not wait here.
|
||||
if (log.isDebugEnabled()) log.debug("No TcpReplicationThread available");
|
||||
} else {
|
||||
// invoking this wakes up the worker thread then returns
|
||||
//add task to thread pool
|
||||
task.serviceChannel(key);
|
||||
getExecutor().execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
|
||||
public interface NioReceiverMBean {
|
||||
|
||||
// Receiver Attributes
|
||||
public String getAddress();
|
||||
|
||||
public boolean getDirect();
|
||||
|
||||
public int getPort();
|
||||
|
||||
public int getAutoBind();
|
||||
|
||||
public int getSecurePort();
|
||||
|
||||
public int getUdpPort();
|
||||
|
||||
public long getSelectorTimeout();
|
||||
|
||||
public int getMaxThreads();
|
||||
|
||||
public int getMinThreads();
|
||||
|
||||
public long getMaxIdleTime();
|
||||
|
||||
public boolean getOoBInline();
|
||||
|
||||
public int getRxBufSize();
|
||||
|
||||
public int getTxBufSize();
|
||||
|
||||
public int getUdpRxBufSize();
|
||||
|
||||
public int getUdpTxBufSize();
|
||||
|
||||
public boolean getSoKeepAlive();
|
||||
|
||||
public boolean getSoLingerOn();
|
||||
|
||||
public int getSoLingerTime();
|
||||
|
||||
public boolean getSoReuseAddress();
|
||||
|
||||
public boolean getTcpNoDelay();
|
||||
|
||||
public int getTimeout();
|
||||
|
||||
public boolean getUseBufferPool();
|
||||
|
||||
public boolean isListening();
|
||||
|
||||
// pool stats
|
||||
public int getPoolSize();
|
||||
|
||||
public int getActiveCount();
|
||||
|
||||
public long getTaskCount();
|
||||
|
||||
public long getCompletedTaskCount();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.ChannelReceiver;
|
||||
import org.apache.catalina.tribes.RemoteProcessException;
|
||||
import org.apache.catalina.tribes.UniqueId;
|
||||
import org.apache.catalina.tribes.io.BufferPool;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.ListenCallback;
|
||||
import org.apache.catalina.tribes.io.ObjectReader;
|
||||
import org.apache.catalina.tribes.transport.AbstractRxTask;
|
||||
import org.apache.catalina.tribes.transport.Constants;
|
||||
import org.apache.catalina.tribes.util.Logs;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* A worker thread class which can drain channels and echo-back the input. Each
|
||||
* instance is constructed with a reference to the owning thread pool object.
|
||||
* When started, the thread loops forever waiting to be awakened to service the
|
||||
* channel associated with a SelectionKey object. The worker is tasked by
|
||||
* calling its serviceChannel() method with a SelectionKey object. The
|
||||
* serviceChannel() method stores the key reference in the thread object then
|
||||
* calls notify() to wake it up. When the channel has been drained, the worker
|
||||
* thread returns itself to its parent pool.
|
||||
*/
|
||||
public class NioReplicationTask extends AbstractRxTask {
|
||||
|
||||
private static final Log log = LogFactory.getLog(NioReplicationTask.class);
|
||||
protected static final StringManager sm = StringManager.getManager(NioReplicationTask.class);
|
||||
|
||||
private ByteBuffer buffer = null;
|
||||
private SelectionKey key;
|
||||
private int rxBufSize;
|
||||
private final NioReceiver receiver;
|
||||
|
||||
public NioReplicationTask (ListenCallback callback, NioReceiver receiver) {
|
||||
super(callback);
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
// loop forever waiting for work to do
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
if ( buffer == null ) {
|
||||
int size = getRxBufSize();
|
||||
if (key.channel() instanceof DatagramChannel) {
|
||||
size = ChannelReceiver.MAX_UDP_SIZE;
|
||||
}
|
||||
if ( (getOptions() & OPTION_DIRECT_BUFFER) == OPTION_DIRECT_BUFFER) {
|
||||
buffer = ByteBuffer.allocateDirect(size);
|
||||
} else {
|
||||
buffer = ByteBuffer.allocate(size);
|
||||
}
|
||||
} else {
|
||||
buffer.clear();
|
||||
}
|
||||
if (key == null) {
|
||||
return; // just in case
|
||||
}
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Servicing key:"+key);
|
||||
|
||||
try {
|
||||
ObjectReader reader = (ObjectReader)key.attachment();
|
||||
if ( reader == null ) {
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("No object reader, cancelling:"+key);
|
||||
cancelKey(key);
|
||||
} else {
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Draining channel:"+key);
|
||||
|
||||
drainChannel(key, reader);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//this is common, since the sockets on the other
|
||||
//end expire after a certain time.
|
||||
if ( e instanceof CancelledKeyException ) {
|
||||
//do nothing
|
||||
} else if ( e instanceof IOException ) {
|
||||
//dont spew out stack traces for IO exceptions unless debug is enabled.
|
||||
if (log.isDebugEnabled()) log.debug ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed["+e.getMessage()+"].", e);
|
||||
else log.warn (sm.getString("nioReplicationTask.unable.drainChannel.ioe", e.getMessage()));
|
||||
} else if ( log.isErrorEnabled() ) {
|
||||
//this is a real error, log it.
|
||||
log.error(sm.getString("nioReplicationTask.exception.drainChannel"),e);
|
||||
}
|
||||
cancelKey(key);
|
||||
}
|
||||
key = null;
|
||||
// done, ready for more, return to pool
|
||||
getTaskPool().returnWorker (this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to initiate a unit of work by this worker thread
|
||||
* on the provided SelectionKey object. This method is
|
||||
* synchronized, as is the run() method, so only one key
|
||||
* can be serviced at a given time.
|
||||
* Before waking the worker thread, and before returning
|
||||
* to the main selection loop, this key's interest set is
|
||||
* updated to remove OP_READ. This will cause the selector
|
||||
* to ignore read-readiness for this channel while the
|
||||
* worker thread is servicing it.
|
||||
* @param key The key to process
|
||||
*/
|
||||
public synchronized void serviceChannel (SelectionKey key) {
|
||||
if ( log.isTraceEnabled() ) log.trace("About to service key:"+key);
|
||||
ObjectReader reader = (ObjectReader)key.attachment();
|
||||
if ( reader != null ) reader.setLastAccess(System.currentTimeMillis());
|
||||
this.key = key;
|
||||
key.interestOps (key.interestOps() & (~SelectionKey.OP_READ));
|
||||
key.interestOps (key.interestOps() & (~SelectionKey.OP_WRITE));
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual code which drains the channel associated with
|
||||
* the given key. This method assumes the key has been
|
||||
* modified prior to invocation to turn off selection
|
||||
* interest in OP_READ. When this method completes it
|
||||
* re-enables OP_READ and calls wakeup() on the selector
|
||||
* so the selector will resume watching this channel.
|
||||
* @param key The key to process
|
||||
* @param reader The reader
|
||||
* @throws Exception IO error
|
||||
*/
|
||||
protected void drainChannel (final SelectionKey key, ObjectReader reader) throws Exception {
|
||||
reader.access();
|
||||
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
|
||||
int count=-1;
|
||||
buffer.clear(); // make buffer empty
|
||||
SocketAddress saddr = null;
|
||||
|
||||
if (channel instanceof SocketChannel) {
|
||||
// loop while data available, channel is non-blocking
|
||||
while ((count = channel.read (buffer)) > 0) {
|
||||
buffer.flip(); // make buffer readable
|
||||
if ( buffer.hasArray() )
|
||||
reader.append(buffer.array(),0,count,false);
|
||||
else
|
||||
reader.append(buffer,count,false);
|
||||
buffer.clear(); // make buffer empty
|
||||
//do we have at least one package?
|
||||
if ( reader.hasPackage() ) break;
|
||||
}
|
||||
} else if (channel instanceof DatagramChannel) {
|
||||
DatagramChannel dchannel = (DatagramChannel)channel;
|
||||
saddr = dchannel.receive(buffer);
|
||||
buffer.flip(); // make buffer readable
|
||||
if ( buffer.hasArray() )
|
||||
reader.append(buffer.array(),0,buffer.limit()-buffer.position(),false);
|
||||
else
|
||||
reader.append(buffer,buffer.limit()-buffer.position(),false);
|
||||
buffer.clear(); // make buffer empty
|
||||
//did we get a package
|
||||
count = reader.hasPackage()?1:-1;
|
||||
}
|
||||
|
||||
int pkgcnt = reader.count();
|
||||
|
||||
if (count < 0 && pkgcnt == 0 ) {
|
||||
//end of stream, and no more packages to process
|
||||
remoteEof(key);
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelMessage[] msgs = pkgcnt == 0? ChannelData.EMPTY_DATA_ARRAY : reader.execute();
|
||||
|
||||
registerForRead(key,reader);//register to read new data, before we send it off to avoid dead locks
|
||||
|
||||
for ( int i=0; i<msgs.length; i++ ) {
|
||||
/**
|
||||
* Use send ack here if you want to ack the request to the remote
|
||||
* server before completing the request
|
||||
* This is considered an asynchronous request
|
||||
*/
|
||||
if (ChannelData.sendAckAsync(msgs[i].getOptions())) sendAck(key,(WritableByteChannel)channel,Constants.ACK_COMMAND,saddr);
|
||||
try {
|
||||
if ( Logs.MESSAGES.isTraceEnabled() ) {
|
||||
try {
|
||||
Logs.MESSAGES.trace("NioReplicationThread - Received msg:" + new UniqueId(msgs[i].getUniqueId()) + " at " + new java.sql.Timestamp(System.currentTimeMillis()));
|
||||
}catch ( Throwable t ) {}
|
||||
}
|
||||
//process the message
|
||||
getCallback().messageDataReceived(msgs[i]);
|
||||
/**
|
||||
* Use send ack here if you want the request to complete on this
|
||||
* server before sending the ack to the remote server
|
||||
* This is considered a synchronized request
|
||||
*/
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,(WritableByteChannel)channel,Constants.ACK_COMMAND,saddr);
|
||||
}catch ( RemoteProcessException e ) {
|
||||
if ( log.isDebugEnabled() ) log.error(sm.getString("nioReplicationTask.process.clusterMsg.failed"),e);
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,(WritableByteChannel)channel,Constants.FAIL_ACK_COMMAND,saddr);
|
||||
}catch ( Exception e ) {
|
||||
log.error(sm.getString("nioReplicationTask.process.clusterMsg.failed"),e);
|
||||
if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,(WritableByteChannel)channel,Constants.FAIL_ACK_COMMAND,saddr);
|
||||
}
|
||||
if ( getUseBufferPool() ) {
|
||||
BufferPool.getBufferPool().returnBuffer(msgs[i].getMessage());
|
||||
msgs[i].setMessage(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
remoteEof(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void remoteEof(SelectionKey key) {
|
||||
// close channel on EOF, invalidates the key
|
||||
if ( log.isDebugEnabled() ) log.debug("Channel closed on the remote end, disconnecting");
|
||||
cancelKey(key);
|
||||
}
|
||||
|
||||
protected void registerForRead(final SelectionKey key, ObjectReader reader) {
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Adding key for read event:"+key);
|
||||
reader.finish();
|
||||
//register our OP_READ interest
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (key.isValid()) {
|
||||
// cycle the selector so this key is active again
|
||||
key.selector().wakeup();
|
||||
// resume interest in OP_READ, OP_WRITE
|
||||
int resumeOps = key.interestOps() | SelectionKey.OP_READ;
|
||||
key.interestOps(resumeOps);
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Registering key for read:"+key);
|
||||
}
|
||||
} catch (CancelledKeyException ckx ) {
|
||||
NioReceiver.cancelledKey(key);
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("CKX Cancelling key:"+key);
|
||||
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("nioReplicationTask.error.register.key", key),x);
|
||||
}
|
||||
}
|
||||
};
|
||||
receiver.addEvent(r);
|
||||
}
|
||||
|
||||
private void cancelKey(final SelectionKey key) {
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Adding key for cancel event:"+key);
|
||||
|
||||
ObjectReader reader = (ObjectReader)key.attachment();
|
||||
if ( reader != null ) {
|
||||
reader.setCancelled(true);
|
||||
reader.finish();
|
||||
}
|
||||
Runnable cx = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ( log.isTraceEnabled() )
|
||||
log.trace("Cancelling key:"+key);
|
||||
|
||||
NioReceiver.cancelledKey(key);
|
||||
}
|
||||
};
|
||||
receiver.addEvent(cx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a reply-acknowledgement (6,2,3), sends it doing a busy write, the ACK is so small
|
||||
* that it should always go to the buffer.
|
||||
* @param key The key to use
|
||||
* @param channel The channel
|
||||
* @param command The command to write
|
||||
* @param udpaddr Target address
|
||||
*/
|
||||
protected void sendAck(SelectionKey key, WritableByteChannel channel, byte[] command, SocketAddress udpaddr) {
|
||||
try {
|
||||
|
||||
ByteBuffer buf = ByteBuffer.wrap(command);
|
||||
int total = 0;
|
||||
if (channel instanceof DatagramChannel) {
|
||||
DatagramChannel dchannel = (DatagramChannel)channel;
|
||||
//were using a shared channel, document says its thread safe
|
||||
//TODO check optimization, one channel per thread?
|
||||
while ( total < command.length ) {
|
||||
total += dchannel.send(buf, udpaddr);
|
||||
}
|
||||
} else {
|
||||
while ( total < command.length ) {
|
||||
total += channel.write(buf);
|
||||
}
|
||||
}
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("ACK sent to " +
|
||||
( (channel instanceof SocketChannel) ?
|
||||
((SocketChannel)channel).socket().getInetAddress() :
|
||||
((DatagramChannel)channel).socket().getInetAddress()));
|
||||
}
|
||||
} catch ( java.io.IOException x ) {
|
||||
log.warn(sm.getString("nioReplicationTask.unable.ack", x.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setRxBufSize(int rxBufSize) {
|
||||
this.rxBufSize = rxBufSize;
|
||||
}
|
||||
|
||||
public int getRxBufSize() {
|
||||
return rxBufSize;
|
||||
}
|
||||
}
|
||||
402
java/org/apache/catalina/tribes/transport/nio/NioSender.java
Normal file
402
java/org/apache/catalina/tribes/transport/nio/NioSender.java
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.catalina.tribes.RemoteProcessException;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* This class is NOT thread safe and should never be used with more than one thread at a time
|
||||
*
|
||||
* This is a state machine, handled by the process method
|
||||
* States are:
|
||||
* - NOT_CONNECTED -> connect() -> CONNECTED
|
||||
* - CONNECTED -> setMessage() -> READY TO WRITE
|
||||
* - READY_TO_WRITE -> write() -> READY TO WRITE | READY TO READ
|
||||
* - READY_TO_READ -> read() -> READY_TO_READ | TRANSFER_COMPLETE
|
||||
* - TRANSFER_COMPLETE -> CONNECTED
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class NioSender extends AbstractSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(NioSender.class);
|
||||
protected static final StringManager sm = StringManager.getManager(NioSender.class);
|
||||
|
||||
|
||||
protected Selector selector;
|
||||
protected SocketChannel socketChannel = null;
|
||||
protected DatagramChannel dataChannel = null;
|
||||
|
||||
/*
|
||||
* STATE VARIABLES *
|
||||
*/
|
||||
protected ByteBuffer readbuf = null;
|
||||
protected ByteBuffer writebuf = null;
|
||||
protected volatile byte[] current = null;
|
||||
protected final XByteBuffer ackbuf = new XByteBuffer(128,true);
|
||||
protected int remaining = 0;
|
||||
protected boolean complete;
|
||||
|
||||
protected boolean connecting = false;
|
||||
|
||||
public NioSender() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* State machine to send data.
|
||||
* @param key The key to use
|
||||
* @param waitForAck Wait for an ack
|
||||
* @return <code>true</code> if the processing was successful
|
||||
* @throws IOException An IO error occurred
|
||||
*/
|
||||
public boolean process(SelectionKey key, boolean waitForAck) throws IOException {
|
||||
int ops = key.readyOps();
|
||||
key.interestOps(key.interestOps() & ~ops);
|
||||
//in case disconnect has been called
|
||||
if ((!isConnected()) && (!connecting)) throw new IOException(sm.getString("nioSender.sender.disconnected"));
|
||||
if ( !key.isValid() ) throw new IOException(sm.getString("nioSender.key.inValid"));
|
||||
if ( key.isConnectable() ) {
|
||||
if ( socketChannel.finishConnect() ) {
|
||||
completeConnect();
|
||||
if ( current != null ) key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
|
||||
return false;
|
||||
} else {
|
||||
//wait for the connection to finish
|
||||
key.interestOps(key.interestOps() | SelectionKey.OP_CONNECT);
|
||||
return false;
|
||||
}//end if
|
||||
} else if ( key.isWritable() ) {
|
||||
boolean writecomplete = write();
|
||||
if ( writecomplete ) {
|
||||
//we are completed, should we read an ack?
|
||||
if ( waitForAck ) {
|
||||
//register to read the ack
|
||||
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
|
||||
} else {
|
||||
//if not, we are ready, setMessage will reregister us for another write interest
|
||||
//do a health check, we have no way of verify a disconnected
|
||||
//socket since we don't register for OP_READ on waitForAck=false
|
||||
read();//this causes overhead
|
||||
setRequestCount(getRequestCount()+1);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
//we are not complete, lets write some more
|
||||
key.interestOps(key.interestOps()|SelectionKey.OP_WRITE);
|
||||
}//end if
|
||||
} else if ( key.isReadable() ) {
|
||||
boolean readcomplete = read();
|
||||
if ( readcomplete ) {
|
||||
setRequestCount(getRequestCount()+1);
|
||||
return true;
|
||||
} else {
|
||||
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
|
||||
}//end if
|
||||
} else {
|
||||
//unknown state, should never happen
|
||||
log.warn(sm.getString("nioSender.unknown.state", Integer.toString(ops)));
|
||||
throw new IOException(sm.getString("nioSender.unknown.state", Integer.toString(ops)));
|
||||
}//end if
|
||||
return false;
|
||||
}
|
||||
|
||||
private void configureSocket() throws IOException {
|
||||
if (socketChannel!=null) {
|
||||
socketChannel.configureBlocking(false);
|
||||
socketChannel.socket().setSendBufferSize(getTxBufSize());
|
||||
socketChannel.socket().setReceiveBufferSize(getRxBufSize());
|
||||
socketChannel.socket().setSoTimeout((int)getTimeout());
|
||||
socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerOn()?getSoLingerTime():0);
|
||||
socketChannel.socket().setTcpNoDelay(getTcpNoDelay());
|
||||
socketChannel.socket().setKeepAlive(getSoKeepAlive());
|
||||
socketChannel.socket().setReuseAddress(getSoReuseAddress());
|
||||
socketChannel.socket().setOOBInline(getOoBInline());
|
||||
socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime());
|
||||
socketChannel.socket().setTrafficClass(getSoTrafficClass());
|
||||
} else if (dataChannel!=null) {
|
||||
dataChannel.configureBlocking(false);
|
||||
dataChannel.socket().setSendBufferSize(getUdpTxBufSize());
|
||||
dataChannel.socket().setReceiveBufferSize(getUdpRxBufSize());
|
||||
dataChannel.socket().setSoTimeout((int)getTimeout());
|
||||
dataChannel.socket().setReuseAddress(getSoReuseAddress());
|
||||
dataChannel.socket().setTrafficClass(getSoTrafficClass());
|
||||
}
|
||||
}
|
||||
|
||||
private void completeConnect() {
|
||||
//we connected, register ourselves for writing
|
||||
setConnected(true);
|
||||
connecting = false;
|
||||
setRequestCount(0);
|
||||
setConnectTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected boolean read() throws IOException {
|
||||
//if there is no message here, we are done
|
||||
if ( current == null ) return true;
|
||||
int read = isUdpBased()?dataChannel.read(readbuf) : socketChannel.read(readbuf);
|
||||
//end of stream
|
||||
if ( read == -1 ) throw new IOException(sm.getString("nioSender.unable.receive.ack"));
|
||||
//no data read
|
||||
else if ( read == 0 ) return false;
|
||||
readbuf.flip();
|
||||
ackbuf.append(readbuf,read);
|
||||
readbuf.clear();
|
||||
if (ackbuf.doesPackageExist() ) {
|
||||
byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes();
|
||||
boolean ack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.ACK_DATA);
|
||||
boolean fack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA);
|
||||
if ( fack && getThrowOnFailedAck() ) throw new RemoteProcessException(sm.getString("nioSender.receive.failedAck"));
|
||||
return ack || fack;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean write() throws IOException {
|
||||
if ( (!isConnected()) || (this.socketChannel==null && this.dataChannel==null)) {
|
||||
throw new IOException(sm.getString("nioSender.not.connected"));
|
||||
}
|
||||
if ( current != null ) {
|
||||
if ( remaining > 0 ) {
|
||||
//we have written everything, or we are starting a new package
|
||||
//protect against buffer overwrite
|
||||
int byteswritten = isUdpBased()?dataChannel.write(writebuf) : socketChannel.write(writebuf);
|
||||
if (byteswritten == -1 ) throw new EOFException();
|
||||
remaining -= byteswritten;
|
||||
//if the entire message was written from the buffer
|
||||
//reset the position counter
|
||||
if ( remaining < 0 ) {
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
return (remaining==0);
|
||||
}
|
||||
//no message to send, we can consider that complete
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect - blocking in this operation
|
||||
*
|
||||
* @throws IOException
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.IDataSender method
|
||||
*/
|
||||
@Override
|
||||
public synchronized void connect() throws IOException {
|
||||
if ( connecting || isConnected()) return;
|
||||
connecting = true;
|
||||
if ( isConnected() ) throw new IOException(sm.getString("nioSender.already.connected"));
|
||||
if ( readbuf == null ) {
|
||||
readbuf = getReadBuffer();
|
||||
} else {
|
||||
readbuf.clear();
|
||||
}
|
||||
if ( writebuf == null ) {
|
||||
writebuf = getWriteBuffer();
|
||||
} else {
|
||||
writebuf.clear();
|
||||
}
|
||||
|
||||
if (isUdpBased()) {
|
||||
InetSocketAddress daddr = new InetSocketAddress(getAddress(),getUdpPort());
|
||||
if ( dataChannel != null ) throw new IOException(sm.getString("nioSender.datagram.already.established"));
|
||||
dataChannel = DatagramChannel.open();
|
||||
configureSocket();
|
||||
dataChannel.connect(daddr);
|
||||
completeConnect();
|
||||
dataChannel.register(getSelector(),SelectionKey.OP_WRITE, this);
|
||||
|
||||
} else {
|
||||
InetSocketAddress addr = new InetSocketAddress(getAddress(),getPort());
|
||||
if ( socketChannel != null ) throw new IOException(sm.getString("nioSender.socketChannel.already.established"));
|
||||
socketChannel = SocketChannel.open();
|
||||
configureSocket();
|
||||
if ( socketChannel.connect(addr) ) {
|
||||
completeConnect();
|
||||
socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this);
|
||||
} else {
|
||||
socketChannel.register(getSelector(), SelectionKey.OP_CONNECT, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* disconnect
|
||||
*
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.IDataSender method
|
||||
*/
|
||||
@Override
|
||||
public void disconnect() {
|
||||
try {
|
||||
connecting = false;
|
||||
setConnected(false);
|
||||
if (socketChannel != null) {
|
||||
try {
|
||||
try {
|
||||
socketChannel.socket().close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
//error free close, all the way
|
||||
//try {socket.shutdownOutput();}catch ( Exception x){}
|
||||
//try {socket.shutdownInput();}catch ( Exception x){}
|
||||
//try {socket.close();}catch ( Exception x){}
|
||||
try {
|
||||
socketChannel.close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
socketChannel = null;
|
||||
}
|
||||
}
|
||||
if (dataChannel != null) {
|
||||
try {
|
||||
try {
|
||||
dataChannel.socket().close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
//error free close, all the way
|
||||
//try {socket.shutdownOutput();}catch ( Exception x){}
|
||||
//try {socket.shutdownInput();}catch ( Exception x){}
|
||||
//try {socket.close();}catch ( Exception x){}
|
||||
try {
|
||||
dataChannel.close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
dataChannel = null;
|
||||
}
|
||||
}
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("nioSender.unable.disconnect", x.getMessage()));
|
||||
if ( log.isDebugEnabled() ) log.debug(sm.getString("nioSender.unable.disconnect", x.getMessage()),x);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
if ( isConnected() && readbuf == null) {
|
||||
readbuf = getReadBuffer();
|
||||
}
|
||||
if ( readbuf != null ) readbuf.clear();
|
||||
if ( writebuf != null ) writebuf.clear();
|
||||
current = null;
|
||||
ackbuf.clear();
|
||||
remaining = 0;
|
||||
complete = false;
|
||||
setAttempt(0);
|
||||
setUdpBased(false);
|
||||
}
|
||||
|
||||
private ByteBuffer getReadBuffer() {
|
||||
return getBuffer(getRxBufSize());
|
||||
}
|
||||
|
||||
private ByteBuffer getWriteBuffer() {
|
||||
return getBuffer(getTxBufSize());
|
||||
}
|
||||
|
||||
private ByteBuffer getBuffer(int size) {
|
||||
return getDirectBuffer()?ByteBuffer.allocateDirect(size):ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* sendMessage
|
||||
*
|
||||
* @param data ChannelMessage
|
||||
* @throws IOException
|
||||
* TODO Implement this org.apache.catalina.tribes.transport.IDataSender method
|
||||
*/
|
||||
public void setMessage(byte[] data) throws IOException {
|
||||
setMessage(data,0,data.length);
|
||||
}
|
||||
|
||||
public void setMessage(byte[] data,int offset, int length) throws IOException {
|
||||
if (data != null) {
|
||||
synchronized (this) {
|
||||
current = data;
|
||||
remaining = length;
|
||||
ackbuf.clear();
|
||||
if (writebuf != null) {
|
||||
writebuf.clear();
|
||||
} else {
|
||||
writebuf = getBuffer(length);
|
||||
}
|
||||
if (writebuf.capacity() < length) {
|
||||
writebuf = getBuffer(length);
|
||||
}
|
||||
|
||||
// TODO use ByteBuffer.wrap to avoid copying the data.
|
||||
writebuf.put(data,offset,length);
|
||||
writebuf.flip();
|
||||
if (isConnected()) {
|
||||
if (isUdpBased())
|
||||
dataChannel.register(getSelector(), SelectionKey.OP_WRITE, this);
|
||||
else
|
||||
socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMessage() {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public Selector getSelector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
public void setSelector(Selector selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.UniqueId;
|
||||
import org.apache.catalina.tribes.io.ChannelData;
|
||||
import org.apache.catalina.tribes.io.XByteBuffer;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.MultiPointSender;
|
||||
import org.apache.catalina.tribes.transport.SenderState;
|
||||
import org.apache.catalina.tribes.util.Logs;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
public class ParallelNioSender extends AbstractSender implements MultiPointSender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ParallelNioSender.class);
|
||||
protected static final StringManager sm = StringManager.getManager(ParallelNioSender.class);
|
||||
protected final long selectTimeout = 5000; //default 5 seconds, same as send timeout
|
||||
protected final Selector selector;
|
||||
protected final HashMap<Member, NioSender> nioSenders = new HashMap<>();
|
||||
|
||||
public ParallelNioSender() throws IOException {
|
||||
selector = Selector.open();
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void sendMessage(Member[] destination, ChannelMessage msg)
|
||||
throws ChannelException {
|
||||
long start = System.currentTimeMillis();
|
||||
this.setUdpBased((msg.getOptions()&Channel.SEND_OPTIONS_UDP) == Channel.SEND_OPTIONS_UDP);
|
||||
byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
|
||||
NioSender[] senders = setupForSend(destination);
|
||||
connect(senders);
|
||||
setData(senders,data);
|
||||
|
||||
int remaining = senders.length;
|
||||
ChannelException cx = null;
|
||||
try {
|
||||
//loop until complete, an error happens, or we timeout
|
||||
long delta = System.currentTimeMillis() - start;
|
||||
boolean waitForAck = (Channel.SEND_OPTIONS_USE_ACK &
|
||||
msg.getOptions()) == Channel.SEND_OPTIONS_USE_ACK;
|
||||
while ( (remaining>0) && (delta<getTimeout()) ) {
|
||||
try {
|
||||
SendResult result = doLoop(selectTimeout, getMaxRetryAttempts(),waitForAck,msg);
|
||||
remaining -= result.getCompleted();
|
||||
if (result.getFailed() != null) {
|
||||
remaining -= result.getFailed().getFaultyMembers().length;
|
||||
if (cx == null) cx = result.getFailed();
|
||||
else cx.addFaultyMember(result.getFailed().getFaultyMembers());
|
||||
}
|
||||
} catch (Exception x ) {
|
||||
if (log.isTraceEnabled()) log.trace("Error sending message", x);
|
||||
if (cx == null) {
|
||||
if ( x instanceof ChannelException ) cx = (ChannelException)x;
|
||||
else cx = new ChannelException(sm.getString("parallelNioSender.send.failed"), x);
|
||||
}
|
||||
for (int i=0; i<senders.length; i++ ) {
|
||||
if (!senders[i].isComplete()) {
|
||||
cx.addFaultyMember(senders[i].getDestination(),x);
|
||||
}
|
||||
}
|
||||
throw cx;
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
if ( remaining > 0 ) {
|
||||
//timeout has occurred
|
||||
ChannelException cxtimeout = new ChannelException(sm.getString(
|
||||
"parallelNioSender.operation.timedout", Long.toString(getTimeout())));
|
||||
if (cx == null) {
|
||||
cx = new ChannelException(sm.getString("parallelNioSender.operation.timedout",
|
||||
Long.toString(getTimeout())));
|
||||
}
|
||||
for (int i=0; i<senders.length; i++ ) {
|
||||
if (!senders[i].isComplete()) {
|
||||
cx.addFaultyMember(senders[i].getDestination(),cxtimeout);
|
||||
}
|
||||
}
|
||||
throw cx;
|
||||
} else if ( cx != null ) {
|
||||
//there was an error
|
||||
throw cx;
|
||||
}
|
||||
} catch (Exception x ) {
|
||||
try {
|
||||
this.disconnect();
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
if ( x instanceof ChannelException ) throw (ChannelException)x;
|
||||
else throw new ChannelException(x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SendResult doLoop(long selectTimeOut, int maxAttempts, boolean waitForAck, ChannelMessage msg)
|
||||
throws ChannelException {
|
||||
SendResult result = new SendResult();
|
||||
int selectedKeys;
|
||||
try {
|
||||
selectedKeys = selector.select(selectTimeOut);
|
||||
} catch (IOException ioe) {
|
||||
throw new ChannelException(sm.getString("parallelNioSender.send.failed"), ioe);
|
||||
}
|
||||
|
||||
if (selectedKeys == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
|
||||
while (it.hasNext()) {
|
||||
SelectionKey sk = it.next();
|
||||
it.remove();
|
||||
int readyOps = sk.readyOps();
|
||||
sk.interestOps(sk.interestOps() & ~readyOps);
|
||||
NioSender sender = (NioSender) sk.attachment();
|
||||
try {
|
||||
if (sender.process(sk,waitForAck)) {
|
||||
sender.setComplete(true);
|
||||
result.complete(sender);
|
||||
if ( Logs.MESSAGES.isTraceEnabled() ) {
|
||||
Logs.MESSAGES.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);
|
||||
}
|
||||
SenderState state = SenderState.getSenderState(sender.getDestination());
|
||||
int attempt = sender.getAttempt()+1;
|
||||
boolean retry = (attempt <= maxAttempts && maxAttempts>0);
|
||||
synchronized (state) {
|
||||
|
||||
//sk.cancel();
|
||||
if (state.isSuspect()) state.setFailing();
|
||||
if (state.isReady()) {
|
||||
state.setSuspect();
|
||||
if ( retry )
|
||||
log.warn(sm.getString("parallelNioSender.send.fail.retrying", sender.getDestination().getName()));
|
||||
else
|
||||
log.warn(sm.getString("parallelNioSender.send.fail", sender.getDestination().getName()), x);
|
||||
}
|
||||
}
|
||||
if ( !isConnected() ) {
|
||||
log.warn(sm.getString("parallelNioSender.sender.disconnected.notRetry", sender.getDestination().getName()));
|
||||
ChannelException cx = new ChannelException(sm.getString("parallelNioSender.sender.disconnected.sendFailed"), x);
|
||||
cx.addFaultyMember(sender.getDestination(),x);
|
||||
result.failed(cx);
|
||||
break;
|
||||
}
|
||||
|
||||
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 = new ChannelException(
|
||||
sm.getString("parallelNioSender.sendFailed.attempt",
|
||||
Integer.toString(sender.getAttempt()),
|
||||
Integer.toString(maxAttempts)), x);
|
||||
cx.addFaultyMember(sender.getDestination(),x);
|
||||
result.failed(cx);
|
||||
}//end if
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class SendResult {
|
||||
private List<NioSender> completeSenders = new ArrayList<>();
|
||||
private ChannelException exception = null;
|
||||
private void complete(NioSender sender) {
|
||||
if (!completeSenders.contains(sender)) completeSenders.add(sender);
|
||||
}
|
||||
private int getCompleted() {
|
||||
return completeSenders.size();
|
||||
}
|
||||
private void failed(ChannelException cx){
|
||||
if (exception == null) exception = cx;
|
||||
exception.addFaultyMember(cx.getFaultyMembers());
|
||||
}
|
||||
|
||||
private ChannelException getFailed() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
private void connect(NioSender[] senders) throws ChannelException {
|
||||
ChannelException x = null;
|
||||
for (int i=0; i<senders.length; i++ ) {
|
||||
try {
|
||||
senders[i].connect();
|
||||
}catch ( IOException io ) {
|
||||
if ( x==null ) x = new ChannelException(io);
|
||||
x.addFaultyMember(senders[i].getDestination(),io);
|
||||
}
|
||||
}
|
||||
if ( x != null ) throw x;
|
||||
}
|
||||
|
||||
private void setData(NioSender[] senders, byte[] data) throws ChannelException {
|
||||
ChannelException x = null;
|
||||
for (int i=0; i<senders.length; i++ ) {
|
||||
try {
|
||||
senders[i].setMessage(data);
|
||||
}catch ( IOException io ) {
|
||||
if ( x==null ) x = new ChannelException(io);
|
||||
x.addFaultyMember(senders[i].getDestination(),io);
|
||||
}
|
||||
}
|
||||
if ( x != null ) throw x;
|
||||
}
|
||||
|
||||
|
||||
private NioSender[] setupForSend(Member[] destination) throws ChannelException {
|
||||
ChannelException cx = null;
|
||||
NioSender[] result = new NioSender[destination.length];
|
||||
for ( int i=0; i<destination.length; i++ ) {
|
||||
NioSender sender = nioSenders.get(destination[i]);
|
||||
try {
|
||||
|
||||
if (sender == null) {
|
||||
sender = new NioSender();
|
||||
AbstractSender.transferProperties(this, sender);
|
||||
nioSenders.put(destination[i], sender);
|
||||
}
|
||||
sender.reset();
|
||||
sender.setDestination(destination[i]);
|
||||
sender.setSelector(selector);
|
||||
sender.setUdpBased(isUdpBased());
|
||||
result[i] = sender;
|
||||
}catch ( UnknownHostException x ) {
|
||||
if (cx == null) cx = new ChannelException(sm.getString("parallelNioSender.unable.setup.NioSender"), x);
|
||||
cx.addFaultyMember(destination[i], x);
|
||||
}
|
||||
}
|
||||
if ( cx != null ) throw cx;
|
||||
else return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
//do nothing, we connect on demand
|
||||
setConnected(true);
|
||||
}
|
||||
|
||||
|
||||
private synchronized void close() throws ChannelException {
|
||||
ChannelException x = null;
|
||||
Object[] members = nioSenders.keySet().toArray();
|
||||
for (int i=0; i<members.length; i++ ) {
|
||||
Member mbr = (Member)members[i];
|
||||
try {
|
||||
NioSender sender = nioSenders.get(mbr);
|
||||
sender.disconnect();
|
||||
}catch ( Exception e ) {
|
||||
if ( x == null ) x = new ChannelException(e);
|
||||
x.addFaultyMember(mbr,e);
|
||||
}
|
||||
nioSenders.remove(mbr);
|
||||
}
|
||||
if ( x != null ) throw x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Member member) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Member member) {
|
||||
//disconnect senders
|
||||
NioSender sender = nioSenders.remove(member);
|
||||
if ( sender != null ) sender.disconnect();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect() {
|
||||
setConnected(false);
|
||||
try {
|
||||
close();
|
||||
} catch (Exception x) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize() throws Throwable {
|
||||
try {disconnect(); }catch ( Exception e){/*Ignore*/}
|
||||
try {
|
||||
selector.close();
|
||||
}catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to close selector", e);
|
||||
}
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keepalive() {
|
||||
boolean result = false;
|
||||
for (Iterator<Entry<Member,NioSender>> i = nioSenders.entrySet().iterator(); i.hasNext();) {
|
||||
Map.Entry<Member, NioSender> entry = i.next();
|
||||
NioSender sender = entry.getValue();
|
||||
if ( sender.keepalive() ) {
|
||||
//nioSenders.remove(entry.getKey());
|
||||
i.remove();
|
||||
result = true;
|
||||
} else {
|
||||
try {
|
||||
sender.read();
|
||||
}catch ( IOException x ) {
|
||||
sender.disconnect();
|
||||
sender.reset();
|
||||
//nioSenders.remove(entry.getKey());
|
||||
i.remove();
|
||||
result = true;
|
||||
}catch ( Exception x ) {
|
||||
log.warn(sm.getString("parallelNioSender.error.keepalive", sender),x);
|
||||
}
|
||||
}
|
||||
}
|
||||
//clean up any cancelled keys
|
||||
if ( result ) try { selector.selectNow(); }catch (Exception e){/*Ignore*/}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelException;
|
||||
import org.apache.catalina.tribes.ChannelMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.transport.AbstractSender;
|
||||
import org.apache.catalina.tribes.transport.DataSender;
|
||||
import org.apache.catalina.tribes.transport.PooledSender;
|
||||
import org.apache.catalina.tribes.util.StringManager;
|
||||
|
||||
public class PooledParallelSender extends PooledSender implements PooledParallelSenderMBean {
|
||||
protected static final StringManager sm = StringManager.getManager(PooledParallelSender.class);
|
||||
|
||||
@Override
|
||||
public void sendMessage(Member[] destination, ChannelMessage message) throws ChannelException {
|
||||
if (!isConnected()) {
|
||||
throw new ChannelException(sm.getString("pooledParallelSender.sender.disconnected"));
|
||||
}
|
||||
ParallelNioSender sender = (ParallelNioSender)getSender();
|
||||
if (sender == null) {
|
||||
ChannelException cx = new ChannelException(sm.getString(
|
||||
"pooledParallelSender.unable.retrieveSender.timeout",
|
||||
Long.toString(getMaxWait())));
|
||||
for (int i = 0; i < destination.length; i++)
|
||||
cx.addFaultyMember(destination[i], new NullPointerException(sm.getString("pooledParallelSender.unable.retrieveSender")));
|
||||
throw cx;
|
||||
} else {
|
||||
try {
|
||||
if (!sender.isConnected()) sender.connect();
|
||||
sender.sendMessage(destination, message);
|
||||
sender.keepalive();
|
||||
} catch (ChannelException x) {
|
||||
sender.disconnect();
|
||||
throw x;
|
||||
} finally {
|
||||
returnSender(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSender getNewDataSender() {
|
||||
try {
|
||||
ParallelNioSender sender = new ParallelNioSender();
|
||||
AbstractSender.transferProperties(this,sender);
|
||||
return sender;
|
||||
} catch ( IOException x ) {
|
||||
throw new RuntimeException(sm.getString("pooledParallelSender.unable.open"),x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.catalina.tribes.transport.nio;
|
||||
|
||||
public interface PooledParallelSenderMBean {
|
||||
|
||||
// Transport Attributes
|
||||
public int getRxBufSize();
|
||||
|
||||
public int getTxBufSize();
|
||||
|
||||
public int getUdpRxBufSize();
|
||||
|
||||
public int getUdpTxBufSize();
|
||||
|
||||
public boolean getDirectBuffer();
|
||||
|
||||
public int getKeepAliveCount();
|
||||
|
||||
public long getKeepAliveTime();
|
||||
|
||||
public long getTimeout();
|
||||
|
||||
public int getMaxRetryAttempts();
|
||||
|
||||
public boolean getOoBInline();
|
||||
|
||||
public boolean getSoKeepAlive();
|
||||
|
||||
public boolean getSoLingerOn();
|
||||
|
||||
public int getSoLingerTime();
|
||||
|
||||
public boolean getSoReuseAddress();
|
||||
|
||||
public int getSoTrafficClass();
|
||||
|
||||
public boolean getTcpNoDelay();
|
||||
|
||||
public boolean getThrowOnFailedAck();
|
||||
|
||||
// PooledSender Attributes
|
||||
public int getPoolSize();
|
||||
|
||||
public long getMaxWait();
|
||||
|
||||
// Operation
|
||||
public boolean isConnected();
|
||||
|
||||
public int getInPoolSize();
|
||||
|
||||
public int getInUsePoolSize();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user