Example #1
0
func newSnapshotManifest(addr, mysqlAddr, masterAddr, dbName string, files []SnapshotFile, pos, masterPos *proto.ReplicationPosition) (*SnapshotManifest, error) {
	nrs, err := proto.NewReplicationState(masterAddr)
	if err != nil {
		return nil, err
	}
	mrs, err := proto.NewReplicationState(mysqlAddr)
	if err != nil {
		return nil, err
	}
	rs := &SnapshotManifest{
		Addr:             addr,
		DbName:           dbName,
		Files:            files,
		ReplicationState: nrs,
		MasterState:      mrs,
	}
	sort.Sort(rs.Files)
	rs.ReplicationState.ReplicationPosition = *pos
	if masterPos != nil {
		rs.MasterState.ReplicationPosition = *masterPos
	}
	return rs, nil
}
Example #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.ReplicationState, 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.MapKey()))
	if err != nil {
		return
	}
	if len(qr.Rows) != 1 {
		err = fmt.Errorf("no reparent for position: %v", slavePosition.MapKey())
		return
	}

	reparentTime, err = qr.Rows[0][0].ParseInt64()
	if err != nil {
		err = fmt.Errorf("bad reparent time: %v %v %v", slavePosition.MapKey(), qr.Rows[0][0], err)
		return
	}

	file, pos, err := parseReplicationPosition(qr.Rows[0][2].String())
	if err != nil {
		return
	}
	rs, err = proto.NewReplicationState(qr.Rows[0][1].String())
	if err != nil {
		return
	}
	rs.ReplicationPosition.MasterLogFile = file
	rs.ReplicationPosition.MasterLogPosition = uint(pos)

	file, pos, err = parseReplicationPosition(qr.Rows[0][3].String())
	if err != nil {
		return
	}
	waitPosition = new(proto.ReplicationPosition)
	waitPosition.MasterLogFile = file
	waitPosition.MasterLogPosition = pos
	return
}
Example #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) (replicationState *proto.ReplicationState, 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.
	lastRepPos, err := mysqld.SlaveStatus()
	if err == ErrNotSlave {
		lastRepPos, err = mysqld.MasterStatus()
	}
	if err != nil {
		return
	}

	cmds := mysqld.flavor.PromoteSlaveCommands()
	if err = mysqld.executeSuperQueryList(cmds); err != nil {
		return
	}
	replicationPosition, err := mysqld.MasterStatus()
	if err != nil {
		return
	}
	mysqldAddr := mysqld.IpAddr()
	replicationState, err = proto.NewReplicationState(mysqldAddr)
	if err != nil {
		return
	}
	replicationState.ReplicationPosition = *replicationPosition
	lastPos := lastRepPos.MapKey()
	newAddr := replicationState.MasterAddr()
	newPos := replicationState.ReplicationPosition.MapKey()
	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.MasterStatus()
	if err != nil {
		return
	}
	if waitPosition.MasterLogFile == replicationPosition.MasterLogFile && waitPosition.MasterLogPosition == replicationPosition.MasterLogPosition {
		// 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, lastPos, newAddr, newPos, waitPosition.MapKey()),
	}
	if err = mysqld.executeSuperQueryList(cmds); err != nil {
		return
	}

	if setReadWrite {
		err = mysqld.SetReadOnly(false)
	}
	return
}