Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
// 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
}
Ejemplo n.º 3
0
// 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
}