Skip to content

Commit 563476f

Browse files
committed
Split destination cache into access vs update
Issue: SPR-11657
1 parent 79de45b commit 563476f

File tree

2 files changed

+39
-26
lines changed

2 files changed

+39
-26
lines changed

spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ public String toString() {
148148
*/
149149
private class DestinationCache {
150150

151-
/** Map from destination -> <sessionId, subscriptionId> */
151+
/** Map from destination -> <sessionId, subscriptionId> for fast look-ups */
152+
private final Map<String, MultiValueMap<String, String>> accessCache =
153+
new ConcurrentHashMap<String, MultiValueMap<String, String>>(DEFAULT_CACHE_LIMIT);
154+
155+
/** Map from destination -> <sessionId, subscriptionId> with locking */
152156
@SuppressWarnings("serial")
153-
private final Map<String, MultiValueMap<String, String>> cache =
157+
private final Map<String, MultiValueMap<String, String>> updateCache =
154158
new LinkedHashMap<String, MultiValueMap<String, String>>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
155159
@Override
156160
protected boolean removeEldestEntry(Map.Entry<String, MultiValueMap<String, String>> eldest) {
@@ -159,57 +163,64 @@ protected boolean removeEldestEntry(Map.Entry<String, MultiValueMap<String, Stri
159163
};
160164

161165

162-
163166
public MultiValueMap<String, String> getSubscriptions(String destination) {
164-
synchronized (this.cache) {
165-
return this.cache.get(destination);
166-
}
167+
return this.accessCache.get(destination);
167168
}
168169

169170
public void addSubscriptions(String destination, MultiValueMap<String, String> subscriptions) {
170-
synchronized (this.cache) {
171-
this.cache.put(destination, subscriptions);
171+
synchronized (this.updateCache) {
172+
this.updateCache.put(destination, subscriptions);
173+
this.accessCache.put(destination, new LinkedMultiValueMap<String, String>(subscriptions));
172174
}
173175
}
174176

175177
public void updateAfterNewSubscription(String destination, String sessionId, String subsId) {
176-
synchronized(this.cache) {
177-
for (String cachedDestination : this.cache.keySet()) {
178+
synchronized(this.updateCache) {
179+
for (String cachedDestination : this.updateCache.keySet()) {
178180
if (getPathMatcher().match(destination, cachedDestination)) {
179-
MultiValueMap<String, String> subscriptions = this.cache.get(cachedDestination);
180-
subscriptions.add(sessionId, subsId);
181+
MultiValueMap<String, String> subs = this.updateCache.get(cachedDestination);
182+
subs.add(sessionId, subsId);
183+
this.accessCache.put(cachedDestination, new LinkedMultiValueMap<String, String>(subs));
181184
}
182185
}
183186
}
184187
}
185188

186189
public void updateAfterRemovedSubscription(String destination, String sessionId, String subsId) {
187-
synchronized(this.cache) {
188-
for (String cachedDestination : this.cache.keySet()) {
190+
synchronized(this.updateCache) {
191+
for (String cachedDestination : this.updateCache.keySet()) {
189192
if (getPathMatcher().match(destination, cachedDestination)) {
190-
MultiValueMap<String, String> subscriptions = this.cache.get(cachedDestination);
191-
List<String> subsIds = subscriptions.get(sessionId);
193+
MultiValueMap<String, String> subs = this.updateCache.get(cachedDestination);
194+
List<String> subsIds = subs.get(sessionId);
192195
subsIds.remove(subsId);
193196
if (subsIds.isEmpty()) {
194-
subscriptions.remove(sessionId);
197+
subs.remove(sessionId);
195198
}
196-
if (subscriptions.isEmpty()) {
197-
this.cache.remove(cachedDestination);
199+
if (subs.isEmpty()) {
200+
this.updateCache.remove(cachedDestination);
201+
this.accessCache.remove(cachedDestination);
202+
}
203+
else {
204+
this.accessCache.put(cachedDestination, new LinkedMultiValueMap<String, String>(subs));
198205
}
199206
}
200207
}
201208
}
202209
}
203210

204211
public void updateAfterRemovedSession(SessionSubscriptionInfo info) {
205-
synchronized(this.cache) {
212+
synchronized(this.updateCache) {
206213
for (String destination : info.getDestinations()) {
207-
for (String cachedDestination : this.cache.keySet()) {
214+
for (String cachedDestination : this.updateCache.keySet()) {
208215
if (getPathMatcher().match(destination, cachedDestination)) {
209-
MultiValueMap<String, String> map = this.cache.get(cachedDestination);
210-
map.remove(info.getSessionId());
211-
if (map.isEmpty()) {
212-
this.cache.remove(cachedDestination);
216+
MultiValueMap<String, String> subs = this.updateCache.get(cachedDestination);
217+
subs.remove(info.getSessionId());
218+
if (subs.isEmpty()) {
219+
this.updateCache.remove(cachedDestination);
220+
this.accessCache.remove(cachedDestination);
221+
}
222+
else {
223+
this.accessCache.put(cachedDestination,new LinkedMultiValueMap<String, String>(subs));
213224
}
214225
}
215226
}
@@ -219,7 +230,7 @@ public void updateAfterRemovedSession(SessionSubscriptionInfo info) {
219230

220231
@Override
221232
public String toString() {
222-
return "[cache=" + this.cache + "]";
233+
return "[cache=" + this.accessCache + "]";
223234
}
224235
}
225236

spring-messaging/src/test/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistryTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,12 @@ public void registerSubscriptionsWithSimpleAndPatternDestinations() {
176176
assertEquals(Arrays.asList(subs1), actual.get(sess2));
177177

178178
this.registry.unregisterSubscription(unsubscribeMessage(sess1, subs1));
179+
actual = this.registry.findSubscriptions(message("/topic/PRICE.STOCK.NASDAQ.IBM"));
179180
assertEquals(1, actual.size());
180181
assertEquals(Arrays.asList(subs1), actual.get(sess2));
181182

182183
this.registry.unregisterSubscription(unsubscribeMessage(sess2, subs1));
184+
actual = this.registry.findSubscriptions(message("/topic/PRICE.STOCK.NASDAQ.IBM"));
183185
assertEquals(0, actual.size());
184186
}
185187

0 commit comments

Comments
 (0)