Architechtural refactory, moved subscription out of tree and into db store
This commit is contained in:
@@ -98,7 +98,7 @@ public class NettyMQTTHandler extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
m_processor.processConnectionLost(clientID, stolen);
|
||||
}
|
||||
ctx.close(/*false*/);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -99,8 +99,16 @@ public class ClientSession {
|
||||
//send SUBACK with 0x80 for this topic filter
|
||||
return false;
|
||||
}
|
||||
subscriptions.add(newSubscription);
|
||||
m_sessionsStore.addNewSubscription(newSubscription);
|
||||
ISessionsStore.ClientTopicCouple matchingCouple = new ISessionsStore.ClientTopicCouple(this.clientID, newSubscription.getTopicFilter());
|
||||
Subscription existingSub = m_sessionsStore.getSubscription(matchingCouple);
|
||||
//update the selected subscriptions if not present or if has a greater qos
|
||||
if (existingSub == null || existingSub.getRequestedQos().byteValue() < newSubscription.getRequestedQos().byteValue()) {
|
||||
if (existingSub != null) {
|
||||
subscriptions.remove(newSubscription);
|
||||
}
|
||||
subscriptions.add(newSubscription);
|
||||
m_sessionsStore.addNewSubscription(newSubscription);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package io.moquette.spi;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
|
||||
@@ -28,6 +27,43 @@ import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
*/
|
||||
public interface ISessionsStore {
|
||||
|
||||
class ClientTopicCouple {
|
||||
public final String topicFilter;
|
||||
public final String clientID;
|
||||
|
||||
public ClientTopicCouple(String clientID, String topicFilter) {
|
||||
this.clientID = clientID;
|
||||
this.topicFilter = topicFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ClientTopicCouple that = (ClientTopicCouple) o;
|
||||
|
||||
if (topicFilter != null ? !topicFilter.equals(that.topicFilter) : that.topicFilter != null) return false;
|
||||
return !(clientID != null ? !clientID.equals(that.clientID) : that.clientID != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = topicFilter != null ? topicFilter.hashCode() : 0;
|
||||
result = 31 * result + (clientID != null ? clientID.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientTopicCouple{" +
|
||||
"topicFilter='" + topicFilter + '\'' +
|
||||
", clientID='" + clientID + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void initStore();
|
||||
|
||||
/**
|
||||
@@ -46,11 +82,14 @@ public interface ISessionsStore {
|
||||
void wipeSubscriptions(String sessionID);
|
||||
|
||||
/**
|
||||
* Updates the subscriptions set for the clientID
|
||||
* Return all topic filters to recreate the subscription tree.
|
||||
* */
|
||||
void updateSubscriptions(String clientID, Set<Subscription> subscriptions);
|
||||
List<ClientTopicCouple> listAllSubscriptions();
|
||||
|
||||
List<Subscription> listAllSubscriptions();
|
||||
/**
|
||||
* @return the subscription stored by clientID and topicFilter, if any else null;
|
||||
* */
|
||||
Subscription getSubscription(ClientTopicCouple couple);
|
||||
|
||||
/**
|
||||
* @return true iff there are subscriptions persisted with clientID
|
||||
|
||||
@@ -26,6 +26,7 @@ import io.moquette.spi.ClientSession;
|
||||
import io.moquette.spi.IMatchingCondition;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
|
||||
import io.moquette.spi.impl.security.IAuthenticator;
|
||||
import io.moquette.spi.impl.security.IAuthorizator;
|
||||
import io.moquette.spi.impl.subscriptions.SubscriptionsStore;
|
||||
@@ -383,6 +384,7 @@ public class ProtocolProcessor {
|
||||
} else {
|
||||
//QoS 1 or 2
|
||||
//if the target subscription is not clean session and is not connected => store it
|
||||
//TODO isCleanSession MUST be on the targetSession not the Subscription
|
||||
if (!sub.isCleanSession() && !targetSession.isActive()) {
|
||||
//store the message in targetSession queue to deliver
|
||||
targetSession.enqueueToDeliver(guid);
|
||||
@@ -621,18 +623,19 @@ public class ProtocolProcessor {
|
||||
|
||||
//fire the publish
|
||||
for(Subscription subscription : newSubscriptions) {
|
||||
subscribeSingleTopic(subscription, subscription.getTopicFilter());
|
||||
subscribeSingleTopic(subscription);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean subscribeSingleTopic(Subscription newSubscription, final String topic) {
|
||||
subscriptions.add(newSubscription);
|
||||
private boolean subscribeSingleTopic(final Subscription newSubscription) {
|
||||
final ClientTopicCouple couple = new ClientTopicCouple(newSubscription.getClientId(), newSubscription.getTopicFilter());
|
||||
subscriptions.add(couple);
|
||||
|
||||
//scans retained messages to be published to the new subscription
|
||||
//TODO this is ugly, it does a linear scan on potential big dataset
|
||||
Collection<IMessagesStore.StoredMessage> messages = m_messagesStore.searchMatching(new IMatchingCondition() {
|
||||
public boolean match(String key) {
|
||||
return SubscriptionsStore.matchTopics(key, topic);
|
||||
return SubscriptionsStore.matchTopics(key, newSubscription.getTopicFilter());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -640,7 +643,7 @@ public class ProtocolProcessor {
|
||||
|
||||
for (IMessagesStore.StoredMessage storedMsg : messages) {
|
||||
//fire the as retained the message
|
||||
LOG.debug("send publish message for topic {}", topic);
|
||||
LOG.debug("send publish message for topic {}", newSubscription.getTopicFilter());
|
||||
//forwardPublishQoS0(newSubscription.getClientId(), storedMsg.getTopic(), storedMsg.getQos(), storedMsg.getPayload(), true);
|
||||
Integer packetID = storedMsg.getQos() == QOSType.MOST_ONE ? null :
|
||||
m_messagesStore.nextPacketID(newSubscription.getClientId());
|
||||
|
||||
@@ -60,6 +60,10 @@ public class Subscription implements Serializable {
|
||||
return topicFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this concept must be moved inside ClientSession and not subscription.
|
||||
* */
|
||||
@Deprecated
|
||||
public boolean isCleanSession() {
|
||||
return this.cleanSession;
|
||||
}
|
||||
@@ -71,20 +75,15 @@ public class Subscription implements Serializable {
|
||||
|
||||
Subscription that = (Subscription) o;
|
||||
|
||||
if (cleanSession != that.cleanSession) return false;
|
||||
if (clientId != null ? !clientId.equals(that.clientId) : that.clientId != null) return false;
|
||||
if (requestedQos != that.requestedQos) return false;
|
||||
if (topicFilter != null ? !topicFilter.equals(that.topicFilter) : that.topicFilter != null) return false;
|
||||
return !(topicFilter != null ? !topicFilter.equals(that.topicFilter) : that.topicFilter != null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = requestedQos.hashCode();
|
||||
result = 31 * result + (clientId != null ? clientId.hashCode() : 0);
|
||||
int result = clientId != null ? clientId.hashCode() : 0;
|
||||
result = 31 * result + (topicFilter != null ? topicFilter.hashCode() : 0);
|
||||
result = 31 * result + (cleanSession ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -68,8 +69,8 @@ public class SubscriptionsStore {
|
||||
public void visit(TreeNode node, int deep) {
|
||||
String subScriptionsStr = "";
|
||||
String indentTabs = indentTabs(deep);
|
||||
for (Subscription sub : node.m_subscriptions) {
|
||||
subScriptionsStr += indentTabs + sub.toString() + "\n";
|
||||
for (ClientTopicCouple couple : node.m_subscriptions) {
|
||||
subScriptionsStr += indentTabs + couple.toString() + "\n";
|
||||
}
|
||||
s += node.getToken() == null ? "" : node.getToken().toString();
|
||||
s += "\n" + (node.m_subscriptions.isEmpty() ? indentTabs : "") + subScriptionsStr /*+ "\n"*/;
|
||||
@@ -92,6 +93,7 @@ public class SubscriptionsStore {
|
||||
|
||||
private AtomicReference<TreeNode> subscriptions = new AtomicReference<>(new TreeNode());
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionsStore.class);
|
||||
private volatile ISessionsStore m_sessionsStore;
|
||||
|
||||
/**
|
||||
* Initialize the subscription tree with the list of subscriptions.
|
||||
@@ -99,22 +101,23 @@ public class SubscriptionsStore {
|
||||
*/
|
||||
public void init(ISessionsStore sessionsStore) {
|
||||
LOG.debug("init invoked");
|
||||
List<Subscription> subscriptions = sessionsStore.listAllSubscriptions();
|
||||
m_sessionsStore = sessionsStore;
|
||||
List<ClientTopicCouple> subscriptions = sessionsStore.listAllSubscriptions();
|
||||
//reload any subscriptions persisted
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Reloading all stored subscriptions...subscription tree before {}", dumpTree());
|
||||
}
|
||||
|
||||
for (Subscription subscription : subscriptions) {
|
||||
LOG.debug("Re-subscribing {} to topic {}", subscription.getClientId(), subscription.getTopicFilter());
|
||||
add(subscription);
|
||||
for (ClientTopicCouple clientTopic : subscriptions) {
|
||||
LOG.debug("Re-subscribing {} to topic {}", clientTopic.clientID, clientTopic.topicFilter);
|
||||
add(clientTopic);
|
||||
}
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Finished loading. Subscription tree after {}", dumpTree());
|
||||
}
|
||||
}
|
||||
|
||||
public void add(Subscription newSubscription) {
|
||||
public void add(ClientTopicCouple newSubscription) {
|
||||
TreeNode oldRoot;
|
||||
NodeCouple couple;
|
||||
do {
|
||||
@@ -146,13 +149,12 @@ public class SubscriptionsStore {
|
||||
if ((matchingChildren = current.childWithToken(token)) != null) {
|
||||
//copy the traversed node
|
||||
current = matchingChildren.copy();
|
||||
// current.m_parent = parent;
|
||||
//update the child just added in the children list
|
||||
parent.updateChild(matchingChildren, current);
|
||||
parent = current;
|
||||
} else {
|
||||
//create a new node for the newly inserted token
|
||||
matchingChildren = new TreeNode(/*current*/);
|
||||
matchingChildren = new TreeNode();
|
||||
matchingChildren.setToken(token);
|
||||
current.addChild(matchingChildren);
|
||||
current = matchingChildren;
|
||||
@@ -168,19 +170,7 @@ public class SubscriptionsStore {
|
||||
oldRoot = subscriptions.get();
|
||||
couple = recreatePath(topic, oldRoot);
|
||||
|
||||
//do the job
|
||||
//search for the subscription to remove
|
||||
Subscription toBeRemoved = null;
|
||||
for (Subscription sub : couple.createdNode.subscriptions()) {
|
||||
if (sub.topicFilter.equals(topic) && sub.getClientId().equals(clientID)) {
|
||||
toBeRemoved = sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toBeRemoved != null) {
|
||||
couple.createdNode.subscriptions().remove(toBeRemoved);
|
||||
}
|
||||
couple.createdNode.remove(new ClientTopicCouple(clientID, topic));
|
||||
//spin lock repeating till we can, swap root, if can't swap just re-do the operation
|
||||
} while(!subscriptions.compareAndSet(oldRoot, couple.root));
|
||||
}
|
||||
@@ -216,16 +206,17 @@ public class SubscriptionsStore {
|
||||
}
|
||||
|
||||
Queue<Token> tokenQueue = new LinkedBlockingDeque<>(tokens);
|
||||
List<Subscription> matchingSubs = new ArrayList<>();
|
||||
List<ClientTopicCouple> matchingSubs = new ArrayList<>();
|
||||
subscriptions.get().matches(tokenQueue, matchingSubs);
|
||||
|
||||
//remove the overlapping subscriptions, selecting ones with greatest qos
|
||||
Map<String, Subscription> subsForClient = new HashMap<>();
|
||||
for (Subscription sub : matchingSubs) {
|
||||
Subscription existingSub = subsForClient.get(sub.getClientId());
|
||||
for (ClientTopicCouple matchingCouple : matchingSubs) {
|
||||
Subscription existingSub = subsForClient.get(matchingCouple.clientID);
|
||||
Subscription sub = m_sessionsStore.getSubscription(matchingCouple);
|
||||
//update the selected subscriptions if not present or if has a greater qos
|
||||
if (existingSub == null || existingSub.getRequestedQos().byteValue() < sub.getRequestedQos().byteValue()) {
|
||||
subsForClient.put(sub.getClientId(), sub);
|
||||
subsForClient.put(matchingCouple.clientID, sub);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(subsForClient.values());
|
||||
|
||||
@@ -15,22 +15,17 @@
|
||||
*/
|
||||
package io.moquette.spi.impl.subscriptions;
|
||||
|
||||
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
class TreeNode {
|
||||
|
||||
private class ClientIDComparator implements Comparator<Subscription> {
|
||||
|
||||
public int compare(Subscription o1, Subscription o2) {
|
||||
return o1.getClientId().compareTo(o2.getClientId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Token m_token;
|
||||
List<TreeNode> m_children = new ArrayList<>();
|
||||
List<Subscription> m_subscriptions = new ArrayList<>();
|
||||
//TODO move to set of ClientIDthe set of clientIDs that has subscriptions to this topic
|
||||
Set<ClientTopicCouple> m_subscriptions = new HashSet<>();
|
||||
|
||||
TreeNode() {
|
||||
}
|
||||
@@ -43,19 +38,7 @@ class TreeNode {
|
||||
this.m_token = topic;
|
||||
}
|
||||
|
||||
void addSubscription(Subscription s) {
|
||||
//avoid double registering for same clientID, topic and QoS
|
||||
if (m_subscriptions.contains(s)) {
|
||||
return;
|
||||
}
|
||||
//remove existing subscription for same client and topic but different QoS
|
||||
Comparator<Subscription> comparator = new ClientIDComparator();
|
||||
Collections.sort(m_subscriptions, comparator);
|
||||
int existingSubIdx = Collections.binarySearch(m_subscriptions, s, comparator);
|
||||
if (existingSubIdx >= 0) {
|
||||
m_subscriptions.remove(existingSubIdx);
|
||||
}
|
||||
|
||||
void addSubscription(ClientTopicCouple s) {
|
||||
m_subscriptions.add(s);
|
||||
}
|
||||
|
||||
@@ -70,7 +53,7 @@ class TreeNode {
|
||||
TreeNode copy() {
|
||||
final TreeNode copy = new TreeNode();
|
||||
copy.m_children = new ArrayList<>(m_children);
|
||||
copy.m_subscriptions = new ArrayList<>(m_subscriptions);
|
||||
copy.m_subscriptions = new HashSet<>(m_subscriptions);
|
||||
copy.m_token = m_token;
|
||||
return copy;
|
||||
}
|
||||
@@ -94,11 +77,15 @@ class TreeNode {
|
||||
m_children.add(newChild);
|
||||
}
|
||||
|
||||
List<Subscription> subscriptions() {
|
||||
Collection<ClientTopicCouple> subscriptions() {
|
||||
return m_subscriptions;
|
||||
}
|
||||
|
||||
void matches(Queue<Token> tokens, List<Subscription> matchingSubs) {
|
||||
public void remove(ClientTopicCouple clientTopicCouple) {
|
||||
m_subscriptions.remove(clientTopicCouple);
|
||||
}
|
||||
|
||||
void matches(Queue<Token> tokens, List<ClientTopicCouple> matchingSubs) {
|
||||
Token t = tokens.poll();
|
||||
|
||||
//check if t is null <=> tokens finished
|
||||
@@ -147,14 +134,14 @@ class TreeNode {
|
||||
TreeNode removeClientSubscriptions(String clientID) {
|
||||
//collect what to delete and then delete to avoid ConcurrentModification
|
||||
TreeNode newSubRoot = this.copy();
|
||||
List<Subscription> subsToRemove = new ArrayList<>();
|
||||
for (Subscription s : newSubRoot.m_subscriptions) {
|
||||
if (s.clientId.equals(clientID)) {
|
||||
List<ClientTopicCouple> subsToRemove = new ArrayList<>();
|
||||
for (ClientTopicCouple s : newSubRoot.m_subscriptions) {
|
||||
if (s.clientID.equals(clientID)) {
|
||||
subsToRemove.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
for (Subscription s : subsToRemove) {
|
||||
for (ClientTopicCouple s : subsToRemove) {
|
||||
newSubRoot.m_subscriptions.remove(s);
|
||||
}
|
||||
|
||||
@@ -166,21 +153,4 @@ class TreeNode {
|
||||
newSubRoot.m_children = newChildren;
|
||||
return newSubRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of subscriptions for the given client.
|
||||
* */
|
||||
Set<Subscription> findAllByClientID(String clientID) {
|
||||
Set<Subscription> subs = new HashSet<>();
|
||||
for (Subscription s : m_subscriptions) {
|
||||
if (s.clientId.equals(clientID)) {
|
||||
subs.add(s);
|
||||
}
|
||||
}
|
||||
//go deep
|
||||
for (TreeNode child : m_children) {
|
||||
subs.addAll(child.findAllByClientID(clientID));
|
||||
}
|
||||
return subs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ class MapDBSessionsStore implements ISessionsStore {
|
||||
private ConcurrentMap<String, Map<Integer, String>> m_inflightStore;
|
||||
//map clientID <-> set of currently in flight packet identifiers
|
||||
private Map<String, Set<Integer>> m_inFlightIds;
|
||||
//persistent Map of clientID, set of Subscriptions
|
||||
private ConcurrentMap<String, Set<Subscription>> m_persistentSubscriptions;
|
||||
private ConcurrentMap<String, PersistentSession> m_persistentSessions;
|
||||
//maps clientID->[guid*], insertion order cares, it's queue
|
||||
private ConcurrentMap<String, List<String>> m_enqueuedStore;
|
||||
@@ -61,7 +59,6 @@ class MapDBSessionsStore implements ISessionsStore {
|
||||
public void initStore() {
|
||||
m_inflightStore = m_db.getHashMap("inflight");
|
||||
m_inFlightIds = m_db.getHashMap("inflightPacketIDs");
|
||||
m_persistentSubscriptions = m_db.getHashMap("subscriptions");
|
||||
m_persistentSessions = m_db.getHashMap("sessions");
|
||||
m_enqueuedStore = m_db.getHashMap("sessionQueue");
|
||||
m_secondPhaseStore = m_db.getHashMap("secondPhase");
|
||||
@@ -71,79 +68,57 @@ class MapDBSessionsStore implements ISessionsStore {
|
||||
public void addNewSubscription(Subscription newSubscription) {
|
||||
LOG.debug("addNewSubscription invoked with subscription {}", newSubscription);
|
||||
final String clientID = newSubscription.getClientId();
|
||||
if (!m_persistentSubscriptions.containsKey(clientID)) {
|
||||
LOG.debug("subscriptions for clientID <{}> not present, empty subscriptions set", clientID);
|
||||
m_persistentSubscriptions.put(clientID, new HashSet<Subscription>());
|
||||
}
|
||||
m_db.getHashMap("subscriptions_" + clientID).put(newSubscription.getTopicFilter(), newSubscription);
|
||||
|
||||
Set<Subscription> subs = m_persistentSubscriptions.get(clientID);
|
||||
if (!subs.contains(newSubscription)) {
|
||||
LOG.debug("updating <{}> subscriptions set with new subscription", clientID);
|
||||
//TODO check the subs doesn't contain another subscription to the same topic with different
|
||||
Subscription existingSubscription = null;
|
||||
for (Subscription scanSub : subs) {
|
||||
if (newSubscription.getTopicFilter().equals(scanSub.getTopicFilter())) {
|
||||
existingSubscription = scanSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (existingSubscription != null) {
|
||||
subs.remove(existingSubscription);
|
||||
}
|
||||
subs.add(newSubscription);
|
||||
m_persistentSubscriptions.put(clientID, subs);
|
||||
LOG.debug("clientID {} subscriptions set now is {}", clientID, subs);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("subscriptions_{}: {}", clientID, m_db.getHashMap("subscriptions_" + clientID));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSubscription(String topic, String clientID) {
|
||||
LOG.debug("removeSubscription topic filter: {} for clientID: {}", topic, clientID);
|
||||
if (!m_persistentSubscriptions.containsKey(clientID)) {
|
||||
public void removeSubscription(String topicFilter, String clientID) {
|
||||
LOG.debug("removeSubscription topic filter: {} for clientID: {}", topicFilter, clientID);
|
||||
if (!m_db.exists("subscriptions_" + clientID)) {
|
||||
return;
|
||||
}
|
||||
Set<Subscription> clientSubscriptions = m_persistentSubscriptions.get(clientID);
|
||||
//search for the subscription to remove
|
||||
Subscription toBeRemoved = null;
|
||||
for (Subscription sub : clientSubscriptions) {
|
||||
if (sub.getTopicFilter().equals(topic)) {
|
||||
toBeRemoved = sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toBeRemoved != null) {
|
||||
clientSubscriptions.remove(toBeRemoved);
|
||||
}
|
||||
m_persistentSubscriptions.put(clientID, clientSubscriptions);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("persisted subscriptions {}", m_persistentSubscriptions);
|
||||
}
|
||||
m_db.getHashMap("subscriptions_" + clientID).remove(topicFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wipeSubscriptions(String clientID) {
|
||||
m_persistentSubscriptions.remove(clientID);
|
||||
LOG.debug("wipeSubscriptions");
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Subscription pre wipe: subscriptions_{}: {}", clientID, m_db.getHashMap("subscriptions_" + clientID));
|
||||
}
|
||||
m_db.delete("subscriptions_" + clientID);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Subscription post wipe: subscriptions_{}: {}", clientID, m_db.getHashMap("subscriptions_" + clientID));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSubscriptions(String clientID, Set<Subscription> subscriptions) {
|
||||
m_persistentSubscriptions.put(clientID, subscriptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Subscription> listAllSubscriptions() {
|
||||
List<Subscription> allSubscriptions = new ArrayList<>();
|
||||
for (Map.Entry<String, Set<Subscription>> entry : m_persistentSubscriptions.entrySet()) {
|
||||
allSubscriptions.addAll(entry.getValue());
|
||||
public List<ClientTopicCouple> listAllSubscriptions() {
|
||||
final List<ClientTopicCouple> allSubscriptions = new ArrayList<>();
|
||||
for (String clientID : m_persistentSessions.keySet()) {
|
||||
ConcurrentMap<String, Subscription> clientSubscriptions = m_db.getHashMap("subscriptions_" + clientID);
|
||||
for (String topicFilter : clientSubscriptions.keySet()) {
|
||||
allSubscriptions.add(new ClientTopicCouple(clientID, topicFilter));
|
||||
}
|
||||
}
|
||||
LOG.debug("retrieveAllSubscriptions returning subs {}", allSubscriptions);
|
||||
return allSubscriptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subscription getSubscription(ClientTopicCouple couple) {
|
||||
ConcurrentMap<String, Subscription> clientSubscriptions = m_db.getHashMap("subscriptions_" + couple.clientID);
|
||||
LOG.debug("subscriptions_{}: {}", couple.clientID, clientSubscriptions);
|
||||
return clientSubscriptions.get(couple.topicFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String clientID) {
|
||||
return m_persistentSubscriptions.containsKey(clientID);
|
||||
return m_db.exists("subscriptions_" + clientID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +129,6 @@ class MapDBSessionsStore implements ISessionsStore {
|
||||
throw new IllegalArgumentException("Can't create a session with the ID of an already existing" + clientID);
|
||||
}
|
||||
LOG.debug("clientID {} is a newcome, creating it's empty subscriptions set", clientID);
|
||||
m_persistentSubscriptions.put(clientID, new HashSet<Subscription>());
|
||||
m_persistentSessions.putIfAbsent(clientID, new PersistentSession(cleanSession, false));
|
||||
return new ClientSession(clientID, m_messagesStore, this, cleanSession);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user