|
@@ -1,18 +1,19 @@
|
|
|
package com.taobao.tddl.dbsync.binlog;
|
|
|
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.util.BitSet;
|
|
|
+import java.util.List;
|
|
|
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.*;
|
|
|
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
|
|
|
+import org.apache.commons.compress.utils.Lists;
|
|
|
+import org.apache.commons.io.IOUtils;
|
|
|
import org.apache.commons.logging.Log;
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
|
|
import com.alibaba.otter.canal.parse.driver.mysql.packets.GTIDSet;
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.mariadb.AnnotateRowsEvent;
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.mariadb.BinlogCheckPointLogEvent;
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidListLogEvent;
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.mariadb.MariaGtidLogEvent;
|
|
|
-import com.taobao.tddl.dbsync.binlog.event.mariadb.StartEncryptionLogEvent;
|
|
|
+import com.taobao.tddl.dbsync.binlog.event.*;
|
|
|
+import com.taobao.tddl.dbsync.binlog.event.mariadb.*;
|
|
|
|
|
|
/**
|
|
|
* Implements a binary-log decoder.
|
|
@@ -56,6 +57,8 @@ public final class LogDecoder {
|
|
|
handleSet.set(flagIndex);
|
|
|
}
|
|
|
|
|
|
+ private LogBuffer compressIterateBuffer;
|
|
|
+
|
|
|
/**
|
|
|
* Decoding an event from binary-log buffer.
|
|
|
*
|
|
@@ -64,7 +67,6 @@ public final class LogDecoder {
|
|
|
*/
|
|
|
public LogEvent decode(LogBuffer buffer, LogContext context) throws IOException {
|
|
|
final int limit = buffer.limit();
|
|
|
-
|
|
|
if (limit >= FormatDescriptionLogEvent.LOG_EVENT_HEADER_LEN) {
|
|
|
LogHeader header = new LogHeader(buffer, context.getFormatDescription());
|
|
|
|
|
@@ -109,6 +111,58 @@ public final class LogDecoder {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * * process compress binlog payload
|
|
|
+ *
|
|
|
+ * @param event
|
|
|
+ * @param context
|
|
|
+ * @return
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public List<LogEvent> processIterateDecode(LogEvent event, LogContext context) throws IOException {
|
|
|
+ List<LogEvent> events = Lists.newArrayList();
|
|
|
+ if (event.getHeader().getType() == LogEvent.TRANSACTION_PAYLOAD_EVENT) {
|
|
|
+ // iterate for compresss payload
|
|
|
+ TransactionPayloadLogEvent compressEvent = ((TransactionPayloadLogEvent) event);
|
|
|
+ LogBuffer iterateBuffer = null;
|
|
|
+ if (compressEvent.isCompressByZstd()) {
|
|
|
+ ZstdCompressorInputStream in = new ZstdCompressorInputStream(
|
|
|
+ new ByteArrayInputStream(compressEvent.getPayload()));
|
|
|
+ byte[] decodeBytes = IOUtils.toByteArray(in);
|
|
|
+ iterateBuffer = new LogBuffer(decodeBytes, 0, decodeBytes.length);
|
|
|
+ } else if (compressEvent.isCompressByNone()) {
|
|
|
+ iterateBuffer = new LogBuffer(compressEvent.getPayload(), 0, compressEvent.getPayload().length);
|
|
|
+ } else {
|
|
|
+ throw new IllegalArgumentException("unkonow compresstype for " + event.getHeader().getLogFileName()
|
|
|
+ + ":" + event.getHeader().getLogPos());
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ context.setIterateDecode(true);
|
|
|
+ while (iterateBuffer.hasRemaining()) {// iterate
|
|
|
+ LogEvent deEvent = decode(iterateBuffer, context);
|
|
|
+ if (deEvent == null) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // compress event logPos = 0
|
|
|
+ deEvent.getHeader().setLogFileName(event.getHeader().getLogFileName());
|
|
|
+ deEvent.getHeader().setLogPos(event.getHeader().getLogPos());
|
|
|
+ // 需要重置payload每个event的eventLen , ack位点更新依赖logPos - eventLen,
|
|
|
+ // 原因:每个payload都是uncompress的eventLen,无法对应物理binlog的eventLen
|
|
|
+ // 隐患:memory计算空间大小时会出现放大的情况,影响getBatch的数量
|
|
|
+ deEvent.getHeader().setEventLen(event.getHeader().getEventLen());
|
|
|
+ events.add(deEvent);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ context.setIterateDecode(false);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // TODO support mariadb compress binlog
|
|
|
+ }
|
|
|
+ return events;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Deserialize an event from buffer.
|
|
|
*
|
|
@@ -127,8 +181,12 @@ public final class LogDecoder {
|
|
|
}
|
|
|
|
|
|
if (checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_OFF && checksumAlg != LogEvent.BINLOG_CHECKSUM_ALG_UNDEF) {
|
|
|
- // remove checksum bytes
|
|
|
- buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
|
|
|
+ if (context.isIterateDecode()) {
|
|
|
+ // transaction compress payload在主事件已经处理了checksum,遍历解析event忽略checksum处理
|
|
|
+ } else {
|
|
|
+ // remove checksum bytes
|
|
|
+ buffer.limit(header.getEventLen() - LogEvent.BINLOG_CHECKSUM_LEN);
|
|
|
+ }
|
|
|
}
|
|
|
GTIDSet gtidSet = context.getGtidSet();
|
|
|
LogEvent gtidLogEvent = context.getGtidLogEvent();
|
|
@@ -360,16 +418,10 @@ public final class LogDecoder {
|
|
|
return event;
|
|
|
}
|
|
|
case LogEvent.TRANSACTION_PAYLOAD_EVENT: {
|
|
|
- if (logger.isWarnEnabled()) {
|
|
|
- logger.warn("Skipping unsupported MySQL TRANSACTION_PAYLOAD_EVENT from: " + context.getLogPosition());
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- // TransactionPayloadLogEvent event = new TransactionPayloadLogEvent(header,
|
|
|
- // buffer, descriptionEvent);
|
|
|
- // /* updating position in context */
|
|
|
- // logPosition.position = header.getLogPos();
|
|
|
- // return event;
|
|
|
+ TransactionPayloadLogEvent event = new TransactionPayloadLogEvent(header, buffer, descriptionEvent);
|
|
|
+ /* updating position in context */
|
|
|
+ logPosition.position = header.getLogPos();
|
|
|
+ return event;
|
|
|
}
|
|
|
case LogEvent.VIEW_CHANGE_EVENT: {
|
|
|
ViewChangeEvent event = new ViewChangeEvent(header, buffer, descriptionEvent);
|