// 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 }
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 }
func (mysqld *Mysqld) StartReplicationCommands(status *proto.ReplicationStatus) ([]string, error) { flavor, err := mysqld.flavor() if err != nil { return nil, fmt.Errorf("StartReplicationCommands needs flavor: %v", err) } params, err := dbconfigs.MysqlParams(mysqld.replParams) if err != nil { return nil, err } return flavor.StartReplicationCommands(¶ms, status) }
// 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 }
// 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 }
// 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.Warningf("getSlaveStatus failed: %v", err) return } // if we're not replicating, we're done if !slavestat.slaveSQLRunning { log.Warningf("Slave is not replicating (SQL)") return } if !slavestat.slaveIORunning { log.Warningf("Slave is not replicating (IO)") return } if slavestat.secondsBehindMaster < 2 { return } log.Infof("Replication lag is high (%v seconds), activating", slavestat.secondsBehindMaster) // 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) } }