93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
package blt
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/localhots/pretty"
|
|
)
|
|
|
|
var (
|
|
// ErrInvalidHeader is returned when event header cannot be parsed.
|
|
ErrInvalidHeader = errors.New("Header is invalid")
|
|
)
|
|
|
|
// EventHeader represents binlog event header.
|
|
type EventHeader struct {
|
|
Timestamp uint32
|
|
Type EventType
|
|
ServerID uint32
|
|
EventLen uint32
|
|
NextOffset uint32
|
|
Flags uint16
|
|
ExtraHeaders []byte
|
|
|
|
eventBody []byte
|
|
}
|
|
|
|
// Spec: https://dev.mysql.com/doc/internals/en/event-header-fields.html
|
|
func (r *Reader) parseHeader(data []byte) (*EventHeader, error) {
|
|
headerLen := r.headerLen()
|
|
if len(data) < headerLen {
|
|
return nil, ErrInvalidHeader
|
|
}
|
|
// pretty.Println(headerLen, data)
|
|
|
|
buf := newReadBuffer(data)
|
|
h := &EventHeader{
|
|
Timestamp: buf.readUint32(),
|
|
Type: EventType(buf.readUint8()),
|
|
ServerID: buf.readUint32(),
|
|
EventLen: buf.readUint32(),
|
|
}
|
|
if r.format.Version == 0 || r.format.Version >= 3 {
|
|
h.NextOffset = buf.readUint32()
|
|
h.Flags = buf.readUint16()
|
|
}
|
|
if r.format.Version >= 4 {
|
|
h.ExtraHeaders = buf.readStringVarLen(headerLen - 19)
|
|
}
|
|
h.eventBody = buf.cur()
|
|
|
|
if h.NextOffset > 0 {
|
|
r.state.Offset = uint64(h.NextOffset)
|
|
}
|
|
|
|
csa := r.format.ServerDetails.ChecksumAlgorithm
|
|
if h.Type != FormatDescriptionEvent && csa == ChecksumAlgorithmCRC32 {
|
|
h.eventBody = h.eventBody[:len(h.eventBody)-4]
|
|
}
|
|
|
|
// pretty.Println(h)
|
|
|
|
switch h.Type {
|
|
case FormatDescriptionEvent:
|
|
r.format = decodeFormatDescription(h.eventBody)
|
|
pretty.Println(h.Type.String(), r.format)
|
|
case RotateEvent:
|
|
r.state = r.decodeRotateEvent(h.eventBody)
|
|
pretty.Println(h.Type.String(), r.state)
|
|
case TableMapEvent:
|
|
tm := r.decodeTableMap(h.eventBody)
|
|
r.tableMap[tm.TableID] = tm
|
|
// pretty.Println(h.Type.String(), tm)
|
|
case WriteRowsEventV0, WriteRowsEventV1, WriteRowsEventV2,
|
|
UpdateRowsEventV0, UpdateRowsEventV1, UpdateRowsEventV2,
|
|
DeleteRowsEventV0, DeleteRowsEventV1, DeleteRowsEventV2:
|
|
r.decodeRowsEvent(h.eventBody, h.Type)
|
|
case XIDEvent, GTIDEvent:
|
|
// TODO: Add support for these too
|
|
case QueryEvent:
|
|
// TODO: Handle schema changes
|
|
}
|
|
|
|
return h, nil
|
|
}
|
|
|
|
func (r *Reader) headerLen() int {
|
|
const defaultHeaderLength = 19
|
|
if r.format.EventHeaderLength > 0 {
|
|
return int(r.format.EventHeaderLength)
|
|
}
|
|
return defaultHeaderLength
|
|
}
|