mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fixed issue #126, support gtid
This commit is contained in:
@@ -8,8 +8,6 @@ import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.apache.commons.lang.math.RandomUtils;
|
||||
@@ -21,6 +19,7 @@ import com.alibaba.otter.canal.common.AbstractCanalLifeCycle;
|
||||
import com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;
|
||||
import com.alibaba.otter.canal.filter.CanalEventFilter;
|
||||
import com.alibaba.otter.canal.parse.CanalEventParser;
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;
|
||||
import com.alibaba.otter.canal.parse.exception.CanalParseException;
|
||||
import com.alibaba.otter.canal.parse.exception.TableIdNotFoundException;
|
||||
import com.alibaba.otter.canal.parse.inbound.EventTransactionBuffer.TransactionFlushCallback;
|
||||
@@ -90,7 +89,6 @@ public abstract class AbstractEventParser<EVENT> extends AbstractCanalLifeCycle
|
||||
protected Throwable exception = null;
|
||||
|
||||
protected boolean isGTIDMode = false; // 是否是GTID模式
|
||||
protected String GTIDSetStr = null;
|
||||
|
||||
protected abstract BinlogParser buildParser();
|
||||
|
||||
@@ -550,13 +548,4 @@ public abstract class AbstractEventParser<EVENT> extends AbstractCanalLifeCycle
|
||||
public void setIsGTIDMode(boolean isGTIDMode) {
|
||||
this.isGTIDMode = isGTIDMode;
|
||||
}
|
||||
|
||||
public String getGTIDSetStr() {
|
||||
return GTIDSetStr;
|
||||
}
|
||||
|
||||
public void setGTIDSetStr(String GTIDSetStr) {
|
||||
this.GTIDSetStr = GTIDSetStr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.alibaba.otter.canal.parse.inbound.mysql;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;
|
||||
import com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvertGTID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.otter.canal.filter.CanalEventFilter;
|
||||
import com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;
|
||||
import com.alibaba.otter.canal.parse.exception.CanalParseException;
|
||||
import com.alibaba.otter.canal.parse.inbound.AbstractEventParser;
|
||||
import com.alibaba.otter.canal.parse.inbound.BinlogParser;
|
||||
@@ -37,20 +35,7 @@ public abstract class AbstractMysqlEventParser extends AbstractEventParser {
|
||||
protected boolean useDruidDdlFilter = true;
|
||||
|
||||
protected BinlogParser buildParser() {
|
||||
LogEventConvert convert;
|
||||
|
||||
if (isGTIDMode()) {
|
||||
EntryPosition position;
|
||||
try {
|
||||
position = findStartPosition(null);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("findStartPosition failed.", e);
|
||||
}
|
||||
convert = new LogEventConvertGTID(MysqlGTIDSet.parse(position.getGtid()));
|
||||
} else {
|
||||
convert = new LogEventConvert();
|
||||
}
|
||||
|
||||
LogEventConvert convert = new LogEventConvert();
|
||||
if (eventFilter != null && eventFilter instanceof AviaterRegexFilter) {
|
||||
convert.setNameFilter((AviaterRegexFilter) eventFilter);
|
||||
}
|
||||
@@ -84,7 +69,18 @@ public abstract class AbstractMysqlEventParser extends AbstractEventParser {
|
||||
* @return
|
||||
*/
|
||||
protected boolean processTableMeta(EntryPosition position) {
|
||||
if (isGTIDMode()) {
|
||||
if (binlogParser instanceof LogEventConvert) {
|
||||
// 记录gtid
|
||||
((LogEventConvert) binlogParser).setGtidSet(MysqlGTIDSet.parse(position.getGtid()));
|
||||
}
|
||||
}
|
||||
|
||||
if (tableMetaTSDB != null) {
|
||||
if (position.getTimestamp() == null || position.getTimestamp() <= 0) {
|
||||
throw new CanalParseException("use gtid and TableMeta TSDB should be config timestamp > 0");
|
||||
}
|
||||
|
||||
return tableMetaTSDB.rollback(position);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,6 @@ import java.util.Map;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.MysqlGTIDSet;
|
||||
import com.alibaba.otter.canal.parse.inbound.BinlogParser;
|
||||
import com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvertGTID;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -354,8 +350,12 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
||||
if (logPosition != null) {
|
||||
return logPosition.getPostion();
|
||||
}
|
||||
return masterPosition;
|
||||
|
||||
if (StringUtils.isNotEmpty(masterPosition.getGtid())) {
|
||||
return masterPosition;
|
||||
}
|
||||
}
|
||||
|
||||
EntryPosition startPosition = findStartPositionInternal(connection);
|
||||
if (needTransactionPosition.get()) {
|
||||
logger.warn("prepare to find last position : {}", startPosition.toString());
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.otter.canal.common.AbstractCanalLifeCycle;
|
||||
import com.alibaba.otter.canal.filter.aviater.AviaterRegexFilter;
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;
|
||||
import com.alibaba.otter.canal.parse.exception.CanalParseException;
|
||||
import com.alibaba.otter.canal.parse.exception.TableIdNotFoundException;
|
||||
import com.alibaba.otter.canal.parse.inbound.BinlogParser;
|
||||
@@ -40,6 +41,7 @@ import com.alibaba.otter.canal.protocol.position.EntryPosition;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.DeleteRowsLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.GtidLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.IntvarLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.LogHeader;
|
||||
import com.taobao.tddl.dbsync.binlog.event.QueryLogEvent;
|
||||
@@ -56,7 +58,6 @@ import com.taobao.tddl.dbsync.binlog.event.UserVarLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.WriteRowsLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.XidLogEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;
|
||||
import com.taobao.tddl.dbsync.binlog.event.GtidLogEvent;
|
||||
|
||||
/**
|
||||
* 基于{@linkplain LogEvent}转化为Entry对象的处理
|
||||
@@ -93,6 +94,17 @@ public class LogEventConvert extends AbstractCanalLifeCycle implements BinlogPar
|
||||
private boolean filterRows = false;
|
||||
private boolean useDruidDdlFilter = true;
|
||||
|
||||
// latest gtid
|
||||
private GTIDSet gtidSet;
|
||||
|
||||
public LogEventConvert(GTIDSet gtidSet){
|
||||
this.gtidSet = gtidSet;
|
||||
}
|
||||
|
||||
public LogEventConvert(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry parse(LogEvent logEvent, boolean isSeek) throws CanalParseException {
|
||||
if (logEvent == null || logEvent instanceof UnknownLogEvent) {
|
||||
@@ -148,10 +160,15 @@ public class LogEventConvert extends AbstractCanalLifeCycle implements BinlogPar
|
||||
|
||||
private Entry parseGTIDLogEvent(GtidLogEvent logEvent) {
|
||||
LogHeader logHeader = logEvent.getHeader();
|
||||
Header header = createHeader("", logHeader, "", "", EventType.GTID);
|
||||
String value = logEvent.getSid().toString() + ":" + logEvent.getGno();
|
||||
Pair.Builder builder = Pair.newBuilder();
|
||||
builder.setKey("gtid");
|
||||
builder.setValue(String.format("%s:%d", logEvent.getSid(), logEvent.getGno()));
|
||||
builder.setValue(value);
|
||||
if (gtidSet != null) {
|
||||
gtidSet.update(value);
|
||||
}
|
||||
|
||||
Header header = createHeader("", logHeader, "", "", EventType.GTID);
|
||||
return createEntry(header, EntryType.GTIDLOG, builder.build().toByteString());
|
||||
}
|
||||
|
||||
@@ -737,6 +754,11 @@ public class LogEventConvert extends AbstractCanalLifeCycle implements BinlogPar
|
||||
headerBuilder.setTableName(tableName);
|
||||
}
|
||||
headerBuilder.setEventLength(logHeader.getEventLen());
|
||||
// enable gtid position
|
||||
if (gtidSet != null) {
|
||||
String gtid = gtidSet.toString();
|
||||
headerBuilder.setGtid(gtid);
|
||||
}
|
||||
return headerBuilder.build();
|
||||
}
|
||||
|
||||
@@ -785,7 +807,7 @@ public class LogEventConvert extends AbstractCanalLifeCycle implements BinlogPar
|
||||
return "LONGTEXT".equalsIgnoreCase(columnType) || "MEDIUMTEXT".equalsIgnoreCase(columnType)
|
||||
|| "TEXT".equalsIgnoreCase(columnType) || "TINYTEXT".equalsIgnoreCase(columnType);
|
||||
}
|
||||
|
||||
|
||||
private boolean isAliSQLHeartBeat(String schema, String table) {
|
||||
return "test".equalsIgnoreCase(schema) && "heartbeat".equalsIgnoreCase(table);
|
||||
}
|
||||
@@ -857,4 +879,8 @@ public class LogEventConvert extends AbstractCanalLifeCycle implements BinlogPar
|
||||
this.filterRows = filterRows;
|
||||
}
|
||||
|
||||
public void setGtidSet(GTIDSet gtidSet) {
|
||||
this.gtidSet = gtidSet;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.alibaba.otter.canal.parse.inbound.mysql.dbsync;
|
||||
|
||||
import com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;
|
||||
import com.alibaba.otter.canal.parse.exception.CanalParseException;
|
||||
import com.alibaba.otter.canal.parse.inbound.BinlogParser;
|
||||
import com.alibaba.otter.canal.protocol.CanalEntry;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.taobao.tddl.dbsync.binlog.LogEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by hiwjd on 2018/5/2.
|
||||
* hiwjd0@gmail.com
|
||||
*/
|
||||
public class LogEventConvertGTID extends LogEventConvert implements BinlogParser<LogEvent> {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger(LogEventConvertGTID.class);
|
||||
|
||||
// latest gtid
|
||||
private GTIDSet gtidSet;
|
||||
|
||||
public LogEventConvertGTID(GTIDSet gtidSet) {
|
||||
this.gtidSet = gtidSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanalEntry.Entry parse(LogEvent event, boolean isSeek) throws CanalParseException {
|
||||
CanalEntry.Entry entry = super.parse(event, isSeek);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry.getEntryType() == CanalEntry.EntryType.GTIDLOG) {
|
||||
try {
|
||||
CanalEntry.Pair pair = CanalEntry.Pair.parseFrom(entry.getStoreValue());
|
||||
gtidSet.update(pair.getValue());
|
||||
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
logger.error("retrive gtid failed.", e);
|
||||
throw new CanalParseException("retrive gtid failed.", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (gtidSet != null) {
|
||||
String gtid = gtidSet.toString();
|
||||
CanalEntry.Header header = entry.getHeader().toBuilder().setGtid(gtid).build();
|
||||
entry = entry.toBuilder().setHeader(header).build();
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,7 @@ public class MysqlDumpTest {
|
||||
@Test
|
||||
public void testSimple() {
|
||||
final MysqlEventParser controller = new MysqlEventParser();
|
||||
final EntryPosition startPosition = new EntryPosition("mysql-bin.000001", 104606L);
|
||||
|
||||
final EntryPosition startPosition = new EntryPosition("mysql-bin.000010", 154L);
|
||||
controller.setConnectionCharset(Charset.forName("UTF-8"));
|
||||
controller.setSlaveId(3344L);
|
||||
controller.setDetectingEnable(false);
|
||||
@@ -39,6 +38,7 @@ public class MysqlDumpTest {
|
||||
controller.setTsdbSpringXml("classpath:tsdb/h2-tsdb.xml");
|
||||
controller.setEventFilter(new AviaterRegexFilter("test\\..*"));
|
||||
controller.setEventBlackFilter(new AviaterRegexFilter("canal_tsdb\\..*"));
|
||||
controller.setIsGTIDMode(true);
|
||||
controller.setEventSink(new AbstractCanalEventSinkTest<List<Entry>>() {
|
||||
|
||||
public boolean sink(List<Entry> entrys, InetSocketAddress remoteAddress, String destination)
|
||||
|
||||
Reference in New Issue
Block a user