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 }