You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by gm...@apache.org on 2019/11/08 17:53:17 UTC

[qpid-dispatch] branch master updated: DISPATCH-1439 - Added two attributes to connection and one to router. 1. connection uptime - The number of seconds the connection has been up 2. connection last delivery seconds - The number of seconds since a delivery was sent on a connection 3. router uptime - the number of seconds since the router started

This is an automated email from the ASF dual-hosted git repository.

gmurthy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new bf6592f  DISPATCH-1439 - Added two attributes to connection and one to router. 1. connection uptime - The number of seconds the connection has been up 2. connection last delivery seconds - The number of seconds since a delivery was sent on a connection 3. router uptime - the number of seconds since the router started
bf6592f is described below

commit bf6592ffbbe742ce52c8c780baf1c07299e62dec
Author: Ganesh Murthy <gm...@apache.org>
AuthorDate: Wed Nov 6 16:13:44 2019 -0500

    DISPATCH-1439 - Added two attributes to connection and one to router.
    1. connection uptime - The number of seconds the connection has been up
    2. connection last delivery seconds - The number of seconds since a delivery was sent on a connection
    3. router uptime - the number of seconds since the router started
---
 docs/man/qdstat.8.adoc                         |   7 ++
 python/qpid_dispatch/management/qdrouter.json  |  19 ++++-
 python/qpid_dispatch_internal/tools/display.py |   9 ++-
 src/router_core/agent_connection.c             |  16 ++++
 src/router_core/agent_connection.h             |   2 +-
 src/router_core/agent_router.c                 |   6 ++
 src/router_core/agent_router.h                 |   2 +-
 src/router_core/connections.c                  |   1 +
 src/router_core/core_link_endpoint.c           |   3 +
 src/router_core/forwarder.c                    |   2 +
 src/router_core/router_core_private.h          |   2 +
 src/router_core/transfer.c                     |   2 +
 tests/system_tests_one_router.py               | 101 +++++++++++++++++++++++++
 tests/system_tests_qdstat.py                   |  18 +++++
 tools/qdstat.in                                |  33 ++++++++
 15 files changed, 218 insertions(+), 5 deletions(-)

diff --git a/docs/man/qdstat.8.adoc b/docs/man/qdstat.8.adoc
index caaed43..9f9b57a 100644
--- a/docs/man/qdstat.8.adoc
+++ b/docs/man/qdstat.8.adoc
@@ -73,6 +73,13 @@ The authentication method and user ID of the connection's authenticated user.
 tenant::
 If the connection is to a listener using multi-tenancy, this column displays the tenant namespace for the connection.
 
+last dlv::
+Time since the last delivery arrived on this connection. Displayed in the days:hours:minutes:seconds format.
+
+uptime::
+Time this connection has been up. Displayed in the days:hours:minutes:seconds format.
+
+
 qdstat -l
 ~~~~~~~~~
 type::
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index c862d8b..79c98cf 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -609,7 +609,12 @@
                     "type": "integer",
                     "description": "Number of deliveries that were sent to the fallback destination due to the primary destination being unreachable.",
                     "graph": true
-                }
+                },
+                "uptimeSeconds": {
+                    "type": "integer",
+                    "graph": true,
+                    "description": "The number of seconds since the router was started."
+                }                
             }
         },       
         "sslProfile": {
@@ -1772,10 +1777,20 @@
                     "description": "If multi-tenancy is on for this connection, the tenant space in effect",
                     "type": "string"
                 },
+                "uptimeSeconds": {
+                    "type": "integer",
+                    "graph": true,
+                    "description": "The number of seconds since the connection was created."
+                },                                
                 "properties": {
                     "description": "Connection properties supplied by the peer.",
                     "type": "map"
-                }
+                },
+                "lastDlvSeconds": {
+                    "type": "integer",
+                    "graph": true,
+                    "description": "The number of seconds since a delivery was sent on this connection. Will display a - (dash) if no deliveries have been sent on the connection."
+                }                
             }
         },
 
diff --git a/python/qpid_dispatch_internal/tools/display.py b/python/qpid_dispatch_internal/tools/display.py
index ead8077..2acb8b7 100644
--- a/python/qpid_dispatch_internal/tools/display.py
+++ b/python/qpid_dispatch_internal/tools/display.py
@@ -45,7 +45,14 @@ def Commas(value):
     sval = left
 
 def TimeLong(value):
-  return strftime("%c", gmtime(value / 1000000000))
+  day = value // (24 * 3600)
+  time = value % (24 * 3600)
+  hour = time // 3600
+  time %= 3600
+  minutes = time // 60
+  time %= 60
+  seconds = time
+  return "%03d:%02d:%02d:%02d" % (day, hour, minutes, seconds)
 
 def TimeShort(value):
   return strftime("%X", gmtime(value / 1000000000))
diff --git a/src/router_core/agent_connection.c b/src/router_core/agent_connection.c
index 488e450..dc26768 100644
--- a/src/router_core/agent_connection.c
+++ b/src/router_core/agent_connection.c
@@ -43,6 +43,8 @@
 #define QDR_CONNECTION_ACTIVE           18
 #define QDR_CONNECTION_ADMIN_STATUS     19
 #define QDR_CONNECTION_OPER_STATUS      20
+#define QDR_CONNECTION_UPTIME_SECONDS   21
+#define QDR_CONNECTION_LAST_DLV_SECONDS 22
 
 const char * const QDR_CONNECTION_DIR_IN  = "in";
 const char * const QDR_CONNECTION_DIR_OUT = "out";
@@ -83,6 +85,9 @@ const char *qdr_connection_columns[] =
      "active",
      "adminStatus",
      "operStatus",
+     "uptimeSeconds",
+     "lastDlvSeconds",
+
      0};
 
 const char *CONNECTION_TYPE = "org.apache.qpid.dispatch.connection";
@@ -240,6 +245,17 @@ static void qdr_connection_insert_column_CT(qdr_core_t *core, qdr_connection_t *
         qd_compose_insert_string(body, text);
         break;
 
+    case QDR_CONNECTION_UPTIME_SECONDS:
+        qd_compose_insert_uint(body, core->uptime_ticks - conn->conn_uptime);
+        break;
+
+    case QDR_CONNECTION_LAST_DLV_SECONDS:
+        if (conn->last_delivery_time==0)
+            qd_compose_insert_null(body);
+        else
+            qd_compose_insert_uint(body, core->uptime_ticks - conn->last_delivery_time);
+        break;
+
     case QDR_CONNECTION_PROPERTIES: {
         pn_data_t *data = conn->connection_info->connection_properties;
         qd_compose_start_map(body);
diff --git a/src/router_core/agent_connection.h b/src/router_core/agent_connection.h
index 0b764b1..247aaf5 100644
--- a/src/router_core/agent_connection.h
+++ b/src/router_core/agent_connection.h
@@ -35,7 +35,7 @@ void qdra_connection_update_CT(qdr_core_t      *core,
                              qdr_query_t       *query,
                              qd_parsed_field_t *in_body);
 
-#define QDR_CONNECTION_COLUMN_COUNT 21
+#define QDR_CONNECTION_COLUMN_COUNT 23
 const char *qdr_connection_columns[QDR_CONNECTION_COLUMN_COUNT + 1];
 
 #endif
diff --git a/src/router_core/agent_router.c b/src/router_core/agent_router.c
index b726686..15c7720 100644
--- a/src/router_core/agent_router.c
+++ b/src/router_core/agent_router.c
@@ -54,6 +54,7 @@
 #define QDR_ROUTER_DELIVERIES_EGRESS_ROUTE_CONTAINER   27
 #define QDR_ROUTER_DELIVERIES_REDIRECTED               28
 #define QDR_ROUTER_LINKS_BLOCKED                       29
+#define QDR_ROUTER_UPTIME_SECONDS                      30
 
 
 const char *qdr_router_columns[] =
@@ -87,6 +88,7 @@ const char *qdr_router_columns[] =
      "deliveriesEgressRouteContainer",
      "deliveriesRedirectedToFallback",
      "linksBlocked",
+     "uptimeSeconds",
      0};
 
 
@@ -233,6 +235,10 @@ static void qdr_agent_write_column_CT(qd_composed_field_t *body, int col, qdr_co
         qd_compose_insert_uint(body, core->links_blocked);
         break;
 
+    case QDR_ROUTER_UPTIME_SECONDS:
+        qd_compose_insert_uint(body, core->uptime_ticks);
+        break;
+
     default:
         qd_compose_insert_null(body);
         break;
diff --git a/src/router_core/agent_router.h b/src/router_core/agent_router.h
index 97452af..5246187 100644
--- a/src/router_core/agent_router.h
+++ b/src/router_core/agent_router.h
@@ -21,7 +21,7 @@
 
 #include "router_core_private.h"
 
-#define QDR_ROUTER_COLUMN_COUNT  30
+#define QDR_ROUTER_COLUMN_COUNT  31
 
 const char *qdr_router_columns[QDR_ROUTER_COLUMN_COUNT + 1];
 
diff --git a/src/router_core/connections.c b/src/router_core/connections.c
index 984a7c2..3594b7e 100644
--- a/src/router_core/connections.c
+++ b/src/router_core/connections.c
@@ -106,6 +106,7 @@ qdr_connection_t *qdr_connection_opened(qdr_core_t            *core,
     DEQ_INIT(conn->work_list);
     conn->connection_info->role = conn->role;
     conn->work_lock = sys_mutex();
+    conn->conn_uptime = core->uptime_ticks;
 
     if (vhost) {
         conn->tenant_space_len = strlen(vhost) + 1;
diff --git a/src/router_core/core_link_endpoint.c b/src/router_core/core_link_endpoint.c
index 268887d..e48b80e 100644
--- a/src/router_core/core_link_endpoint.c
+++ b/src/router_core/core_link_endpoint.c
@@ -133,6 +133,9 @@ qdr_delivery_t *qdrc_endpoint_delivery_CT(qdr_core_t *core, qdrc_endpoint_t *end
     qdr_delivery_t *dlv = new_qdr_delivery_t();
     uint64_t       *tag = (uint64_t*) dlv->tag;
 
+    if (endpoint->link->conn)
+        endpoint->link->conn->last_delivery_time = core->uptime_ticks;
+
     ZERO(dlv);
     set_safe_ptr_qdr_link_t(endpoint->link, &dlv->link_sp);
     dlv->msg            = message;
diff --git a/src/router_core/forwarder.c b/src/router_core/forwarder.c
index b33772a..04575f3 100644
--- a/src/router_core/forwarder.c
+++ b/src/router_core/forwarder.c
@@ -116,6 +116,8 @@ qdr_delivery_t *qdr_forward_new_delivery_CT(qdr_core_t *core, qdr_delivery_t *in
 {
     qdr_delivery_t *out_dlv = new_qdr_delivery_t();
     uint64_t       *tag = (uint64_t*) out_dlv->tag;
+    if (link->conn)
+        link->conn->last_delivery_time = core->uptime_ticks;
 
     ZERO(out_dlv);
     set_safe_ptr_qdr_link_t(link, &out_dlv->link_sp);
diff --git a/src/router_core/router_core_private.h b/src/router_core/router_core_private.h
index 17256a5..4106db1 100644
--- a/src/router_core/router_core_private.h
+++ b/src/router_core/router_core_private.h
@@ -659,6 +659,8 @@ struct qdr_connection_t {
     qdr_conn_admin_status_t     admin_status;
     qdr_error_t                *error;
     bool                        closed; // This bit is used in the case where a client is trying to force close this connection.
+    uint32_t                    conn_uptime; // Timestamp which can be used to calculate the number of seconds this connection has been up and running.
+    uint32_t                    last_delivery_time; // Timestamp which can be used to calculate the number of seconds since the last delivery arrived on this connection.
 };
 
 DEQ_DECLARE(qdr_connection_t, qdr_connection_list_t);
diff --git a/src/router_core/transfer.c b/src/router_core/transfer.c
index 175eba2..58ad85e 100644
--- a/src/router_core/transfer.c
+++ b/src/router_core/transfer.c
@@ -639,6 +639,8 @@ static void qdr_link_deliver_CT(qdr_core_t *core, qdr_action_t *action, bool dis
 
     if (!link)
         return;
+    if (link->conn)
+        link->conn->last_delivery_time = core->uptime_ticks;
 
     //
     // Record the ingress time so we can track the age of this delivery.
diff --git a/tests/system_tests_one_router.py b/tests/system_tests_one_router.py
index 1840229..5578e20 100644
--- a/tests/system_tests_one_router.py
+++ b/tests/system_tests_one_router.py
@@ -502,6 +502,11 @@ class OneRouterTest(TestCase):
         test.run()
         self.assertEqual(None, test.error)
 
+    def test_48_connection_uptime_last_dlv(self):
+        test = ConnectionUptimeLastDlvTest(self.address, "test_48")
+        test.run()
+        self.assertEqual(None, test.error)
+
 
 class Entity(object):
     def __init__(self, status_code, status_description, attrs):
@@ -2684,6 +2689,102 @@ class MulticastUnsettledNoReceiverTest(MessagingHandler):
         Container(self).run()
 
 
+class UptimeLastDlvChecker(object):
+    def __init__(self, parent, lastDlv=None, uptime=0):
+        self.parent = parent
+        self.uptime = uptime
+        self.lastDlv = lastDlv
+        self.expected_num_connections = 2
+        self.num_connections = 0
+
+    def on_timer_task(self, event):
+        local_node = Node.connect(self.parent.address, timeout=TIMEOUT)
+        result = local_node.query('org.apache.qpid.dispatch.connection')
+        container_id_index = result.attribute_names.index('container')
+        uptime_seconds_index = result.attribute_names.index('uptimeSeconds')
+        last_dlv_seconds_index = result.attribute_names.index('lastDlvSeconds')
+
+        for res in result.results:
+            container_id = res[container_id_index]
+
+            # We only care if the container_id is "UPTIME-TEST"
+            if container_id == self.parent.container_id:
+                uptime_seconds = res[uptime_seconds_index]
+                if self.uptime != 0 and uptime_seconds < self.uptime:
+                    self.parent.error = "The connection uptime should be greater than or equal to %d seconds but instead is %d seconds" % (self.uptime, uptime_seconds)
+                last_dlv_seconds = res[last_dlv_seconds_index]
+                if self.lastDlv == '-':
+                    if last_dlv_seconds != self.lastDlv:
+                        self.parent.error = "Expected lastDlvSeconds to be empty"
+                else:
+                    if not last_dlv_seconds >= self.lastDlv:
+                        self.parent.error = "Connection lastDeliverySeconds must be greater than or equal to $d but is %d" % (self.lastDlv, last_dlv_seconds)
+                    else:
+                        self.parent.success = True
+                self.num_connections += 1
+
+        if self.expected_num_connections != self.num_connections:
+            self.parent.error = "Number of client connections expected=%d, but got %d" % (self.expected_num_connections, self.num_connections)
+
+        self.parent.cancel_custom()
+
+
+class ConnectionUptimeLastDlvTest(MessagingHandler):
+    def __init__(self, address, dest):
+        super(ConnectionUptimeLastDlvTest, self).__init__()
+        self.timer = None
+        self.sender_conn = None
+        self.receiver_conn = None
+        self.address = address
+        self.sender = None
+        self.receiver = None
+        self.error = None
+        self.custom_timer = None
+        self.container_id = "UPTIME-TEST"
+        self.dest = dest
+        self.reactor = None
+        self.success = False
+
+    def cancel_custom(self):
+        self.custom_timer.cancel()
+        if self.error or self.success:
+            self.timer.cancel()
+            self.sender_conn.close()
+            self.receiver_conn.close()
+        else:
+            msg = Message(body=self.container_id)
+            self.sender.send(msg)
+
+            # We have now sent a message that the router must have sent to the
+            # receiver. We will wait for 2 seconds and once again check
+            # uptime and lastDlv
+            self.custom_timer = self.reactor.schedule(2, UptimeLastDlvChecker(self, uptime=7, lastDlv=2))
+
+    def timeout(self):
+        self.error = "Timeout Expired:, Test took too long to execute. "
+        self.sender_conn.close()
+        self.receiver_conn.close()
+
+    def on_start(self, event):
+        self.timer = event.reactor.schedule(TIMEOUT, Timeout(self))
+        self.sender_conn = event.container.connect(self.address)
+        self.receiver_conn = event.container.connect(self.address)
+
+        # Let's create a sender and receiver but not send any messages.
+        self.sender = event.container.create_sender(self.sender_conn, self.dest)
+        self.receiver = event.container.create_receiver(self.receiver_conn, self.dest)
+
+        # Execute a management query for connections after 5 seconds
+        # This will help us check the uptime and lastDlv time
+        # No deliveries were sent on any link yet, so the lastDlv must be "-"
+        self.reactor = event.reactor
+        self.custom_timer = event.reactor.schedule(5, UptimeLastDlvChecker(self, uptime=5, lastDlv=None))
+
+    def run(self):
+        container = Container(self)
+        container.container_id = self.container_id
+        container.run()
+
 class AnonymousSenderNoRecvLargeMessagedTest(MessagingHandler):
     def __init__(self, address):
         super(AnonymousSenderNoRecvLargeMessagedTest, self).__init__(auto_accept=False)
diff --git a/tests/system_tests_qdstat.py b/tests/system_tests_qdstat.py
index 2147263..9bee375 100644
--- a/tests/system_tests_qdstat.py
+++ b/tests/system_tests_qdstat.py
@@ -109,6 +109,7 @@ class QdstatTest(system_test.TestCase):
         self.assertTrue("Deliveries to Fallback" in outs)
         self.assertTrue("Egress Count" in outs)
         self.assertTrue("Ingress Count" in outs)
+        self.assertTrue("Uptime" in outs)
 
     def test_address_priority(self):
         out = self.run_qdstat(['--address'])
@@ -256,9 +257,26 @@ class QdstatTest(system_test.TestCase):
         self.assertEqual(sender_addresses, COUNT)
         self.assertEqual(receiver_addresses, COUNT)
 
+        # Test if there is a non-zero uptime for the router in the output of
+        # qdstat -g
+        non_zero_seconds = False
+        outs = self.run_qdstat(args=None)
+        parts = outs.split("\n")
+        for part in parts:
+            if "Uptime" in part:
+                uptime_parts = part.split(" ")
+                for uptime_part in uptime_parts:
+                    if uptime_part.startswith("000"):
+                        time_parts = uptime_part.split(":")
+                        if int(time_parts[3]) > 0:
+                            non_zero_seconds = True
+        self.assertTrue(non_zero_seconds)
+
         c.close()
 
 
+
+
 class QdstatLinkPriorityTest(system_test.TestCase):
     """Need 2 routers to get inter-router links for the link priority test"""
     @classmethod
diff --git a/tools/qdstat.in b/tools/qdstat.in
index 267237f..e9bd2f5 100755
--- a/tools/qdstat.in
+++ b/tools/qdstat.in
@@ -200,6 +200,28 @@ class BusManager(Node):
         if show_date_id:
             self.display_datetime_router_id()
 
+        has_uptime = False
+        has_last_dlv = False
+
+        if objects:
+            first_conn = objects[0]
+            try:
+                lastDlvSeconds = first_conn.lastDlvSeconds
+                has_last_dlv = True
+            except:
+                pass
+            try:
+                uptime = first_conn.uptimeSeconds
+                has_uptime = True
+            except:
+                pass
+
+        # This is so that, this qdstat can be used against older routers without Python keyerrors
+        if has_last_dlv:
+            heads.append(Header("last dlv"))
+        if has_uptime:
+            heads.append(Header("uptime"))
+
         for conn in objects:
             row = []
             row.append(conn.identity)
@@ -210,6 +232,13 @@ class BusManager(Node):
             row.append(self.connSecurity(conn))
             row.append(self.connAuth(conn))
             row.append(self.noTrailingSlash(get(conn, 'tenant')))
+            if has_last_dlv:
+                if conn.lastDlvSeconds is None:
+                    row.append('-')
+                else:
+                    row.append(TimeLong(conn.lastDlvSeconds))
+            if has_uptime:
+                row.append(TimeLong(conn.uptimeSeconds))
             rows.append(row)
         title = "Connections"
         dispRows = rows
@@ -291,6 +320,10 @@ class BusManager(Node):
         rows.append(('Version',       router.version))
         rows.append(('Mode',          router.mode))
         rows.append(('Router Id',     router.id))
+        try:
+            rows.append(('Uptime',        TimeLong(router.uptimeSeconds)))
+        except:
+            pass
         rows.append(('Area',          router.area))
         rows.append(('Link Routes',   router.linkRouteCount))
         rows.append(('Auto Links',    router.autoLinkCount))


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org