Skip to content

automatic topic alias management

Takatoshi Kondo edited this page Jul 17, 2021 · 3 revisions

automatic topic alias management

Two independent topic alias maximum

There are two independent TopicAliasMaximum. One is client to broker, the other is broker to client.

client to broker

It is notified by CONNACK packet.

See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901088 This limits how many topic aliases can be used by the client. The value is decided by the broker.

broker to client

It is notified by CONNECT packet.

See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901051 This limits how many topic aliases to the client can be used by the broker. The value is decided by the client. So MQTT.js client option topicAliasMaximum should be this one.

Important note

The two Topic Alias Maximum is not negotiated. They are independent values. TopicAlias mapping is also independent. So client to broker topic1-TopicAlias:1 and broker to client topic2-TopicAlias:1 can exist at the same time.

client                           broker
TopicAliasMaximum=10             TopicAliasMaximum=5
(options.topicAliasMaximum=10)
   |                                |
   |                                |
   | CONNECT(TopicAliasMaximum:10)  |
   |------------------------------->|
   |                                |
   |                                |
   | CONNACK(TopicAliasMaximum:5)   |
   |<-------------------------------|
   |                                |
   |                                |
The client can use               The broker can use
1-5 topic aliases.               1-10 topic aliases.
   |                                |
   |                                |
   |  PUBLISH(topic:t1, ta:1)       |   (ta means TopicAlias)
   |------------------------------->|
   |                                |
   |                             The broker needs to manage
   |                             topic:t1 - ta:1 mapping
   |                                |
   |                                |
   |  PUBLISH(topic:t2, ta:1)       |
   |<-------------------------------|
   |                                |
The client needs to manage
topic:t2 - ta:1 mapping

Topic Alias lifetime

The spec said as follows:

https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113

Topic Alias mappings exist only within a Network Connection and last only for the lifetime of that Network Connection. A receiver MUST NOT carry forward any Topic Alias mappings from one Network Connection to another [MQTT-3.3.2-7].

So the lifetime of mapping is only in the network connection not session. See https://markmail.org/message/3j47bqjdvcaxdcji

Impact for implementation

Consider the following scenario.

  1. The client sends CONNECT to the broker.
  2. The broker sends CONNACK(Topic Alias Maximum:10) to the client.
  3. The client sends PUBLISH(topic:'t1', ta:1, qos:0) to the broker.
  4. The client sends PUBLISH(topic:'', ta:1, qos:1) to the broker.
  5. Network disconnected. The PUBLISH packet in the step4 is stored in the client's store.
  6. The client reconnects to the broker. (sends CONNECT)
  7. The broker sends CONNACK(Topic Alias Maximum:10) to the client.
  8. The client re-sends PUBLISH(topic:'', ta:1, qos:1) to the broker. It is protocol error.

The spec is a little ambiguous. It only referred to "A receiver MUST NOT carry forward", but sender and receiver is a pair. So the sender must not send topic alias just after reconnection. Consider TopicAliasMaximum at the step7 is different from the step2 case.

Here is the solution. Add the TopicAlias map to the sender (in this case the client). At the step3, register the topic-alias pair to the map. At the step4, get the topic from the alias using the map and create the packet clone for storing. The storing packet has the recovered topic, and remove TopicAlias from the storing packet. Then send the original packet. At the step8, resending packet is the stored packet. So it has topic and doesn't have TopicAlias. No protocol error.


Sending Topic Alias

Automatic Topic Alias replacing

If the endpoint calls the member function set_auto_replace_topic_alias_send() then the endpoint adds existing mapped topic alias and replaces topic with empty string automatically.

https://github.com/redboltz/mqtt_cpp/blob/0edd93edfb3270cfd4435571a3e4440c6a9bb25b/include/mqtt/endpoint.hpp#L860-L870

example scenario:

1. PUBLISH topic:'t1', ta:1                   (register)
2. PUBLISH topic:'t1'       -> topic:'', ta:1 (auto use existing map entry)
3. PUBLISH topic:'t2', ta:1                   (register overwrite)
4. PUBLISH topic:'t2'       -> topic:'', ta:1 (auto use existing map entry based on the receent map)
5. PUBLISH topic:'t1'                         (t1 is no longer mapped to ta:1)

User doesn't need to manage which topic is mapped to which topic alias. If the user want to register topic alias, then publish topic with topic alias. If the user want to use topic alias, then publish topic without topic alias. If there is a mapped topic alias then added it as a property and update the topic to empty string.

Automatic Topic Alias mapping

If the endpoint calls the member function set_auto_map_topic_alias_send() then the endpoint adds existing mapped topic alias and replaces topic with empty string automatically. In addition, if no mapped topic alias exists, then assign a new vacant topic alias automatically and register it. If topic alias is fully used, then LRU(Least Recently Used) topic-alias entry is overwritten.

example scenario:

The broker returns CONNACK (TopicAliasMaximum:3)
1. PUBLISH topic:'t1' -> 't1', ta:1 (auto assign t1:1 and register)
2. PUBLISH topic:'t1' -> ''  , ta:1 (auto use existing map entry)
3. PUBLISH topic:'t2' -> 't2', ta:2 (auto assign t1:2 and register. 2 was vacant)
4. PUBLISH topic:'t3' -> 't3', ta:3 (auto assign t1:3 and register. 3 was vacant)
5. PUBLISH topic:'t4' -> 't4', ta:1 (LRU entry is overwritten)

Also user can manually register topic-alias pair using PUBLISH topic:'some', ta:X. It works well with automatic topic alias mapping.

Receiving Topic Alias

In order to enable Topic Alias, you need to call set_topic_alias_maximum(). The parameter is capacity. For the limit of MQTT spec, you can use mqtt::topic_alias_max. If you call set_topic_alias_maximum() with greater than 0 argument, then the client automatically sets topic_alias_maximum property when sending CONNECT packet. The broker's connection automatically sets topic_alias_maximum property when sending CONNACK packet. This is recommended way to setup Topic Alias for receiving.

There is alternative way. You can overwrite Topic Alias receiving capacity by manually set topic_alias_maximum property to CONNECT or CONNACK packet. If you do that, you don't need to call set_topic_alias_maximuum().

mqtt_cpp automatically complements topic from alias on receiving PUBLISH packet. User doesn't need to manage topic alias map.