예제 #1
0
파일: mysqld.go 프로젝트: dumbunny/vitess
// Wait returns nil when mysqld is up and accepting connections.
func (mysqld *Mysqld) Wait(ctx context.Context) error {
	log.Infof("Waiting for mysqld socket file (%v) to be ready...", mysqld.config.SocketFile)
	for {
		select {
		case <-ctx.Done():
			return errors.New("deadline exceeded waiting for mysqld socket file to appear: " + mysqld.config.SocketFile)
		default:
		}

		_, statErr := os.Stat(mysqld.config.SocketFile)
		if statErr == nil {
			// Make sure the socket file isn't stale.
			// Use a user that exists even before we apply the init_db_sql_file.
			conn, connErr := mysql.Connect(sqldb.ConnParams{
				Uname:      "root",
				Charset:    "utf8",
				UnixSocket: mysqld.config.SocketFile,
			})
			if connErr == nil {
				conn.Close()
				return nil
			}
			log.Infof("mysqld socket file exists, but can't connect: %v", connErr)
		} else if !os.IsNotExist(statErr) {
			return fmt.Errorf("can't stat mysqld socket file: %v", statErr)
		}
		time.Sleep(100 * time.Millisecond)
	}
}
예제 #2
0
파일: mysqld.go 프로젝트: nosix-me/vitess
func (mt *Mysqld) createDbaConnection() (*mysql.Connection, error) {
	params, err := dbconfigs.MysqlParams(mt.dbaParams)
	if err != nil {
		return nil, err
	}
	return mysql.Connect(params)
}
예제 #3
0
func TestMySQL(t *testing.T) {
	hdl, err := LaunchVitess(MySQLOnly("vttest"), Schema("create table a(id int, name varchar(128), primary key(id))"))
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		err = hdl.TearDown()
		if err != nil {
			t.Error(err)
			return
		}
	}()
	params, err := hdl.MySQLConnParams()
	if err != nil {
		t.Error(err)
	}
	conn, err := mysql.Connect(params)
	if err != nil {
		t.Error(err)
	}
	_, err = conn.ExecuteFetch("insert into a values(1, 'name')", 10, false)
	if err != nil {
		t.Error(err)
	}
	qr, err := conn.ExecuteFetch("select * from a", 10, false)
	if err != nil {
		t.Error(err)
	}
	if qr.RowsAffected != 1 {
		t.Errorf("Rows affected: %d, want 1", qr.RowsAffected)
	}
}
예제 #4
0
func TestSchemaReload(t *testing.T) {
	conn, err := mysql.Connect(connParams)
	if err != nil {
		t.Error(err)
		return
	}
	_, err = conn.ExecuteFetch("create table vitess_temp(intval int)", 10, false)
	if err != nil {
		t.Error(err)
		return
	}
	defer func() {
		_, _ = conn.ExecuteFetch("drop table vitess_temp", 10, false)
		conn.Close()
	}()
	framework.Server.ReloadSchema()
	client := framework.NewClient()
	waitTime := 50 * time.Millisecond
	for i := 0; i < 10; i++ {
		time.Sleep(waitTime)
		waitTime += 50 * time.Millisecond
		_, err = client.Execute("select * from vitess_temp", nil)
		if err == nil {
			return
		}
		want := "error: table vitess_temp not found in schema"
		if err.Error() != want {
			t.Errorf("Error: %v, want %s", err, want)
			return
		}
	}
	t.Error("schema did not reload")
}
예제 #5
0
func CreateGenericConnection(info *mysql.ConnectionParams) (*DBConnection, error) {
	params, err := dbconfigs.MysqlParams(info)
	if err != nil {
		return nil, err
	}
	c, err := mysql.Connect(params)
	return &DBConnection{c}, err
}
예제 #6
0
// NewDBConnection returns a new DBConnection based on the ConnectionParams
// and will use the provided stats to collect timing.
func NewDBConnection(info *mysql.ConnectionParams, mysqlStats *stats.Timings) (*DBConnection, error) {
	params, err := dbconfigs.MysqlParams(info)
	if err != nil {
		return nil, err
	}
	c, err := mysql.Connect(params)
	return &DBConnection{c, mysqlStats}, err
}
예제 #7
0
func (dc *DBClient) Connect() error {
	var err error
	dc.dbConn, err = mysql.Connect(*dc.dbConfig)
	if err != nil {
		return fmt.Errorf("error in connecting to mysql db, err %v", err)
	}
	return nil
}
예제 #8
0
func (dc *DBClient) Connect() error {
	params, err := dbconfigs.MysqlParams(dc.dbConfig)
	if err != nil {
		return err
	}
	dc.dbConn, err = mysql.Connect(params)
	if err != nil {
		return fmt.Errorf("error in connecting to mysql db, err %v", err)
	}
	return nil
}
예제 #9
0
// NewSlaveConnection creates a new slave connection to the mysqld instance.
// It uses a pools.IDPool to ensure that the server IDs used to connect are
// unique within this process. This is done with the assumptions that:
//
// 1) No other processes are making fake slave connections to our mysqld.
// 2) No real slave servers will have IDs in the range 1-N where N is the peak
//    number of concurrent fake slave connections we will ever make.
func NewSlaveConnection(mysqld *Mysqld) (*SlaveConnection, error) {
	params, err := dbconfigs.MysqlParams(mysqld.dba)
	if err != nil {
		return nil, err
	}

	conn, err := mysql.Connect(params)
	if err != nil {
		return nil, err
	}

	sc := &SlaveConnection{
		Connection: conn,
		mysqld:     mysqld,
		slaveID:    slaveIDPool.Get(),
	}
	log.Infof("new slave connection: slaveID=%d", sc.slaveID)
	return sc, nil
}
예제 #10
0
// setupPrimerConnections creates the channel and the consumers for
// the sql statements
func (pc *PrimeCache) setupPrimerConnections() error {
	pc.workerChannel = make(chan string, 1000)
	for i := 0; i < pc.WorkerCount; i++ {
		// connect to the database using client for a replay connection
		params, err := dbconfigs.MysqlParams(&pc.dbcfgs.App.ConnectionParams)
		if err != nil {
			return fmt.Errorf("cannot get parameters to connect to MySQL: %v", err)
		}

		dbConn, err := mysql.Connect(params)
		if err != nil {
			return fmt.Errorf("mysql.Connect failed: %v", err)
		}

		// and launch the go routine that applies the statements
		go applyLoop(dbConn, pc.workerChannel)
	}
	return nil
}
예제 #11
0
파일: mysqld.go 프로젝트: rjammala/vitess
func NewMysqld(config *Mycnf, dba, repl mysql.ConnectionParams) *Mysqld {
	if dba == DefaultDbaParams {
		dba.UnixSocket = config.SocketFile
	}

	// the super connection is not linked to a specific database
	// (allows us to create them)
	superParams := dba
	superParams.DbName = ""
	createSuperConnection := func() (*mysql.Connection, error) {
		return mysql.Connect(superParams)
	}
	return &Mysqld{config,
		dba,
		repl,
		createSuperConnection,
		TabletDir(config.ServerId),
		SnapshotDir(config.ServerId),
	}
}
예제 #12
0
func TestSidecarTables(t *testing.T) {
	conn, err := mysql.Connect(connParams)
	if err != nil {
		t.Error(err)
		return
	}
	defer conn.Close()
	for _, table := range []string{
		"redo_log_transaction",
		"redo_log_statement",
		"transaction",
		"participant",
	} {
		_, err = conn.ExecuteFetch(fmt.Sprintf("describe _vt.%s", table), 10, false)
		if err != nil {
			t.Error(err)
			return
		}
	}
}
예제 #13
0
func CreateGenericConnection(info mysql.ConnectionParams) (*DBConnection, error) {
	c, err := mysql.Connect(info)
	return &DBConnection{c}, err
}
예제 #14
0
func (sq *SqlQuery) allowQueries(dbconfig *dbconfigs.DBConfig, schemaOverrides []SchemaOverride, qrs *QueryRules) {
	sq.statemu.Lock()
	v := sq.state.Get()
	switch v {
	case CONNECTING, ABORT, SERVING:
		sq.statemu.Unlock()
		log.Infof("Ignoring allowQueries request, current state: %v", v)
		return
	case INITIALIZING, SHUTTING_DOWN:
		panic("unreachable")
	}
	// state is NOT_SERVING
	sq.setState(CONNECTING)
	sq.statemu.Unlock()

	// Try connecting. disallowQueries can change the state to ABORT during this time.
	waitTime := time.Second
	for {
		params, err := dbconfigs.MysqlParams(&dbconfig.ConnectionParams)
		if err == nil {
			c, err := mysql.Connect(params)
			if err == nil {
				c.Close()
				break
			}
			log.Errorf("mysql.Connect() error: %v", err)
		} else {
			log.Errorf("dbconfigs.MysqlParams error: %v", err)
		}
		time.Sleep(waitTime)
		// Cap at 32 seconds
		if waitTime < 30*time.Second {
			waitTime = waitTime * 2
		}
		if sq.state.Get() == ABORT {
			// Exclusive transition. No need to lock statemu.
			sq.setState(NOT_SERVING)
			log.Infof("allowQueries aborting")
			return
		}
	}

	// Connection successful. Keep statemu locked.
	sq.statemu.Lock()
	defer sq.statemu.Unlock()
	if sq.state.Get() == ABORT {
		sq.setState(NOT_SERVING)
		log.Infof("allowQueries aborting")
		return
	}
	sq.setState(INITIALIZING)

	defer func() {
		if x := recover(); x != nil {
			log.Errorf("%s", x.(*TabletError).Message)
			sq.setState(NOT_SERVING)
			return
		}
		sq.setState(SERVING)
	}()

	sq.qe.Open(&dbconfig.ConnectionParams, schemaOverrides, qrs)
	sq.dbconfig = dbconfig
	sq.sessionId = Rand()
	log.Infof("Session id: %d", sq.sessionId)
}
예제 #15
0
파일: sqlquery.go 프로젝트: jekey/vitess
func (sq *SqlQuery) allowQueries(dbconfig *dbconfigs.DBConfig, schemaOverrides []SchemaOverride, qrs *QueryRules, mysqld *mysqlctl.Mysqld) {
	sq.statemu.Lock()
	defer sq.statemu.Unlock()

	v := sq.state.Get()
	switch v {
	case CONNECTING, ABORT, SERVING:
		log.Infof("Ignoring allowQueries request, current state: %v", v)
		return
	case INITIALIZING, SHUTTING_DOWN:
		panic("unreachable")
	}
	// state is NOT_SERVING
	sq.setState(CONNECTING)

	// When this function exits, state can be CONNECTING or ABORT
	func() {
		sq.statemu.Unlock()
		defer sq.statemu.Lock()

		waitTime := time.Second
		// disallowQueries can change the state to ABORT during this time.
		for sq.state.Get() != ABORT {
			params, err := dbconfigs.MysqlParams(&dbconfig.ConnectionParams)
			if err == nil {
				c, err := mysql.Connect(params)
				if err == nil {
					c.Close()
					break
				}
				log.Errorf("mysql.Connect() error: %v", err)
			} else {
				log.Errorf("dbconfigs.MysqlParams error: %v", err)
			}
			time.Sleep(waitTime)
			// Cap at 32 seconds
			if waitTime < 30*time.Second {
				waitTime = waitTime * 2
			}
		}
	}()

	if sq.state.Get() == ABORT {
		sq.setState(NOT_SERVING)
		log.Infof("allowQueries aborting")
		return
	}
	sq.setState(INITIALIZING)

	defer func() {
		if x := recover(); x != nil {
			log.Errorf("%s", x.(*TabletError).Message)
			sq.qe.Close()
			sq.rci.Close()
			sq.setState(NOT_SERVING)
			return
		}
		sq.setState(SERVING)
	}()

	sq.qe.Open(dbconfig, schemaOverrides, qrs)
	if dbconfig.EnableRowcache && dbconfig.EnableInvalidator {
		sq.rci.Open(dbconfig.DbName, mysqld)
	}
	sq.dbconfig = dbconfig
	sq.sessionId = Rand()
	log.Infof("Session id: %d", sq.sessionId)
}
예제 #16
0
// OneRun tries a single cycle connecting to MySQL, and if behind on
// replication, starts playing the logs ahead to prime the cache.
func (pc *PrimeCache) OneRun() {
	// connect to the database using dba for a control connection
	params, err := dbconfigs.MysqlParams(&pc.dbcfgs.Dba)
	if err != nil {
		log.Errorf("Cannot get parameters to connect to MySQL: %v", err)
		return
	}

	pc.dbConn, err = mysql.Connect(params)
	if err != nil {
		log.Errorf("mysql.Connect failed: %v", err)
		return
	}

	// get the slave status
	slavestat, err := pc.getSlaveStatus()
	if err != nil {
		log.Errorf("getSlaveStatus failed: %v", err)
		return
	}

	// if we're not replicating, we're done
	if !slavestat.slaveSQLRunning {
		log.Errorf("Slave is not replicating (SQL)")
		return
	}
	if !slavestat.slaveIORunning {
		log.Errorf("Slave is not replicating (IO)")
		return
	}
	if slavestat.secondsBehindMaster < 2 {
		log.Errorf("Slave lag is negligible - %v seconds", slavestat.secondsBehindMaster)
		return
	}

	// setup the connections to the db to apply the statements
	if err := pc.setupPrimerConnections(); err != nil {
		log.Errorf("setupPrimerConnections failed: %v", err)
		return
	}

	// open the binlogs from where we are on
	reader, err := pc.openBinlog(slavestat)
	if err != nil {
		log.Errorf("openBinlog failed: %v", err)
		return
	}

	maxLineCount := 10000
	var maxLeadBytes int64 = 5000000

	// and start the loop
	lineCount := 0
	deleteCount := 0
	appliedDeleteCount := 0
	updateCount := 0
	appliedUpdateCount := 0
	sleepCount := 0
	var logPos uint64
	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		line := scanner.Text()
		lowerLine := strings.ToLower(line)
		lineCount++

		if p, isComment := parseLogPos(line); isComment {
			// handle the comments with a log pos
			if p > logPos {
				logPos = p
			}

		} else if s, isDelete := parseDeleteStatement(line, lowerLine); isDelete {
			// handle delete statements
			deleteCount++
			if s != "" {
				appliedDeleteCount++
				pc.workerChannel <- s
			}

		} else if s, isUpdate := parseUpdateStatement(line, lowerLine); isUpdate {
			// handle update statements
			updateCount++
			if s != "" {
				appliedUpdateCount++
				pc.workerChannel <- s
			}
		}

		if lineCount%maxLineCount == 0 {
			var leadBytes int64
			for {
				slavestat, err = pc.getSlaveStatus()
				if err != nil {
					log.Errorf("getSlaveStatus failed: %v", err)
					return
				}

				// see how far ahead we are (it's signed because
				// we can be behind too)
				leadBytes = int64(logPos) - int64(slavestat.execMasterLogPos)
				if leadBytes > maxLeadBytes {
					sleepCount++
					log.Infof("Sleeping for 1 second waiting for SQL thread to advance: %v > %v", leadBytes, maxLeadBytes)
					time.Sleep(1 * time.Second)
					continue
				} else {
					break
				}
			}

			log.Infof("STATS: readahead: %10d lag: %7d sleeps: %4d deletes: %10d missed updates: %10d updates: %10d\n",
				leadBytes, slavestat.secondsBehindMaster, sleepCount, deleteCount, updateCount-appliedUpdateCount, appliedUpdateCount)
		}
	}
	reader.Close()
	if err := scanner.Err(); err != nil {
		log.Errorf("Scanner failed: %v", err)
	}
}
예제 #17
0
func (dc DBClient) Connect() (*mysql.Connection, error) {
	return mysql.Connect(*dc.dbConfig)
}