Introduced the FlightZone concept (inbound and outbound) and separated logic of storage system.

This commit is contained in:
andsel
2017-04-09 19:22:50 +02:00
parent 5c6889fbd5
commit 6dc762f47f
21 changed files with 356 additions and 396 deletions
@@ -47,7 +47,7 @@ final class BrokerInterceptor implements Interceptor {
private final ExecutorService executor;
private BrokerInterceptor(int poolSize, List<InterceptHandler> handlers) {
LOG.info("Initializing broker interceptor. InterceptorIds = {}.", getInterceptorIds(handlers));
LOG.info("Initializing broker interceptor. InterceptorIds={}", getInterceptorIds(handlers));
this.handlers = new HashMap<>();
for (Class<?> messageType : InterceptHandler.ALL_MESSAGE_TYPES) {
this.handlers.put(messageType, new CopyOnWriteArrayList<InterceptHandler>());
@@ -94,10 +94,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyClientConnected(final MqttConnectMessage msg) {
for (final InterceptHandler handler : this.handlers.get(InterceptConnectMessage.class)) {
LOG.debug(
"Sending MQTT CONNECT message to interceptor. MqttClientId = {}, interceptorId = {}.",
msg.payload().clientIdentifier(),
handler.getID());
LOG.debug("Sending MQTT CONNECT message to interceptor. CId={}, interceptorId={}",
msg.payload().clientIdentifier(), handler.getID());
executor.execute(new Runnable() {
@Override
@@ -111,12 +109,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyClientDisconnected(final String clientID, final String username) {
for (final InterceptHandler handler : this.handlers.get(InterceptDisconnectMessage.class)) {
LOG.debug(
"Notifying MQTT client disconnection to interceptor. MqttClientId = {}, username = {}, "
+ "interceptorId = {}.",
clientID,
username,
handler.getID());
LOG.debug("Notifying MQTT client disconnection to interceptor. CId={}, username={}, interceptorId={}",
clientID, username, handler.getID());
executor.execute(new Runnable() {
@Override
@@ -130,12 +124,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyClientConnectionLost(final String clientID, final String username) {
for (final InterceptHandler handler : this.handlers.get(InterceptConnectionLostMessage.class)) {
LOG.debug(
"Notifying unexpected MQTT client disconnection to interceptor. MqttClientId = {}, "
+ "username = {}, interceptorId = {}.",
clientID,
username,
handler.getID());
LOG.debug("Notifying unexpected MQTT client disconnection to interceptor CId={}, username={}, " +
"interceptorId={}", clientID, username, handler.getID());
executor.execute(new Runnable() {
@Override
@@ -151,13 +141,8 @@ final class BrokerInterceptor implements Interceptor {
int messageId = msg.variableHeader().messageId();
String topic = msg.variableHeader().topicName();
for (final InterceptHandler handler : this.handlers.get(InterceptPublishMessage.class)) {
LOG.debug(
"Notifying MQTT PUBLISH message to interceptor. MqttClientId = {}, messageId = {}, topic = {}, "
+ "interceptorId = {}.",
clientID,
messageId,
topic,
handler.getID());
LOG.debug("Notifying MQTT PUBLISH message to interceptor. CId={}, messageId={}, topic={}, interceptorId={}",
clientID, messageId, topic, handler.getID());
executor.execute(new Runnable() {
@Override
@@ -171,12 +156,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyTopicSubscribed(final Subscription sub, final String username) {
for (final InterceptHandler handler : this.handlers.get(InterceptSubscribeMessage.class)) {
LOG.debug(
"Notifying MQTT SUBSCRIBE message to interceptor. MqttClientId = {}, topicFilter = {}, "
+ "interceptorId = {}.",
sub.getClientId(),
sub.getTopicFilter(),
handler.getID());
LOG.debug("Notifying MQTT SUBSCRIBE message to interceptor. CId={}, topicFilter={}, interceptorId={}",
sub.getClientId(), sub.getTopicFilter(), handler.getID());
executor.execute(new Runnable() {
@Override
@@ -190,12 +171,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyTopicUnsubscribed(final String topic, final String clientID, final String username) {
for (final InterceptHandler handler : this.handlers.get(InterceptUnsubscribeMessage.class)) {
LOG.debug(
"Notifying MQTT UNSUBSCRIBE message to interceptor. MqttClientId = {}, topic = {}, "
+ "interceptorId = {}.",
clientID,
topic,
handler.getID());
LOG.debug("Notifying MQTT UNSUBSCRIBE message to interceptor. CId={}, topic={}, interceptorId={}", clientID,
topic, handler.getID());
executor.execute(new Runnable() {
@Override
@@ -209,13 +186,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void notifyMessageAcknowledged(final InterceptAcknowledgedMessage msg) {
for (final InterceptHandler handler : this.handlers.get(InterceptAcknowledgedMessage.class)) {
LOG.debug(
"Notifying MQTT ACK message to interceptor. MqttClientId = {}, messageId = {}, topic = {}, "
+ "interceptorId = {}.",
msg.getMsg().getClientID(),
msg.getMsg().getMessageID(),
msg.getTopic(),
handler.getID());
LOG.debug("Notifying MQTT ACK message to interceptor. CId={}, messageId={}, topic={}, interceptorId={}",
msg.getMsg().getClientID(), msg.getPacketID(), msg.getTopic(), handler.getID());
executor.execute(new Runnable() {
@Override
@@ -229,10 +201,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void addInterceptHandler(InterceptHandler interceptHandler) {
Class<?>[] interceptedMessageTypes = getInterceptedMessageTypes(interceptHandler);
LOG.info(
"Adding MQTT message interceptor. InterceptorId = {}, handledMessageTypes = {}.",
interceptHandler.getID(),
interceptedMessageTypes);
LOG.info( "Adding MQTT message interceptor. InterceptorId={}, handledMessageTypes={}",
interceptHandler.getID(), interceptedMessageTypes);
for (Class<?> interceptMessageType : interceptedMessageTypes) {
this.handlers.get(interceptMessageType).add(interceptHandler);
}
@@ -241,10 +211,8 @@ final class BrokerInterceptor implements Interceptor {
@Override
public void removeInterceptHandler(InterceptHandler interceptHandler) {
Class<?>[] interceptedMessageTypes = getInterceptedMessageTypes(interceptHandler);
LOG.info(
"Removing MQTT message interceptor. InterceptorId = {}, handledMessageTypes = {}.",
interceptHandler.getID(),
interceptedMessageTypes);
LOG.info("Removing MQTT message interceptor. InterceptorId={}, handledMessageTypes={}",
interceptHandler.getID(), interceptedMessageTypes);
for (Class<?> interceptMessageType : interceptedMessageTypes) {
this.handlers.get(interceptMessageType).remove(interceptHandler);
}
@@ -25,17 +25,16 @@ class InternalRepublisher {
void publishRetained(ClientSession targetSession, Collection<IMessagesStore.StoredMessage> messages) {
for (IMessagesStore.StoredMessage storedMsg : messages) {
// fire as retained the message
Integer packetID = storedMsg.getQos() == MqttQoS.AT_MOST_ONCE ? null : targetSession.nextPacketId();
if (packetID != null) {
LOG.debug("Adding message to inflight zone. ClientId={}, packetId={}, messageId={}, topic={}",
targetSession.clientID, packetID, storedMsg.getMessageID(), storedMsg.getTopic());
targetSession.inFlightAckWaiting(storedMsg.getGuid(), packetID);
}
MqttPublishMessage publishMsg = retainedPublish(storedMsg);
// set the PacketIdentifier only for QoS > 0
if (publishMsg.fixedHeader().qosLevel() != MqttQoS.AT_MOST_ONCE) {
if (storedMsg.getQos() != MqttQoS.AT_MOST_ONCE) {
LOG.debug("Adding message to inflight zone. ClientId={}, topic={}", targetSession.clientID,
storedMsg.getTopic());
int packetID = targetSession.inFlightAckWaiting(storedMsg.getGuid());
// set the PacketIdentifier only for QoS > 0
publishMsg = retainedPublish(storedMsg, packetID);
}
this.messageSender.sendPublish(targetSession, publishMsg);
}
}
@@ -46,13 +45,13 @@ class InternalRepublisher {
for (IMessagesStore.StoredMessage pubEvt : storedPublishes) {
// put in flight zone
LOG.debug("Adding message ot inflight zone. ClientId={}, guid={}, messageId={}, topic={}",
clientSession.clientID, pubEvt.getGuid(), pubEvt.getMessageID(), pubEvt.getTopic());
clientSession.inFlightAckWaiting(pubEvt.getGuid(), pubEvt.getMessageID());
LOG.debug("Adding message ot inflight zone. ClientId={}, guid={}, topic={}", clientSession.clientID,
pubEvt.getGuid(), pubEvt.getTopic());
int messageId = clientSession.inFlightAckWaiting(pubEvt.getGuid());
MqttPublishMessage publishMsg = notRetainedPublish(pubEvt);
// set the PacketIdentifier only for QoS > 0
if (publishMsg.fixedHeader().qosLevel() != MqttQoS.AT_MOST_ONCE) {
publishMsg = notRetainedPublish(pubEvt, pubEvt.getMessageID());
publishMsg = notRetainedPublish(pubEvt, messageId);
}
this.messageSender.sendPublish(clientSession, publishMsg);
}
@@ -63,25 +63,20 @@ class MessagesPublisher {
// refCnt = 0
ByteBuf message = origMessage.retainedDuplicate();
if (targetIsActive) {
LOG.debug(
"Sending PUBLISH message to active subscriber. MessageId={}, CId={}, topicFilter={}, qos={}",
pubMsg.getMessageID(),
sub.getClientId(),
sub.getTopicFilter(),
qos);
LOG.debug("Sending PUBLISH message to active subscriber. CId={}, topicFilter={}, qos={}",
sub.getClientId(), sub.getTopicFilter(), qos);
MqttPublishMessage publishMsg = notRetainedPublish(topic, qos, message);
if (qos != MqttQoS.AT_MOST_ONCE) {
// QoS 1 or 2
int messageId = targetSession.nextPacketId();
targetSession.inFlightAckWaiting(guid, messageId);
int messageId = targetSession.inFlightAckWaiting(guid);
// set the PacketIdentifier only for QoS > 0
publishMsg = notRetainedPublishWithMessageId(topic, qos, message, messageId);
}
this.messageSender.sendPublish(targetSession, publishMsg);
} else {
if (!targetSession.isCleanSession()) {
LOG.debug("Storing pending PUBLISH inactive message. MessageId={}, CId={}, topicFilter={}, qos={}",
pubMsg.getMessageID(), sub.getClientId(), sub.getTopicFilter(), qos);
LOG.debug("Storing pending PUBLISH inactive message. CId={}, topicFilter={}, qos={}",
sub.getClientId(), sub.getTopicFilter(), qos);
// store the message in targetSession queue to deliver
targetSession.enqueue(pubMsg);
}
@@ -474,7 +474,7 @@ public class ProtocolProcessor {
targetSession.inFlightAcknowledged(messageID);
String topic = inflightMsg.getTopic();
m_interceptor.notifyMessageAcknowledged(new InterceptAcknowledgedMessage(inflightMsg, topic, username));
m_interceptor.notifyMessageAcknowledged(new InterceptAcknowledgedMessage(inflightMsg, topic, username, messageID));
}
public static IMessagesStore.StoredMessage asStoredMessage(MqttPublishMessage msg) {
@@ -485,7 +485,6 @@ public class ProtocolProcessor {
IMessagesStore.StoredMessage stored = new IMessagesStore.StoredMessage(payloadContent,
msg.fixedHeader().qosLevel(), msg.variableHeader().topicName());
stored.setRetained(msg.fixedHeader().isRetain());
stored.setMessageID(msg.variableHeader().messageId());
return stored;
}
@@ -540,7 +539,6 @@ public class ProtocolProcessor {
} else {
toStoreMsg.setClientID(clientId);
}
toStoreMsg.setMessageID(1);
if (qos == EXACTLY_ONCE) { // QoS2
guid = m_messagesStore.storePublishForFuture(toStoreMsg);
}
@@ -568,18 +566,12 @@ public class ProtocolProcessor {
private void forwardPublishWill(WillMessage will, String clientID) {
// it has just to publish the message downstream to the subscribers
// NB it's a will publish, it needs a PacketIdentifier for this conn, default to 1
Integer messageId = null;
if (will.getQos() != AT_MOST_ONCE) {
messageId = m_sessionsStore.nextPacketID(clientID);
}
IMessagesStore.StoredMessage tobeStored = asStoredMessage(will);
tobeStored.setClientID(clientID);
tobeStored.setMessageID(messageId);
Topic topic = new Topic(tobeStored.getTopic());
List<Subscription> topicMatchingSubscriptions = subscriptions.matches(topic);
LOG.info("Publishing will message. CId={}, messageId={}, topic={}", clientID, messageId, topic);
LOG.info("Publishing will message. CId={}, topic={}", clientID, topic);
this.messagesPublisher.publish2Subscribers(tobeStored, topicMatchingSubscriptions);
}
@@ -626,7 +618,7 @@ public class ProtocolProcessor {
StoredMessage inflightMsg = targetSession.secondPhaseAcknowledged(messageID);
String username = NettyUtils.userName(channel);
String topic = inflightMsg.getTopic();
m_interceptor.notifyMessageAcknowledged(new InterceptAcknowledgedMessage(inflightMsg, topic, username));
m_interceptor.notifyMessageAcknowledged(new InterceptAcknowledgedMessage(inflightMsg, topic, username, messageID));
}
public void processDisconnect(Channel channel) throws InterruptedException {
@@ -759,8 +751,7 @@ public class ProtocolProcessor {
if (!validTopic) {
// close the connection, not valid topicFilter is a protocol violation
channel.close();
LOG.error( "Topic filter is not valid. CId={}, topics={}, badTopicFilter={}", clientID, topics,
topic);
LOG.error("Topic filter is not valid. CId={}, topics={}, badTopicFilter={}", clientID, topics, topic);
return;
}
@@ -16,6 +16,8 @@ import io.netty.handler.codec.mqtt.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import static io.moquette.spi.impl.DebugUtils.payload2Str;
import static io.moquette.spi.impl.ProtocolProcessor.asStoredMessage;
import static io.moquette.spi.impl.Utils.messageId;
import static io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader.from;
@@ -23,7 +25,7 @@ import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
class Qos2PublishHandler extends QosPublishHandler {
private static final Logger LOG = LoggerFactory.getLogger(Qos1PublishHandler.class);
private static final Logger LOG = LoggerFactory.getLogger(Qos2PublishHandler.class);
private final SubscriptionsStore subscriptions;
private final IMessagesStore m_messagesStore;
@@ -57,18 +59,16 @@ class Qos2PublishHandler extends QosPublishHandler {
String clientID = NettyUtils.clientID(channel);
toStoreMsg.setClientID(clientID);
LOG.info("Sending publish message to subscribers CId={}, topic={}, messageId={}", clientID, topic, messageID);
if (LOG.isTraceEnabled()) {
LOG.trace( "Sending publish message to subscribers. ClientId={}, topic={}, messageId={}, payload={}, " +
"subscriptionTree={}", clientID, topic, messageID, DebugUtils.payload2Str(toStoreMsg.getMessage()),
subscriptions.dumpTree());
} else {
LOG.info("Sending publish message to subscribers. ClientId={}, topic={}, messageId={}", clientID, topic,
messageID);
LOG.trace("payload={}, subs Tree={}", payload2Str(toStoreMsg.getMessage()), subscriptions.dumpTree());
}
// QoS2
MessageGUID guid = m_messagesStore.storePublishForFuture(toStoreMsg);
// TODO Don't send PUBREC for Hz publish notification, if (msg.isLocal()) {
ClientSession sourceSession = m_sessionsStore.sessionForClient(clientID);
sourceSession.markAsInboundInflight(messageID, guid);
sendPubRec(clientID, messageID);
// Next the client will send us a pub rel
@@ -92,18 +92,22 @@ class Qos2PublishHandler extends QosPublishHandler {
void processPubRel(Channel channel, MqttMessage msg) {
String clientID = NettyUtils.clientID(channel);
int messageID = messageId(msg);
LOG.info("Processing PUBREL message. ClientId={}, messageId={}", clientID, messageID);
LOG.info("Processing PUBREL message. CId={}, messageId={}", clientID, messageID);
ClientSession targetSession = m_sessionsStore.sessionForClient(clientID);
IMessagesStore.StoredMessage evt = targetSession.storedMessage(messageID);
IMessagesStore.StoredMessage evt = targetSession.inboundInflight(messageID);
if (evt == null) {
LOG.warn("Can't find inbound inflight message for CId={}, messageId={}", clientID, messageID);
throw new IllegalArgumentException("Can't find inbound inflight message");
}
final Topic topic = new Topic(evt.getTopic());
List<Subscription> topicMatchingSubscriptions = subscriptions.matches(topic);
if (LOG.isDebugEnabled()) {
LOG.debug("Sending publish message to subscribers. ClientId={}, topic={}, messageId={}, payload={}, " +
"subscriptionTree={}", clientID, topic, messageID, DebugUtils.payload2Str(evt.getMessage()),
LOG.debug("Sending publish message to subscribers. CId={}, topic={}, messageId={}, payload={}, " +
"subscriptionTree={}", clientID, topic, messageID, payload2Str(evt.getMessage()),
subscriptions.dumpTree());
} else {
LOG.info("Sending publish message to subscribers. ClientId={}, topic={}, messageId={}", clientID, topic,
LOG.info("Sending publish message to subscribers. CId={}, topic={}, messageId={}", clientID, topic,
messageID);
}
this.publisher.publish2Subscribers(evt, topicMatchingSubscriptions);
@@ -120,14 +124,14 @@ class Qos2PublishHandler extends QosPublishHandler {
}
private void sendPubRec(String clientID, int messageID) {
LOG.debug("Sending PUBREC message. ClientId={}, messageId={}", clientID, messageID);
LOG.debug("Sending PUBREC message. CId={}, messageId={}", clientID, messageID);
MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBREC, false, AT_MOST_ONCE, false, 0);
MqttMessage pubRecMessage = new MqttMessage(fixedHeader, from(messageID));
connectionDescriptors.sendMessage(pubRecMessage, messageID, clientID);
}
private void sendPubComp(String clientID, int messageID) {
LOG.debug("Sending PUBCOMP message. ClientId={}, messageId={}", clientID, messageID);
LOG.debug("Sending PUBCOMP message. CId={}, messageId={}", clientID, messageID);
MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBCOMP, false, AT_MOST_ONCE, false, 0);
MqttMessage pubCompMessage = new MqttMessage(fixedHeader, from(messageID));
connectionDescriptors.sendMessage(pubCompMessage, messageID, clientID);