github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/election/storage.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package election 15 16 import ( 17 "context" 18 "time" 19 ) 20 21 // Storage describes the requirements of a storage that can be used for leader election. 22 type Storage interface { 23 // Get gets the current record from the storage. It returns the current record stored 24 // in the storage and any error encountered. Note that if the record has not created yet, 25 // it should return an empty record and a nil error. 26 Get(ctx context.Context) (*Record, error) 27 // Update updates the record in the storage if the stored record version matches the given 28 // record version. It returns ErrRecordConflict if the stored record version does not match 29 // or any other error encountered. 30 Update(ctx context.Context, record *Record, isLeaderChanged bool) error 31 } 32 33 // Record holds the information of a leader election. 34 type Record struct { 35 // LeaderID is the ID of the leader. If it is empty, it means 36 // there is no leader and all members may try to become leader. 37 LeaderID string `json:"leader_id"` 38 // Members is the members that are eligible to become leader, 39 // which includes the leader itself. 40 Members []*Member `json:"members"` 41 // Version is the internal version of the record. It can be used by 42 // specific storage implementation to determine whether the record has 43 // been changed by another writer. The caller of the storage interface 44 // should treat this value as opaque. 45 // 46 // Skip serializing this field, because it is not part of the record content. 47 Version int64 `json:"-"` 48 } 49 50 // Member is a member in a leader election. 51 type Member struct { 52 // ID is the ID of the member. 53 ID string `json:"id"` 54 // Name is the human-readable name of the member. 55 // It is used for logging and diagnostics. 56 Name string `json:"name"` 57 // Address is the address of the member. 58 Address string `json:"address"` 59 // LeaseDuration is the duration that a client will wait before 60 // it can remove this member when the client hasn't observed 61 // any renewals from the member. 62 LeaseDuration time.Duration `json:"lease_duration"` 63 // RenewTime is the last time when the member renewed its lease. 64 RenewTime time.Time `json:"renew_time"` 65 } 66 67 // Clone returns a deep copy of the member. 68 func (m *Member) Clone() *Member { 69 return &Member{ 70 ID: m.ID, 71 Name: m.Name, 72 Address: m.Address, 73 LeaseDuration: m.LeaseDuration, 74 RenewTime: m.RenewTime, 75 } 76 } 77 78 // Clone returns a deep copy of the record. 79 func (r *Record) Clone() *Record { 80 members := make([]*Member, len(r.Members)) 81 for i, m := range r.Members { 82 members[i] = m.Clone() 83 } 84 return &Record{ 85 LeaderID: r.LeaderID, 86 Members: members, 87 Version: r.Version, 88 } 89 } 90 91 // FindMember finds the member with the given ID in the record. 92 func (r *Record) FindMember(id string) (*Member, bool) { 93 for _, m := range r.Members { 94 if m.ID == id { 95 return m, true 96 } 97 } 98 return nil, false 99 }