mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fixbug: soTimeout doesn't work.
This commit is contained in:
@@ -5,7 +5,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -37,7 +37,6 @@ import com.alibaba.otter.canal.protocol.ClientIdentity;
|
|||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
import com.alibaba.otter.canal.protocol.exception.CanalClientException;
|
import com.alibaba.otter.canal.protocol.exception.CanalClientException;
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于{@linkplain CanalServerWithNetty}定义的网络协议接口,对于canal数据进行get/rollback/ack等操作
|
* 基于{@linkplain CanalServerWithNetty}定义的网络协议接口,对于canal数据进行get/rollback/ack等操作
|
||||||
@@ -57,6 +56,8 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
private final ByteBuffer readHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
|
private final ByteBuffer readHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
|
||||||
private final ByteBuffer writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
|
private final ByteBuffer writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
|
||||||
private SocketChannel channel;
|
private SocketChannel channel;
|
||||||
|
private ReadableByteChannel readableChannel;
|
||||||
|
private WritableByteChannel writableChannel;
|
||||||
private List<Compression> supportedCompressions = new ArrayList<Compression>();
|
private List<Compression> supportedCompressions = new ArrayList<Compression>();
|
||||||
private ClientIdentity clientIdentity;
|
private ClientIdentity clientIdentity;
|
||||||
private ClientRunningMonitor runningMonitor; // 运行控制
|
private ClientRunningMonitor runningMonitor; // 运行控制
|
||||||
@@ -130,7 +131,9 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
address = getNextAddress();
|
address = getNextAddress();
|
||||||
}
|
}
|
||||||
channel.connect(address);
|
channel.connect(address);
|
||||||
Packet p = Packet.parseFrom(readNextPacket(channel));
|
readableChannel = Channels.newChannel(channel.socket().getInputStream());
|
||||||
|
writableChannel = Channels.newChannel(channel.socket().getOutputStream());
|
||||||
|
Packet p = Packet.parseFrom(readNextPacket());
|
||||||
if (p.getVersion() != 1) {
|
if (p.getVersion() != 1) {
|
||||||
throw new CanalClientException("unsupported version at this client.");
|
throw new CanalClientException("unsupported version at this client.");
|
||||||
}
|
}
|
||||||
@@ -143,18 +146,19 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
supportedCompressions.addAll(handshake.getSupportedCompressionsList());
|
supportedCompressions.addAll(handshake.getSupportedCompressionsList());
|
||||||
//
|
//
|
||||||
ClientAuth ca = ClientAuth.newBuilder()
|
ClientAuth ca = ClientAuth.newBuilder()
|
||||||
.setUsername(username != null ? username : "")
|
.setUsername(username != null ? username : "")
|
||||||
.setNetReadTimeout(soTimeout)
|
.setPassword(ByteString.copyFromUtf8(password != null ? password : ""))
|
||||||
.setNetWriteTimeout(soTimeout)
|
.setNetReadTimeout(soTimeout)
|
||||||
.build();
|
.setNetWriteTimeout(soTimeout)
|
||||||
writeWithHeader(channel,
|
.build();
|
||||||
Packet.newBuilder()
|
writeWithHeader(
|
||||||
.setType(PacketType.CLIENTAUTHENTICATION)
|
Packet.newBuilder()
|
||||||
.setBody(ca.toByteString())
|
.setType(PacketType.CLIENTAUTHENTICATION)
|
||||||
.build()
|
.setBody(ca.toByteString())
|
||||||
.toByteArray());
|
.build()
|
||||||
|
.toByteArray());
|
||||||
//
|
//
|
||||||
Packet ack = Packet.parseFrom(readNextPacket(channel));
|
Packet ack = Packet.parseFrom(readNextPacket());
|
||||||
if (ack.getType() != PacketType.ACK) {
|
if (ack.getType() != PacketType.ACK) {
|
||||||
throw new CanalClientException("unexpected packet type when ack is expected");
|
throw new CanalClientException("unexpected packet type when ack is expected");
|
||||||
}
|
}
|
||||||
@@ -173,16 +177,28 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doDisconnnect() throws CanalClientException {
|
private void doDisconnnect() throws CanalClientException {
|
||||||
|
if (readableChannel != null) {
|
||||||
|
quietlyClose(readableChannel);
|
||||||
|
readableChannel = null;
|
||||||
|
}
|
||||||
|
if (writableChannel != null) {
|
||||||
|
quietlyClose(writableChannel);
|
||||||
|
writableChannel = null;
|
||||||
|
}
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
try {
|
quietlyClose(channel);
|
||||||
channel.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("exception on closing channel:{} \n {}", channel, e);
|
|
||||||
}
|
|
||||||
channel = null;
|
channel = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void quietlyClose(Channel channel) {
|
||||||
|
try {
|
||||||
|
channel.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("exception on closing channel:{} \n {}", channel, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void subscribe() throws CanalClientException {
|
public void subscribe() throws CanalClientException {
|
||||||
subscribe(""); // 传递空字符即可
|
subscribe(""); // 传递空字符即可
|
||||||
}
|
}
|
||||||
@@ -190,19 +206,19 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
public void subscribe(String filter) throws CanalClientException {
|
public void subscribe(String filter) throws CanalClientException {
|
||||||
waitClientRunning();
|
waitClientRunning();
|
||||||
try {
|
try {
|
||||||
writeWithHeader(channel,
|
writeWithHeader(
|
||||||
Packet.newBuilder()
|
Packet.newBuilder()
|
||||||
.setType(PacketType.SUBSCRIPTION)
|
.setType(PacketType.SUBSCRIPTION)
|
||||||
.setBody(Sub.newBuilder()
|
.setBody(Sub.newBuilder()
|
||||||
.setDestination(clientIdentity.getDestination())
|
.setDestination(clientIdentity.getDestination())
|
||||||
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
||||||
.setFilter(filter != null ? filter : "")
|
.setFilter(filter != null ? filter : "")
|
||||||
.build()
|
.build()
|
||||||
.toByteString())
|
.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
//
|
//
|
||||||
Packet p = Packet.parseFrom(readNextPacket(channel));
|
Packet p = Packet.parseFrom(readNextPacket());
|
||||||
Ack ack = Ack.parseFrom(p.getBody());
|
Ack ack = Ack.parseFrom(p.getBody());
|
||||||
if (ack.getErrorCode() > 0) {
|
if (ack.getErrorCode() > 0) {
|
||||||
throw new CanalClientException("failed to subscribe with reason: " + ack.getErrorMessage());
|
throw new CanalClientException("failed to subscribe with reason: " + ack.getErrorMessage());
|
||||||
@@ -217,18 +233,18 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
public void unsubscribe() throws CanalClientException {
|
public void unsubscribe() throws CanalClientException {
|
||||||
waitClientRunning();
|
waitClientRunning();
|
||||||
try {
|
try {
|
||||||
writeWithHeader(channel,
|
writeWithHeader(
|
||||||
Packet.newBuilder()
|
Packet.newBuilder()
|
||||||
.setType(PacketType.UNSUBSCRIPTION)
|
.setType(PacketType.UNSUBSCRIPTION)
|
||||||
.setBody(Unsub.newBuilder()
|
.setBody(Unsub.newBuilder()
|
||||||
.setDestination(clientIdentity.getDestination())
|
.setDestination(clientIdentity.getDestination())
|
||||||
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
||||||
.build()
|
.build()
|
||||||
.toByteString())
|
.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
//
|
//
|
||||||
Packet p = Packet.parseFrom(readNextPacket(channel));
|
Packet p = Packet.parseFrom(readNextPacket());
|
||||||
Ack ack = Ack.parseFrom(p.getBody());
|
Ack ack = Ack.parseFrom(p.getBody());
|
||||||
if (ack.getErrorCode() > 0) {
|
if (ack.getErrorCode() > 0) {
|
||||||
throw new CanalClientException("failed to unSubscribe with reason: " + ack.getErrorMessage());
|
throw new CanalClientException("failed to unSubscribe with reason: " + ack.getErrorMessage());
|
||||||
@@ -261,29 +277,28 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
unit = TimeUnit.MILLISECONDS;
|
unit = TimeUnit.MILLISECONDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeWithHeader(channel,
|
writeWithHeader(
|
||||||
Packet.newBuilder()
|
Packet.newBuilder()
|
||||||
.setType(PacketType.GET)
|
.setType(PacketType.GET)
|
||||||
.setBody(Get.newBuilder()
|
.setBody(Get.newBuilder()
|
||||||
.setAutoAck(false)
|
.setAutoAck(false)
|
||||||
.setDestination(clientIdentity.getDestination())
|
.setDestination(clientIdentity.getDestination())
|
||||||
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
||||||
.setFetchSize(size)
|
.setFetchSize(size)
|
||||||
.setTimeout(time)
|
.setTimeout(time)
|
||||||
.setUnit(unit.ordinal())
|
.setUnit(unit.ordinal())
|
||||||
.build()
|
.build()
|
||||||
.toByteString())
|
.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
|
|
||||||
return receiveMessages();
|
return receiveMessages();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CanalClientException(e);
|
throw new CanalClientException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message receiveMessages() throws InvalidProtocolBufferException, IOException {
|
private Message receiveMessages() throws IOException {
|
||||||
Packet p = Packet.parseFrom(readNextPacket(channel));
|
Packet p = Packet.parseFrom(readNextPacket());
|
||||||
switch (p.getType()) {
|
switch (p.getType()) {
|
||||||
case MESSAGES: {
|
case MESSAGES: {
|
||||||
if (!p.getCompression().equals(Compression.NONE)) {
|
if (!p.getCompression().equals(Compression.NONE)) {
|
||||||
@@ -310,16 +325,16 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
public void ack(long batchId) throws CanalClientException {
|
public void ack(long batchId) throws CanalClientException {
|
||||||
waitClientRunning();
|
waitClientRunning();
|
||||||
ClientAck ca = ClientAck.newBuilder()
|
ClientAck ca = ClientAck.newBuilder()
|
||||||
.setDestination(clientIdentity.getDestination())
|
.setDestination(clientIdentity.getDestination())
|
||||||
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
||||||
.setBatchId(batchId)
|
.setBatchId(batchId)
|
||||||
.build();
|
.build();
|
||||||
try {
|
try {
|
||||||
writeWithHeader(channel, Packet.newBuilder()
|
writeWithHeader(Packet.newBuilder()
|
||||||
.setType(PacketType.CLIENTACK)
|
.setType(PacketType.CLIENTACK)
|
||||||
.setBody(ca.toByteString())
|
.setBody(ca.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CanalClientException(e);
|
throw new CanalClientException(e);
|
||||||
}
|
}
|
||||||
@@ -328,16 +343,16 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
public void rollback(long batchId) throws CanalClientException {
|
public void rollback(long batchId) throws CanalClientException {
|
||||||
waitClientRunning();
|
waitClientRunning();
|
||||||
ClientRollback ca = ClientRollback.newBuilder()
|
ClientRollback ca = ClientRollback.newBuilder()
|
||||||
.setDestination(clientIdentity.getDestination())
|
.setDestination(clientIdentity.getDestination())
|
||||||
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
.setClientId(String.valueOf(clientIdentity.getClientId()))
|
||||||
.setBatchId(batchId)
|
.setBatchId(batchId)
|
||||||
.build();
|
.build();
|
||||||
try {
|
try {
|
||||||
writeWithHeader(channel, Packet.newBuilder()
|
writeWithHeader(Packet.newBuilder()
|
||||||
.setType(PacketType.CLIENTROLLBACK)
|
.setType(PacketType.CLIENTROLLBACK)
|
||||||
.setBody(ca.toByteString())
|
.setBody(ca.toByteString())
|
||||||
.build()
|
.build()
|
||||||
.toByteArray());
|
.toByteArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CanalClientException(e);
|
throw new CanalClientException(e);
|
||||||
}
|
}
|
||||||
@@ -350,7 +365,15 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
|
|
||||||
// ==================== helper method ====================
|
// ==================== helper method ====================
|
||||||
|
|
||||||
private void writeWithHeader(SocketChannel channel, byte[] body) throws IOException {
|
private void writeWithHeader(byte[] body) throws IOException {
|
||||||
|
writeWithHeader(writableChannel, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] readNextPacket() throws IOException {
|
||||||
|
return readNextPacket(readableChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeWithHeader(WritableByteChannel channel, byte[] body) throws IOException {
|
||||||
synchronized (writeDataLock) {
|
synchronized (writeDataLock) {
|
||||||
writeHeader.clear();
|
writeHeader.clear();
|
||||||
writeHeader.putInt(body.length);
|
writeHeader.putInt(body.length);
|
||||||
@@ -360,7 +383,7 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] readNextPacket(SocketChannel channel) throws IOException {
|
private byte[] readNextPacket(ReadableByteChannel channel) throws IOException {
|
||||||
synchronized (readDataLock) {
|
synchronized (readDataLock) {
|
||||||
readHeader.clear();
|
readHeader.clear();
|
||||||
read(channel, readHeader);
|
read(channel, readHeader);
|
||||||
@@ -371,7 +394,7 @@ public class SimpleCanalConnector implements CanalConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void read(SocketChannel channel, ByteBuffer buffer) throws IOException {
|
private void read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {
|
||||||
while (buffer.hasRemaining()) {
|
while (buffer.hasRemaining()) {
|
||||||
int r = channel.read(buffer);
|
int r = channel.read(buffer);
|
||||||
if (r == -1) {
|
if (r == -1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user