<p>Joshua C. Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11130">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">stasis: Improve topic/subscription names and statistics.<br><br>Topic names now follow: <subsystem>:<functionality>[/<object>]<br><br>This ensures that they are all unique, and also provides better<br>insight in to what each topic is for.<br><br>Subscriber ids now also use the main topic name they are<br>subscribed to and an incrementing integer as their identifier to<br>make it easier to understand what the subscription is primarily<br>responsible for.<br><br>Both the CLI commands for listing topic and subscription statistics<br>now sort to make it a bit easier to see what is going on.<br><br>Subscriptions will now show all topics that they are receiving messages<br>from, not just the main topic they were subscribed to.<br><br>ASTERISK-28335<br><br>Change-Id: I484e971a38c3640f2bd156282e532eed84bf220d<br>---<br>M apps/app_voicemail.c<br>M include/asterisk/stasis.h<br>M main/app.c<br>M main/cdr.c<br>M main/cel.c<br>M main/channel_internal_api.c<br>M main/devicestate.c<br>M main/endpoints.c<br>M main/manager.c<br>M main/parking.c<br>M main/presencestate.c<br>M main/rtp_engine.c<br>M main/security_events.c<br>M main/stasis.c<br>M main/stasis_bridges.c<br>M main/stasis_cache.c<br>M main/stasis_cache_pattern.c<br>M main/stasis_channels.c<br>M main/stasis_endpoints.c<br>M main/stasis_system.c<br>M main/test.c<br>M res/res_corosync.c<br>M res/stasis/app.c<br>23 files changed, 283 insertions(+), 63 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/30/11130/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c</span><br><span>index a5a3691..a151f0c 100644</span><br><span>--- a/apps/app_voicemail.c</span><br><span>+++ b/apps/app_voicemail.c</span><br><span>@@ -13334,6 +13334,7 @@</span><br><span> static void mwi_sub_event_cb(struct stasis_subscription_change *change)</span><br><span> {</span><br><span>        struct mwi_sub_task *mwist;</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *topic;</span><br><span>   char *context;</span><br><span>       char *mailbox;</span><br><span> </span><br><span>@@ -13342,7 +13343,9 @@</span><br><span>                 return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (separate_mailbox(ast_strdupa(stasis_topic_name(change->topic)), &mailbox, &context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The topic name is prefixed with "mwi:all/" as this is a pool topic */</span><br><span style="color: hsl(120, 100%, 40%);">+    topic = stasis_topic_name(change->topic) + 8;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (separate_mailbox(ast_strdupa(topic), &mailbox, &context)) {</span><br><span>              ast_free(mwist);</span><br><span>             return;</span><br><span>      }</span><br><span>diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h</span><br><span>index 09db9ea..0b229bf 100644</span><br><span>--- a/include/asterisk/stasis.h</span><br><span>+++ b/include/asterisk/stasis.h</span><br><span>@@ -514,6 +514,8 @@</span><br><span>  * from a topic and destroy it. As a result the topic can persist until</span><br><span>  * the last subscriber unsubscribes itself even if there is no</span><br><span>  * publisher.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Topic names should be in the form of <subsystem>:<functionality>[/<object>]</span><br><span>  */</span><br><span> struct stasis_topic *stasis_topic_create(const char *name);</span><br><span> </span><br><span>diff --git a/main/app.c b/main/app.c</span><br><span>index ec74490..e8a4d2f 100644</span><br><span>--- a/main/app.c</span><br><span>+++ b/main/app.c</span><br><span>@@ -3337,7 +3337,7 @@</span><br><span>            stasis_publish(mailbox_specific_topic, clear_msg);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   stasis_topic_pool_delete_topic(mwi_topic_pool, stasis_topic_name(mailbox_specific_topic));</span><br><span style="color: hsl(120, 100%, 40%);">+    stasis_topic_pool_delete_topic(mwi_topic_pool, mwi_state->uniqueid);</span><br><span> </span><br><span>  ao2_cleanup(clear_msg);</span><br><span>      return 0;</span><br><span>@@ -3430,7 +3430,7 @@</span><br><span>    if (STASIS_MESSAGE_TYPE_INIT(ast_mwi_vm_app_type) != 0) {</span><br><span>            return -1;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-       mwi_topic_all = stasis_topic_create("stasis_mwi_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+    mwi_topic_all = stasis_topic_create("mwi:all");</span><br><span>    if (!mwi_topic_all) {</span><br><span>                return -1;</span><br><span>   }</span><br><span>@@ -3446,7 +3446,7 @@</span><br><span>    if (!mwi_topic_pool) {</span><br><span>               return -1;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-       queue_topic_all = stasis_topic_create("stasis_queue_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+        queue_topic_all = stasis_topic_create("queue:all");</span><br><span>        if (!queue_topic_all) {</span><br><span>              return -1;</span><br><span>   }</span><br><span>diff --git a/main/cdr.c b/main/cdr.c</span><br><span>index 53f3362..f8f038c 100644</span><br><span>--- a/main/cdr.c</span><br><span>+++ b/main/cdr.c</span><br><span>@@ -4504,7 +4504,7 @@</span><br><span>               return AST_MODULE_LOAD_FAILURE;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   cdr_topic = stasis_topic_create("cdr_engine");</span><br><span style="color: hsl(120, 100%, 40%);">+      cdr_topic = stasis_topic_create("cdr:aggregator");</span><br><span>         if (!cdr_topic) {</span><br><span>            return AST_MODULE_LOAD_FAILURE;</span><br><span>      }</span><br><span>diff --git a/main/cel.c b/main/cel.c</span><br><span>index 95376db..1e77d25 100644</span><br><span>--- a/main/cel.c</span><br><span>+++ b/main/cel.c</span><br><span>@@ -1431,12 +1431,12 @@</span><br><span>  */</span><br><span> static int create_subscriptions(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   cel_aggregation_topic = stasis_topic_create("cel_aggregation_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+       cel_aggregation_topic = stasis_topic_create("cel:aggregator");</span><br><span>     if (!cel_aggregation_topic) {</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   cel_topic = stasis_topic_create("cel_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+       cel_topic = stasis_topic_create("cel:misc");</span><br><span>       if (!cel_topic) {</span><br><span>            return -1;</span><br><span>   }</span><br><span>diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c</span><br><span>index 22a2bb6..be8fd7c 100644</span><br><span>--- a/main/channel_internal_api.c</span><br><span>+++ b/main/channel_internal_api.c</span><br><span>@@ -1520,14 +1520,23 @@</span><br><span> </span><br><span> int ast_channel_internal_setup_topics(struct ast_channel *chan)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *topic_name = chan->uniqueid.unique_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+     int ret;</span><br><span>     ast_assert(chan->topic == NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_strlen_zero(topic_name)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              topic_name = "<dummy-channel>";</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_strlen_zero(chan->uniqueid.unique_id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           static int dummy_id;</span><br><span style="color: hsl(120, 100%, 40%);">+          ret = ast_asprintf(&topic_name, "channel:dummy-%d", ast_atomic_fetchadd_int(&dummy_id, +1));</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ret = ast_asprintf(&topic_name, "channel:%s", chan->uniqueid.unique_id);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span>   }</span><br><span> </span><br><span>        chan->topic = stasis_topic_create(topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(topic_name);</span><br><span>        if (!chan->topic) {</span><br><span>               return -1;</span><br><span>   }</span><br><span>diff --git a/main/devicestate.c b/main/devicestate.c</span><br><span>index b6c740c..ecf255f 100644</span><br><span>--- a/main/devicestate.c</span><br><span>+++ b/main/devicestate.c</span><br><span>@@ -902,7 +902,7 @@</span><br><span>         if (STASIS_MESSAGE_TYPE_INIT(ast_device_state_message_type) != 0) {</span><br><span>          return -1;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-       device_state_topic_all = stasis_topic_create("ast_device_state_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+     device_state_topic_all = stasis_topic_create("devicestate:all");</span><br><span>   if (!device_state_topic_all) {</span><br><span>               return -1;</span><br><span>   }</span><br><span>diff --git a/main/endpoints.c b/main/endpoints.c</span><br><span>index b958932..c53e31d 100644</span><br><span>--- a/main/endpoints.c</span><br><span>+++ b/main/endpoints.c</span><br><span>@@ -255,9 +255,17 @@</span><br><span>        }</span><br><span> </span><br><span>        if (!ast_strlen_zero(resource)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             char *topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+             int ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ret = ast_asprintf(&topic_name, "endpoint:%s", endpoint->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span> </span><br><span>                endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(),</span><br><span style="color: hsl(0, 100%, 40%);">-                 endpoint->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                     topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_free(topic_name);</span><br><span>                if (!endpoint->topics) {</span><br><span>                  return NULL;</span><br><span>                 }</span><br><span>@@ -284,8 +292,17 @@</span><br><span>             endpoint_publish_snapshot(endpoint);</span><br><span>                 ao2_link(endpoints, endpoint);</span><br><span>       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              char *topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+             int ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ret = ast_asprintf(&topic_name, "endpoint:%s", endpoint->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          endpoint->topics = stasis_cp_sink_create(ast_endpoint_cache_all(),</span><br><span style="color: hsl(0, 100%, 40%);">-                   endpoint->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                     topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_free(topic_name);</span><br><span>                if (!endpoint->topics) {</span><br><span>                  return NULL;</span><br><span>                 }</span><br><span>diff --git a/main/manager.c b/main/manager.c</span><br><span>index 0c715e4..8e7a8b2 100644</span><br><span>--- a/main/manager.c</span><br><span>+++ b/main/manager.c</span><br><span>@@ -8996,7 +8996,7 @@</span><br><span>               if (res != 0) {</span><br><span>                      return -1;</span><br><span>           }</span><br><span style="color: hsl(0, 100%, 40%);">-               manager_topic = stasis_topic_create("manager_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+               manager_topic = stasis_topic_create("manager:core");</span><br><span>               if (!manager_topic) {</span><br><span>                        return -1;</span><br><span>           }</span><br><span>diff --git a/main/parking.c b/main/parking.c</span><br><span>index bf0d0b6..d77a767 100644</span><br><span>--- a/main/parking.c</span><br><span>+++ b/main/parking.c</span><br><span>@@ -56,7 +56,7 @@</span><br><span>           return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   parking_topic = stasis_topic_create("ast_parking");</span><br><span style="color: hsl(120, 100%, 40%);">+ parking_topic = stasis_topic_create("parking:all");</span><br><span>        if (!parking_topic) {</span><br><span>                return -1;</span><br><span>   }</span><br><span>diff --git a/main/presencestate.c b/main/presencestate.c</span><br><span>index 65b7f69..45433b1 100644</span><br><span>--- a/main/presencestate.c</span><br><span>+++ b/main/presencestate.c</span><br><span>@@ -500,7 +500,7 @@</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   presence_state_topic_all = stasis_topic_create("ast_presence_state_topic_all");</span><br><span style="color: hsl(120, 100%, 40%);">+     presence_state_topic_all = stasis_topic_create("presence_state:all");</span><br><span>      if (!presence_state_topic_all) {</span><br><span>             return -1;</span><br><span>   }</span><br><span>diff --git a/main/rtp_engine.c b/main/rtp_engine.c</span><br><span>index fd1613c..403b663 100644</span><br><span>--- a/main/rtp_engine.c</span><br><span>+++ b/main/rtp_engine.c</span><br><span>@@ -3539,7 +3539,7 @@</span><br><span>   ast_rwlock_init(&mime_types_lock);</span><br><span>       ast_rwlock_init(&static_RTP_PT_lock);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rtp_topic = stasis_topic_create("rtp_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+       rtp_topic = stasis_topic_create("rtp:all");</span><br><span>        if (!rtp_topic) {</span><br><span>            return -1;</span><br><span>   }</span><br><span>diff --git a/main/security_events.c b/main/security_events.c</span><br><span>index 37dce02..0328eca 100644</span><br><span>--- a/main/security_events.c</span><br><span>+++ b/main/security_events.c</span><br><span>@@ -484,7 +484,7 @@</span><br><span> {</span><br><span>    ast_register_cleanup(security_stasis_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      security_topic = stasis_topic_create("ast_security");</span><br><span style="color: hsl(120, 100%, 40%);">+       security_topic = stasis_topic_create("security:all");</span><br><span>      if (!security_topic) {</span><br><span>               return -1;</span><br><span>   }</span><br><span>diff --git a/main/stasis.c b/main/stasis.c</span><br><span>index fa92eeb..2e75e50 100644</span><br><span>--- a/main/stasis.c</span><br><span>+++ b/main/stasis.c</span><br><span>@@ -349,6 +349,8 @@</span><br><span>     int messages_dispatched;</span><br><span>     /*! \brief The ids of the subscribers to this topic */</span><br><span>       struct ao2_container *subscribers;</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! \brief Pointer to the topic (NOT refcounted, and must NOT be accessed) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_topic *topic;</span><br><span>  /*! \brief Name of the topic */</span><br><span>      char name[0];</span><br><span> };</span><br><span>@@ -366,6 +368,9 @@</span><br><span>    struct stasis_topic_statistics *statistics;</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     /*! Unique incrementing integer for subscriber ids */</span><br><span style="color: hsl(120, 100%, 40%);">+ int subscriber_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /*! Name of the topic */</span><br><span>     char name[0];</span><br><span> };</span><br><span>@@ -412,11 +417,11 @@</span><br><span>  ao2_cleanup(statistics->subscribers);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_topic_statistics *stasis_topic_statistics_create(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_topic_statistics *stasis_topic_statistics_create(struct stasis_topic *topic)</span><br><span> {</span><br><span>     struct stasis_topic_statistics *statistics;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- statistics = ao2_alloc(sizeof(*statistics) + strlen(name) + 1, topic_statistics_destroy);</span><br><span style="color: hsl(120, 100%, 40%);">+     statistics = ao2_alloc(sizeof(*statistics) + strlen(topic->name) + 1, topic_statistics_destroy);</span><br><span>  if (!statistics) {</span><br><span>           return NULL;</span><br><span>         }</span><br><span>@@ -427,7 +432,9 @@</span><br><span>              return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   strcpy(statistics->name, name); /* SAFE */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* This is strictly used for the pointer address when showing the topic */</span><br><span style="color: hsl(120, 100%, 40%);">+    statistics->topic = topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ strcpy(statistics->name, topic->name); /* SAFE */</span><br><span>      ao2_link(topic_statistics, statistics);</span><br><span> </span><br><span>  return statistics;</span><br><span>@@ -448,7 +455,7 @@</span><br><span>     res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX);</span><br><span>         res |= AST_VECTOR_INIT(&topic->upstream_topics, 0);</span><br><span> #ifdef AST_DEVMODE</span><br><span style="color: hsl(0, 100%, 40%);">-        topic->statistics = stasis_topic_statistics_create(name);</span><br><span style="color: hsl(120, 100%, 40%);">+  topic->statistics = stasis_topic_statistics_create(topic);</span><br><span>        if (!topic->name || !topic->statistics || res)</span><br><span> #else</span><br><span>        if (!topic->name || res)</span><br><span>@@ -477,8 +484,8 @@</span><br><span>    const char *file;</span><br><span>    /*! \brief The function where the subscription originates */</span><br><span>         const char *func;</span><br><span style="color: hsl(0, 100%, 40%);">-       /*! \brief Name of the topic we subscribed to */</span><br><span style="color: hsl(0, 100%, 40%);">-        char *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! \brief Names of the topics we are subscribed to */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ao2_container *topics;</span><br><span>        /*! \brief The message type that currently took the longest to process */</span><br><span>    struct stasis_message_type *highest_time_message_type;</span><br><span>       /*! \brief Highest time spent invoking a message */</span><br><span>@@ -495,6 +502,8 @@</span><br><span>    int uses_threadpool;</span><br><span>         /*! \brief The line number where the subscription originates */</span><br><span>      int lineno;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! \brief Pointer to the subscription (NOT refcounted, and must NOT be accessed) */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct stasis_subscription *sub;</span><br><span>     /*! \brief Unique ID of the subscription */</span><br><span>  char uniqueid[0];</span><br><span> };</span><br><span>@@ -503,7 +512,7 @@</span><br><span> /*! \internal */</span><br><span> struct stasis_subscription {</span><br><span>    /*! Unique ID for this subscription */</span><br><span style="color: hsl(0, 100%, 40%);">-  char uniqueid[AST_UUID_STR_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+      char *uniqueid;</span><br><span>      /*! Topic subscribed to. */</span><br><span>  struct stasis_topic *topic;</span><br><span>  /*! Mailbox for processing incoming messages. */</span><br><span>@@ -546,6 +555,7 @@</span><br><span>        * be bad. */</span><br><span>        ast_assert(stasis_subscription_is_done(sub));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(sub->uniqueid);</span><br><span>  ao2_cleanup(sub->topic);</span><br><span>  sub->topic = NULL;</span><br><span>        ast_taskprocessor_unreference(sub->mailbox);</span><br><span>@@ -628,26 +638,37 @@</span><br><span> }</span><br><span> </span><br><span> #ifdef AST_DEVMODE</span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_subscription_statistics *stasis_subscription_statistics_create(const char *uniqueid,</span><br><span style="color: hsl(0, 100%, 40%);">- const char *topic, int needs_mailbox, int use_thread_pool, const char *file, int lineno,</span><br><span style="color: hsl(120, 100%, 40%);">+static void subscription_statistics_destroy(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct stasis_subscription_statistics *statistics = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ao2_cleanup(statistics->topics);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_subscription_statistics *stasis_subscription_statistics_create(struct stasis_subscription *sub,</span><br><span style="color: hsl(120, 100%, 40%);">+        int needs_mailbox, int use_thread_pool, const char *file, int lineno,</span><br><span>        const char *func)</span><br><span> {</span><br><span>       struct stasis_subscription_statistics *statistics;</span><br><span style="color: hsl(0, 100%, 40%);">-      size_t uniqueid_len = strlen(uniqueid) + 1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- statistics = ao2_alloc(sizeof(*statistics) + uniqueid_len + strlen(topic) + 1, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics = ao2_alloc(sizeof(*statistics) + strlen(sub->uniqueid) + 1, subscription_statistics_destroy);</span><br><span>         if (!statistics) {</span><br><span>           return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ statistics->topics = ast_str_container_alloc(1);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!statistics->topics) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ao2_ref(statistics, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  statistics->file = file;</span><br><span>  statistics->lineno = lineno;</span><br><span>      statistics->func = func;</span><br><span>  statistics->uses_mailbox = needs_mailbox;</span><br><span>         statistics->uses_threadpool = use_thread_pool;</span><br><span style="color: hsl(0, 100%, 40%);">-       strcpy(statistics->uniqueid, uniqueid); /* SAFE */</span><br><span style="color: hsl(0, 100%, 40%);">-   statistics->topic = statistics->uniqueid + uniqueid_len;</span><br><span style="color: hsl(0, 100%, 40%);">-  strcpy(statistics->topic, topic); /* SAFE */</span><br><span style="color: hsl(120, 100%, 40%);">+       strcpy(statistics->uniqueid, sub->uniqueid); /* SAFE */</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics->sub = sub;</span><br><span>    ao2_link(subscription_statistics, statistics);</span><br><span> </span><br><span>   return statistics;</span><br><span>@@ -665,6 +686,7 @@</span><br><span>     const char *func)</span><br><span> {</span><br><span>       struct stasis_subscription *sub;</span><br><span style="color: hsl(120, 100%, 40%);">+      int ret;</span><br><span> </span><br><span>         if (!topic) {</span><br><span>                return NULL;</span><br><span>@@ -675,12 +697,17 @@</span><br><span>         if (!sub) {</span><br><span>          return NULL;</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid));</span><br><span> </span><br><span> #ifdef AST_DEVMODE</span><br><span style="color: hsl(0, 100%, 40%);">-    sub->statistics = stasis_subscription_statistics_create(sub->uniqueid, topic->name, needs_mailbox,</span><br><span style="color: hsl(0, 100%, 40%);">-             use_thread_pool, file, lineno, func);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!sub->statistics) {</span><br><span style="color: hsl(120, 100%, 40%);">+    ret = ast_asprintf(&sub->uniqueid, "%s:%s-%d", file, stasis_topic_name(topic), ast_atomic_fetchadd_int(&topic->subscriber_id, +1));</span><br><span style="color: hsl(120, 100%, 40%);">+   sub->statistics = stasis_subscription_statistics_create(sub, needs_mailbox, use_thread_pool, file, lineno, func);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ret < 0 || !sub->statistics) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_ref(sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+      ret = ast_asprintf(&sub->uniqueid, "%s-%d", stasis_topic_name(topic), ast_atomic_fetchadd_int(&topic->subscriber_id, +1));</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ret < 0) {</span><br><span>            ao2_ref(sub, -1);</span><br><span>            return NULL;</span><br><span>         }</span><br><span>@@ -1012,6 +1039,7 @@</span><br><span> </span><br><span> #ifdef AST_DEVMODE</span><br><span>  ast_str_container_add(topic->statistics->subscribers, stasis_subscription_uniqueid(sub));</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_str_container_add(sub->statistics->topics, stasis_topic_name(topic));</span><br><span> #endif</span><br><span> </span><br><span>        ao2_unlock(topic);</span><br><span>@@ -1035,6 +1063,7 @@</span><br><span> #ifdef AST_DEVMODE</span><br><span>     if (!res) {</span><br><span>          ast_str_container_remove(topic->statistics->subscribers, stasis_subscription_uniqueid(sub));</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_str_container_remove(sub->statistics->topics, stasis_topic_name(topic));</span><br><span>   }</span><br><span> #endif</span><br><span> </span><br><span>@@ -1498,6 +1527,7 @@</span><br><span> struct topic_pool_entry {</span><br><span>         struct stasis_forward *forward;</span><br><span>      struct stasis_topic *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+   char name[0];</span><br><span> };</span><br><span> </span><br><span> static void topic_pool_entry_dtor(void *obj)</span><br><span>@@ -1509,10 +1539,19 @@</span><br><span>    entry->topic = NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct topic_pool_entry *topic_pool_entry_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct topic_pool_entry *topic_pool_entry_alloc(const char *topic_name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       return ao2_alloc_options(sizeof(struct topic_pool_entry), topic_pool_entry_dtor,</span><br><span style="color: hsl(0, 100%, 40%);">-                AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct topic_pool_entry *topic_pool_entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  topic_pool_entry = ao2_alloc_options(sizeof(*topic_pool_entry) + strlen(topic_name) + 1,</span><br><span style="color: hsl(120, 100%, 40%);">+              topic_pool_entry_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!topic_pool_entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   strcpy(topic_pool_entry->name, topic_name); /* Safe */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return topic_pool_entry;</span><br><span> }</span><br><span> </span><br><span> struct stasis_topic_pool {</span><br><span>@@ -1550,7 +1589,7 @@</span><br><span>              break;</span><br><span>       case OBJ_SEARCH_OBJECT:</span><br><span>              object = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-           key = stasis_topic_name(object->topic);</span><br><span style="color: hsl(120, 100%, 40%);">+            key = object->name;</span><br><span>               break;</span><br><span>       default:</span><br><span>             /* Hash can only work on something with a full key. */</span><br><span>@@ -1569,10 +1608,10 @@</span><br><span> </span><br><span>         switch (flags & OBJ_SEARCH_MASK) {</span><br><span>       case OBJ_SEARCH_OBJECT:</span><br><span style="color: hsl(0, 100%, 40%);">-         right_key = stasis_topic_name(object_right->topic);</span><br><span style="color: hsl(120, 100%, 40%);">+                right_key = object_right->name;</span><br><span>           /* Fall through */</span><br><span>   case OBJ_SEARCH_KEY:</span><br><span style="color: hsl(0, 100%, 40%);">-            cmp = strcasecmp(stasis_topic_name(object_left->topic), right_key);</span><br><span style="color: hsl(120, 100%, 40%);">+                cmp = strcasecmp(object_left->name, right_key);</span><br><span>           break;</span><br><span>       case OBJ_SEARCH_PARTIAL_KEY:</span><br><span>                 /* Not supported by container */</span><br><span>@@ -1649,18 +1688,29 @@</span><br><span> {</span><br><span>      RAII_VAR(struct topic_pool_entry *, topic_pool_entry, NULL, ao2_cleanup);</span><br><span>    SCOPED_AO2LOCK(topic_container_lock, pool->pool_container);</span><br><span style="color: hsl(120, 100%, 40%);">+        char *new_topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+ int ret;</span><br><span> </span><br><span>         topic_pool_entry = ao2_find(pool->pool_container, topic_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);</span><br><span>       if (topic_pool_entry) {</span><br><span>              return topic_pool_entry->topic;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   topic_pool_entry = topic_pool_entry_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+  topic_pool_entry = topic_pool_entry_alloc(topic_name);</span><br><span>       if (!topic_pool_entry) {</span><br><span>             return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   topic_pool_entry->topic = stasis_topic_create(topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* To provide further detail and to ensure that the topic is unique within the scope of the</span><br><span style="color: hsl(120, 100%, 40%);">+    * system we prefix it with the pooling topic name, which should itself already be unique.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   ret = ast_asprintf(&new_topic_name, "%s/%s", stasis_topic_name(pool->pool_topic), topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   topic_pool_entry->topic = stasis_topic_create(new_topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(new_topic_name);</span><br><span>    if (!topic_pool_entry->topic) {</span><br><span>           return NULL;</span><br><span>         }</span><br><span>@@ -2084,10 +2134,48 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Subscription statistics ao2 container sort function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param obj_left pointer to the (user-defined part) of an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param obj_right pointer to the (user-defined part) of an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param flags flags from ao2_callback()</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_POINTER - if set, 'obj_right', is an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval <0 if obj_left < obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval =0 if obj_left == obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval >0 if obj_left > obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int statistics_subscription_sort_cmp(const void *obj_left, const void *obj_right, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct stasis_subscription_statistics *statistics_left = obj_left;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct stasis_subscription_statistics *statistics_right = obj_right;</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *right_key = obj_right;</span><br><span style="color: hsl(120, 100%, 40%);">+    int cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+      case OBJ_POINTER:</span><br><span style="color: hsl(120, 100%, 40%);">+             right_key = statistics_right->uniqueid;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Fall through */</span><br><span style="color: hsl(120, 100%, 40%);">+    case OBJ_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+         cmp = strcmp(statistics_left->uniqueid, right_key);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OBJ_PARTIAL_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+         cmp = strncmp(statistics_left->uniqueid, right_key, strlen(right_key));</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span>  * \brief CLI command implementation for 'stasis statistics show subscriptions'</span><br><span>  */</span><br><span> static char *statistics_show_subscriptions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ao2_container *sorted_subscriptions;</span><br><span>  struct ao2_iterator iter;</span><br><span>    struct stasis_subscription_statistics *statistics;</span><br><span>   int count = 0;</span><br><span>@@ -2112,9 +2200,22 @@</span><br><span>              return CLI_SHOWUSAGE;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ sorted_subscriptions = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+               statistics_subscription_sort_cmp, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!sorted_subscriptions) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_cli(a->fd, "Could not create container for sorting subscription statistics\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ao2_container_dup(sorted_subscriptions, subscription_statistics, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ao2_ref(sorted_subscriptions, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_cli(a->fd, "Could not sort subscription statistics\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ast_cli(a->fd, "\n" FMT_HEADERS, "Subscription", "Dropped", "Passed", "Lowest Invoke", "Highest Invoke");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    iter = ao2_iterator_init(subscription_statistics, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ iter = ao2_iterator_init(sorted_subscriptions, 0);</span><br><span>   while ((statistics = ao2_iterator_next(&iter))) {</span><br><span>                ast_cli(a->fd, FMT_FIELDS, statistics->uniqueid, statistics->messages_dropped, statistics->messages_passed,</span><br><span>                      statistics->lowest_time_invoked, statistics->highest_time_invoked);</span><br><span>@@ -2125,6 +2226,8 @@</span><br><span>    }</span><br><span>    ao2_iterator_destroy(&iter);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_ref(sorted_subscriptions, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         ast_cli(a->fd, FMT_FIELDS2, "Total", dropped, passed);</span><br><span>  ast_cli(a->fd, "\n%d subscriptions\n\n", count);</span><br><span> </span><br><span>@@ -2169,6 +2272,8 @@</span><br><span> static char *statistics_show_subscription(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span>        struct stasis_subscription_statistics *statistics;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ao2_iterator i;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *name;</span><br><span> </span><br><span>      switch (cmd) {</span><br><span>       case CLI_INIT:</span><br><span>@@ -2196,7 +2301,7 @@</span><br><span>       }</span><br><span> </span><br><span>        ast_cli(a->fd, "Subscription: %s\n", statistics->uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">-     ast_cli(a->fd, "Topic: %s\n", statistics->topic);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_cli(a->fd, "Pointer Address: %p\n", statistics->sub);</span><br><span>    ast_cli(a->fd, "Source filename: %s\n", S_OR(statistics->file, "<unavailable>"));</span><br><span>    ast_cli(a->fd, "Source line number: %d\n", statistics->lineno);</span><br><span>      ast_cli(a->fd, "Source function: %s\n", S_OR(statistics->func, "<unavailable>"));</span><br><span>@@ -2213,6 +2318,16 @@</span><br><span>   }</span><br><span>    ao2_unlock(statistics);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "Number of topics: %d\n", ao2_container_count(statistics->topics));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_cli(a->fd, "Subscribed topics:\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  i = ao2_iterator_init(statistics->topics, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      while ((name = ao2_iterator_next(&i))) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_cli(a->fd, "\t%s\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_ref(name, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_iterator_destroy(&i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      ao2_ref(statistics, -1);</span><br><span> </span><br><span>         return CLI_SUCCESS;</span><br><span>@@ -2220,18 +2335,56 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Topic ao2 container sort function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param obj_left pointer to the (user-defined part) of an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param obj_right pointer to the (user-defined part) of an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param flags flags from ao2_callback()</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_POINTER - if set, 'obj_right', is an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval <0 if obj_left < obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval =0 if obj_left == obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval >0 if obj_left > obj_right</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int statistics_topic_sort_cmp(const void *obj_left, const void *obj_right, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct stasis_topic_statistics *topic_left = obj_left;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct stasis_topic_statistics *topic_right = obj_right;</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *right_key = obj_right;</span><br><span style="color: hsl(120, 100%, 40%);">+    int cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+      case OBJ_POINTER:</span><br><span style="color: hsl(120, 100%, 40%);">+             right_key = topic_right->name;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Fall through */</span><br><span style="color: hsl(120, 100%, 40%);">+    case OBJ_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+         cmp = strcmp(topic_left->name, right_key);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OBJ_PARTIAL_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+         cmp = strncmp(topic_left->name, right_key, strlen(right_key));</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span>  * \brief CLI command implementation for 'stasis statistics show topics'</span><br><span>  */</span><br><span> static char *statistics_show_topics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ao2_container *sorted_topics;</span><br><span>         struct ao2_iterator iter;</span><br><span>    struct stasis_topic_statistics *statistics;</span><br><span>  int count = 0;</span><br><span>       int not_dispatched = 0;</span><br><span>      int dispatched = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-#define FMT_HEADERS          "%-64s %10s %10s %16s %16s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-#define FMT_FIELDS               "%-64s %10d %10d %16ld %16ld\n"</span><br><span style="color: hsl(0, 100%, 40%);">-#define FMT_FIELDS2            "%-64s %10d %10d\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define FMT_HEADERS              "%-64s %10s %10s %10s %16s %16s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define FMT_FIELDS                "%-64s %10d %10d %10d %16ld %16ld\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define FMT_FIELDS2             "%-64s %10s %10d %10d\n"</span><br><span> </span><br><span>       switch (cmd) {</span><br><span>       case CLI_INIT:</span><br><span>@@ -2248,11 +2401,25 @@</span><br><span>             return CLI_SHOWUSAGE;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_cli(a->fd, "\n" FMT_HEADERS, "Topic", "Dropped", "Dispatched", "Lowest Dispatch", "Highest Dispatch");</span><br><span style="color: hsl(120, 100%, 40%);">+     sorted_topics = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+              statistics_topic_sort_cmp, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!sorted_topics) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_cli(a->fd, "Could not create container for sorting topic statistics\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   iter = ao2_iterator_init(topic_statistics, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ao2_container_dup(sorted_topics, topic_statistics, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_ref(sorted_topics, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_cli(a->fd, "Could not sort topic statistics\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "\n" FMT_HEADERS, "Topic", "Subscribers", "Dropped", "Dispatched", "Lowest Dispatch", "Highest Dispatch");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  iter = ao2_iterator_init(sorted_topics, 0);</span><br><span>  while ((statistics = ao2_iterator_next(&iter))) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_cli(a->fd, FMT_FIELDS, statistics->name, statistics->messages_not_dispatched, statistics->messages_dispatched,</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, FMT_FIELDS, statistics->name, ao2_container_count(statistics->subscribers),</span><br><span style="color: hsl(120, 100%, 40%);">+                   statistics->messages_not_dispatched, statistics->messages_dispatched,</span><br><span>                  statistics->lowest_time_dispatched, statistics->highest_time_dispatched);</span><br><span>              not_dispatched += statistics->messages_not_dispatched;</span><br><span>            dispatched += statistics->messages_dispatched;</span><br><span>@@ -2261,7 +2428,9 @@</span><br><span>    }</span><br><span>    ao2_iterator_destroy(&iter);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ast_cli(a->fd, FMT_FIELDS2, "Total", not_dispatched, dispatched);</span><br><span style="color: hsl(120, 100%, 40%);">+        ao2_ref(sorted_topics, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, FMT_FIELDS2, "Total", "", not_dispatched, dispatched);</span><br><span>         ast_cli(a->fd, "\n%d topics\n\n", count);</span><br><span> </span><br><span> #undef FMT_HEADERS</span><br><span>@@ -2334,6 +2503,7 @@</span><br><span>     }</span><br><span> </span><br><span>        ast_cli(a->fd, "Topic: %s\n", statistics->name);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_cli(a->fd, "Pointer Address: %p\n", statistics->topic);</span><br><span>  ast_cli(a->fd, "Number of messages published that went to no subscriber: %d\n", statistics->messages_not_dispatched);</span><br><span>        ast_cli(a->fd, "Number of messages that went to at least one subscriber: %d\n", statistics->messages_dispatched);</span><br><span>    ast_cli(a->fd, "Lowest amount of time (in milliseconds) spent dispatching message: %ld\n", statistics->lowest_time_dispatched);</span><br><span>diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c</span><br><span>index cfdf117..31d3eac 100644</span><br><span>--- a/main/stasis_bridges.c</span><br><span>+++ b/main/stasis_bridges.c</span><br><span>@@ -294,12 +294,21 @@</span><br><span> </span><br><span> int bridge_topics_init(struct ast_bridge *bridge)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        char *topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+     int ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   if (ast_strlen_zero(bridge->uniqueid)) {</span><br><span>          ast_log(LOG_ERROR, "Bridge id initialization required\n");</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bridge->topic = stasis_topic_pool_get_topic(bridge_topic_pool, bridge->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+       ret = ast_asprintf(&topic_name, "bridge:%s", bridge->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge->topic = stasis_topic_pool_get_topic(bridge_topic_pool, topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_free(topic_name);</span><br><span>        if (!bridge->topic) {</span><br><span>             return -1;</span><br><span>   }</span><br><span>@@ -1365,7 +1374,7 @@</span><br><span> </span><br><span>        ast_register_cleanup(stasis_bridging_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      bridge_topic_all = stasis_topic_create("ast_bridge_topic_all");</span><br><span style="color: hsl(120, 100%, 40%);">+     bridge_topic_all = stasis_topic_create("bridge:all");</span><br><span>      if (!bridge_topic_all) {</span><br><span>             return -1;</span><br><span>   }</span><br><span>diff --git a/main/stasis_cache.c b/main/stasis_cache.c</span><br><span>index ee8a1dd..6be4bf1 100644</span><br><span>--- a/main/stasis_cache.c</span><br><span>+++ b/main/stasis_cache.c</span><br><span>@@ -948,10 +948,11 @@</span><br><span> struct stasis_caching_topic *stasis_caching_topic_create(struct stasis_topic *original_topic, struct stasis_cache *cache)</span><br><span> {</span><br><span>         struct stasis_caching_topic *caching_topic;</span><br><span style="color: hsl(120, 100%, 40%);">+   static int caching_id;</span><br><span>       char *new_name;</span><br><span>      int ret;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ret = ast_asprintf(&new_name, "%s-cached", stasis_topic_name(original_topic));</span><br><span style="color: hsl(120, 100%, 40%);">+  ret = ast_asprintf(&new_name, "cache:%d/%s", ast_atomic_fetchadd_int(&caching_id, +1), stasis_topic_name(original_topic));</span><br><span>         if (ret < 0) {</span><br><span>            return NULL;</span><br><span>         }</span><br><span>diff --git a/main/stasis_cache_pattern.c b/main/stasis_cache_pattern.c</span><br><span>index 04d8164..463be69 100644</span><br><span>--- a/main/stasis_cache_pattern.c</span><br><span>+++ b/main/stasis_cache_pattern.c</span><br><span>@@ -67,13 +67,14 @@</span><br><span> {</span><br><span>        char *cached_name = NULL;</span><br><span>    struct stasis_cp_all *all;</span><br><span style="color: hsl(120, 100%, 40%);">+    static int cache_id;</span><br><span> </span><br><span>     all = ao2_t_alloc(sizeof(*all), all_dtor, name);</span><br><span>     if (!all) {</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_asprintf(&cached_name, "%s-cached", name);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_asprintf(&cached_name, "cache_pattern:%d/%s", ast_atomic_fetchadd_int(&cache_id, +1), name);</span><br><span>   if (!cached_name) {</span><br><span>          ao2_ref(all, -1);</span><br><span> </span><br><span>diff --git a/main/stasis_channels.c b/main/stasis_channels.c</span><br><span>index d39fb08..e8842c1 100644</span><br><span>--- a/main/stasis_channels.c</span><br><span>+++ b/main/stasis_channels.c</span><br><span>@@ -1658,7 +1658,7 @@</span><br><span> </span><br><span>       ast_register_cleanup(stasis_channels_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      channel_topic_all = stasis_topic_create("ast_channel_topic_all");</span><br><span style="color: hsl(120, 100%, 40%);">+   channel_topic_all = stasis_topic_create("channel:all");</span><br><span>    if (!channel_topic_all) {</span><br><span>            return -1;</span><br><span>   }</span><br><span>diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c</span><br><span>index b3a837b..289a90e 100644</span><br><span>--- a/main/stasis_endpoints.c</span><br><span>+++ b/main/stasis_endpoints.c</span><br><span>@@ -460,7 +460,7 @@</span><br><span>     int res = 0;</span><br><span>         ast_register_cleanup(endpoints_stasis_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     endpoint_cache_all = stasis_cp_all_create("endpoint_topic_all",</span><br><span style="color: hsl(120, 100%, 40%);">+     endpoint_cache_all = stasis_cp_all_create("endpoint:all",</span><br><span>          endpoint_snapshot_get_id);</span><br><span>   if (!endpoint_cache_all) {</span><br><span>           return -1;</span><br><span>diff --git a/main/stasis_system.c b/main/stasis_system.c</span><br><span>index 961a2b0..4c84f57 100644</span><br><span>--- a/main/stasis_system.c</span><br><span>+++ b/main/stasis_system.c</span><br><span>@@ -374,7 +374,7 @@</span><br><span> {</span><br><span>   ast_register_cleanup(stasis_system_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        system_topic = stasis_topic_create("ast_system");</span><br><span style="color: hsl(120, 100%, 40%);">+   system_topic = stasis_topic_create("system:all");</span><br><span>  if (!system_topic) {</span><br><span>                 return 1;</span><br><span>    }</span><br><span>diff --git a/main/test.c b/main/test.c</span><br><span>index 2abe698..32df829 100644</span><br><span>--- a/main/test.c</span><br><span>+++ b/main/test.c</span><br><span>@@ -1224,7 +1224,7 @@</span><br><span>   ast_register_cleanup(test_cleanup);</span><br><span> </span><br><span>      /* Create stasis topic */</span><br><span style="color: hsl(0, 100%, 40%);">-       test_suite_topic = stasis_topic_create("test_suite_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+ test_suite_topic = stasis_topic_create("testsuite:all");</span><br><span>   if (!test_suite_topic) {</span><br><span>             return -1;</span><br><span>   }</span><br><span>diff --git a/res/res_corosync.c b/res/res_corosync.c</span><br><span>index bf172e3..6e66c4f 100644</span><br><span>--- a/res/res_corosync.c</span><br><span>+++ b/res/res_corosync.c</span><br><span>@@ -1131,7 +1131,7 @@</span><br><span>               goto failed;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   corosync_aggregate_topic = stasis_topic_create("corosync_aggregate_topic");</span><br><span style="color: hsl(120, 100%, 40%);">+ corosync_aggregate_topic = stasis_topic_create("corosync:aggregator");</span><br><span>     if (!corosync_aggregate_topic) {</span><br><span>             ast_log(AST_LOG_ERROR, "Failed to create stasis topic for corosync\n");</span><br><span>            goto failed;</span><br><span>diff --git a/res/stasis/app.c b/res/stasis/app.c</span><br><span>index 0f0923a..a69ca55 100644</span><br><span>--- a/res/stasis/app.c</span><br><span>+++ b/res/stasis/app.c</span><br><span>@@ -919,6 +919,8 @@</span><br><span>      int res = 0;</span><br><span>         size_t context_size = strlen("stasis-") + strlen(name) + 1;</span><br><span>        char context_name[context_size];</span><br><span style="color: hsl(120, 100%, 40%);">+      char *topic_name;</span><br><span style="color: hsl(120, 100%, 40%);">+     int ret;</span><br><span> </span><br><span>         ast_assert(name != NULL);</span><br><span>    ast_assert(handler != NULL);</span><br><span>@@ -939,7 +941,13 @@</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   app->topic = stasis_topic_create(name);</span><br><span style="color: hsl(120, 100%, 40%);">+    ret = ast_asprintf(&topic_name, "ari:application/%s", name);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ret < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   app->topic = stasis_topic_create(topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(topic_name);</span><br><span>        if (!app->topic) {</span><br><span>                return NULL;</span><br><span>         }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11130">change 11130</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/11130"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I484e971a38c3640f2bd156282e532eed84bf220d </div>
<div style="display:none"> Gerrit-Change-Number: 11130 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua C. Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>