@@ -14,7 +14,7 @@ import (
1414 "errors"
1515 "fmt"
1616 "log"
17- "sync/atomic "
17+ "sync"
1818 "time"
1919
2020 "github.com/tarantool/go-tarantool"
@@ -69,12 +69,13 @@ type ConnectionPool struct {
6969 connOpts tarantool.Opts
7070 opts OptsPool
7171
72- notify chan tarantool.ConnEvent
73- state State
74- control chan struct {}
75- roPool * RoundRobinStrategy
76- rwPool * RoundRobinStrategy
77- anyPool * RoundRobinStrategy
72+ notify chan tarantool.ConnEvent
73+ state state
74+ control chan struct {}
75+ roPool * RoundRobinStrategy
76+ rwPool * RoundRobinStrategy
77+ anyPool * RoundRobinStrategy
78+ poolsMutex sync.RWMutex
7879}
7980
8081// ConnectWithOpts creates pool for instances with addresses addrs
@@ -100,6 +101,7 @@ func ConnectWithOpts(addrs []string, connOpts tarantool.Opts, opts OptsPool) (co
100101 connOpts : connOpts ,
101102 opts : opts ,
102103 notify : notify ,
104+ state : unknownState ,
103105 control : make (chan struct {}),
104106 rwPool : rwPool ,
105107 roPool : roPool ,
@@ -109,10 +111,12 @@ func ConnectWithOpts(addrs []string, connOpts tarantool.Opts, opts OptsPool) (co
109111
110112 somebodyAlive := connPool .fillPools ()
111113 if ! somebodyAlive {
112- connPool .Close ()
114+ connPool .state .set (closedState )
115+ connPool .closeImpl ()
113116 return nil , ErrNoConnection
114117 }
115118
119+ connPool .state .set (connectedState )
116120 go connPool .checker ()
117121
118122 return connPool , nil
@@ -128,7 +132,10 @@ func Connect(addrs []string, connOpts tarantool.Opts) (connPool *ConnectionPool,
128132
129133// ConnectedNow gets connected status of pool.
130134func (connPool * ConnectionPool ) ConnectedNow (mode Mode ) (bool , error ) {
131- if connPool .getState () != connConnected {
135+ connPool .poolsMutex .RLock ()
136+ defer connPool .poolsMutex .RUnlock ()
137+
138+ if connPool .state .get () != connectedState {
132139 return false , nil
133140 }
134141 switch mode {
@@ -157,10 +164,8 @@ func (connPool *ConnectionPool) ConfiguredTimeout(mode Mode) (time.Duration, err
157164 return conn .ConfiguredTimeout (), nil
158165}
159166
160- // Close closes connections in pool.
161- func (connPool * ConnectionPool ) Close () []error {
167+ func (connPool * ConnectionPool ) closeImpl () []error {
162168 close (connPool .control )
163- connPool .state = connClosed
164169
165170 errs := make ([]error , 0 , len (connPool .addrs ))
166171
@@ -177,6 +182,17 @@ func (connPool *ConnectionPool) Close() []error {
177182 return errs
178183}
179184
185+ // Close closes connections in pool.
186+ func (connPool * ConnectionPool ) Close () []error {
187+ if connPool .state .cas (connectedState , closedState ) {
188+ connPool .poolsMutex .Lock ()
189+ defer connPool .poolsMutex .Unlock ()
190+
191+ return connPool .closeImpl ()
192+ }
193+ return nil
194+ }
195+
180196// GetAddrs gets addresses of connections in pool.
181197func (connPool * ConnectionPool ) GetAddrs () []string {
182198 cpy := make ([]string , len (connPool .addrs ))
@@ -188,6 +204,13 @@ func (connPool *ConnectionPool) GetAddrs() []string {
188204func (connPool * ConnectionPool ) GetPoolInfo () map [string ]* ConnectionInfo {
189205 info := make (map [string ]* ConnectionInfo )
190206
207+ connPool .poolsMutex .RLock ()
208+ defer connPool .poolsMutex .RUnlock ()
209+
210+ if connPool .state .get () != connectedState {
211+ return info
212+ }
213+
191214 for _ , addr := range connPool .addrs {
192215 conn , role := connPool .getConnectionFromPool (addr )
193216 if conn != nil {
@@ -638,11 +661,9 @@ func (connPool *ConnectionPool) getConnectionFromPool(addr string) (*tarantool.C
638661func (connPool * ConnectionPool ) deleteConnectionFromPool (addr string ) {
639662 _ = connPool .anyPool .DeleteConnByAddr (addr )
640663 conn := connPool .rwPool .DeleteConnByAddr (addr )
641- if conn ! = nil {
642- return
664+ if conn = = nil {
665+ connPool . roPool . DeleteConnByAddr ( addr )
643666 }
644-
645- connPool .roPool .DeleteConnByAddr (addr )
646667}
647668
648669func (connPool * ConnectionPool ) setConnectionToPool (addr string , conn * tarantool.Connection ) error {
@@ -689,39 +710,39 @@ func (connPool *ConnectionPool) refreshConnection(addr string) {
689710}
690711
691712func (connPool * ConnectionPool ) checker () {
692-
693713 timer := time .NewTicker (connPool .opts .CheckTimeout )
694714 defer timer .Stop ()
695715
696- for connPool .getState () != connClosed {
716+ for connPool .state . get () != closedState {
697717 select {
698718 case <- connPool .control :
699719 return
700720 case e := <- connPool .notify :
701- if connPool .getState () == connClosed {
702- return
703- }
704- if e .Conn .ClosedNow () {
721+ connPool .poolsMutex .Lock ()
722+ if connPool .state .get () == connectedState && e .Conn .ClosedNow () {
705723 connPool .deleteConnectionFromPool (e .Conn .Addr ())
706724 }
725+ connPool .poolsMutex .Unlock ()
707726 case <- timer .C :
708- for _ , addr := range connPool .addrs {
709- if connPool .getState () == connClosed {
710- return
727+ connPool .poolsMutex .Lock ()
728+ if connPool .state .get () == connectedState {
729+ for _ , addr := range connPool .addrs {
730+ // Reopen connection
731+ // Relocate connection between subpools
732+ // if ro/rw was updated
733+ connPool .refreshConnection (addr )
711734 }
712-
713- // Reopen connection
714- // Relocate connection between subpools
715- // if ro/rw was updated
716- connPool .refreshConnection (addr )
717735 }
736+ connPool .poolsMutex .Unlock ()
718737 }
719738 }
720739}
721740
722741func (connPool * ConnectionPool ) fillPools () bool {
723742 somebodyAlive := false
724743
744+ // It is called before checker() goroutine and before closeImpl() may be
745+ // called so we don't expect concurrency issues here.
725746 for _ , addr := range connPool .addrs {
726747 conn , err := tarantool .Connect (addr , connPool .connOpts )
727748 if err != nil {
@@ -740,10 +761,6 @@ func (connPool *ConnectionPool) fillPools() bool {
740761 return somebodyAlive
741762}
742763
743- func (connPool * ConnectionPool ) getState () uint32 {
744- return atomic .LoadUint32 ((* uint32 )(& connPool .state ))
745- }
746-
747764func (connPool * ConnectionPool ) getNextConnection (mode Mode ) (* tarantool.Connection , error ) {
748765
749766 switch mode {
0 commit comments