vitess.io/vitess@v0.16.2/go/vt/vtorc/process/election_dao.go (about)

     1  /*
     2     Copyright 2015 Shlomi Noach, courtesy Booking.com
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package process
    18  
    19  import (
    20  	"vitess.io/vitess/go/vt/external/golib/sqlutils"
    21  	"vitess.io/vitess/go/vt/log"
    22  	"vitess.io/vitess/go/vt/vtorc/config"
    23  	"vitess.io/vitess/go/vt/vtorc/db"
    24  	"vitess.io/vitess/go/vt/vtorc/util"
    25  )
    26  
    27  // AttemptElection tries to grab leadership (become active node)
    28  func AttemptElection() (bool, error) {
    29  	{
    30  		sqlResult, err := db.ExecVTOrc(`
    31  		insert ignore into active_node (
    32  				anchor, hostname, token, first_seen_active, last_seen_active
    33  			) values (
    34  				1, ?, ?, now(), now()
    35  			)
    36  		`,
    37  			ThisHostname, util.ProcessToken.Hash,
    38  		)
    39  		if err != nil {
    40  			log.Error(err)
    41  			return false, err
    42  		}
    43  		rows, err := sqlResult.RowsAffected()
    44  		if err != nil {
    45  			log.Error(err)
    46  			return false, err
    47  		}
    48  		if rows > 0 {
    49  			// We managed to insert a row
    50  			return true, nil
    51  		}
    52  	}
    53  	{
    54  		// takeover from a node that has been inactive
    55  		sqlResult, err := db.ExecVTOrc(`
    56  			update active_node set
    57  				hostname = ?,
    58  				token = ?,
    59  				first_seen_active=now(),
    60  				last_seen_active=now()
    61  			where
    62  				anchor = 1
    63  			  and last_seen_active < (now() - interval ? second)
    64  		`,
    65  			ThisHostname, util.ProcessToken.Hash, config.ActiveNodeExpireSeconds,
    66  		)
    67  		if err != nil {
    68  			log.Error(err)
    69  			return false, err
    70  		}
    71  		rows, err := sqlResult.RowsAffected()
    72  		if err != nil {
    73  			log.Error(err)
    74  			return false, err
    75  		}
    76  		if rows > 0 {
    77  			// We managed to update a row: overtaking a previous leader
    78  			return true, nil
    79  		}
    80  	}
    81  	{
    82  		// Update last_seen_active is this very node is already the active node
    83  		sqlResult, err := db.ExecVTOrc(`
    84  			update active_node set
    85  				last_seen_active=now()
    86  			where
    87  				anchor = 1
    88  				and hostname = ?
    89  				and token = ?
    90  		`,
    91  			ThisHostname, util.ProcessToken.Hash,
    92  		)
    93  		if err != nil {
    94  			log.Error(err)
    95  			return false, err
    96  		}
    97  		rows, err := sqlResult.RowsAffected()
    98  		if err != nil {
    99  			log.Error(err)
   100  			return false, err
   101  		}
   102  		if rows > 0 {
   103  			// Reaffirmed our own leadership
   104  			return true, nil
   105  		}
   106  	}
   107  	return false, nil
   108  }
   109  
   110  // GrabElection forcibly grabs leadership. Use with care!!
   111  func GrabElection() error {
   112  	_, err := db.ExecVTOrc(`
   113  			replace into active_node (
   114  					anchor, hostname, token, first_seen_active, last_seen_active
   115  				) values (
   116  					1, ?, ?, now(), now()
   117  				)
   118  			`,
   119  		ThisHostname, util.ProcessToken.Hash,
   120  	)
   121  	if err != nil {
   122  		log.Error(err)
   123  	}
   124  	return err
   125  }
   126  
   127  // Reelect clears the way for re-elections. Active node is immediately demoted.
   128  func Reelect() error {
   129  	_, err := db.ExecVTOrc(`delete from active_node where anchor = 1`)
   130  	if err != nil {
   131  		log.Error(err)
   132  	}
   133  	return err
   134  }
   135  
   136  // ElectedNode returns the details of the elected node, as well as answering the question "is this process the elected one"?
   137  func ElectedNode() (node *NodeHealth, isElected bool, err error) {
   138  	node = &NodeHealth{}
   139  	query := `
   140  		select
   141  			hostname,
   142  			token,
   143  			first_seen_active,
   144  			last_seen_Active
   145  		from
   146  			active_node
   147  		where
   148  			anchor = 1
   149  		`
   150  	err = db.QueryVTOrcRowsMap(query, func(m sqlutils.RowMap) error {
   151  		node.Hostname = m.GetString("hostname")
   152  		node.Token = m.GetString("token")
   153  		node.FirstSeenActive = m.GetString("first_seen_active")
   154  		node.LastSeenActive = m.GetString("last_seen_active")
   155  
   156  		return nil
   157  	})
   158  
   159  	isElected = (node.Hostname == ThisHostname && node.Token == util.ProcessToken.Hash)
   160  	if err != nil {
   161  		log.Error(err)
   162  	}
   163  	return node, isElected, err //nolint copylocks: return copies lock value
   164  }