func positionCmd(mysqld *mysqlctl.Mysqld, subFlags *flag.FlagSet, args []string) error { subFlags.Parse(args) if len(args) < 3 { return fmt.Errorf("Not enough arguments for position operation.") } pos1, err := myproto.DecodeReplicationPosition(args[1]) if err != nil { return err } switch args[0] { case "equal": pos2, err := myproto.DecodeReplicationPosition(args[2]) if err != nil { return err } fmt.Println(pos1.Equal(pos2)) case "at_least": pos2, err := myproto.DecodeReplicationPosition(args[2]) if err != nil { return err } fmt.Println(pos1.AtLeast(pos2)) case "append": gtid, err := myproto.DecodeGTID(args[2]) if err != nil { return err } fmt.Println(myproto.AppendGTID(pos1, gtid)) } return nil }
// WaitBlpPos will wait for the filtered replication to reach at least // the provided position. func (mysqld *Mysqld) WaitBlpPos(bp *blproto.BlpPosition, waitTimeout time.Duration) error { timeOut := time.Now().Add(waitTimeout) for { if time.Now().After(timeOut) { break } cmd := binlogplayer.QueryBlpCheckpoint(bp.Uid) qr, err := mysqld.fetchSuperQuery(cmd) if err != nil { return err } if len(qr.Rows) != 1 { return fmt.Errorf("WaitBlpPos(%v) returned unexpected row count: %v", bp.Uid, len(qr.Rows)) } var gtid proto.GTID if !qr.Rows[0][0].IsNull() { gtid, err = proto.DecodeGTID(qr.Rows[0][0].String()) if err != nil { return err } } if gtid == bp.GTIDField.Value { return nil } log.Infof("Sleeping 1 second waiting for binlog replication(%v) to catch up: %v != %v", bp.Uid, gtid, bp.GTIDField) time.Sleep(1 * time.Second) } return fmt.Errorf("WaitBlpPos(%v) timed out", bp.Uid) }
// ReadStartPosition will return the current start position and the flags for // the provided binlog player. func ReadStartPosition(dbClient VtClient, uid uint32) (*proto.BlpPosition, string, error) { selectRecovery := QueryBlpCheckpoint(uid) qr, err := dbClient.ExecuteFetch(selectRecovery, 1, true) if err != nil { return nil, "", fmt.Errorf("error %v in selecting from recovery table %v", err, selectRecovery) } if qr.RowsAffected != 1 { return nil, "", fmt.Errorf("checkpoint information not available in db for %v", uid) } gtid, err := myproto.DecodeGTID(qr.Rows[0][0].String()) if err != nil { return nil, "", err } return &proto.BlpPosition{ Uid: uid, GTIDField: myproto.GTIDField{Value: gtid}, }, string(qr.Rows[0][1].Raw()), nil }
// writeRecoveryPosition will write the current GTID as the recovery position // for the next transaction. // We will also try to get the timestamp for the transaction. Two cases: // - we have statements, and they start with a SET TIMESTAMP that we // can parse: then we update transaction_timestamp in blp_checkpoint // with it, and set SecondsBehindMaster to now() - transaction_timestamp // - otherwise (the statements are probably filtered out), we leave // transaction_timestamp alone (keeping the old value), and we don't // change SecondsBehindMaster func (blp *BinlogPlayer) writeRecoveryPosition(tx *proto.BinlogTransaction) error { gtid, err := myproto.DecodeGTID(tx.TransactionID) if err != nil { return err } now := time.Now().Unix() blp.blpPos.Position = myproto.AppendGTID(blp.blpPos.Position, gtid) updateRecovery := UpdateBlpCheckpoint(blp.blpPos.Uid, blp.blpPos.Position, now, tx.Timestamp) qr, err := blp.exec(updateRecovery) if err != nil { return fmt.Errorf("Error %v in writing recovery info %v", err, updateRecovery) } if qr.RowsAffected != 1 { return fmt.Errorf("Cannot update blp_recovery table, affected %v rows", qr.RowsAffected) } blp.blplStats.SetLastPosition(blp.blpPos.Position) if tx.Timestamp != 0 { blp.blplStats.SecondsBehindMaster.Set(now - tx.Timestamp) } return nil }
func (rci *RowcacheInvalidator) processEvent(event *blproto.StreamEvent) error { defer rci.handleInvalidationError(event) switch event.Category { case "DDL": log.Infof("DDL invalidation: %s", event.Sql) rci.handleDDLEvent(event.Sql) case "DML": rci.handleDMLEvent(event) case "ERR": rci.handleUnrecognizedEvent(event.Sql) case "POS": gtid, err := myproto.DecodeGTID(event.TransactionID) if err != nil { return err } rci.AppendGTID(gtid) default: log.Errorf("unknown event: %#v", event) rci.qe.queryServiceStats.InternalErrors.Add("Invalidation", 1) return nil } rci.lagSeconds.Set(time.Now().Unix() - event.Timestamp) return nil }