@@ -6,6 +6,7 @@ package vip
66import (
77 "context"
88 "net"
9+ "sync/atomic"
910
1011 "github.com/pingcap/tiproxy/lib/config"
1112 "github.com/pingcap/tiproxy/pkg/manager/elect"
@@ -17,23 +18,25 @@ const (
1718 // vipKey is the key in etcd for VIP election.
1819 vipKey = "/tiproxy/vip/owner"
1920 // sessionTTL is the session's TTL in seconds for VIP election.
20- sessionTTL = 5
21+ // The etcd client keeps alive every TTL/3 seconds.
22+ // The TTL determines the failover time so it should be short.
23+ sessionTTL = 3
2124)
2225
2326type VIPManager interface {
2427 Start (context.Context , * clientv3.Client ) error
25- OnElected ()
26- OnRetired ()
28+ Resign ()
2729 Close ()
2830}
2931
3032var _ VIPManager = (* vipManager )(nil )
3133
3234type vipManager struct {
33- operation NetworkOperation
34- cfgGetter config.ConfigGetter
35- election elect.Election
36- lg * zap.Logger
35+ operation NetworkOperation
36+ cfgGetter config.ConfigGetter
37+ election elect.Election
38+ delOnRetire atomic.Bool
39+ lg * zap.Logger
3740}
3841
3942func NewVIPManager (lg * zap.Logger , cfgGetter config.ConfigGetter ) (* vipManager , error ) {
@@ -55,6 +58,7 @@ func NewVIPManager(lg *zap.Logger, cfgGetter config.ConfigGetter) (*vipManager,
5558 return nil , err
5659 }
5760 vm .operation = operation
61+ vm .delOnRetire .Store (true )
5862 return vm , nil
5963}
6064
@@ -81,6 +85,16 @@ func (vm *vipManager) Start(ctx context.Context, etcdCli *clientv3.Client) error
8185}
8286
8387func (vm * vipManager ) OnElected () {
88+ vm .addVIP ()
89+ }
90+
91+ func (vm * vipManager ) OnRetired () {
92+ if vm .delOnRetire .Load () {
93+ vm .delVIP ()
94+ }
95+ }
96+
97+ func (vm * vipManager ) addVIP () {
8498 hasIP , err := vm .operation .HasIP ()
8599 if err != nil {
86100 vm .lg .Error ("checking addresses failed" , zap .Error (err ))
@@ -101,7 +115,7 @@ func (vm *vipManager) OnElected() {
101115 vm .lg .Info ("adding VIP success" )
102116}
103117
104- func (vm * vipManager ) OnRetired () {
118+ func (vm * vipManager ) delVIP () {
105119 hasIP , err := vm .operation .HasIP ()
106120 if err != nil {
107121 vm .lg .Error ("checking addresses failed" , zap .Error (err ))
@@ -118,9 +132,19 @@ func (vm *vipManager) OnRetired() {
118132 vm .lg .Info ("deleting VIP success" )
119133}
120134
121- func (vm * vipManager ) Close () {
122- // The OnRetired() will be called when the election is closed.
135+ // Resign stops compaign but does not delete the VIP.
136+ // It's called before graceful wait to avoid that the VIP is deleted before another member adds VIP.
137+ func (vm * vipManager ) Resign () {
138+ vm .delOnRetire .Store (false )
123139 if vm .election != nil {
124140 vm .election .Close ()
141+ vm .election = nil
125142 }
126143}
144+
145+ // Close stops compaign and deletes the VIP.
146+ // It's called after graceful wait to ensure the VIP is finally deleted.
147+ func (vm * vipManager ) Close () {
148+ vm .Resign ()
149+ vm .delVIP ()
150+ }
0 commit comments