File 0001-db-list-speedup.patch of Package openstack-neutron

From 0125cc8183b8835a28122aa5f6c28d8d7796f82e Mon Sep 17 00:00:00 2001
From: Dirk Mueller <dirk@dmllr.de>
Date: Fri, 9 Nov 2018 14:45:42 +0100
Subject: [PATCH] Newton Backport of:

https://review.openstack.org/#/c/567603/6

Improve DbListCommand operation from O(n^2) to O(n)

Right now the DbListCommand retrieves the uuid's of all the elements
passed in as argument. This is an O(n^2) operation so when the number
of elements in a grows it's likely that we get Timeout Exceptions.

Instead of doing this, whenever possible, we'll retrieve all the
elements (from the in-memory replica) and only fetch those who were
passed as arguments avoiding the O(n^2) operation.

NOTE: this cherry pick conflicted because in stable/pike, the commands.py
file was in different location.

Closes-Bug: #1769897
(cherry picked from fd64d41ea6f208a5752fbcd45952a04633ee1392)
Signed-off-by: Daniel Alvarez <dalvarez@redhat.com>

Change-Id: I69ea39a259d83cdd8512e77314d752de771f6ee5
---
 neutron/agent/ovsdb/native/commands.py | 52 +++++++++++++++++---------
 1 file changed, 34 insertions(+), 18 deletions(-)

diff --git a/neutron/agent/ovsdb/native/commands.py b/neutron/agent/ovsdb/native/commands.py
index deb4cdbfe7..3db5a47ebe 100644
--- a/neutron/agent/ovsdb/native/commands.py
+++ b/neutron/agent/ovsdb/native/commands.py
@@ -473,37 +473,53 @@ class DbListCommand(BaseCommand):
 
     def run_idl(self, txn):
         table_schema = self.api._tables[self.table]
+        idx = idlutils.get_index_column(table_schema)
         columns = self.columns or list(table_schema.columns.keys()) + ['_uuid']
-        if self.records:
-            row_uuids = []
+        # If there's an index for this table, we'll fetch all columns and
+        # remove the unwanted ones based on self.records. Otherwise, let's try
+        # to get the uuid of the wanted ones which is an O(n^2) operation.
+        if not idx and self.records:
+            rows = []
             for record in self.records:
                 try:
-                    row_uuids.append(idlutils.row_by_record(
-                                     self.api.idl, self.table, record).uuid)
+                    rows.append(idlutils.row_by_record(
+                                self.api.idl, self.table, record))
                 except idlutils.RowNotFound:
                     if self.if_exists:
                         continue
-                    # NOTE(kevinbenton): this is converted to a RuntimeError
-                    # for compat with the vsctl version. It might make more
-                    # sense to change this to a RowNotFoundError in the future.
-                    raise RuntimeError(_(
-                          "Row doesn't exist in the DB. Request info: "
-                          "Table=%(table)s. Columns=%(columns)s. "
-                          "Records=%(records)s.") % {
-                              "table": self.table,
-                              "columns": self.columns,
-                              "records": self.records,
-                          })
+                    self._raise_notfound()
         else:
-            row_uuids = table_schema.rows.keys()
+            rows = table_schema.rows.values()
+
+        if idx and self.records:
+            match = lambda row: getattr(row, idx) in self.records
+        else:
+            match = lambda row: True
+
         self.result = [
             {
-                c: idlutils.get_column_value(table_schema.rows[uuid], c)
+                c: idlutils.get_column_value(row, c)
                 for c in columns
             }
-            for uuid in row_uuids
+            for row in rows if match(row)
         ]
 
+        if (not self.if_exists and idx and self.records and
+                len(self.result) < len(self.records)):
+            self._raise_notfound()
+
+    def _raise_notfound(self):
+        # NOTE(kevinbenton): this is converted to a RuntimeError
+        # for compat with the vsctl version. It might make more
+        # sense to change this to a RowNotFoundError in the future.
+        raise RuntimeError(
+            "Row doesn't exist in the DB. Request info: "
+            "Table=%(table)s. Columns=%(columns)s. "
+            "Records=%(records)s." % {
+                "table": self.table,
+                "columns": self.columns,
+                "records": self.records})
+
 
 class DbFindCommand(BaseCommand):
     def __init__(self, api, table, *conditions, **kwargs):
-- 
2.19.1

openSUSE Build Service is sponsored by