1
1
package org .jgroups .stack ;
2
2
3
3
import org .jgroups .Address ;
4
+ import org .jgroups .Global ;
4
5
import org .jgroups .PhysicalAddress ;
5
6
import org .jgroups .annotations .GuardedBy ;
7
+ import org .jgroups .util .*;
6
8
import org .jgroups .blocks .cs .*;
7
9
import org .jgroups .logging .Log ;
8
10
import org .jgroups .logging .LogFactory ;
9
11
import org .jgroups .protocols .PingData ;
10
- import org .jgroups .util .ByteArrayDataInputStream ;
11
- import org .jgroups .util .ByteArrayDataOutputStream ;
12
- import org .jgroups .util .SocketFactory ;
13
- import org .jgroups .util .Util ;
14
12
15
13
import java .io .DataInput ;
16
14
import java .net .InetAddress ;
19
17
20
18
import static java .lang .System .currentTimeMillis ;
21
19
import static java .util .concurrent .TimeUnit .MILLISECONDS ;
20
+ import static org .jgroups .stack .GossipType .GET_MBRS_RSP_LAST ;
22
21
import static org .jgroups .util .Util .printTime ;
23
22
24
23
28
27
*/
29
28
public class RouterStub extends ReceiverAdapter implements Comparable <RouterStub >, ConnectionListener {
30
29
public interface StubReceiver {void receive (GossipData data );}
31
- public interface MembersNotification {void members (List <PingData > mbrs );}
32
30
public interface CloseListener {void closed (RouterStub stub );}
31
+ public interface MembersNotification {
32
+ void members (List <PingData > mbrs );
33
+ default void members (String group , List <PingData > mbrs , boolean last ) {members (mbrs );}
34
+ }
33
35
34
36
protected BaseServer client ;
35
37
protected IpAddress local ; // bind address
@@ -55,9 +57,15 @@ public interface CloseListener {void closed(RouterStub stub);}
55
57
// When sending and non_blocking, how many messages to queue max
56
58
protected int max_send_queue =128 ;
57
59
60
+ // the max members in the get_all_members_list
61
+ protected int max_cache_size =10 ;
62
+
63
+ // the max age of elements in the get_all_members_list
64
+ protected long max_cache_age =5000 ;
65
+
58
66
// map to correlate GET_MBRS requests and responses
59
67
protected final Map <String ,List <MembersNotification >> get_members_map =new HashMap <>();
60
-
68
+ protected final LazyRemovalList < MembersNotification > get_all_members_list ;
61
69
62
70
public RouterStub (InetSocketAddress local_sa , InetSocketAddress remote_sa , boolean use_nio , CloseListener l , SocketFactory sf ) {
63
71
this (local_sa , remote_sa , use_nio , l , sf , -1 );
@@ -93,6 +101,7 @@ public RouterStub(InetSocketAddress local_sa, InetSocketAddress remote_sa, boole
93
101
this .max_send_queue =max_send_queue ;
94
102
if (resolveRemoteAddress ()) // sets remote
95
103
client =createClient (sf );
104
+ get_all_members_list =new LazyRemovalList <>(max_cache_size , max_cache_age );
96
105
}
97
106
98
107
@@ -118,8 +127,10 @@ public RouterStub(InetSocketAddress local_sa, InetSocketAddress remote_sa, boole
118
127
public RouterStub nonBlockingSends (boolean b ) {this .non_blocking_sends =b ; return this ;}
119
128
public int maxSendQueue () {return max_send_queue ;}
120
129
public RouterStub maxSendQueue (int s ) {this .max_send_queue =s ; return this ;}
121
-
122
-
130
+ public int maxCacheSize () {return max_cache_size ;}
131
+ public RouterStub maxCacheSize (int max_cache_size ) {this .max_cache_size =max_cache_size ; return this ;}
132
+ public long maxCacheAge () {return max_cache_age ;}
133
+ public RouterStub maxCacheAge (long max_cache_age ) {this .max_cache_age =max_cache_age ; return this ;}
123
134
124
135
/**
125
136
* Registers mbr with the GossipRouter under the given group, with the given logical name and physical address.
@@ -180,10 +191,14 @@ public void destroy() {
180
191
public void getMembers (final String group , MembersNotification callback ) throws Exception {
181
192
if (callback == null )
182
193
return ;
183
- // if(!isConnected()) throw new Exception ("not connected");
184
- synchronized (get_members_map ) {
185
- List <MembersNotification > set =get_members_map .computeIfAbsent (group , k -> new ArrayList <>());
186
- set .add (callback );
194
+ if (group == null ) {
195
+ get_all_members_list .add (callback );
196
+ }
197
+ else {
198
+ synchronized (get_members_map ) {
199
+ List <MembersNotification > list =get_members_map .computeIfAbsent (group , __ -> new ArrayList <>());
200
+ list .add (callback );
201
+ }
187
202
}
188
203
try {
189
204
writeRequest (new GossipData (GossipType .GET_MBRS , group , null ));
@@ -230,12 +245,16 @@ public void receive(Address sender, DataInput in, int length) {
230
245
receiver .receive (data );
231
246
break ;
232
247
case GET_MBRS_RSP :
233
- notifyResponse (data .getGroup (), data .getPingData ());
248
+ case GET_MBRS_RSP_LAST :
249
+ List <PingData > ping_data =data .getPingData ();
250
+ if (ping_data != null )
251
+ notifyResponse (data .getGroup (), data .getPingData (), data .getType () == GET_MBRS_RSP_LAST );
234
252
break ;
235
253
}
236
254
if (handle_heartbeats )
237
255
last_heartbeat =currentTimeMillis ();
238
- } catch (Exception ex ) {
256
+ }
257
+ catch (Exception ex ) {
239
258
log .error (Util .getMessage ("FailedReadingData" ), ex );
240
259
}
241
260
}
@@ -299,28 +318,36 @@ public void writeRequest(GossipData req) throws Exception {
299
318
}
300
319
301
320
protected void removeResponse (String group , MembersNotification notif ) {
321
+ if (group == null || group .equals (Global .ALL_GROUPS )) {
322
+ get_all_members_list .remove (notif );
323
+ return ;
324
+ }
302
325
synchronized (get_members_map ) {
303
- List <MembersNotification > set =get_members_map .get (group );
304
- if (set == null || set .isEmpty ()) {
326
+ List <MembersNotification > list =get_members_map .get (group );
327
+ if (list == null || list .isEmpty ()) {
305
328
get_members_map .remove (group );
306
329
return ;
307
330
}
308
- if (set .remove (notif ) && set .isEmpty ())
331
+ if (list .remove (notif ) && list .isEmpty ())
309
332
get_members_map .remove (group );
310
333
}
311
334
}
312
335
313
- protected void notifyResponse (String group , List <PingData > list ) {
314
- if (group == null )
336
+ protected void notifyResponse (String group , final List <PingData > list , boolean last ) {
337
+ if (group .startsWith (Global .ALL_GROUPS )) {
338
+ int index =group .indexOf (':' );
339
+ final String grp =group .substring (index +1 );
340
+ get_all_members_list .forEach (n -> n .members (grp , list , last ));
341
+ if (last )
342
+ get_all_members_list .clear (false );
315
343
return ;
316
- if (list == null )
317
- list =Collections .emptyList ();
344
+ }
318
345
synchronized (get_members_map ) {
319
- List <MembersNotification > set =get_members_map .get (group );
320
- while (set != null && !set .isEmpty ()) {
346
+ List <MembersNotification > l =get_members_map .get (group );
347
+ while (l != null && !l .isEmpty ()) {
321
348
try {
322
- MembersNotification rsp =set .remove (0 );
323
- rsp .members (list );
349
+ MembersNotification rsp =l .remove (0 );
350
+ rsp .members (group , list , last );
324
351
}
325
352
catch (Throwable t ) {
326
353
log .error ("failed notifying %s: %s" , group , t );
0 commit comments