func newSnapshotManifest(addr, mysqlAddr, masterAddr, dbName string, files []SnapshotFile, pos, masterPos proto.ReplicationPosition) (*SnapshotManifest, error) { nrs, err := proto.NewReplicationStatus(masterAddr) if err != nil { return nil, err } rs := &SnapshotManifest{ Addr: addr, DbName: dbName, Files: files, ReplicationStatus: nrs, MasterPosition: masterPos, } sort.Sort(rs.Files) rs.ReplicationStatus.Position = pos return rs, nil }
// Return a replication state that will reparent a slave to the // correct master for a specified position. func (mysqld *Mysqld) ReparentPosition(slavePosition proto.ReplicationPosition) (rs *proto.ReplicationStatus, waitPosition proto.ReplicationPosition, reparentTime int64, err error) { qr, err := mysqld.fetchSuperQuery(fmt.Sprintf("SELECT time_created_ns, new_addr, new_position, wait_position FROM _vt.reparent_log WHERE last_position = '%v'", slavePosition)) if err != nil { return } if len(qr.Rows) != 1 { err = fmt.Errorf("no reparent for position: %v", slavePosition) return } reparentTime, err = qr.Rows[0][0].ParseInt64() if err != nil { err = fmt.Errorf("bad reparent time: %v %v %v", slavePosition, qr.Rows[0][0], err) return } rs, err = proto.NewReplicationStatus(qr.Rows[0][1].String()) if err != nil { return } flavor, err := mysqld.flavor() if err != nil { err = fmt.Errorf("can't parse replication position: %v", err) return } rs.Position, err = flavor.ParseReplicationPosition(qr.Rows[0][2].String()) if err != nil { return } waitPosition, err = flavor.ParseReplicationPosition(qr.Rows[0][3].String()) if err != nil { return } return }
// setReadWrite: set the new master in read-write mode. // // replicationState: info slaves need to reparent themselves // waitPosition: slaves can wait for this position when restarting replication // timePromoted: this timestamp (unix nanoseconds) is inserted into _vt.replication_log to verify the replication config func (mysqld *Mysqld) PromoteSlave(setReadWrite bool, hookExtraEnv map[string]string) (replicationStatus *proto.ReplicationStatus, waitPosition proto.ReplicationPosition, timePromoted int64, err error) { if err = mysqld.StopSlave(hookExtraEnv); err != nil { return } // If we are forced, we have to get our status as a master, not a slave. var lastRepPos proto.ReplicationPosition slaveStatus, err := mysqld.SlaveStatus() if err == ErrNotSlave { lastRepPos, err = mysqld.MasterPosition() } else { if err != nil { return } lastRepPos = slaveStatus.Position } // Promote to master. flavor, err := mysqld.flavor() if err != nil { err = fmt.Errorf("PromoteSlave needs flavor: %v", err) return } cmds := flavor.PromoteSlaveCommands() if err = mysqld.ExecuteSuperQueryList(cmds); err != nil { return } // Write a row so there's something in the binlog before we fetch the // master position. Otherwise, the slave may request a GTID that has // already been purged from the binlog. cmds = []string{ fmt.Sprintf("INSERT INTO _vt.replication_log (time_created_ns, note) VALUES (%v, 'first binlog event')", time.Now().UnixNano()), } if err = mysqld.ExecuteSuperQueryList(cmds); err != nil { return } replicationPosition, err := mysqld.MasterPosition() if err != nil { return } mysqldAddr := mysqld.IpAddr() replicationStatus, err = proto.NewReplicationStatus(mysqldAddr) if err != nil { return } replicationStatus.Position = replicationPosition timePromoted = time.Now().UnixNano() // write a row to verify that replication is functioning cmds = []string{ fmt.Sprintf("INSERT INTO _vt.replication_log (time_created_ns, note) VALUES (%v, 'reparent check')", timePromoted), } if err = mysqld.ExecuteSuperQueryList(cmds); err != nil { return } // this is the wait-point for checking replication waitPosition, err = mysqld.MasterPosition() if err != nil { return } if waitPosition.Equal(replicationPosition) { // We inserted a row, but our binlog position didn't change. This is a // serious problem. We don't want to ever promote a master like that. err = fmt.Errorf("cannot promote slave to master, non-functional binlogs") return } cmds = []string{ fmt.Sprintf("INSERT INTO _vt.reparent_log (time_created_ns, last_position, new_addr, new_position, wait_position) VALUES (%v, '%v', '%v', '%v', '%v')", timePromoted, lastRepPos, replicationStatus.MasterAddr(), replicationPosition, waitPosition), } if err = mysqld.ExecuteSuperQueryList(cmds); err != nil { return } if setReadWrite { err = mysqld.SetReadOnly(false) } return }