@@ -60,7 +60,12 @@ public ConsistentHashingStickyKeyConsumerSelector(int numberOfPoints) {
60
60
* It is not changed unless a consumer is removed or a colliding consumer with higher priority is added.
61
61
*/
62
62
private static class HashRingEntry {
63
- private final List <Consumer > consumers ;
63
+ // This class is used to store the consumer and the order in which it was added to the hash ring
64
+ // sorting will be by priority, consumer name and the order in which it was added
65
+ record ConsumerEntry (Consumer consumer , int addOrder ) {
66
+ }
67
+
68
+ private final List <ConsumerEntry > consumers ;
64
69
private final int hash ;
65
70
Consumer selectedConsumer ;
66
71
@@ -70,22 +75,24 @@ public HashRingEntry(int hash) {
70
75
}
71
76
72
77
public void addConsumer (Consumer consumer ) {
73
- consumers .add (consumer );
74
- selectConsumer ();
78
+ consumers .add (new ConsumerEntry ( consumer , consumers . size ()) );
79
+ selectConsumer (true );
75
80
}
76
81
77
82
public void removeConsumer (Consumer consumer ) {
78
- consumers .remove ( consumer );
79
- selectConsumer ();
83
+ consumers .removeIf ( consumerEntry -> consumerEntry . consumer (). equals ( consumer ) );
84
+ selectConsumer (false );
80
85
}
81
86
82
87
public Consumer getSelectedConsumer () {
83
88
return selectedConsumer ;
84
89
}
85
90
86
- private void selectConsumer () {
91
+ private void selectConsumer (boolean performSorting ) {
87
92
if (consumers .size () > 1 ) {
88
- sortConsumersByPriorityLevelAndName (consumers );
93
+ if (performSorting ) {
94
+ sortConsumersByPriorityLevelAndName (consumers );
95
+ }
89
96
List <Consumer > priorityConsumers = pickPriorityConsumers (consumers );
90
97
if (priorityConsumers .size () > 1 ) {
91
98
// use the hash to select a consumer from the priority consumers
@@ -104,24 +111,27 @@ private void selectConsumer() {
104
111
selectedConsumer = priorityConsumers .get (0 );
105
112
}
106
113
} else if (consumers .size () == 1 ) {
107
- selectedConsumer = consumers .get (0 );
114
+ selectedConsumer = consumers .get (0 ). consumer () ;
108
115
} else {
109
116
selectedConsumer = null ;
110
117
}
111
118
}
112
119
113
- private static List <Consumer > pickPriorityConsumers (List <Consumer > consumers ) {
114
- Consumer firstConsumer = consumers .get (0 );
120
+ private static List <Consumer > pickPriorityConsumers (List <ConsumerEntry > consumers ) {
121
+ Consumer firstConsumer = consumers .get (0 ). consumer () ;
115
122
List <Consumer > priorityConsumers = consumers .stream ()
116
- .takeWhile (c -> c .getPriorityLevel () == firstConsumer .getPriorityLevel ()
117
- && c .consumerName ().equals (firstConsumer .consumerName ()))
123
+ .takeWhile (c -> c .consumer ().getPriorityLevel () == firstConsumer .getPriorityLevel ()
124
+ && c .consumer ().consumerName ().equals (firstConsumer .consumerName ()))
125
+ .map (ConsumerEntry ::consumer )
118
126
.toList ();
119
127
return priorityConsumers ;
120
128
}
121
129
122
- private static void sortConsumersByPriorityLevelAndName (List <Consumer > consumers ) {
123
- consumers .sort (Comparator .comparing (Consumer ::getPriorityLevel ).reversed ()
124
- .thenComparing (Consumer ::consumerName ));
130
+ private static void sortConsumersByPriorityLevelAndName (List <ConsumerEntry > consumers ) {
131
+ consumers .sort (Comparator .<ConsumerEntry , Integer >
132
+ comparing (entry -> entry .consumer ().getPriorityLevel ()).reversed ()
133
+ .thenComparing (entry -> entry .consumer ().consumerName ())
134
+ .thenComparing (ConsumerEntry ::addOrder ));
125
135
}
126
136
}
127
137
@@ -191,12 +201,24 @@ public Map<Consumer, List<Range>> getConsumerKeyHashRanges() {
191
201
Map <Consumer , List <Range >> result = new LinkedHashMap <>();
192
202
rwLock .readLock ().lock ();
193
203
try {
204
+ if (hashRing .isEmpty ()) {
205
+ return result ;
206
+ }
194
207
int start = 0 ;
208
+ int lastKey = 0 ;
195
209
for (Map .Entry <Integer , HashRingEntry > entry : hashRing .entrySet ()) {
196
210
Consumer consumer = entry .getValue ().getSelectedConsumer ();
197
211
result .computeIfAbsent (consumer , key -> new ArrayList <>())
198
212
.add (Range .of (start , entry .getKey ()));
199
- start = entry .getKey () + 1 ;
213
+ lastKey = entry .getKey ();
214
+ start = lastKey + 1 ;
215
+ }
216
+ // Handle wrap-around
217
+ HashRingEntry firstHashRingEntry = hashRing .firstEntry ().getValue ();
218
+ Consumer firstSelectedConsumer = firstHashRingEntry .getSelectedConsumer ();
219
+ List <Range > ranges = result .get (firstSelectedConsumer );
220
+ if (lastKey != Integer .MAX_VALUE - 1 ) {
221
+ ranges .add (Range .of (lastKey + 1 , Integer .MAX_VALUE - 1 ));
200
222
}
201
223
} finally {
202
224
rwLock .readLock ().unlock ();
0 commit comments