2
2
3
3
import java .io .IOException ;
4
4
import java .net .InetSocketAddress ;
5
+ import java .net .SocketAddress ;
5
6
import java .nio .channels .SocketChannel ;
6
7
import java .util .ArrayList ;
7
8
import java .util .Arrays ;
8
9
import java .util .Collection ;
9
10
import java .util .Collections ;
10
11
import java .util .List ;
11
12
import java .util .concurrent .atomic .AtomicInteger ;
13
+ import java .util .concurrent .locks .Lock ;
14
+ import java .util .concurrent .locks .ReadWriteLock ;
15
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
16
+ import java .util .stream .Collectors ;
12
17
13
18
/**
14
19
* Basic reconnection strategy that changes addresses in a round-robin fashion.
15
20
* To be used with {@link TarantoolClientImpl}.
16
21
*/
17
- public class RoundRobinSocketProviderImpl extends BaseSocketChannelProvider {
22
+ public class RoundRobinSocketProviderImpl extends BaseSocketChannelProvider implements RefreshableSocketProvider {
18
23
19
- /**
20
- * Timeout to establish socket connection with an individual server.
21
- */
22
- private int timeout ; // 0 is infinite.
24
+ private static final int NO_TIMEOUT = 0 ;
23
25
24
26
/**
25
- * Server addresses as configured .
27
+ * Timeout to establish socket connection with an individual server .
26
28
*/
27
- private final List < String > addresses = new ArrayList <>() ;
29
+ private int timeout = NO_TIMEOUT ;
28
30
29
31
/**
30
32
* Socket addresses.
@@ -39,42 +41,63 @@ public class RoundRobinSocketProviderImpl extends BaseSocketChannelProvider {
39
41
/**
40
42
* Lock
41
43
*/
42
- // private ReadWriteLock addressListLock = new ReentrantReadWriteLock();
44
+ private ReadWriteLock addressListLock = new ReentrantReadWriteLock ();
43
45
44
46
/**
45
47
* Constructs an instance.
46
48
*
47
49
* @param addresses Array of addresses in a form of [host]:[port].
48
50
*/
49
51
public RoundRobinSocketProviderImpl (String ... addresses ) {
50
- if (addresses == null || addresses .length == 0 ) {
51
- throw new IllegalArgumentException ("Addresses are null or empty ." );
52
+ if (addresses .length == 0 ) {
53
+ throw new IllegalArgumentException ("Addresses list must contain at least one address ." );
52
54
}
53
55
54
56
updateAddressList (Arrays .asList (addresses ));
55
57
}
56
58
57
59
private void updateAddressList (Collection <String > addresses ) {
58
- String lastAddress = getLastObtainedAddress ();
59
- this .addresses .clear ();
60
- this .addresses .addAll (addresses );
61
- this .addresses .forEach (address -> socketAddresses .add (parseAddress (address )));
62
- if (lastAddress != null ) {
63
- int recoveredPosition = this .addresses .indexOf (lastAddress );
64
- currentPosition .set (recoveredPosition );
60
+ Lock writeLock = addressListLock .writeLock ();
61
+ writeLock .lock ();
62
+ try {
63
+ InetSocketAddress lastAddress = getLastObtainedAddress ();
64
+ socketAddresses .clear ();
65
+ addresses .stream ()
66
+ .map (this ::parseAddress )
67
+ .collect (Collectors .toCollection (() -> socketAddresses ));
68
+ if (lastAddress != null ) {
69
+ int recoveredPosition = socketAddresses .indexOf (lastAddress );
70
+ currentPosition .set (recoveredPosition );
71
+ } else {
72
+ currentPosition .set (-1 );
73
+ }
74
+ } finally {
75
+ writeLock .unlock ();
65
76
}
66
77
}
67
78
68
79
/**
69
80
* @return Configured addresses in a form of [host]:[port].
70
81
*/
71
- public List <String > getAddresses () {
72
- return Collections .unmodifiableList (this .addresses );
82
+ public List <SocketAddress > getAddresses () {
83
+ Lock readLock = addressListLock .readLock ();
84
+ readLock .lock ();
85
+ try {
86
+ return Collections .unmodifiableList (this .socketAddresses );
87
+ } finally {
88
+ readLock .unlock ();
89
+ }
73
90
}
74
91
75
- public String getLastObtainedAddress () {
76
- int index = currentPosition .get ();
77
- return index >= 0 ? addresses .get (index ) : null ;
92
+ private InetSocketAddress getLastObtainedAddress () {
93
+ Lock readLock = addressListLock .readLock ();
94
+ readLock .lock ();
95
+ try {
96
+ int index = currentPosition .get ();
97
+ return index >= 0 ? socketAddresses .get (index ) : null ;
98
+ } finally {
99
+ readLock .unlock ();
100
+ }
78
101
}
79
102
80
103
/**
@@ -91,9 +114,7 @@ public RoundRobinSocketProviderImpl setTimeout(int timeout) {
91
114
if (timeout < 0 ) {
92
115
throw new IllegalArgumentException ("timeout is negative." );
93
116
}
94
-
95
117
this .timeout = timeout ;
96
-
97
118
return this ;
98
119
}
99
120
@@ -108,6 +129,7 @@ public int getTimeout() {
108
129
@ Override
109
130
protected SocketChannel doRetry (int retryNumber , Throwable lastError ) {
110
131
int attempts = getAddressCount ();
132
+ // todo: recalc deadline?
111
133
long deadline = System .currentTimeMillis () + timeout * attempts ;
112
134
while (!Thread .currentThread ().isInterrupted ()) {
113
135
try {
@@ -135,18 +157,30 @@ protected SocketChannel doRetry(int retryNumber, Throwable lastError) {
135
157
* @return Number of configured addresses.
136
158
*/
137
159
protected int getAddressCount () {
138
- return socketAddresses .size ();
160
+ Lock readLock = addressListLock .readLock ();
161
+ readLock .lock ();
162
+ try {
163
+ return socketAddresses .size ();
164
+ } finally {
165
+ readLock .unlock ();
166
+ }
139
167
}
140
168
141
169
/**
142
170
* @return Socket address to use for the next reconnection attempt.
143
171
*/
144
172
protected InetSocketAddress getNextSocketAddress () {
145
- int position = currentPosition .updateAndGet (i -> (i + 1 ) % socketAddresses .size ());
146
- return socketAddresses .get (position );
173
+ Lock readLock = addressListLock .readLock ();
174
+ readLock .lock ();
175
+ try {
176
+ int position = currentPosition .updateAndGet (i -> (i + 1 ) % socketAddresses .size ());
177
+ return socketAddresses .get (position );
178
+ } finally {
179
+ readLock .unlock ();
180
+ }
147
181
}
148
182
149
- public void setAddresses (Collection <String > addresses ) {
183
+ public void refreshAddresses (Collection <String > addresses ) {
150
184
if (addresses == null || addresses .isEmpty ()) {
151
185
throw new IllegalArgumentException ("Addresses are null or empty." );
152
186
}
0 commit comments