|
@@ -37,21 +37,23 @@ import com.taobao.tddl.dbsync.binlog.LogBuffer;
|
|
|
import com.taobao.tddl.dbsync.binlog.LogContext;
|
|
|
import com.taobao.tddl.dbsync.binlog.LogDecoder;
|
|
|
import com.taobao.tddl.dbsync.binlog.LogEvent;
|
|
|
+import com.taobao.tddl.dbsync.binlog.event.FormatDescriptionLogEvent;
|
|
|
|
|
|
public class MysqlConnection implements ErosaConnection {
|
|
|
|
|
|
- private static final Logger logger = LoggerFactory.getLogger(MysqlConnection.class);
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(MysqlConnection.class);
|
|
|
|
|
|
private MysqlConnector connector;
|
|
|
private long slaveId;
|
|
|
- private Charset charset = Charset.forName("UTF-8");
|
|
|
+ private Charset charset = Charset.forName("UTF-8");
|
|
|
private BinlogFormat binlogFormat;
|
|
|
private BinlogImage binlogImage;
|
|
|
|
|
|
// tsdb releated
|
|
|
private AuthenticationInfo authInfo;
|
|
|
- protected int connTimeout = 5 * 1000; // 5秒
|
|
|
- protected int soTimeout = 60 * 60 * 1000; // 1小时
|
|
|
+ protected int connTimeout = 5 * 1000; // 5秒
|
|
|
+ protected int soTimeout = 60 * 60 * 1000; // 1小时
|
|
|
+ private int binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_OFF;
|
|
|
// dump binlog bytes, 暂不包括meta与TSDB
|
|
|
private AtomicLong receivedBinlogBytes;
|
|
|
|
|
@@ -118,7 +120,7 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
*/
|
|
|
public void seek(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException {
|
|
|
updateSettings();
|
|
|
-
|
|
|
+ loadBinlogChecksum();
|
|
|
sendBinlogDump(binlogfilename, binlogPosition);
|
|
|
DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
|
|
|
fetcher.start(connector.getChannel());
|
|
@@ -128,6 +130,7 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
decoder.handle(LogEvent.QUERY_EVENT);
|
|
|
decoder.handle(LogEvent.XID_EVENT);
|
|
|
LogContext context = new LogContext();
|
|
|
+ context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));
|
|
|
while (fetcher.fetch()) {
|
|
|
accumulateReceivedBytes(fetcher.limit());
|
|
|
LogEvent event = null;
|
|
@@ -145,12 +148,14 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
|
|
|
public void dump(String binlogfilename, Long binlogPosition, SinkFunction func) throws IOException {
|
|
|
updateSettings();
|
|
|
+ loadBinlogChecksum();
|
|
|
sendRegisterSlave();
|
|
|
sendBinlogDump(binlogfilename, binlogPosition);
|
|
|
DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
|
|
|
fetcher.start(connector.getChannel());
|
|
|
LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);
|
|
|
LogContext context = new LogContext();
|
|
|
+ context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));
|
|
|
while (fetcher.fetch()) {
|
|
|
accumulateReceivedBytes(fetcher.limit());
|
|
|
LogEvent event = null;
|
|
@@ -173,6 +178,7 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
@Override
|
|
|
public void dump(GTIDSet gtidSet, SinkFunction func) throws IOException {
|
|
|
updateSettings();
|
|
|
+ loadBinlogChecksum();
|
|
|
sendBinlogDumpGTID(gtidSet);
|
|
|
|
|
|
DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
|
|
@@ -180,6 +186,7 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
fetcher.start(connector.getChannel());
|
|
|
LogDecoder decoder = new LogDecoder(LogEvent.UNKNOWN_EVENT, LogEvent.ENUM_END_EVENT);
|
|
|
LogContext context = new LogContext();
|
|
|
+ context.setFormatDescription(new FormatDescriptionLogEvent(4, binlogChecksum));
|
|
|
// fix bug: #890 将gtid传输至context中,供decode使用
|
|
|
context.setGtidSet(gtidSet);
|
|
|
while (fetcher.fetch()) {
|
|
@@ -207,9 +214,11 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
@Override
|
|
|
public void dump(String binlogfilename, Long binlogPosition, MultiStageCoprocessor coprocessor) throws IOException {
|
|
|
updateSettings();
|
|
|
+ loadBinlogChecksum();
|
|
|
sendRegisterSlave();
|
|
|
sendBinlogDump(binlogfilename, binlogPosition);
|
|
|
((MysqlMultiStageCoprocessor) coprocessor).setConnection(this);
|
|
|
+ ((MysqlMultiStageCoprocessor) coprocessor).setBinlogChecksum(binlogChecksum);
|
|
|
DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
|
|
|
try {
|
|
|
fetcher.start(connector.getChannel());
|
|
@@ -234,9 +243,10 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
@Override
|
|
|
public void dump(GTIDSet gtidSet, MultiStageCoprocessor coprocessor) throws IOException {
|
|
|
updateSettings();
|
|
|
+ loadBinlogChecksum();
|
|
|
sendBinlogDumpGTID(gtidSet);
|
|
|
-
|
|
|
((MysqlMultiStageCoprocessor) coprocessor).setConnection(this);
|
|
|
+ ((MysqlMultiStageCoprocessor) coprocessor).setBinlogChecksum(binlogChecksum);
|
|
|
DirectLogFetcher fetcher = new DirectLogFetcher(connector.getReceiveBufferSize());
|
|
|
try {
|
|
|
fetcher.start(connector.getChannel());
|
|
@@ -482,6 +492,52 @@ public class MysqlConnection implements ErosaConnection {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取主库checksum信息
|
|
|
+ *
|
|
|
+ * <pre>
|
|
|
+ * mariadb区别于mysql会在binlog的第一个事件Rotate_Event里也会采用checksum逻辑,而mysql是在第二个binlog事件之后才感知是否需要处理checksum
|
|
|
+ * 导致maraidb只要是开启checksum就会出现binlog文件名解析乱码
|
|
|
+ * fixed issue : https://github.com/alibaba/canal/issues/1081
|
|
|
+ * </pre>
|
|
|
+ */
|
|
|
+ private void loadBinlogChecksum() {
|
|
|
+ if (checkMariaDB()) {
|
|
|
+ ResultSetPacket rs = null;
|
|
|
+ try {
|
|
|
+ rs = query("select @@global.binlog_checksum");
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new CanalParseException(e);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> columnValues = rs.getFieldValues();
|
|
|
+ if (columnValues != null && columnValues.size() >= 1 && columnValues.get(0).toUpperCase().equals("CRC32")) {
|
|
|
+ binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_CRC32;
|
|
|
+ } else {
|
|
|
+ binlogChecksum = LogEvent.BINLOG_CHECKSUM_ALG_OFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取是否为mariadb
|
|
|
+ */
|
|
|
+ private boolean checkMariaDB() {
|
|
|
+ ResultSetPacket rs = null;
|
|
|
+ try {
|
|
|
+ rs = query("SELECT @@version");
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new CanalParseException(e);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> columnValues = rs.getFieldValues();
|
|
|
+ if (columnValues != null && columnValues.size() >= 1) {
|
|
|
+ return StringUtils.containsIgnoreCase(columnValues.get(0), "MariaDB");
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
private void accumulateReceivedBytes(long x) {
|
|
|
if (receivedBinlogBytes != null) {
|
|
|
receivedBinlogBytes.addAndGet(x);
|