1- package com .ss .mqtt .broker .model ;
1+ package com .ss .mqtt .broker .model . topic ;
22
3- import static com .ss .mqtt .broker .model .AbstractTopic .MULTI_LEVEL_WILDCARD ;
4- import static com .ss .mqtt .broker .model .AbstractTopic .SINGLE_LEVEL_WILDCARD ;
3+ import static com .ss .mqtt .broker .model .topic .AbstractTopic .MULTI_LEVEL_WILDCARD ;
4+ import static com .ss .mqtt .broker .model .topic .AbstractTopic .SINGLE_LEVEL_WILDCARD ;
5+ import com .ss .mqtt .broker .model .Subscriber ;
56import com .ss .mqtt .broker .network .client .MqttClient ;
7+ import com .ss .rlib .common .function .NotNullSupplier ;
68import com .ss .rlib .common .util .array .Array ;
79import com .ss .rlib .common .util .array .ConcurrentArray ;
810import com .ss .rlib .common .util .dictionary .ConcurrentObjectDictionary ;
911import com .ss .rlib .common .util .dictionary .DictionaryFactory ;
1012import com .ss .rlib .common .util .dictionary .ObjectDictionary ;
1113import org .jetbrains .annotations .NotNull ;
14+ import org .jetbrains .annotations .Nullable ;
1215
13- public class TopicSubscriber {
16+ public class TopicSubscribers {
17+
18+ private final static NotNullSupplier <TopicSubscribers > TOPIC_SUBSCRIBER_SUPPLIER = TopicSubscribers ::new ;
1419
1520 private static boolean filterByQos (@ NotNull Array <Subscriber > subscribers , @ NotNull Subscriber candidate ) {
1621 var existed = subscribers .findAny (candidate , Subscriber ::equals );
@@ -24,38 +29,38 @@ private static boolean filterByQos(@NotNull Array<Subscriber> subscribers, @NotN
2429 }
2530 }
2631
27- private static TopicSubscriber collectSubscribers (
28- @ NotNull ConcurrentObjectDictionary <String , TopicSubscriber > topicSubscribers ,
32+ private static TopicSubscribers collectSubscribers (
33+ @ NotNull ConcurrentObjectDictionary <String , TopicSubscribers > topicSubscribers ,
2934 @ NotNull String topicName ,
3035 @ NotNull Array <Subscriber > resultSubscribers
3136 ) {
3237 var ts = topicSubscribers .get (topicName );
3338 if (ts != null ) {
34- long stamp = ts .subscribers .readLock ();
39+ long stamp = ts .getSubscribers () .readLock ();
3540 try {
36- ts .subscribers .forEachFiltered (resultSubscribers , TopicSubscriber ::filterByQos , Array ::add );
41+ ts .getSubscribers () .forEachFiltered (resultSubscribers , TopicSubscribers ::filterByQos , Array ::add );
3742 } finally {
38- ts .subscribers .readUnlock (stamp );
43+ ts .getSubscribers () .readUnlock (stamp );
3944 }
4045 }
4146 return ts ;
4247 }
4348
44- private final ConcurrentObjectDictionary <String , TopicSubscriber > topicSubscribers =
45- DictionaryFactory .newConcurrentStampedLockObjectDictionary ();
46- private final ConcurrentArray <Subscriber > subscribers = ConcurrentArray .ofType (Subscriber .class );
49+ private @ Nullable ConcurrentObjectDictionary <String , TopicSubscribers > topicSubscribers ;
50+ private @ Nullable ConcurrentArray <Subscriber > subscribers ;
4751
4852 public void addSubscriber (@ NotNull TopicFilter topicFilter , @ NotNull Subscriber subscriber ) {
4953 addSubscriber (0 , topicFilter , subscriber );
5054 }
5155
5256 private void addSubscriber (int level , @ NotNull TopicFilter topicFilter , @ NotNull Subscriber subscriber ) {
53- if (level == topicFilter .levels . length ) {
54- subscribers .runInWriteLock (subscriber , ConcurrentArray ::add );
57+ if (level == topicFilter .size () ) {
58+ getSubscribers () .runInWriteLock (subscriber , ConcurrentArray ::add );
5559 } else {
56- var topicSubscriber = topicSubscribers .getInWriteLock (
57- topicFilter .levels [level ],
58- (ts , topic ) -> ts .getOrCompute (topic , TopicSubscriber ::new )
60+ var topicSubscriber = getTopicSubscribers ().getInWriteLock (
61+ topicFilter .getSegment (level ),
62+ TOPIC_SUBSCRIBER_SUPPLIER ,
63+ ObjectDictionary ::getOrCompute
5964 );
6065 //noinspection ConstantConditions
6166 topicSubscriber .addSubscriber (level + 1 , topicFilter , subscriber );
@@ -67,10 +72,13 @@ public boolean removeSubscriber(@NotNull TopicFilter topicFilter, @NotNull MqttC
6772 }
6873
6974 private boolean removeSubscriber (int level , @ NotNull TopicFilter topicFilter , @ NotNull MqttClient mqttClient ) {
70- if (level == topicFilter .levels . length ) {
71- return subscribers . removeIfInWriteLock (mqttClient , ( client , subscriber ) -> client . equals ( subscriber . getMqttClient ()) );
75+ if (level == topicFilter .size () ) {
76+ return getSubscribers (). removeConvertedIfInWriteLock (mqttClient , Subscriber :: getMqttClient , Object :: equals );
7277 } else {
73- var topicSubscriber = topicSubscribers .getInReadLock (topicFilter .levels [level ], ObjectDictionary ::get );
78+ var topicSubscriber = getTopicSubscribers ().getInReadLock (
79+ topicFilter .getSegment (level ),
80+ ObjectDictionary ::get
81+ );
7482 if (topicSubscriber == null ) {
7583 return false ;
7684 } else {
@@ -81,7 +89,7 @@ private boolean removeSubscriber(int level, @NotNull TopicFilter topicFilter, @N
8189
8290 public @ NotNull Array <Subscriber > matches (@ NotNull TopicName topicName ) {
8391 var resultArray = Array .ofType (Subscriber .class );
84- processLevel (0 , topicName .levels [ 0 ] , topicName , resultArray );
92+ processLevel (0 , topicName .getSegment ( 0 ) , topicName , resultArray );
8593 return resultArray ;
8694 }
8795
@@ -103,14 +111,36 @@ private void processSegment(
103111 @ NotNull TopicName topicName ,
104112 @ NotNull Array <Subscriber > resultSubscribers
105113 ) {
106- var topicSubscriber = topicSubscribers .getInReadLock (
114+ var topicSubscriber = getTopicSubscribers () .getInReadLock (
107115 segment ,
108116 resultSubscribers ,
109- TopicSubscriber ::collectSubscribers
117+ TopicSubscribers ::collectSubscribers
110118 );
111- if (topicSubscriber != null && nextLevel < topicName .levels . length ) {
112- var nextSegment = topicName .levels [ nextLevel ] ;
119+ if (topicSubscriber != null && nextLevel < topicName .size () ) {
120+ var nextSegment = topicName .getSegment ( nextLevel ) ;
113121 topicSubscriber .processLevel (nextLevel , nextSegment , topicName , resultSubscribers );
114122 }
115123 }
124+
125+ private @ NotNull ConcurrentObjectDictionary <String , TopicSubscribers > getTopicSubscribers () {
126+ if (topicSubscribers == null ) {
127+ synchronized (this ) {
128+ if (topicSubscribers == null ) {
129+ topicSubscribers = DictionaryFactory .newConcurrentStampedLockObjectDictionary ();
130+ }
131+ }
132+ }
133+ return topicSubscribers ;
134+ }
135+
136+ private @ NotNull ConcurrentArray <Subscriber > getSubscribers () {
137+ if (subscribers == null ) {
138+ synchronized (this ) {
139+ if (subscribers == null ) {
140+ subscribers = ConcurrentArray .ofType (Subscriber .class );
141+ }
142+ }
143+ }
144+ return subscribers ;
145+ }
116146}
0 commit comments