//This builds BinlogResponse for each transaction. func (blp *Blp) buildTxnResponse() (txnResponseList []*mysqlctl.BinlogResponse, dmlCount int64) { var line []byte var keyspaceIdStr string var keyspaceId key.KeyspaceId dmlBuffer := make([]string, 0, 10) for _, event := range blp.txnLineBuffer { line = event.LogLine if bytes.HasPrefix(line, mysqlctl.BINLOG_BEGIN) { streamBuf := new(mysqlctl.BinlogResponse) streamBuf.BlPosition = event.BlPosition streamBuf.SqlType = mysqlctl.BEGIN txnResponseList = append(txnResponseList, streamBuf) continue } if bytes.HasPrefix(line, mysqlctl.BINLOG_COMMIT) { commitEvent := createCommitEvent(event) txnResponseList = append(txnResponseList, commitEvent) continue } sqlType := mysqlctl.GetSqlType(event.firstKw) if sqlType == mysqlctl.DML { keyspaceIdStr, keyspaceId = parseKeyspaceId(line, mysqlctl.GetDmlType(event.firstKw)) if keyspaceIdStr == "" { continue } if !blp.keyspaceRange.Contains(keyspaceId) { dmlBuffer = dmlBuffer[:0] continue } dmlCount += 1 //extract keyspace id - match it with client's request, //extract index ids. dmlBuffer = append(dmlBuffer, string(line)) dmlEvent := blp.createDmlEvent(event, keyspaceIdStr) dmlEvent.Sql = make([]string, len(dmlBuffer)) dmlLines := copy(dmlEvent.Sql, dmlBuffer) if dmlLines < len(dmlBuffer) { relog.Warning("The entire dml buffer was not properly copied") } txnResponseList = append(txnResponseList, dmlEvent) dmlBuffer = dmlBuffer[:0] } else { //add as prefixes to the DML from last DML. //start a new dml buffer and keep adding to it. dmlBuffer = append(dmlBuffer, string(line)) } } return txnResponseList, dmlCount }
func (blp *Blp) parseEventData(sendReply mysqlctl.SendUpdateStreamResponse, event *eventBuffer) { if bytes.HasPrefix(event.LogLine, mysqlctl.BINLOG_SET_TIMESTAMP) { blp.extractEventTimestamp(event) blp.initialSeek = false if blp.inTxn { blp.txnLineBuffer = append(blp.txnLineBuffer, event) } } else if bytes.HasPrefix(event.LogLine, mysqlctl.BINLOG_BEGIN) { blp.handleBeginEvent(event) } else if bytes.HasPrefix(event.LogLine, mysqlctl.BINLOG_ROLLBACK) { blp.inTxn = false blp.txnLineBuffer = blp.txnLineBuffer[:0] } else if bytes.HasPrefix(event.LogLine, mysqlctl.BINLOG_COMMIT) { blp.handleCommitEvent(sendReply, event) blp.inTxn = false blp.txnLineBuffer = blp.txnLineBuffer[:0] } else if len(event.LogLine) > 0 { sqlType := mysqlctl.GetSqlType(event.firstKw) if blp.inTxn && mysqlctl.IsTxnStatement(event.LogLine, event.firstKw) { blp.txnLineBuffer = append(blp.txnLineBuffer, event) } else if sqlType == mysqlctl.DDL { blp.handleDdlEvent(sendReply, event) } else { if sqlType == mysqlctl.DML { lineBuf := make([][]byte, 0, 10) for _, dml := range blp.txnLineBuffer { lineBuf = append(lineBuf, dml.LogLine) } panic(NewBinlogParseError(fmt.Sprintf("DML outside a txn - len %v, dml '%v', txn buffer '%v'", len(blp.txnLineBuffer), string(event.LogLine), string(bytes.Join(lineBuf, mysqlctl.SEMICOLON_BYTE))))) } //Ignore these often occuring statement types. if !mysqlctl.IgnoredStatement(event.LogLine) { relog.Warning("Unknown statement '%v'", string(event.LogLine)) } } } }