@@ -32,17 +32,35 @@ var (
32
32
ErrNoHealthyInstance = errors .New ("can't find healthy instance in pool" )
33
33
)
34
34
35
+ // ConnectionListener provides an observer semantics for components interested
36
+ // in knowing the role changes of connections in a ConnectionPool.
37
+ type ConnectionListener interface {
38
+ // Added is called before a connection with a role added into a list of
39
+ // active connections.
40
+ Added (conn * tarantool.Connection , role Role )
41
+ // Removed is called after a connection with a role removed from a list
42
+ // of active connections.
43
+ Removed (conn * tarantool.Connection , role Role )
44
+ // Updated is called if a connection with a role updated in a list
45
+ // of active connections.
46
+ Updated (conn * tarantool.Connection , oldRole , newRole Role )
47
+ }
48
+
35
49
/*
36
50
Additional options (configurable via ConnectWithOpts):
37
51
38
52
- CheckTimeout - time interval to check for connection timeout and try to switch connection.
53
+
54
+ - ConnectionListener - a listener for connection updates.
39
55
*/
40
56
type OptsPool struct {
41
57
// timeout for timer to reopen connections
42
58
// that have been closed by some events and
43
59
// to relocate connection between subpools
44
60
// if ro/rw role has been updated
45
61
CheckTimeout time.Duration
62
+ // ConnectionListener provides an ability to observe connection updates.
63
+ ConnectionListener ConnectionListener
46
64
}
47
65
48
66
/*
@@ -174,9 +192,22 @@ func (connPool *ConnectionPool) closeImpl() []error {
174
192
if err := conn .Close (); err != nil {
175
193
errs = append (errs , err )
176
194
}
195
+ if conn := connPool .rwPool .DeleteConnByAddr (addr ); conn != nil {
196
+ if connPool .opts .ConnectionListener != nil {
197
+ connPool .opts .ConnectionListener .Removed (conn , MasterRole )
198
+ }
199
+ continue
200
+ }
201
+ if conn := connPool .roPool .DeleteConnByAddr (addr ); conn != nil {
202
+ if connPool .opts .ConnectionListener != nil {
203
+ connPool .opts .ConnectionListener .Removed (conn , ReplicaRole )
204
+ }
205
+ continue
206
+ }
207
+ if connPool .opts .ConnectionListener != nil {
208
+ connPool .opts .ConnectionListener .Removed (conn , UnknownRole )
209
+ }
177
210
}
178
- connPool .rwPool .DeleteConnByAddr (addr )
179
- connPool .roPool .DeleteConnByAddr (addr )
180
211
}
181
212
182
213
return errs
@@ -659,10 +690,22 @@ func (connPool *ConnectionPool) getConnectionFromPool(addr string) (*tarantool.C
659
690
}
660
691
661
692
func (connPool * ConnectionPool ) deleteConnectionFromPool (addr string ) {
662
- _ = connPool .anyPool .DeleteConnByAddr (addr )
663
- conn := connPool .rwPool .DeleteConnByAddr (addr )
664
- if conn == nil {
665
- connPool .roPool .DeleteConnByAddr (addr )
693
+ if conn := connPool .anyPool .DeleteConnByAddr (addr ); conn != nil {
694
+ if conn := connPool .rwPool .DeleteConnByAddr (addr ); conn != nil {
695
+ if connPool .opts .ConnectionListener != nil {
696
+ connPool .opts .ConnectionListener .Removed (conn , MasterRole )
697
+ }
698
+ return
699
+ }
700
+ if conn := connPool .roPool .DeleteConnByAddr (addr ); conn != nil {
701
+ if connPool .opts .ConnectionListener != nil {
702
+ connPool .opts .ConnectionListener .Removed (conn , ReplicaRole )
703
+ }
704
+ return
705
+ }
706
+ if connPool .opts .ConnectionListener != nil {
707
+ connPool .opts .ConnectionListener .Removed (conn , UnknownRole )
708
+ }
666
709
}
667
710
}
668
711
@@ -672,6 +715,10 @@ func (connPool *ConnectionPool) setConnectionToPool(addr string, conn *tarantool
672
715
return err
673
716
}
674
717
718
+ if connPool .opts .ConnectionListener != nil {
719
+ connPool .opts .ConnectionListener .Added (conn , role )
720
+ }
721
+
675
722
connPool .anyPool .AddConn (addr , conn )
676
723
677
724
switch role {
@@ -684,16 +731,32 @@ func (connPool *ConnectionPool) setConnectionToPool(addr string, conn *tarantool
684
731
return nil
685
732
}
686
733
734
+ func (connPool * ConnectionPool ) updateConnectionInPool (addr string , conn * tarantool.Connection , oldRole Role , newRole Role ) {
735
+ switch oldRole {
736
+ case MasterRole :
737
+ connPool .rwPool .DeleteConnByAddr (addr )
738
+ case ReplicaRole :
739
+ connPool .roPool .DeleteConnByAddr (addr )
740
+ }
741
+
742
+ if connPool .opts .ConnectionListener != nil {
743
+ connPool .opts .ConnectionListener .Updated (conn , oldRole , newRole )
744
+ }
745
+
746
+ switch newRole {
747
+ case MasterRole :
748
+ connPool .rwPool .AddConn (addr , conn )
749
+ case ReplicaRole :
750
+ connPool .roPool .AddConn (addr , conn )
751
+ }
752
+ }
753
+
687
754
func (connPool * ConnectionPool ) refreshConnection (addr string ) {
688
755
if conn , oldRole := connPool .getConnectionFromPool (addr ); conn != nil {
689
756
if ! conn .ClosedNow () {
690
- curRole , _ := connPool .getConnectionRole (conn )
691
- if oldRole != curRole {
692
- connPool .deleteConnectionFromPool (addr )
693
- err := connPool .setConnectionToPool (addr , conn )
694
- if err != nil {
695
- conn .Close ()
696
- log .Printf ("tarantool: storing connection to %s failed: %s\n " , addr , err .Error ())
757
+ if curRole , err := connPool .getConnectionRole (conn ); err == nil {
758
+ if oldRole != curRole {
759
+ connPool .updateConnectionInPool (addr , conn , oldRole , curRole )
697
760
}
698
761
}
699
762
}
0 commit comments