@@ -17,6 +17,7 @@ limitations under the License.
1717package node
1818
1919import (
20+ "context"
2021 "database/sql"
2122 "fmt"
2223 "strings"
@@ -29,19 +30,17 @@ import (
2930)
3031
3132const (
32- // mysqlReadyTries represents the number of tries with 1 second sleep between them to check if MySQL is ready
33- mysqlReadyTries = 10
3433 // connRetry represents the number of tries to connect to master server
3534 connRetry = 10
3635)
3736
3837// SQLInterface expose abstract operations that can be applied on a MySQL node
3938type SQLInterface interface {
40- Wait () error
41- DisableSuperReadOnly () (func (), error )
42- ChangeMasterTo (string , string , string ) error
43- MarkConfigurationDone () error
44- SetPurgedGTID () error
39+ Wait (ctx context. Context ) error
40+ DisableSuperReadOnly (ctx context. Context ) (func (), error )
41+ ChangeMasterTo (ctx context. Context , host string , user string , pass string ) error
42+ MarkConfigurationDone (ctx context. Context ) error
43+ SetPurgedGTID (ctx context. Context ) error
4544 Host () string
4645}
4746
@@ -62,38 +61,35 @@ func newNodeConn(dsn, host string) SQLInterface {
6261 }
6362}
6463
65- func (r * nodeSQLRunner ) Wait () error {
64+ // Wait method pings MySQL until it's ready (runs SELECT 1;). The timeout should be set in ctx context.Context
65+ func (r * nodeSQLRunner ) Wait (ctx context.Context ) error {
6666 log .V (1 ).Info ("wait for mysql to be ready" )
6767
68- for i := 0 ; i < mysqlReadyTries ; i ++ {
69- if err := r .runQuery ("SELECT 1" ); err == nil {
70- break
68+ for {
69+ select {
70+ case <- ctx .Done ():
71+ // timeout expired
72+ return fmt .Errorf ("timeout: mysql is not ready" )
73+ case <- time .After (time .Second ):
74+ if err := r .runQuery (ctx , "SELECT 1" ); err == nil {
75+ return nil
76+ }
7177 }
72- // wait a second
73- time .Sleep (1 * time .Second )
7478 }
75- if err := r .runQuery ("SELECT 1" ); err != nil {
76- log .V (1 ).Info ("mysql is not ready" , "error" , err )
77- return err
78- }
79-
80- log .V (1 ).Info ("mysql is ready" )
81- return nil
82-
8379}
8480
85- func (r * nodeSQLRunner ) DisableSuperReadOnly () (func (), error ) {
81+ func (r * nodeSQLRunner ) DisableSuperReadOnly (ctx context. Context ) (func (), error ) {
8682 enable := func () {
87- err := r .runQuery ("SET GLOBAL SUPER_READ_ONLY = 0;" )
83+ err := r .runQuery (ctx , "SET GLOBAL SUPER_READ_ONLY = 0;" )
8884 if err != nil {
8985 log .Error (err , "failed to set node super read only" , "node" , r .Host ())
9086 }
9187 }
92- return enable , r .runQuery ("SET GLOBAL READ_ONLY = 1; SET GLOBAL SUPER_READ_ONLY = 0;" )
88+ return enable , r .runQuery (ctx , "SET GLOBAL READ_ONLY = 1; SET GLOBAL SUPER_READ_ONLY = 0;" )
9389}
9490
9591// ChangeMasterTo changes the master host and starts slave.
96- func (r * nodeSQLRunner ) ChangeMasterTo (masterHost , user , pass string ) error {
92+ func (r * nodeSQLRunner ) ChangeMasterTo (ctx context. Context , masterHost , user , pass string ) error {
9793 // slave node
9894 query := `
9995 STOP SLAVE;
@@ -103,14 +99,14 @@ func (r *nodeSQLRunner) ChangeMasterTo(masterHost, user, pass string) error {
10399 MASTER_PASSWORD=?,
104100 MASTER_CONNECT_RETRY=?;
105101 `
106- if err := r .runQuery (query ,
102+ if err := r .runQuery (ctx , query ,
107103 masterHost , user , pass , connRetry ,
108104 ); err != nil {
109105 return fmt .Errorf ("failed to configure slave node, err: %s" , err )
110106 }
111107
112108 query = "START SLAVE;"
113- if err := r .runQuery (query ); err != nil {
109+ if err := r .runQuery (ctx , query ); err != nil {
114110 log .Info ("failed to start slave in the simple mode, trying a second method" )
115111 // TODO: https://bugs.mysql.com/bug.php?id=83713
116112 query2 := `
@@ -120,14 +116,14 @@ func (r *nodeSQLRunner) ChangeMasterTo(masterHost, user, pass string) error {
120116 reset slave;
121117 start slave;
122118 `
123- if err := r .runQuery (query2 ); err != nil {
119+ if err := r .runQuery (ctx , query2 ); err != nil {
124120 return fmt .Errorf ("failed to start slave node, err: %s" , err )
125121 }
126122 }
127123 return nil
128124}
129125
130- func (r * nodeSQLRunner ) MarkConfigurationDone () error {
126+ func (r * nodeSQLRunner ) MarkConfigurationDone (ctx context. Context ) error {
131127 query := `
132128 CREATE TABLE IF NOT EXISTS %s.%s (
133129 ok tinyint(1) NOT NULL
@@ -137,7 +133,7 @@ func (r *nodeSQLRunner) MarkConfigurationDone() error {
137133 `
138134 query = fmt .Sprintf (query , constants .OperatorDbName , "readiness" )
139135
140- if err := r .runQuery (query ); err != nil {
136+ if err := r .runQuery (ctx , query ); err != nil {
141137 return fmt .Errorf ("failed to mark configuration done, err: %s" , err )
142138 }
143139 return nil
@@ -148,7 +144,7 @@ func (r *nodeSQLRunner) Host() string {
148144}
149145
150146// runQuery executes a query
151- func (r * nodeSQLRunner ) runQuery (q string , args ... interface {}) error {
147+ func (r * nodeSQLRunner ) runQuery (ctx context. Context , q string , args ... interface {}) error {
152148 db , close , err := r .dbConn ()
153149 if err != nil {
154150 return err
@@ -160,24 +156,23 @@ func (r *nodeSQLRunner) runQuery(q string, args ...interface{}) error {
160156 if ! r .enableBinLog {
161157 q = "SET @@SESSION.SQL_LOG_BIN = 0;\n " + q
162158 }
163- if _ , err := db .Exec ( q , args ... ); err != nil {
159+ if _ , err := db .ExecContext ( ctx , q , args ... ); err != nil {
164160 return err
165161 }
166162
167163 return nil
168164}
169165
170166// readFromMysql executes the given query and loads the values into give variables
171- func (r * nodeSQLRunner ) readFromMysql (query string , values ... interface {}) error {
167+ func (r * nodeSQLRunner ) readFromMysql (ctx context. Context , query string , values ... interface {}) error {
172168 db , close , err := r .dbConn ()
173169 if err != nil {
174170 return err
175171 }
176172 defer close ()
177173
178- // nolint: gosec
179174 log .V (1 ).Info ("running query" , "query" , query )
180- row := db .QueryRow ( query )
175+ row := db .QueryRowContext ( ctx , query )
181176 if row == nil {
182177 return fmt .Errorf ("no row found" )
183178 }
@@ -206,14 +201,14 @@ func (r *nodeSQLRunner) dbConn() (*sql.DB, func(), error) {
206201 return db , close , nil
207202}
208203
209- func (r * nodeSQLRunner ) SetPurgedGTID () error {
204+ func (r * nodeSQLRunner ) SetPurgedGTID (ctx context. Context ) error {
210205 // first check if the GTID should be set, if the table exists or if the GTID was set before (used)
211206 // nolint: gosec
212207 qq := fmt .Sprintf ("SELECT used FROM %[1]s.%[2]s WHERE id=1" ,
213208 constants .OperatorDbName , constants .OperatorGtidsTableName )
214209
215210 var used bool
216- if err := r .readFromMysql (qq , & used ); err != nil {
211+ if err := r .readFromMysql (ctx , qq , & used ); err != nil {
217212 // if it's a: "Table doesn't exist" error then GTID should not be set, it's a master case.
218213 if isMySQLError (err , 1146 ) {
219214 log .V (1 ).Info ("GTID purged table does not exists" , "host" , r .Host ())
@@ -239,7 +234,7 @@ func (r *nodeSQLRunner) SetPurgedGTID() error {
239234 COMMIT;
240235 ` , constants .OperatorDbName , constants .OperatorGtidsTableName )
241236
242- if err := r .runQuery (query ); err != nil {
237+ if err := r .runQuery (ctx , query ); err != nil {
243238 return err
244239 }
245240
0 commit comments