bridge: Rate limit the statistics update.
authorAlex Wang <alexw@nicira.com>
Thu, 18 Sep 2014 21:10:24 +0000 (14:10 -0700)
committerAlex Wang <alexw@nicira.com>
Tue, 23 Sep 2014 22:57:46 +0000 (15:57 -0700)
When ovs is running with large topology (e.g. large number of
interfaces), the stats update to ovsdb becomes huge and normally
requires multiple run of ovsdb jsonrpc message processing loop to
consume.

To prevent the periodic stats update from backlogging in the
jsonrpc sending queue, this commit adds rate limiting logic
which only allows new update if the previous one is done.

Signed-off-by: Alex Wang <alexw@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
Acked-by: Flavio Leitner <fbl@redhat.com>
vswitchd/bridge.c

index 5dcd3ba..656182f 100644 (file)
@@ -191,6 +191,10 @@ static bool force_status_commit = true;
 static int stats_timer_interval;
 static long long int stats_timer = LLONG_MIN;
 
+/* Current stats database transaction, NULL if there is no ongoing
+ * transaction. */
+static struct ovsdb_idl_txn *stats_txn;
+
 /* In some datapaths, creating and destroying OpenFlow ports can be extremely
  * expensive.  This can cause bridge_reconfigure() to take a long time during
  * which no other work can be done.  To deal with this problem, we limit port
@@ -2386,35 +2390,39 @@ bridge_run(void)
 
     /* Refresh interface and mirror stats if necessary. */
     if (time_msec() >= stats_timer) {
-        if (cfg) {
-            struct ovsdb_idl_txn *txn;
-
-            txn = ovsdb_idl_txn_create(idl);
-            HMAP_FOR_EACH (br, node, &all_bridges) {
-                struct port *port;
-                struct mirror *m;
-
-                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
-                    struct iface *iface;
+        enum ovsdb_idl_txn_status status;
 
-                    LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-                        iface_refresh_stats(iface);
+        /* Rate limit the update.  Do not start a new update if the
+         * previous one is not done. */
+        if (!stats_txn) {
+            if (cfg) {
+                stats_txn = ovsdb_idl_txn_create(idl);
+                HMAP_FOR_EACH (br, node, &all_bridges) {
+                    struct port *port;
+                    struct mirror *m;
+
+                    HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+                        struct iface *iface;
+
+                        LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+                            iface_refresh_stats(iface);
+                        }
+                        port_refresh_stp_stats(port);
+                    }
+                    HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
+                        mirror_refresh_stats(m);
                     }
-
-                    port_refresh_stp_stats(port);
-                }
-
-                HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
-                    mirror_refresh_stats(m);
                 }
-
+                refresh_controller_status();
             }
-            refresh_controller_status();
-            ovsdb_idl_txn_commit(txn);
-            ovsdb_idl_txn_destroy(txn); /* XXX */
         }
 
-        stats_timer = time_msec() + stats_timer_interval;
+        status = ovsdb_idl_txn_commit(stats_txn);
+        if (status != TXN_INCOMPLETE) {
+            stats_timer = time_msec() + stats_timer_interval;
+            ovsdb_idl_txn_destroy(stats_txn);
+            stats_txn = NULL;
+        }
     }
 
     if (!status_txn) {